Skip to content
Open
60 changes: 45 additions & 15 deletions compiler/rustc_codegen_cranelift/src/global_asm.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
//! The AOT driver uses [`cranelift_object`] to write object files suitable for linking into a
//! standalone executable.

use std::fmt::Write as _;
use std::io::Write;
use std::path::PathBuf;
use std::process::{Command, Stdio};
use std::sync::Arc;

use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
use rustc_codegen_ssa::traits::{AsmCodegenMethods, GlobalAsmOperandRef};
use rustc_middle::mir::interpret::{GlobalAlloc, PointerArithmetic, Scalar as ConstScalar};
use rustc_middle::ty::TyCtxt;
use rustc_middle::ty::layout::{
FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasTyCtxt, HasTypingEnv, LayoutError, LayoutOfHelpers,
Expand Down Expand Up @@ -107,21 +109,50 @@ 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 } => {
global_asm.push_str(string);
}
GlobalAsmOperandRef::SymFn { instance } => {
if cfg!(not(feature = "inline_asm_sym")) {
tcx.dcx().span_err(
span,
"asm! and global_asm! sym operands are not yet supported",
);
}
GlobalAsmOperandRef::Const { value, ty, instance: _ } => {
match value {
ConstScalar::Int(int) => {
let string = rustc_codegen_ssa::common::asm_const_to_str(
tcx,
int,
FullyMonomorphizedLayoutCx(tcx).layout_of(ty),
);
global_asm.push_str(&string);
}

let symbol = tcx.symbol_name(instance);
// FIXME handle the case where the function was made private to the
// current codegen unit
global_asm.push_str(symbol.name);
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",
);
}

// FIXME handle the case where the function was made private to the
// current codegen unit
tcx.symbol_name(instance)
}
GlobalAlloc::Static(def_id) => {
let instance = Instance::mono(tcx, def_id);
tcx.symbol_name(instance)
}
GlobalAlloc::Memory(_)
| GlobalAlloc::VTable(..)
| GlobalAlloc::TypeId { .. } => unreachable!(),
};

global_asm.push_str(symbol_name.name);

if offset != Size::ZERO {
let offset = tcx.sign_extend_to_target_isize(offset.bytes());
write!(global_asm, "{offset:+}").unwrap();
}
}
}
}
GlobalAsmOperandRef::SymStatic { def_id } => {
if cfg!(not(feature = "inline_asm_sym")) {
Expand All @@ -130,7 +161,6 @@ fn codegen_global_asm_inner<'tcx>(
"asm! and global_asm! sym operands are not yet supported",
);
}

let instance = Instance::mono(tcx, def_id);
let symbol = tcx.symbol_name(instance);
global_asm.push_str(symbol.name);
Expand Down
11 changes: 9 additions & 2 deletions compiler/rustc_codegen_cranelift/src/inline_asm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,17 @@ pub(crate) fn codegen_inline_asm_terminator<'tcx>(
}
InlineAsmOperand::Const { ref value } => {
let (const_value, ty) = crate::constant::eval_mir_constant(fx, value);
let mir::ConstValue::Scalar(scalar) = const_value else {
span_bug!(
span,
"expected Scalar for promoted asm const, but got {:#?}",
const_value
)
};

let value = rustc_codegen_ssa::common::asm_const_to_str(
fx.tcx,
span,
const_value,
scalar.assert_scalar_int(),
fx.layout_of(ty),
);
CInlineAsmOperand::Const { value }
Expand Down
146 changes: 96 additions & 50 deletions compiler/rustc_codegen_gcc/src/asm.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
// cSpell:ignoreRegExp [afkspqvwy]reg

use std::borrow::Cow;
use std::fmt::Write;

use gccjit::{LValue, RValue, ToRValue, Type};
use rustc_abi::Size;
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,
ConstCodegenMethods, GlobalAsmOperandRef, InlineAsmOperandRef,
};
use rustc_middle::bug;
use rustc_middle::mir::interpret::{GlobalAlloc, PointerArithmetic, Scalar};
use rustc_middle::ty::Instance;
use rustc_middle::ty::layout::LayoutOf;
use rustc_span::Span;
use rustc_target::asm::*;

Expand Down Expand Up @@ -143,6 +147,9 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
// Clobbers collected from `out("explicit register") _` and `inout("explicit_reg") var => _`
let mut clobbers = vec![];

// Symbols name that needs to be inserted to asm const ptr template string.
let mut const_syms = vec![];

// We're trying to preallocate space for the template
let mut constants_len = 0;

Expand Down Expand Up @@ -303,16 +310,11 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
}
}

