Use cg_ssa's version of codegen_naked_asm in cg_clif
This commit is contained in:
@@ -8,8 +8,6 @@ use rustc_ast::InlineAsmOptions;
|
|||||||
use rustc_codegen_ssa::base::is_call_from_compiler_builtins_to_upstream_monomorphization;
|
use rustc_codegen_ssa::base::is_call_from_compiler_builtins_to_upstream_monomorphization;
|
||||||
use rustc_data_structures::profiling::SelfProfilerRef;
|
use rustc_data_structures::profiling::SelfProfilerRef;
|
||||||
use rustc_index::IndexVec;
|
use rustc_index::IndexVec;
|
||||||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
|
||||||
use rustc_middle::mir::InlineAsmMacro;
|
|
||||||
use rustc_middle::ty::TypeVisitableExt;
|
use rustc_middle::ty::TypeVisitableExt;
|
||||||
use rustc_middle::ty::adjustment::PointerCoercion;
|
use rustc_middle::ty::adjustment::PointerCoercion;
|
||||||
use rustc_middle::ty::layout::{FnAbiOf, HasTypingEnv};
|
use rustc_middle::ty::layout::{FnAbiOf, HasTypingEnv};
|
||||||
@@ -18,7 +16,6 @@ use rustc_middle::ty::print::with_no_trimmed_paths;
|
|||||||
use crate::constant::ConstantCx;
|
use crate::constant::ConstantCx;
|
||||||
use crate::debuginfo::{FunctionDebugContext, TypeDebugContext};
|
use crate::debuginfo::{FunctionDebugContext, TypeDebugContext};
|
||||||
use crate::enable_verifier;
|
use crate::enable_verifier;
|
||||||
use crate::inline_asm::codegen_naked_asm;
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::pretty_clif::CommentWriter;
|
use crate::pretty_clif::CommentWriter;
|
||||||
|
|
||||||
@@ -37,7 +34,7 @@ pub(crate) fn codegen_fn<'tcx>(
|
|||||||
cached_func: Function,
|
cached_func: Function,
|
||||||
module: &mut dyn Module,
|
module: &mut dyn Module,
|
||||||
instance: Instance<'tcx>,
|
instance: Instance<'tcx>,
|
||||||
) -> Option<CodegenedFunction> {
|
) -> CodegenedFunction {
|
||||||
debug_assert!(!instance.args.has_infer());
|
debug_assert!(!instance.args.has_infer());
|
||||||
|
|
||||||
let symbol_name = tcx.symbol_name(instance).name.to_string();
|
let symbol_name = tcx.symbol_name(instance).name.to_string();
|
||||||
@@ -54,38 +51,6 @@ pub(crate) fn codegen_fn<'tcx>(
|
|||||||
String::from_utf8_lossy(&buf).into_owned()
|
String::from_utf8_lossy(&buf).into_owned()
|
||||||
});
|
});
|
||||||
|
|
||||||
if tcx.codegen_fn_attrs(instance.def_id()).flags.contains(CodegenFnAttrFlags::NAKED) {
|
|
||||||
assert_eq!(mir.basic_blocks.len(), 1);
|
|
||||||
assert!(mir.basic_blocks[START_BLOCK].statements.is_empty());
|
|
||||||
|
|
||||||
match &mir.basic_blocks[START_BLOCK].terminator().kind {
|
|
||||||
TerminatorKind::InlineAsm {
|
|
||||||
asm_macro: InlineAsmMacro::NakedAsm,
|
|
||||||
template,
|
|
||||||
operands,
|
|
||||||
options,
|
|
||||||
line_spans: _,
|
|
||||||
targets: _,
|
|
||||||
unwind: _,
|
|
||||||
} => {
|
|
||||||
codegen_naked_asm(
|
|
||||||
tcx,
|
|
||||||
cx,
|
|
||||||
module,
|
|
||||||
instance,
|
|
||||||
mir.basic_blocks[START_BLOCK].terminator().source_info.span,
|
|
||||||
&symbol_name,
|
|
||||||
template,
|
|
||||||
operands,
|
|
||||||
*options,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Declare function
|
// Declare function
|
||||||
let sig = get_function_sig(tcx, module.target_config().default_call_conv, instance);
|
let sig = get_function_sig(tcx, module.target_config().default_call_conv, instance);
|
||||||
let func_id = module.declare_function(&symbol_name, Linkage::Local, &sig).unwrap();
|
let func_id = module.declare_function(&symbol_name, Linkage::Local, &sig).unwrap();
|
||||||
@@ -166,7 +131,7 @@ pub(crate) fn codegen_fn<'tcx>(
|
|||||||
// Verify function
|
// Verify function
|
||||||
verify_func(tcx, &clif_comments, &func);
|
verify_func(tcx, &clif_comments, &func);
|
||||||
|
|
||||||
Some(CodegenedFunction { symbol_name, func_id, func, clif_comments, func_debug_cx })
|
CodegenedFunction { symbol_name, func_id, func, clif_comments, func_debug_cx }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn compile_fn(
|
pub(crate) fn compile_fn(
|
||||||
|
|||||||
@@ -22,7 +22,10 @@ use rustc_data_structures::sync::{IntoDynSyncSend, par_map};
|
|||||||
use rustc_metadata::EncodedMetadata;
|
use rustc_metadata::EncodedMetadata;
|
||||||
use rustc_metadata::fs::copy_to_stdout;
|
use rustc_metadata::fs::copy_to_stdout;
|
||||||
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
|
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
|
||||||
use rustc_middle::mir::mono::{CodegenUnit, MonoItem};
|
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
||||||
|
use rustc_middle::mir::mono::{
|
||||||
|
CodegenUnit, Linkage as RLinkage, MonoItem, MonoItemData, Visibility,
|
||||||
|
};
|
||||||
use rustc_session::Session;
|
use rustc_session::Session;
|
||||||
use rustc_session::config::{DebugInfo, OutFileName, OutputFilenames, OutputType};
|
use rustc_session::config::{DebugInfo, OutFileName, OutputFilenames, OutputType};
|
||||||
|
|
||||||
@@ -30,7 +33,7 @@ use crate::CodegenCx;
|
|||||||
use crate::base::CodegenedFunction;
|
use crate::base::CodegenedFunction;
|
||||||
use crate::concurrency_limiter::{ConcurrencyLimiter, ConcurrencyLimiterToken};
|
use crate::concurrency_limiter::{ConcurrencyLimiter, ConcurrencyLimiterToken};
|
||||||
use crate::debuginfo::TypeDebugContext;
|
use crate::debuginfo::TypeDebugContext;
|
||||||
use crate::global_asm::GlobalAsmConfig;
|
use crate::global_asm::{GlobalAsmConfig, GlobalAsmContext};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::unwind_module::UnwindModule;
|
use crate::unwind_module::UnwindModule;
|
||||||
|
|
||||||
@@ -530,19 +533,35 @@ fn codegen_cgu_content(
|
|||||||
let mut type_dbg = TypeDebugContext::default();
|
let mut type_dbg = TypeDebugContext::default();
|
||||||
super::predefine_mono_items(tcx, module, &mono_items);
|
super::predefine_mono_items(tcx, module, &mono_items);
|
||||||
let mut codegened_functions = vec![];
|
let mut codegened_functions = vec![];
|
||||||
for (mono_item, _) in mono_items {
|
for (mono_item, item_data) in mono_items {
|
||||||
match mono_item {
|
match mono_item {
|
||||||
MonoItem::Fn(inst) => {
|
MonoItem::Fn(instance) => {
|
||||||
if let Some(codegened_function) = crate::base::codegen_fn(
|
if tcx.codegen_fn_attrs(instance.def_id()).flags.contains(CodegenFnAttrFlags::NAKED)
|
||||||
|
{
|
||||||
|
rustc_codegen_ssa::mir::naked_asm::codegen_naked_asm(
|
||||||
|
&mut GlobalAsmContext { tcx, global_asm: &mut cx.global_asm },
|
||||||
|
instance,
|
||||||
|
MonoItemData {
|
||||||
|
linkage: RLinkage::External,
|
||||||
|
visibility: if item_data.linkage == RLinkage::Internal {
|
||||||
|
Visibility::Hidden
|
||||||
|
} else {
|
||||||
|
item_data.visibility
|
||||||
|
},
|
||||||
|
..item_data
|
||||||
|
},
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let codegened_function = crate::base::codegen_fn(
|
||||||
tcx,
|
tcx,
|
||||||
&mut cx,
|
&mut cx,
|
||||||
&mut type_dbg,
|
&mut type_dbg,
|
||||||
Function::new(),
|
Function::new(),
|
||||||
module,
|
module,
|
||||||
inst,
|
instance,
|
||||||
) {
|
);
|
||||||
codegened_functions.push(codegened_function);
|
codegened_functions.push(codegened_function);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
MonoItem::Static(def_id) => {
|
MonoItem::Static(def_id) => {
|
||||||
let data_id = crate::constant::codegen_static(tcx, module, def_id);
|
let data_id = crate::constant::codegen_static(tcx, module, def_id);
|
||||||
|
|||||||
@@ -126,6 +126,11 @@ pub(crate) fn codegen_and_compile_fn<'tcx>(
|
|||||||
module: &mut dyn Module,
|
module: &mut dyn Module,
|
||||||
instance: Instance<'tcx>,
|
instance: Instance<'tcx>,
|
||||||
) {
|
) {
|
||||||
|
if tcx.codegen_fn_attrs(instance.def_id()).flags.contains(CodegenFnAttrFlags::NAKED) {
|
||||||
|
tcx.dcx()
|
||||||
|
.span_fatal(tcx.def_span(instance.def_id()), "Naked asm is not supported in JIT mode");
|
||||||
|
}
|
||||||
|
|
||||||
cranelift_codegen::timing::set_thread_profiler(Box::new(super::MeasuremeProfiler(
|
cranelift_codegen::timing::set_thread_profiler(Box::new(super::MeasuremeProfiler(
|
||||||
tcx.prof.clone(),
|
tcx.prof.clone(),
|
||||||
)));
|
)));
|
||||||
@@ -135,16 +140,15 @@ pub(crate) fn codegen_and_compile_fn<'tcx>(
|
|||||||
crate::PrintOnPanic(|| format!("{:?} {}", instance, tcx.symbol_name(instance).name));
|
crate::PrintOnPanic(|| format!("{:?} {}", instance, tcx.symbol_name(instance).name));
|
||||||
|
|
||||||
let cached_func = std::mem::replace(&mut cached_context.func, Function::new());
|
let cached_func = std::mem::replace(&mut cached_context.func, Function::new());
|
||||||
if let Some(codegened_func) = crate::base::codegen_fn(
|
let codegened_func = crate::base::codegen_fn(
|
||||||
tcx,
|
tcx,
|
||||||
cx,
|
cx,
|
||||||
&mut TypeDebugContext::default(),
|
&mut TypeDebugContext::default(),
|
||||||
cached_func,
|
cached_func,
|
||||||
module,
|
module,
|
||||||
instance,
|
instance,
|
||||||
) {
|
);
|
||||||
crate::base::compile_fn(cx, &tcx.prof, cached_context, module, codegened_func);
|
crate::base::compile_fn(cx, &tcx.prof, cached_context, module, codegened_func);
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,102 +7,206 @@ use std::process::{Command, Stdio};
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
|
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
|
||||||
|
use rustc_codegen_ssa::traits::{AsmCodegenMethods, GlobalAsmOperandRef};
|
||||||
use rustc_hir::{InlineAsmOperand, ItemId};
|
use rustc_hir::{InlineAsmOperand, ItemId};
|
||||||
use rustc_middle::mir::interpret::ErrorHandled;
|
use rustc_middle::mir::interpret::ErrorHandled;
|
||||||
|
use rustc_middle::ty::TyCtxt;
|
||||||
|
use rustc_middle::ty::layout::{
|
||||||
|
FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasTyCtxt, HasTypingEnv, LayoutError, LayoutOfHelpers,
|
||||||
|
};
|
||||||
use rustc_session::config::{OutputFilenames, OutputType};
|
use rustc_session::config::{OutputFilenames, OutputType};
|
||||||
use rustc_target::asm::InlineAsmArch;
|
use rustc_target::asm::InlineAsmArch;
|
||||||
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
pub(crate) struct GlobalAsmContext<'a, 'tcx> {
|
||||||
|
pub tcx: TyCtxt<'tcx>,
|
||||||
|
pub global_asm: &'a mut String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> AsmCodegenMethods<'tcx> for GlobalAsmContext<'_, 'tcx> {
|
||||||
|
fn codegen_global_asm(
|
||||||
|
&mut self,
|
||||||
|
template: &[InlineAsmTemplatePiece],
|
||||||
|
operands: &[GlobalAsmOperandRef<'tcx>],
|
||||||
|
options: InlineAsmOptions,
|
||||||
|
_line_spans: &[Span],
|
||||||
|
) {
|
||||||
|
codegen_global_asm_inner(self.tcx, self.global_asm, template, operands, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mangled_name(&self, instance: Instance<'tcx>) -> String {
|
||||||
|
self.tcx.symbol_name(instance).name.to_owned()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> LayoutOfHelpers<'tcx> for GlobalAsmContext<'_, 'tcx> {
|
||||||
|
#[inline]
|
||||||
|
fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
|
||||||
|
if let LayoutError::SizeOverflow(_) | LayoutError::ReferencesError(_) = err {
|
||||||
|
self.tcx.sess.dcx().span_fatal(span, err.to_string())
|
||||||
|
} else {
|
||||||
|
self.tcx
|
||||||
|
.sess
|
||||||
|
.dcx()
|
||||||
|
.span_fatal(span, format!("failed to get layout for `{}`: {}", ty, err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> FnAbiOfHelpers<'tcx> for GlobalAsmContext<'_, 'tcx> {
|
||||||
|
#[inline]
|
||||||
|
fn handle_fn_abi_err(
|
||||||
|
&self,
|
||||||
|
err: FnAbiError<'tcx>,
|
||||||
|
span: Span,
|
||||||
|
fn_abi_request: FnAbiRequest<'tcx>,
|
||||||
|
) -> ! {
|
||||||
|
FullyMonomorphizedLayoutCx(self.tcx).handle_fn_abi_err(err, span, fn_abi_request)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> HasTyCtxt<'tcx> for GlobalAsmContext<'_, 'tcx> {
|
||||||
|
fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
|
||||||
|
self.tcx
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> rustc_abi::HasDataLayout for GlobalAsmContext<'_, 'tcx> {
|
||||||
|
fn data_layout(&self) -> &rustc_abi::TargetDataLayout {
|
||||||
|
&self.tcx.data_layout
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> HasTypingEnv<'tcx> for GlobalAsmContext<'_, 'tcx> {
|
||||||
|
fn typing_env(&self) -> ty::TypingEnv<'tcx> {
|
||||||
|
ty::TypingEnv::fully_monomorphized()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn codegen_global_asm_item(tcx: TyCtxt<'_>, global_asm: &mut String, item_id: ItemId) {
|
pub(crate) fn codegen_global_asm_item(tcx: TyCtxt<'_>, global_asm: &mut String, item_id: ItemId) {
|
||||||
let item = tcx.hir_item(item_id);
|
let item = tcx.hir_item(item_id);
|
||||||
if let rustc_hir::ItemKind::GlobalAsm { asm, .. } = item.kind {
|
let rustc_hir::ItemKind::GlobalAsm { asm, .. } = item.kind else {
|
||||||
let is_x86 =
|
bug!("Expected GlobalAsm found {:?}", item);
|
||||||
matches!(tcx.sess.asm_arch.unwrap(), InlineAsmArch::X86 | InlineAsmArch::X86_64);
|
};
|
||||||
|
|
||||||
if is_x86 {
|
// Adapted from rustc_codegen_ssa::mono_items::MonoItem::define
|
||||||
if !asm.options.contains(InlineAsmOptions::ATT_SYNTAX) {
|
let operands: Vec<_> = asm
|
||||||
global_asm.push_str("\n.intel_syntax noprefix\n");
|
.operands
|
||||||
} else {
|
.iter()
|
||||||
global_asm.push_str("\n.att_syntax\n");
|
.map(|(op, op_sp)| match *op {
|
||||||
|
InlineAsmOperand::Const { ref anon_const } => {
|
||||||
|
match tcx.const_eval_poly(anon_const.def_id.to_def_id()) {
|
||||||
|
Ok(const_value) => {
|
||||||
|
let ty = tcx.typeck_body(anon_const.body).node_type(anon_const.hir_id);
|
||||||
|
let string = rustc_codegen_ssa::common::asm_const_to_str(
|
||||||
|
tcx,
|
||||||
|
*op_sp,
|
||||||
|
const_value,
|
||||||
|
FullyMonomorphizedLayoutCx(tcx).layout_of(ty),
|
||||||
|
);
|
||||||
|
GlobalAsmOperandRef::Const { string }
|
||||||
|
}
|
||||||
|
Err(ErrorHandled::Reported { .. }) => {
|
||||||
|
// An error has already been reported and
|
||||||
|
// compilation is guaranteed to fail if execution
|
||||||
|
// hits this path. So an empty string instead of
|
||||||
|
// a stringified constant value will suffice.
|
||||||
|
GlobalAsmOperandRef::Const { string: String::new() }
|
||||||
|
}
|
||||||
|
Err(ErrorHandled::TooGeneric(_)) => {
|
||||||
|
span_bug!(*op_sp, "asm const cannot be resolved; too generic")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
InlineAsmOperand::SymFn { expr } => {
|
||||||
|
if cfg!(not(feature = "inline_asm_sym")) {
|
||||||
|
tcx.dcx().span_err(
|
||||||
|
item.span,
|
||||||
|
"asm! and global_asm! sym operands are not yet supported",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let ty = tcx.typeck(item_id.owner_id).expr_ty(expr);
|
||||||
|
let instance = match ty.kind() {
|
||||||
|
&ty::FnDef(def_id, args) => Instance::new(def_id, args),
|
||||||
|
_ => span_bug!(*op_sp, "asm sym is not a function"),
|
||||||
|
};
|
||||||
|
GlobalAsmOperandRef::SymFn { instance }
|
||||||
|
}
|
||||||
|
InlineAsmOperand::SymStatic { path: _, def_id } => {
|
||||||
|
GlobalAsmOperandRef::SymStatic { def_id }
|
||||||
|
}
|
||||||
|
InlineAsmOperand::In { .. }
|
||||||
|
| InlineAsmOperand::Out { .. }
|
||||||
|
| InlineAsmOperand::InOut { .. }
|
||||||
|
| InlineAsmOperand::SplitInOut { .. }
|
||||||
|
| InlineAsmOperand::Label { .. } => {
|
||||||
|
span_bug!(*op_sp, "invalid operand type for global_asm!")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
codegen_global_asm_inner(tcx, global_asm, asm.template, &operands, asm.options);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn codegen_global_asm_inner<'tcx>(
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
global_asm: &mut String,
|
||||||
|
template: &[InlineAsmTemplatePiece],
|
||||||
|
operands: &[GlobalAsmOperandRef<'tcx>],
|
||||||
|
options: InlineAsmOptions,
|
||||||
|
) {
|
||||||
|
let is_x86 = matches!(tcx.sess.asm_arch.unwrap(), InlineAsmArch::X86 | InlineAsmArch::X86_64);
|
||||||
|
|
||||||
|
if is_x86 {
|
||||||
|
if !options.contains(InlineAsmOptions::ATT_SYNTAX) {
|
||||||
|
global_asm.push_str("\n.intel_syntax noprefix\n");
|
||||||
|
} else {
|
||||||
|
global_asm.push_str("\n.att_syntax\n");
|
||||||
}
|
}
|
||||||
for piece in asm.template {
|
}
|
||||||
match *piece {
|
for piece in template {
|
||||||
InlineAsmTemplatePiece::String(ref s) => global_asm.push_str(s),
|
match *piece {
|
||||||
InlineAsmTemplatePiece::Placeholder { operand_idx, modifier: _, span: op_sp } => {
|
InlineAsmTemplatePiece::String(ref s) => global_asm.push_str(s),
|
||||||
match asm.operands[operand_idx].0 {
|
InlineAsmTemplatePiece::Placeholder { operand_idx, modifier: _, span } => {
|
||||||
InlineAsmOperand::Const { ref anon_const } => {
|
match operands[operand_idx] {
|
||||||
match tcx.const_eval_poly(anon_const.def_id.to_def_id()) {
|
GlobalAsmOperandRef::Const { ref string } => {
|
||||||
Ok(const_value) => {
|
global_asm.push_str(string);
|
||||||
let ty = tcx
|
}
|
||||||
.typeck_body(anon_const.body)
|
GlobalAsmOperandRef::SymFn { instance } => {
|
||||||
.node_type(anon_const.hir_id);
|
if cfg!(not(feature = "inline_asm_sym")) {
|
||||||
let string = rustc_codegen_ssa::common::asm_const_to_str(
|
tcx.dcx().span_err(
|
||||||
tcx,
|
span,
|
||||||
op_sp,
|
"asm! and global_asm! sym operands are not yet supported",
|
||||||
const_value,
|
);
|
||||||
FullyMonomorphizedLayoutCx(tcx).layout_of(ty),
|
|
||||||
);
|
|
||||||
global_asm.push_str(&string);
|
|
||||||
}
|
|
||||||
Err(ErrorHandled::Reported { .. }) => {
|
|
||||||
// An error has already been reported and compilation is
|
|
||||||
// guaranteed to fail if execution hits this path.
|
|
||||||
}
|
|
||||||
Err(ErrorHandled::TooGeneric(_)) => {
|
|
||||||
span_bug!(op_sp, "asm const cannot be resolved; too generic");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
InlineAsmOperand::SymFn { expr } => {
|
|
||||||
if cfg!(not(feature = "inline_asm_sym")) {
|
|
||||||
tcx.dcx().span_err(
|
|
||||||
item.span,
|
|
||||||
"asm! and global_asm! sym operands are not yet supported",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let ty = tcx.typeck(item_id.owner_id).expr_ty(expr);
|
let symbol = tcx.symbol_name(instance);
|
||||||
let instance = match ty.kind() {
|
// FIXME handle the case where the function was made private to the
|
||||||
&ty::FnDef(def_id, args) => Instance::new(def_id, args),
|
// current codegen unit
|
||||||
_ => span_bug!(op_sp, "asm sym is not a function"),
|
global_asm.push_str(symbol.name);
|
||||||
};
|
}
|
||||||
let symbol = tcx.symbol_name(instance);
|
GlobalAsmOperandRef::SymStatic { def_id } => {
|
||||||
// FIXME handle the case where the function was made private to the
|
if cfg!(not(feature = "inline_asm_sym")) {
|
||||||
// current codegen unit
|
tcx.dcx().span_err(
|
||||||
global_asm.push_str(symbol.name);
|
span,
|
||||||
|
"asm! and global_asm! sym operands are not yet supported",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
InlineAsmOperand::SymStatic { path: _, def_id } => {
|
|
||||||
if cfg!(not(feature = "inline_asm_sym")) {
|
|
||||||
tcx.dcx().span_err(
|
|
||||||
item.span,
|
|
||||||
"asm! and global_asm! sym operands are not yet supported",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let instance = Instance::mono(tcx, def_id);
|
let instance = Instance::mono(tcx, def_id);
|
||||||
let symbol = tcx.symbol_name(instance);
|
let symbol = tcx.symbol_name(instance);
|
||||||
global_asm.push_str(symbol.name);
|
global_asm.push_str(symbol.name);
|
||||||
}
|
|
||||||
InlineAsmOperand::In { .. }
|
|
||||||
| InlineAsmOperand::Out { .. }
|
|
||||||
| InlineAsmOperand::InOut { .. }
|
|
||||||
| InlineAsmOperand::SplitInOut { .. }
|
|
||||||
| InlineAsmOperand::Label { .. } => {
|
|
||||||
span_bug!(op_sp, "invalid operand type for global_asm!")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
global_asm.push('\n');
|
global_asm.push('\n');
|
||||||
if is_x86 {
|
if is_x86 {
|
||||||
global_asm.push_str(".att_syntax\n\n");
|
global_asm.push_str(".att_syntax\n\n");
|
||||||
}
|
|
||||||
} else {
|
|
||||||
bug!("Expected GlobalAsm found {:?}", item);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -161,7 +161,6 @@ pub(crate) fn codegen_inline_asm_inner<'tcx>(
|
|||||||
stack_slots_input: Vec::new(),
|
stack_slots_input: Vec::new(),
|
||||||
stack_slots_output: Vec::new(),
|
stack_slots_output: Vec::new(),
|
||||||
stack_slot_size: Size::from_bytes(0),
|
stack_slot_size: Size::from_bytes(0),
|
||||||
is_naked: false,
|
|
||||||
};
|
};
|
||||||
asm_gen.allocate_registers();
|
asm_gen.allocate_registers();
|
||||||
asm_gen.allocate_stack_slots();
|
asm_gen.allocate_stack_slots();
|
||||||
@@ -201,114 +200,6 @@ pub(crate) fn codegen_inline_asm_inner<'tcx>(
|
|||||||
call_inline_asm(fx, &asm_name, asm_gen.stack_slot_size, inputs, outputs);
|
call_inline_asm(fx, &asm_name, asm_gen.stack_slot_size, inputs, outputs);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn codegen_naked_asm<'tcx>(
|
|
||||||
tcx: TyCtxt<'tcx>,
|
|
||||||
cx: &mut crate::CodegenCx,
|
|
||||||
module: &mut dyn Module,
|
|
||||||
instance: Instance<'tcx>,
|
|
||||||
span: Span,
|
|
||||||
symbol_name: &str,
|
|
||||||
template: &[InlineAsmTemplatePiece],
|
|
||||||
operands: &[InlineAsmOperand<'tcx>],
|
|
||||||
options: InlineAsmOptions,
|
|
||||||
) {
|
|
||||||
// FIXME add .eh_frame unwind info directives
|
|
||||||
|
|
||||||
let operands = operands
|
|
||||||
.iter()
|
|
||||||
.map(|operand| match *operand {
|
|
||||||
InlineAsmOperand::In { .. }
|
|
||||||
| InlineAsmOperand::Out { .. }
|
|
||||||
| InlineAsmOperand::InOut { .. } => {
|
|
||||||
span_bug!(span, "invalid operand type for naked asm")
|
|
||||||
}
|
|
||||||
InlineAsmOperand::Const { ref value } => {
|
|
||||||
let cv = instance.instantiate_mir_and_normalize_erasing_regions(
|
|
||||||
tcx,
|
|
||||||
ty::TypingEnv::fully_monomorphized(),
|
|
||||||
ty::EarlyBinder::bind(value.const_),
|
|
||||||
);
|
|
||||||
let const_value = cv
|
|
||||||
.eval(tcx, ty::TypingEnv::fully_monomorphized(), value.span)
|
|
||||||
.expect("erroneous constant missed by mono item collection");
|
|
||||||
|
|
||||||
let value = rustc_codegen_ssa::common::asm_const_to_str(
|
|
||||||
tcx,
|
|
||||||
span,
|
|
||||||
const_value,
|
|
||||||
FullyMonomorphizedLayoutCx(tcx).layout_of(cv.ty()),
|
|
||||||
);
|
|
||||||
CInlineAsmOperand::Const { value }
|
|
||||||
}
|
|
||||||
InlineAsmOperand::SymFn { ref value } => {
|
|
||||||
if cfg!(not(feature = "inline_asm_sym")) {
|
|
||||||
tcx.dcx()
|
|
||||||
.span_err(span, "asm! and global_asm! sym operands are not yet supported");
|
|
||||||
}
|
|
||||||
|
|
||||||
let const_ = instance.instantiate_mir_and_normalize_erasing_regions(
|
|
||||||
tcx,
|
|
||||||
ty::TypingEnv::fully_monomorphized(),
|
|
||||||
ty::EarlyBinder::bind(value.const_),
|
|
||||||
);
|
|
||||||
if let ty::FnDef(def_id, args) = *const_.ty().kind() {
|
|
||||||
let instance = ty::Instance::resolve_for_fn_ptr(
|
|
||||||
tcx,
|
|
||||||
ty::TypingEnv::fully_monomorphized(),
|
|
||||||
def_id,
|
|
||||||
args,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
let symbol = tcx.symbol_name(instance);
|
|
||||||
|
|
||||||
// Pass a wrapper rather than the function itself as the function itself may not
|
|
||||||
// be exported from the main codegen unit and may thus be unreachable from the
|
|
||||||
// object file created by an external assembler.
|
|
||||||
let wrapper_name = format!(
|
|
||||||
"__inline_asm_{}_wrapper_n{}",
|
|
||||||
cx.cgu_name.as_str().replace('.', "__").replace('-', "_"),
|
|
||||||
cx.inline_asm_index
|
|
||||||
);
|
|
||||||
cx.inline_asm_index += 1;
|
|
||||||
let sig =
|
|
||||||
get_function_sig(tcx, module.target_config().default_call_conv, instance);
|
|
||||||
create_wrapper_function(module, sig, &wrapper_name, symbol.name);
|
|
||||||
|
|
||||||
CInlineAsmOperand::Symbol { symbol: wrapper_name }
|
|
||||||
} else {
|
|
||||||
span_bug!(span, "invalid type for asm sym (fn)");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
InlineAsmOperand::SymStatic { def_id } => {
|
|
||||||
assert!(tcx.is_static(def_id));
|
|
||||||
let instance = Instance::mono(tcx, def_id);
|
|
||||||
CInlineAsmOperand::Symbol { symbol: tcx.symbol_name(instance).name.to_owned() }
|
|
||||||
}
|
|
||||||
InlineAsmOperand::Label { .. } => {
|
|
||||||
span_bug!(span, "asm! label operands are not yet supported");
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let asm_gen = InlineAssemblyGenerator {
|
|
||||||
tcx,
|
|
||||||
arch: tcx.sess.asm_arch.unwrap(),
|
|
||||||
enclosing_def_id: instance.def_id(),
|
|
||||||
template,
|
|
||||||
operands: &operands,
|
|
||||||
options,
|
|
||||||
registers: Vec::new(),
|
|
||||||
stack_slots_clobber: Vec::new(),
|
|
||||||
stack_slots_input: Vec::new(),
|
|
||||||
stack_slots_output: Vec::new(),
|
|
||||||
stack_slot_size: Size::from_bytes(0),
|
|
||||||
is_naked: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
let generated_asm = asm_gen.generate_asm_wrapper(symbol_name);
|
|
||||||
cx.global_asm.push_str(&generated_asm);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct InlineAssemblyGenerator<'a, 'tcx> {
|
struct InlineAssemblyGenerator<'a, 'tcx> {
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
arch: InlineAsmArch,
|
arch: InlineAsmArch,
|
||||||
@@ -321,13 +212,10 @@ struct InlineAssemblyGenerator<'a, 'tcx> {
|
|||||||
stack_slots_input: Vec<Option<Size>>,
|
stack_slots_input: Vec<Option<Size>>,
|
||||||
stack_slots_output: Vec<Option<Size>>,
|
stack_slots_output: Vec<Option<Size>>,
|
||||||
stack_slot_size: Size,
|
stack_slot_size: Size,
|
||||||
is_naked: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> {
|
impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> {
|
||||||
fn allocate_registers(&mut self) {
|
fn allocate_registers(&mut self) {
|
||||||
assert!(!self.is_naked);
|
|
||||||
|
|
||||||
let sess = self.tcx.sess;
|
let sess = self.tcx.sess;
|
||||||
let map = allocatable_registers(
|
let map = allocatable_registers(
|
||||||
self.arch,
|
self.arch,
|
||||||
@@ -451,8 +339,6 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn allocate_stack_slots(&mut self) {
|
fn allocate_stack_slots(&mut self) {
|
||||||
assert!(!self.is_naked);
|
|
||||||
|
|
||||||
let mut slot_size = Size::from_bytes(0);
|
let mut slot_size = Size::from_bytes(0);
|
||||||
let mut slots_clobber = vec![None; self.operands.len()];
|
let mut slots_clobber = vec![None; self.operands.len()];
|
||||||
let mut slots_input = vec![None; self.operands.len()];
|
let mut slots_input = vec![None; self.operands.len()];
|
||||||
@@ -582,32 +468,31 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> {
|
|||||||
if is_x86 {
|
if is_x86 {
|
||||||
generated_asm.push_str(".intel_syntax noprefix\n");
|
generated_asm.push_str(".intel_syntax noprefix\n");
|
||||||
}
|
}
|
||||||
if !self.is_naked {
|
|
||||||
Self::prologue(&mut generated_asm, self.arch);
|
|
||||||
|
|
||||||
// Save clobbered registers
|
Self::prologue(&mut generated_asm, self.arch);
|
||||||
if !self.options.contains(InlineAsmOptions::NORETURN) {
|
|
||||||
for (reg, slot) in self
|
|
||||||
.registers
|
|
||||||
.iter()
|
|
||||||
.zip(self.stack_slots_clobber.iter().copied())
|
|
||||||
.filter_map(|(r, s)| r.zip(s))
|
|
||||||
{
|
|
||||||
Self::save_register(&mut generated_asm, self.arch, reg, slot);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write input registers
|
// Save clobbered registers
|
||||||
|
if !self.options.contains(InlineAsmOptions::NORETURN) {
|
||||||
for (reg, slot) in self
|
for (reg, slot) in self
|
||||||
.registers
|
.registers
|
||||||
.iter()
|
.iter()
|
||||||
.zip(self.stack_slots_input.iter().copied())
|
.zip(self.stack_slots_clobber.iter().copied())
|
||||||
.filter_map(|(r, s)| r.zip(s))
|
.filter_map(|(r, s)| r.zip(s))
|
||||||
{
|
{
|
||||||
Self::restore_register(&mut generated_asm, self.arch, reg, slot);
|
Self::save_register(&mut generated_asm, self.arch, reg, slot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Write input registers
|
||||||
|
for (reg, slot) in self
|
||||||
|
.registers
|
||||||
|
.iter()
|
||||||
|
.zip(self.stack_slots_input.iter().copied())
|
||||||
|
.filter_map(|(r, s)| r.zip(s))
|
||||||
|
{
|
||||||
|
Self::restore_register(&mut generated_asm, self.arch, reg, slot);
|
||||||
|
}
|
||||||
|
|
||||||
if is_x86 && self.options.contains(InlineAsmOptions::ATT_SYNTAX) {
|
if is_x86 && self.options.contains(InlineAsmOptions::ATT_SYNTAX) {
|
||||||
generated_asm.push_str(".att_syntax\n");
|
generated_asm.push_str(".att_syntax\n");
|
||||||
}
|
}
|
||||||
@@ -701,32 +586,30 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> {
|
|||||||
generated_asm.push_str(".intel_syntax noprefix\n");
|
generated_asm.push_str(".intel_syntax noprefix\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if !self.is_naked {
|
if !self.options.contains(InlineAsmOptions::NORETURN) {
|
||||||
if !self.options.contains(InlineAsmOptions::NORETURN) {
|
// Read output registers
|
||||||
// Read output registers
|
for (reg, slot) in self
|
||||||
for (reg, slot) in self
|
.registers
|
||||||
.registers
|
.iter()
|
||||||
.iter()
|
.zip(self.stack_slots_output.iter().copied())
|
||||||
.zip(self.stack_slots_output.iter().copied())
|
.filter_map(|(r, s)| r.zip(s))
|
||||||
.filter_map(|(r, s)| r.zip(s))
|
{
|
||||||
{
|
Self::save_register(&mut generated_asm, self.arch, reg, slot);
|
||||||
Self::save_register(&mut generated_asm, self.arch, reg, slot);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Restore clobbered registers
|
|
||||||
for (reg, slot) in self
|
|
||||||
.registers
|
|
||||||
.iter()
|
|
||||||
.zip(self.stack_slots_clobber.iter().copied())
|
|
||||||
.filter_map(|(r, s)| r.zip(s))
|
|
||||||
{
|
|
||||||
Self::restore_register(&mut generated_asm, self.arch, reg, slot);
|
|
||||||
}
|
|
||||||
|
|
||||||
Self::epilogue(&mut generated_asm, self.arch);
|
|
||||||
} else {
|
|
||||||
Self::epilogue_noreturn(&mut generated_asm, self.arch);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Restore clobbered registers
|
||||||
|
for (reg, slot) in self
|
||||||
|
.registers
|
||||||
|
.iter()
|
||||||
|
.zip(self.stack_slots_clobber.iter().copied())
|
||||||
|
.filter_map(|(r, s)| r.zip(s))
|
||||||
|
{
|
||||||
|
Self::restore_register(&mut generated_asm, self.arch, reg, slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
Self::epilogue(&mut generated_asm, self.arch);
|
||||||
|
} else {
|
||||||
|
Self::epilogue_noreturn(&mut generated_asm, self.arch);
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_x86 {
|
if is_x86 {
|
||||||
|
|||||||
Reference in New Issue
Block a user