Auto merge of #140914 - Zalathar:asm-bindings, r=compiler-errors
cg_llvm: Clean up some inline assembly bindings This PR combines a few loosely-related cleanups to LLVM bindings related to inline assembly. These include: - Replacing `LLVMRustInlineAsm` with LLVM-C's `LLVMGetInlineAsm` - Adjusting FFI declarations to avoid the need for explicit `as_c_char_ptr` conversions - Flattening control flow in `inline_asm_call` There should be no functional changes.
This commit is contained in:
@@ -14,7 +14,7 @@ use smallvec::SmallVec;
|
||||
use tracing::debug;
|
||||
|
||||
use crate::builder::Builder;
|
||||
use crate::common::{AsCCharPtr, Funclet};
|
||||
use crate::common::Funclet;
|
||||
use crate::context::CodegenCx;
|
||||
use crate::type_::Type;
|
||||
use crate::type_of::LayoutLlvmExt;
|
||||
@@ -435,13 +435,7 @@ impl<'tcx> AsmCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> {
|
||||
template_str.push_str("\n.att_syntax\n");
|
||||
}
|
||||
|
||||
unsafe {
|
||||
llvm::LLVMAppendModuleInlineAsm(
|
||||
self.llmod,
|
||||
template_str.as_c_char_ptr(),
|
||||
template_str.len(),
|
||||
);
|
||||
}
|
||||
llvm::append_module_inline_asm(self.llmod, template_str.as_bytes());
|
||||
}
|
||||
|
||||
fn mangled_name(&self, instance: Instance<'tcx>) -> String {
|
||||
@@ -482,67 +476,67 @@ pub(crate) fn inline_asm_call<'ll>(
|
||||
|
||||
debug!("Asm Output Type: {:?}", output);
|
||||
let fty = bx.cx.type_func(&argtys, output);
|
||||
|
||||
// Ask LLVM to verify that the constraints are well-formed.
|
||||
let constraints_ok =
|
||||
unsafe { llvm::LLVMRustInlineAsmVerify(fty, cons.as_c_char_ptr(), cons.len()) };
|
||||
let constraints_ok = unsafe { llvm::LLVMRustInlineAsmVerify(fty, cons.as_ptr(), cons.len()) };
|
||||
debug!("constraint verification result: {:?}", constraints_ok);
|
||||
if constraints_ok {
|
||||
let v = unsafe {
|
||||
llvm::LLVMRustInlineAsm(
|
||||
fty,
|
||||
asm.as_c_char_ptr(),
|
||||
asm.len(),
|
||||
cons.as_c_char_ptr(),
|
||||
cons.len(),
|
||||
volatile,
|
||||
alignstack,
|
||||
dia,
|
||||
can_throw,
|
||||
)
|
||||
};
|
||||
|
||||
let call = if !labels.is_empty() {
|
||||
assert!(catch_funclet.is_none());
|
||||
bx.callbr(fty, None, None, v, inputs, dest.unwrap(), labels, None, None)
|
||||
} else if let Some((catch, funclet)) = catch_funclet {
|
||||
bx.invoke(fty, None, None, v, inputs, dest.unwrap(), catch, funclet, None)
|
||||
} else {
|
||||
bx.call(fty, None, None, v, inputs, None, None)
|
||||
};
|
||||
|
||||
// Store mark in a metadata node so we can map LLVM errors
|
||||
// back to source locations. See #17552.
|
||||
let key = "srcloc";
|
||||
let kind = bx.get_md_kind_id(key);
|
||||
|
||||
// `srcloc` contains one 64-bit integer for each line of assembly code,
|
||||
// where the lower 32 bits hold the lo byte position and the upper 32 bits
|
||||
// hold the hi byte position.
|
||||
let mut srcloc = vec![];
|
||||
if dia == llvm::AsmDialect::Intel && line_spans.len() > 1 {
|
||||
// LLVM inserts an extra line to add the ".intel_syntax", so add
|
||||
// a dummy srcloc entry for it.
|
||||
//
|
||||
// Don't do this if we only have 1 line span since that may be
|
||||
// due to the asm template string coming from a macro. LLVM will
|
||||
// default to the first srcloc for lines that don't have an
|
||||
// associated srcloc.
|
||||
srcloc.push(llvm::LLVMValueAsMetadata(bx.const_u64(0)));
|
||||
}
|
||||
srcloc.extend(line_spans.iter().map(|span| {
|
||||
llvm::LLVMValueAsMetadata(
|
||||
bx.const_u64(u64::from(span.lo().to_u32()) | (u64::from(span.hi().to_u32()) << 32)),
|
||||
)
|
||||
}));
|
||||
let md = unsafe { llvm::LLVMMDNodeInContext2(bx.llcx, srcloc.as_ptr(), srcloc.len()) };
|
||||
let md = bx.get_metadata_value(md);
|
||||
llvm::LLVMSetMetadata(call, kind, md);
|
||||
|
||||
Some(call)
|
||||
} else {
|
||||
// LLVM has detected an issue with our constraints, bail out
|
||||
None
|
||||
if !constraints_ok {
|
||||
// LLVM has detected an issue with our constraints, so bail out.
|
||||
return None;
|
||||
}
|
||||
|
||||
let v = unsafe {
|
||||
llvm::LLVMGetInlineAsm(
|
||||
fty,
|
||||
asm.as_ptr(),
|
||||
asm.len(),
|
||||
cons.as_ptr(),
|
||||
cons.len(),
|
||||
volatile,
|
||||
alignstack,
|
||||
dia,
|
||||
can_throw,
|
||||
)
|
||||
};
|
||||
|
||||
let call = if !labels.is_empty() {
|
||||
assert!(catch_funclet.is_none());
|
||||
bx.callbr(fty, None, None, v, inputs, dest.unwrap(), labels, None, None)
|
||||
} else if let Some((catch, funclet)) = catch_funclet {
|
||||
bx.invoke(fty, None, None, v, inputs, dest.unwrap(), catch, funclet, None)
|
||||
} else {
|
||||
bx.call(fty, None, None, v, inputs, None, None)
|
||||
};
|
||||
|
||||
// Store mark in a metadata node so we can map LLVM errors
|
||||
// back to source locations. See #17552.
|
||||
let key = "srcloc";
|
||||
let kind = bx.get_md_kind_id(key);
|
||||
|
||||
// `srcloc` contains one 64-bit integer for each line of assembly code,
|
||||
// where the lower 32 bits hold the lo byte position and the upper 32 bits
|
||||
// hold the hi byte position.
|
||||
let mut srcloc = vec![];
|
||||
if dia == llvm::AsmDialect::Intel && line_spans.len() > 1 {
|
||||
// LLVM inserts an extra line to add the ".intel_syntax", so add
|
||||
// a dummy srcloc entry for it.
|
||||
//
|
||||
// Don't do this if we only have 1 line span since that may be
|
||||
// due to the asm template string coming from a macro. LLVM will
|
||||
// default to the first srcloc for lines that don't have an
|
||||
// associated srcloc.
|
||||
srcloc.push(llvm::LLVMValueAsMetadata(bx.const_u64(0)));
|
||||
}
|
||||
srcloc.extend(line_spans.iter().map(|span| {
|
||||
llvm::LLVMValueAsMetadata(
|
||||
bx.const_u64(u64::from(span.lo().to_u32()) | (u64::from(span.hi().to_u32()) << 32)),
|
||||
)
|
||||
}));
|
||||
let md = unsafe { llvm::LLVMMDNodeInContext2(bx.llcx, srcloc.as_ptr(), srcloc.len()) };
|
||||
let md = bx.get_metadata_value(md);
|
||||
llvm::LLVMSetMetadata(call, kind, md);
|
||||
|
||||
Some(call)
|
||||
}
|
||||
|
||||
/// If the register is an xmm/ymm/zmm register then return its index.
|
||||
|
||||
@@ -1148,9 +1148,9 @@ unsafe fn embed_bitcode(
|
||||
// We need custom section flags, so emit module-level inline assembly.
|
||||
let section_flags = if cgcx.is_pe_coff { "n" } else { "e" };
|
||||
let asm = create_section_with_flags_asm(".llvmbc", section_flags, bitcode);
|
||||
llvm::LLVMAppendModuleInlineAsm(llmod, asm.as_c_char_ptr(), asm.len());
|
||||
llvm::append_module_inline_asm(llmod, &asm);
|
||||
let asm = create_section_with_flags_asm(".llvmcmd", section_flags, cmdline.as_bytes());
|
||||
llvm::LLVMAppendModuleInlineAsm(llmod, asm.as_c_char_ptr(), asm.len());
|
||||
llvm::append_module_inline_asm(llmod, &asm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//! Bindings to the LLVM-C API (`LLVM*`), and to our own `extern "C"` wrapper
|
||||
//! functions around the unstable LLVM C++ API (`LLVMRust*`).
|
||||
//!
|
||||
//! ## Passing pointer/length strings as `*const c_uchar`
|
||||
//! ## Passing pointer/length strings as `*const c_uchar` (PTR_LEN_STR)
|
||||
//!
|
||||
//! Normally it's a good idea for Rust-side bindings to match the corresponding
|
||||
//! C-side function declarations as closely as possible. But when passing `&str`
|
||||
@@ -471,7 +471,7 @@ pub(crate) enum MetadataType {
|
||||
MD_kcfi_type = 36,
|
||||
}
|
||||
|
||||
/// LLVMRustAsmDialect
|
||||
/// Must match the layout of `LLVMInlineAsmDialect`.
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
#[repr(C)]
|
||||
pub(crate) enum AsmDialect {
|
||||
@@ -1014,8 +1014,25 @@ unsafe extern "C" {
|
||||
pub(crate) fn LLVMGetDataLayoutStr(M: &Module) -> *const c_char;
|
||||
pub(crate) fn LLVMSetDataLayout(M: &Module, Triple: *const c_char);
|
||||
|
||||
/// See Module::setModuleInlineAsm.
|
||||
pub(crate) fn LLVMAppendModuleInlineAsm(M: &Module, Asm: *const c_char, Len: size_t);
|
||||
/// Append inline assembly to a module. See `Module::appendModuleInlineAsm`.
|
||||
pub(crate) fn LLVMAppendModuleInlineAsm(
|
||||
M: &Module,
|
||||
Asm: *const c_uchar, // See "PTR_LEN_STR".
|
||||
Len: size_t,
|
||||
);
|
||||
|
||||
/// Create the specified uniqued inline asm string. See `InlineAsm::get()`.
|
||||
pub(crate) fn LLVMGetInlineAsm<'ll>(
|
||||
Ty: &'ll Type,
|
||||
AsmString: *const c_uchar, // See "PTR_LEN_STR".
|
||||
AsmStringSize: size_t,
|
||||
Constraints: *const c_uchar, // See "PTR_LEN_STR".
|
||||
ConstraintsSize: size_t,
|
||||
HasSideEffects: llvm::Bool,
|
||||
IsAlignStack: llvm::Bool,
|
||||
Dialect: AsmDialect,
|
||||
CanThrow: llvm::Bool,
|
||||
) -> &'ll Value;
|
||||
|
||||
// Operations on integer types
|
||||
pub(crate) fn LLVMInt1TypeInContext(C: &Context) -> &Type;
|
||||
@@ -1766,7 +1783,7 @@ unsafe extern "C" {
|
||||
pub(crate) fn LLVMDIBuilderCreateNameSpace<'ll>(
|
||||
Builder: &DIBuilder<'ll>,
|
||||
ParentScope: Option<&'ll Metadata>,
|
||||
Name: *const c_uchar,
|
||||
Name: *const c_uchar, // See "PTR_LEN_STR".
|
||||
NameLen: size_t,
|
||||
ExportSymbols: llvm::Bool,
|
||||
) -> &'ll Metadata;
|
||||
@@ -1994,21 +2011,9 @@ unsafe extern "C" {
|
||||
/// Prints the statistics collected by `-Zprint-codegen-stats`.
|
||||
pub(crate) fn LLVMRustPrintStatistics(OutStr: &RustString);
|
||||
|
||||
/// Prepares inline assembly.
|
||||
pub(crate) fn LLVMRustInlineAsm(
|
||||
Ty: &Type,
|
||||
AsmString: *const c_char,
|
||||
AsmStringLen: size_t,
|
||||
Constraints: *const c_char,
|
||||
ConstraintsLen: size_t,
|
||||
SideEffects: Bool,
|
||||
AlignStack: Bool,
|
||||
Dialect: AsmDialect,
|
||||
CanThrow: Bool,
|
||||
) -> &Value;
|
||||
pub(crate) fn LLVMRustInlineAsmVerify(
|
||||
Ty: &Type,
|
||||
Constraints: *const c_char,
|
||||
Constraints: *const c_uchar, // See "PTR_LEN_STR".
|
||||
ConstraintsLen: size_t,
|
||||
) -> bool;
|
||||
|
||||
|
||||
@@ -441,3 +441,11 @@ pub(crate) fn set_dso_local<'ll>(v: &'ll Value) {
|
||||
LLVMRustSetDSOLocal(v, true);
|
||||
}
|
||||
}
|
||||
|
||||
/// Safe wrapper for `LLVMAppendModuleInlineAsm`, which delegates to
|
||||
/// `Module::appendModuleInlineAsm`.
|
||||
pub(crate) fn append_module_inline_asm<'ll>(llmod: &'ll Module, asm: &[u8]) {
|
||||
unsafe {
|
||||
LLVMAppendModuleInlineAsm(llmod, asm.as_ptr(), asm.len());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user