InlineAsmOperandRef::Const { ref string } => {
constants_len += string.len() + att_dialect as usize;
InlineAsmOperandRef::Const { .. } => {
// We don't know the size at this point, just some estimate.
constants_len += 20;
}

InlineAsmOperandRef::SymFn { instance } => {
// TODO(@Amanieu): Additional mangling is needed on
// some targets to add a leading underscore (Mach-O)
// or byte count suffixes (x86 Windows).
constants_len += self.tcx.symbol_name(instance).name.len();
}
InlineAsmOperandRef::SymStatic { def_id } => {
// TODO(@Amanieu): Additional mangling is needed on
// some targets to add a leading underscore (Mach-O).
Expand Down Expand Up @@ -402,24 +404,22 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
// processed in the previous pass
}

InlineAsmOperandRef::SymFn { instance } => {
inputs.push(AsmInOperand {
constraint: "X".into(),
rust_idx,
val: get_fn(self.cx, instance).get_address(None),
});
}
InlineAsmOperandRef::Const { value, ty: _, instance } => match value {
Scalar::Int(_) => (),
Scalar::Ptr(ptr, _) => {
let (prov, _) = ptr.prov_and_relative_offset();
let global_alloc = self.tcx.global_alloc(prov.alloc_id());
let (val, sym) = self.cx.alloc_to_backend(global_alloc, instance).unwrap();
const_syms.push(sym.unwrap());
inputs.push(AsmInOperand { constraint: "X".into(), rust_idx, val });
}
},

InlineAsmOperandRef::SymStatic { def_id } => {
inputs.push(AsmInOperand {
constraint: "X".into(),
rust_idx,
val: self.cx.get_static(def_id).get_address(None),
});
}

InlineAsmOperandRef::Const { .. } => {
// processed in the previous pass
// TODO(@Amanieu): Additional mangling is needed on
// some targets to add a leading underscore (MachO).
constants_len +=
self.tcx.symbol_name(Instance::mono(self.tcx, def_id)).name.len();
}

InlineAsmOperandRef::Label { .. } => {
Expand Down Expand Up @@ -495,12 +495,33 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
push_to_template(modifier, gcc_index);
}

InlineAsmOperandRef::SymFn { instance } => {
// 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);
InlineAsmOperandRef::Const { value, ty, instance: _ } => {
match value {
Scalar::Int(int) => {
// Const operands get injected directly into the template
let string = rustc_codegen_ssa::common::asm_const_to_str(
self.tcx,
int,
self.layout_of(ty),
);
template_str.push_str(&string);
}

Scalar::Ptr(ptr, _) => {
let (_, offset) = ptr.prov_and_relative_offset();
let instance = const_syms.remove(0);
// TODO(@Amanieu): Additional mangling is needed on
// some targets to add a leading underscore (Mach-O)
// or byte count suffixes (x86 Windows).
template_str.push_str(self.tcx.symbol_name(instance).name);

if offset != Size::ZERO {
let offset =
self.sign_extend_to_target_isize(offset.bytes());
write!(template_str, "{offset:+}").unwrap();
}
}
}
}

InlineAsmOperandRef::SymStatic { def_id } => {
Expand All @@ -511,10 +532,6 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
template_str.push_str(name);
}

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

InlineAsmOperandRef::Label { label } => {
let label_gcc_index =
labels.iter().position(|&l| l == label).expect("wrong rust index");
Expand Down Expand Up @@ -893,23 +910,52 @@ 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::Const { value, ty, instance } => {
match value {
Scalar::Int(int) => {
// Const operands get injected directly into the
// template. Note that we don't need to escape %
// here unlike normal inline assembly.
let string = rustc_codegen_ssa::common::asm_const_to_str(
self.tcx,
int,
self.layout_of(ty),
);
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);
Scalar::Ptr(ptr, _) => {
let (prov, offset) = ptr.prov_and_relative_offset();
let global_alloc = self.tcx.global_alloc(prov.alloc_id());
let symbol_name = match global_alloc {
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).
self.tcx.symbol_name(instance)
}
_ => {
let (_, syms) = self
.alloc_to_backend(global_alloc, instance)
.unwrap();
// TODO(antoyo): set the global variable as used.
// TODO(@Amanieu): Additional mangling is needed on
// some targets to add a leading underscore (Mach-O).
self.tcx.symbol_name(syms.unwrap())
}
};
template_str.push_str(symbol_name.name);

if offset != Size::ZERO {
let offset =
self.sign_extend_to_target_isize(offset.bytes());
write!(template_str, "{offset:+}").unwrap();
}
}
}
}

GlobalAsmOperandRef::SymStatic { def_id } => {
// TODO(antoyo): set the global variable as used.
// TODO(@Amanieu): Additional mangling is needed on
Expand Down
Loading
Loading