Skip to content

Commit 1a7f290

Browse files
committed
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.
2 parents 420ca71 + eccf064 commit 1a7f290

File tree

5 files changed

+89
-109
lines changed

5 files changed

+89
-109
lines changed

compiler/rustc_codegen_llvm/src/asm.rs

+56-62
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use smallvec::SmallVec;
1414
use tracing::debug;
1515

1616
use crate::builder::Builder;
17-
use crate::common::{AsCCharPtr, Funclet};
17+
use crate::common::Funclet;
1818
use crate::context::CodegenCx;
1919
use crate::type_::Type;
2020
use crate::type_of::LayoutLlvmExt;
@@ -435,13 +435,7 @@ impl<'tcx> AsmCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> {
435435
template_str.push_str("\n.att_syntax\n");
436436
}
437437

438-
unsafe {
439-
llvm::LLVMAppendModuleInlineAsm(
440-
self.llmod,
441-
template_str.as_c_char_ptr(),
442-
template_str.len(),
443-
);
444-
}
438+
llvm::append_module_inline_asm(self.llmod, template_str.as_bytes());
445439
}
446440

447441
fn mangled_name(&self, instance: Instance<'tcx>) -> String {
@@ -482,67 +476,67 @@ pub(crate) fn inline_asm_call<'ll>(
482476

483477
debug!("Asm Output Type: {:?}", output);
484478
let fty = bx.cx.type_func(&argtys, output);
479+
485480
// Ask LLVM to verify that the constraints are well-formed.
486-
let constraints_ok =
487-
unsafe { llvm::LLVMRustInlineAsmVerify(fty, cons.as_c_char_ptr(), cons.len()) };
481+
let constraints_ok = unsafe { llvm::LLVMRustInlineAsmVerify(fty, cons.as_ptr(), cons.len()) };
488482
debug!("constraint verification result: {:?}", constraints_ok);
489-
if constraints_ok {
490-
let v = unsafe {
491-
llvm::LLVMRustInlineAsm(
492-
fty,
493-
asm.as_c_char_ptr(),
494-
asm.len(),
495-
cons.as_c_char_ptr(),
496-
cons.len(),
497-
volatile,
498-
alignstack,
499-
dia,
500-
can_throw,
501-
)
502-
};
483+
if !constraints_ok {
484+
// LLVM has detected an issue with our constraints, so bail out.
485+
return None;
486+
}
503487

504-
let call = if !labels.is_empty() {
505-
assert!(catch_funclet.is_none());
506-
bx.callbr(fty, None, None, v, inputs, dest.unwrap(), labels, None, None)
507-
} else if let Some((catch, funclet)) = catch_funclet {
508-
bx.invoke(fty, None, None, v, inputs, dest.unwrap(), catch, funclet, None)
509-
} else {
510-
bx.call(fty, None, None, v, inputs, None, None)
511-
};
488+
let v = unsafe {
489+
llvm::LLVMGetInlineAsm(
490+
fty,
491+
asm.as_ptr(),
492+
asm.len(),
493+
cons.as_ptr(),
494+
cons.len(),
495+
volatile,
496+
alignstack,
497+
dia,
498+
can_throw,
499+
)
500+
};
512501

513-
// Store mark in a metadata node so we can map LLVM errors
514-
// back to source locations. See #17552.
515-
let key = "srcloc";
516-
let kind = bx.get_md_kind_id(key);
502+
let call = if !labels.is_empty() {
503+
assert!(catch_funclet.is_none());
504+
bx.callbr(fty, None, None, v, inputs, dest.unwrap(), labels, None, None)
505+
} else if let Some((catch, funclet)) = catch_funclet {
506+
bx.invoke(fty, None, None, v, inputs, dest.unwrap(), catch, funclet, None)
507+
} else {
508+
bx.call(fty, None, None, v, inputs, None, None)
509+
};
517510

518-
// `srcloc` contains one 64-bit integer for each line of assembly code,
519-
// where the lower 32 bits hold the lo byte position and the upper 32 bits
520-
// hold the hi byte position.
521-
let mut srcloc = vec![];
522-
if dia == llvm::AsmDialect::Intel && line_spans.len() > 1 {
523-
// LLVM inserts an extra line to add the ".intel_syntax", so add
524-
// a dummy srcloc entry for it.
525-
//
526-
// Don't do this if we only have 1 line span since that may be
527-
// due to the asm template string coming from a macro. LLVM will
528-
// default to the first srcloc for lines that don't have an
529-
// associated srcloc.
530-
srcloc.push(llvm::LLVMValueAsMetadata(bx.const_u64(0)));
531-
}
532-
srcloc.extend(line_spans.iter().map(|span| {
533-
llvm::LLVMValueAsMetadata(
534-
bx.const_u64(u64::from(span.lo().to_u32()) | (u64::from(span.hi().to_u32()) << 32)),
535-
)
536-
}));
537-
let md = unsafe { llvm::LLVMMDNodeInContext2(bx.llcx, srcloc.as_ptr(), srcloc.len()) };
538-
let md = bx.get_metadata_value(md);
539-
llvm::LLVMSetMetadata(call, kind, md);
511+
// Store mark in a metadata node so we can map LLVM errors
512+
// back to source locations. See #17552.
513+
let key = "srcloc";
514+
let kind = bx.get_md_kind_id(key);
540515

541-
Some(call)
542-
} else {
543-
// LLVM has detected an issue with our constraints, bail out
544-
None
516+
// `srcloc` contains one 64-bit integer for each line of assembly code,
517+
// where the lower 32 bits hold the lo byte position and the upper 32 bits
518+
// hold the hi byte position.
519+
let mut srcloc = vec![];
520+
if dia == llvm::AsmDialect::Intel && line_spans.len() > 1 {
521+
// LLVM inserts an extra line to add the ".intel_syntax", so add
522+
// a dummy srcloc entry for it.
523+
//
524+
// Don't do this if we only have 1 line span since that may be
525+
// due to the asm template string coming from a macro. LLVM will
526+
// default to the first srcloc for lines that don't have an
527+
// associated srcloc.
528+
srcloc.push(llvm::LLVMValueAsMetadata(bx.const_u64(0)));
545529
}
530+
srcloc.extend(line_spans.iter().map(|span| {
531+
llvm::LLVMValueAsMetadata(
532+
bx.const_u64(u64::from(span.lo().to_u32()) | (u64::from(span.hi().to_u32()) << 32)),
533+
)
534+
}));
535+
let md = unsafe { llvm::LLVMMDNodeInContext2(bx.llcx, srcloc.as_ptr(), srcloc.len()) };
536+
let md = bx.get_metadata_value(md);
537+
llvm::LLVMSetMetadata(call, kind, md);
538+
539+
Some(call)
546540
}
547541

548542
/// If the register is an xmm/ymm/zmm register then return its index.

compiler/rustc_codegen_llvm/src/back/write.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1148,9 +1148,9 @@ unsafe fn embed_bitcode(
11481148
// We need custom section flags, so emit module-level inline assembly.
11491149
let section_flags = if cgcx.is_pe_coff { "n" } else { "e" };
11501150
let asm = create_section_with_flags_asm(".llvmbc", section_flags, bitcode);
1151-
llvm::LLVMAppendModuleInlineAsm(llmod, asm.as_c_char_ptr(), asm.len());
1151+
llvm::append_module_inline_asm(llmod, &asm);
11521152
let asm = create_section_with_flags_asm(".llvmcmd", section_flags, cmdline.as_bytes());
1153-
llvm::LLVMAppendModuleInlineAsm(llmod, asm.as_c_char_ptr(), asm.len());
1153+
llvm::append_module_inline_asm(llmod, &asm);
11541154
}
11551155
}
11561156
}

