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
10 changes: 8 additions & 2 deletions compiler/rustc_codegen_cranelift/src/global_asm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ use std::sync::Arc;

use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
use rustc_codegen_ssa::traits::{AsmCodegenMethods, GlobalAsmOperandRef};
use rustc_middle::ty::TyCtxt;
use rustc_middle::ty::layout::{
FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasTyCtxt, HasTypingEnv, LayoutError, LayoutOfHelpers,
};
use rustc_middle::ty::{Instance, TyCtxt};
use rustc_session::config::{OutputFilenames, OutputType};
use rustc_target::asm::InlineAsmArch;

Expand Down Expand Up @@ -107,7 +107,7 @@ fn codegen_global_asm_inner<'tcx>(
InlineAsmTemplatePiece::String(ref s) => global_asm.push_str(s),
InlineAsmTemplatePiece::Placeholder { operand_idx, modifier: _, span } => {
match operands[operand_idx] {
GlobalAsmOperandRef::Const { ref string } => {
GlobalAsmOperandRef::Interpolate { ref string } => {
global_asm.push_str(string);
}
GlobalAsmOperandRef::SymFn { instance } => {
Expand Down Expand Up @@ -135,6 +135,12 @@ fn codegen_global_asm_inner<'tcx>(
let symbol = tcx.symbol_name(instance);
global_asm.push_str(symbol.name);
}
GlobalAsmOperandRef::ConstPointer { value: _, instance: _ } => {
tcx.dcx().span_err(
span,
"asm! and global_asm! const pointer operands are not yet supported",
);
}
}
}
}
Expand Down
151 changes: 120 additions & 31 deletions compiler/rustc_codegen_gcc/src/asm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@

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 @@ -303,10 +303,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("is"),
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 @@ -418,6 +426,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 @@ -495,6 +507,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 @@ -511,7 +532,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 @@ -869,6 +890,100 @@ 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()
.map(|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.prov_and_relative_offset();
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,
mir::interpret::GlobalAlloc::TypeId { .. } => {
// This is not an actual allocation, just return the offset.
return format!("{}", offset.bytes());
}
};

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

let sym_name = self.tcx.symbol_name(instance).to_string();

let init = crate::consts::const_alloc_to_gcc_uncached(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 }
Copy link
Contributor

Choose a reason for hiding this comment

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

What about negative offset? Should it be symbol-offset instead of the current symbol+-offset?

Copy link
Member Author

Choose a reason for hiding this comment

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

Hmm, offset is unsigned, so I elected to just emit +{offset}. If the offset is negative, CTFE will just produce 2's complement values as unsigned (which is okay for the wrapping semantics, and note that you have to use wrapping semantics to get pointer out of bound in the first place).

Assemblers seem to be happy with +0xFFFFFFFFFFFFFFFF instead of -1; do you think it's worth changing the generated code so we always treat offset as signed?

Copy link
Contributor

Choose a reason for hiding this comment

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

IMO -1 seems a lot safer than +0xFFFFFFFFFFFFFFFF since we don't have to worry about the bitwidth of the addition.

}
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 @@ -892,33 +1007,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