compiler/rustc_codegen_llvm/src/llvm/ffi.rs

+23-18
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! Bindings to the LLVM-C API (`LLVM*`), and to our own `extern "C"` wrapper
22
//! functions around the unstable LLVM C++ API (`LLVMRust*`).
33
//!
4-
//! ## Passing pointer/length strings as `*const c_uchar`
4+
//! ## Passing pointer/length strings as `*const c_uchar` (PTR_LEN_STR)
55
//!
66
//! Normally it's a good idea for Rust-side bindings to match the corresponding
77
//! C-side function declarations as closely as possible. But when passing `&str`
@@ -471,7 +471,7 @@ pub(crate) enum MetadataType {
471471
MD_kcfi_type = 36,
472472
}
473473

474-
/// LLVMRustAsmDialect
474+
/// Must match the layout of `LLVMInlineAsmDialect`.
475475
#[derive(Copy, Clone, PartialEq)]
476476
#[repr(C)]
477477
pub(crate) enum AsmDialect {
@@ -1014,8 +1014,25 @@ unsafe extern "C" {
10141014
pub(crate) fn LLVMGetDataLayoutStr(M: &Module) -> *const c_char;
10151015
pub(crate) fn LLVMSetDataLayout(M: &Module, Triple: *const c_char);
10161016

1017-
/// See Module::setModuleInlineAsm.
1018-
pub(crate) fn LLVMAppendModuleInlineAsm(M: &Module, Asm: *const c_char, Len: size_t);
1017+
/// Append inline assembly to a module. See `Module::appendModuleInlineAsm`.
1018+
pub(crate) fn LLVMAppendModuleInlineAsm(
1019+
M: &Module,
1020+
Asm: *const c_uchar, // See "PTR_LEN_STR".
1021+
Len: size_t,
1022+
);
1023+
1024+
/// Create the specified uniqued inline asm string. See `InlineAsm::get()`.
1025+
pub(crate) fn LLVMGetInlineAsm<'ll>(
1026+
Ty: &'ll Type,
1027+
AsmString: *const c_uchar, // See "PTR_LEN_STR".
1028+
AsmStringSize: size_t,
1029+
Constraints: *const c_uchar, // See "PTR_LEN_STR".
1030+
ConstraintsSize: size_t,
1031+
HasSideEffects: llvm::Bool,
1032+
IsAlignStack: llvm::Bool,
1033+
Dialect: AsmDialect,
1034+
CanThrow: llvm::Bool,
1035+
) -> &'ll Value;
10191036

10201037
// Operations on integer types
10211038
pub(crate) fn LLVMInt1TypeInContext(C: &Context) -> &Type;
@@ -1766,7 +1783,7 @@ unsafe extern "C" {
17661783
pub(crate) fn LLVMDIBuilderCreateNameSpace<'ll>(
17671784
Builder: &DIBuilder<'ll>,
17681785
ParentScope: Option<&'ll Metadata>,
1769-
Name: *const c_uchar,
1786+
Name: *const c_uchar, // See "PTR_LEN_STR".
17701787
NameLen: size_t,
17711788
ExportSymbols: llvm::Bool,
17721789
) -> &'ll Metadata;
@@ -1994,21 +2011,9 @@ unsafe extern "C" {
19942011
/// Prints the statistics collected by `-Zprint-codegen-stats`.
19952012
pub(crate) fn LLVMRustPrintStatistics(OutStr: &RustString);
19962013

1997-
/// Prepares inline assembly.
1998-
pub(crate) fn LLVMRustInlineAsm(
1999-
Ty: &Type,
2000-
AsmString: *const c_char,
2001-
AsmStringLen: size_t,
2002-
Constraints: *const c_char,
2003-
ConstraintsLen: size_t,
2004-
SideEffects: Bool,
2005-
AlignStack: Bool,
2006-
Dialect: AsmDialect,
2007-
CanThrow: Bool,
2008-
) -> &Value;
20092014
pub(crate) fn LLVMRustInlineAsmVerify(
20102015
Ty: &Type,
2011-
Constraints: *const c_char,
2016+
Constraints: *const c_uchar, // See "PTR_LEN_STR".
20122017
ConstraintsLen: size_t,
20132018
) -> bool;
20142019

compiler/rustc_codegen_llvm/src/llvm/mod.rs

+8
Original file line numberDiff line numberDiff line change
@@ -441,3 +441,11 @@ pub(crate) fn set_dso_local<'ll>(v: &'ll Value) {
441441
LLVMRustSetDSOLocal(v, true);
442442
}
443443
}
444+
445+
/// Safe wrapper for `LLVMAppendModuleInlineAsm`, which delegates to
446+
/// `Module::appendModuleInlineAsm`.
447+
pub(crate) fn append_module_inline_asm<'ll>(llmod: &'ll Module, asm: &[u8]) {
448+
unsafe {
449+
LLVMAppendModuleInlineAsm(llmod, asm.as_ptr(), asm.len());
450+
}
451+
}

compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp

-27
Original file line numberDiff line numberDiff line change
@@ -622,37 +622,10 @@ extern "C" LLVMValueRef LLVMRustBuildAtomicStore(LLVMBuilderRef B,
622622
return wrap(SI);
623623
}
624624

625-
enum class LLVMRustAsmDialect {
626-
Att,
627-
Intel,
628-
};
629-
630-
static InlineAsm::AsmDialect fromRust(LLVMRustAsmDialect Dialect) {
631-
switch (Dialect) {
632-
case LLVMRustAsmDialect::Att:
633-
return InlineAsm::AD_ATT;
634-
case LLVMRustAsmDialect::Intel:
635-
return InlineAsm::AD_Intel;
636-
default:
637-
report_fatal_error("bad AsmDialect.");
638-
}
639-
}
640-
641625
extern "C" uint64_t LLVMRustGetArrayNumElements(LLVMTypeRef Ty) {
642626
return unwrap(Ty)->getArrayNumElements();
643627
}
644628

645-
extern "C" LLVMValueRef
646-
LLVMRustInlineAsm(LLVMTypeRef Ty, char *AsmString, size_t AsmStringLen,
647-
char *Constraints, size_t ConstraintsLen,
648-
LLVMBool HasSideEffects, LLVMBool IsAlignStack,
649-
LLVMRustAsmDialect Dialect, LLVMBool CanThrow) {
650-
return wrap(InlineAsm::get(
651-
unwrap<FunctionType>(Ty), StringRef(AsmString, AsmStringLen),
652-
StringRef(Constraints, ConstraintsLen), HasSideEffects, IsAlignStack,
653-
fromRust(Dialect), CanThrow));
654-
}
655-
656629
extern "C" bool LLVMRustInlineAsmVerify(LLVMTypeRef Ty, char *Constraints,
657630
size_t ConstraintsLen) {
658631
// llvm::Error converts to true if it is an error.

0 commit comments

Comments
 (0)