Skip to content

Commit d41b791

Browse files
committed
Auto merge of #42971 - stepancheg:ir-demangle, r=nagisa
When writing LLVM IR output demangled fn name in comments `--emit=llvm-ir` looks like this now: ``` ; <alloc::vec::Vec<T> as core::ops::index::IndexMut<core::ops::range::RangeFull>>::index_mut ; Function Attrs: inlinehint uwtable define internal { i8*, i64 } @"_ZN106_$LT$alloc..vec..Vec$LT$T$GT$$u20$as$u20$core..ops..index..IndexMut$LT$core..ops..range..RangeFull$GT$$GT$9index_mut17h7f7b576609f30262E"(%"alloc::vec::Vec<u8>"* dereferenceable(24)) unnamed_addr #0 { start: ... ``` cc rust-lang/rust-playground#15
2 parents 4a92ae2 + b62bdaa commit d41b791

File tree

6 files changed

+173
-5
lines changed

6 files changed

+173
-5
lines changed

src/Cargo.lock

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/librustc_llvm/ffi.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -1597,7 +1597,13 @@ extern "C" {
15971597
Output: *const c_char,
15981598
FileType: FileType)
15991599
-> LLVMRustResult;
1600-
pub fn LLVMRustPrintModule(PM: PassManagerRef, M: ModuleRef, Output: *const c_char);
1600+
pub fn LLVMRustPrintModule(PM: PassManagerRef,
1601+
M: ModuleRef,
1602+
Output: *const c_char,
1603+
Demangle: extern fn(*const c_char,
1604+
size_t,
1605+
*mut c_char,
1606+
size_t) -> size_t);
16011607
pub fn LLVMRustSetLLVMOptions(Argc: c_int, Argv: *const *const c_char);
16021608
pub fn LLVMRustPrintPasses();
16031609
pub fn LLVMRustSetNormalizedTarget(M: ModuleRef, triple: *const c_char);

src/librustc_trans/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ flate2 = "0.2"
1515
jobserver = "0.1.5"
1616
log = "0.3"
1717
owning_ref = "0.3.3"
18+
rustc-demangle = "0.1.4"
1819
rustc = { path = "../librustc" }
1920
rustc_back = { path = "../librustc_back" }
2021
rustc_bitflags = { path = "../librustc_bitflags" }

src/librustc_trans/back/write.rs

+37-2
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,18 @@ use syntax_pos::MultiSpan;
2929
use context::{is_pie_binary, get_reloc_model};
3030
use jobserver::{Client, Acquired};
3131
use crossbeam::{scope, Scope};
32+
use rustc_demangle;
3233

3334
use std::cmp;
3435
use std::ffi::CString;
3536
use std::fs;
3637
use std::io;
38+
use std::io::Write;
3739
use std::path::{Path, PathBuf};
3840
use std::str;
3941
use std::sync::mpsc::{channel, Sender};
40-
use libc::{c_uint, c_void};
42+
use std::slice;
43+
use libc::{c_uint, c_void, c_char, size_t};
4144

4245
pub const RELOC_MODEL_ARGS : [(&'static str, llvm::RelocMode); 7] = [
4346
("pic", llvm::RelocMode::PIC),
@@ -510,8 +513,40 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext,
510513
if config.emit_ir {
511514
let out = output_names.temp_path(OutputType::LlvmAssembly, module_name);
512515
let out = path2cstr(&out);
516+
517+
extern "C" fn demangle_callback(input_ptr: *const c_char,
518+
input_len: size_t,
519+
output_ptr: *mut c_char,
520+
output_len: size_t) -> size_t {
521+
let input = unsafe {
522+
slice::from_raw_parts(input_ptr as *const u8, input_len as usize)
523+
};
524+
525+
let input = match str::from_utf8(input) {
526+
Ok(s) => s,
527+
Err(_) => return 0,
528+
};
529+
530+
let output = unsafe {
531+
slice::from_raw_parts_mut(output_ptr as *mut u8, output_len as usize)
532+
};
533+
let mut cursor = io::Cursor::new(output);
534+
535+
let demangled = match rustc_demangle::try_demangle(input) {
536+
Ok(d) => d,
537+
Err(_) => return 0,
538+
};
539+
540+
if let Err(_) = write!(cursor, "{:#}", demangled) {
541+
// Possible only if provided buffer is not big enough
542+
return 0;
543+
}
544+
545+
cursor.position() as size_t
546+
}
547+
513548
with_codegen(tm, llmod, config.no_builtins, |cpm| {
514-
llvm::LLVMRustPrintModule(cpm, llmod, out.as_ptr());
549+
llvm::LLVMRustPrintModule(cpm, llmod, out.as_ptr(), demangle_callback);
515550
llvm::LLVMDisposePassManager(cpm);
516551
})
517552
}

src/librustc_trans/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ extern crate rustc_const_math;
5252
#[macro_use]
5353
#[no_link]
5454
extern crate rustc_bitflags;
55+
extern crate rustc_demangle;
5556
extern crate jobserver;
5657

5758
#[macro_use] extern crate log;

src/rustllvm/PassWrapper.cpp

+126-2
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,14 @@
1010

1111
#include <stdio.h>
1212

13+
#include <vector>
14+
1315
#include "rustllvm.h"
1416

1517
#include "llvm/Analysis/TargetLibraryInfo.h"
1618
#include "llvm/Analysis/TargetTransformInfo.h"
1719
#include "llvm/IR/AutoUpgrade.h"
20+
#include "llvm/IR/AssemblyAnnotationWriter.h"
1821
#include "llvm/Support/CBindingWrapping.h"
1922
#include "llvm/Support/FileSystem.h"
2023
#include "llvm/Support/Host.h"
@@ -503,8 +506,129 @@ LLVMRustWriteOutputFile(LLVMTargetMachineRef Target, LLVMPassManagerRef PMR,
503506
return LLVMRustResult::Success;
504507
}
505508

509+
510+
// Callback to demangle function name
511+
// Parameters:
512+
// * name to be demangled
513+
// * name len
514+
// * output buffer
515+
// * output buffer len
516+
// Returns len of demangled string, or 0 if demangle failed.
517+
typedef size_t (*DemangleFn)(const char*, size_t, char*, size_t);
518+
519+
520+
namespace {
521+
522+
class RustAssemblyAnnotationWriter : public AssemblyAnnotationWriter {
523+
DemangleFn Demangle;
524+
std::vector<char> Buf;
525+
526+
public:
527+
RustAssemblyAnnotationWriter(DemangleFn Demangle) : Demangle(Demangle) {}
528+
529+
// Return empty string if demangle failed
530+
// or if name does not need to be demangled
531+
StringRef CallDemangle(StringRef name) {
532+
if (!Demangle) {
533+
return StringRef();
534+
}
535+
536+
if (Buf.size() < name.size() * 2) {
537+
// Semangled name usually shorter than mangled,
538+
// but allocate twice as much memory just in case
539+
Buf.resize(name.size() * 2);
540+
}
541+
542+
auto R = Demangle(name.data(), name.size(), Buf.data(), Buf.size());
543+
if (!R) {
544+
// Demangle failed.
545+
return StringRef();
546+
}
547+
548+
auto Demangled = StringRef(Buf.data(), R);
549+
if (Demangled == name) {
550+
// Do not print anything if demangled name is equal to mangled.
551+
return StringRef();
552+
}
553+
554+
return Demangled;
555+
}
556+
557+
void emitFunctionAnnot(const Function *F,
558+
formatted_raw_ostream &OS) override {
559+
StringRef Demangled = CallDemangle(F->getName());
560+
if (Demangled.empty()) {
561+
return;
562+
}
563+
564+
OS << "; " << Demangled << "\n";
565+
}
566+
567+
void emitInstructionAnnot(const Instruction *I,
568+
formatted_raw_ostream &OS) override {
569+
const char *Name;
570+
const Value *Value;
571+
if (const CallInst *CI = dyn_cast<CallInst>(I)) {
572+
Name = "call";
573+
Value = CI->getCalledValue();
574+
} else if (const InvokeInst* II = dyn_cast<InvokeInst>(I)) {
575+
Name = "invoke";
576+
Value = II->getCalledValue();
577+
} else {
578+
// Could demangle more operations, e. g.
579+
// `store %place, @function`.
580+
return;
581+
}
582+
583+
if (!Value->hasName()) {
584+
return;
585+
}
586+
587+
StringRef Demangled = CallDemangle(Value->getName());
588+
if (Demangled.empty()) {
589+
return;
590+
}
591+
592+
OS << "; " << Name << " " << Demangled << "\n";
593+
}
594+
};
595+
596+
class RustPrintModulePass : public ModulePass {
597+
raw_ostream* OS;
598+
DemangleFn Demangle;
599+
public:
600+
static char ID;
601+
RustPrintModulePass() : ModulePass(ID), OS(nullptr), Demangle(nullptr) {}
602+
RustPrintModulePass(raw_ostream &OS, DemangleFn Demangle)
603+
: ModulePass(ID), OS(&OS), Demangle(Demangle) {}
604+
605+
bool runOnModule(Module &M) override {
606+
RustAssemblyAnnotationWriter AW(Demangle);
607+
608+
M.print(*OS, &AW, false);
609+
610+
return false;
611+
}
612+
613+
void getAnalysisUsage(AnalysisUsage &AU) const override {
614+
AU.setPreservesAll();
615+
}
616+
617+
static StringRef name() { return "RustPrintModulePass"; }
618+
};
619+
620+
} // namespace
621+
622+
namespace llvm {
623+
void initializeRustPrintModulePassPass(PassRegistry&);
624+
}
625+
626+
char RustPrintModulePass::ID = 0;
627+
INITIALIZE_PASS(RustPrintModulePass, "print-rust-module",
628+
"Print rust module to stderr", false, false)
629+
506630
extern "C" void LLVMRustPrintModule(LLVMPassManagerRef PMR, LLVMModuleRef M,
507-
const char *Path) {
631+
const char *Path, DemangleFn Demangle) {
508632
llvm::legacy::PassManager *PM = unwrap<llvm::legacy::PassManager>(PMR);
509633
std::string ErrorInfo;
510634

@@ -515,7 +639,7 @@ extern "C" void LLVMRustPrintModule(LLVMPassManagerRef PMR, LLVMModuleRef M,
515639

516640
formatted_raw_ostream FOS(OS);
517641

518-
PM->add(createPrintModulePass(FOS));
642+
PM->add(new RustPrintModulePass(FOS, Demangle));
519643

520644
PM->run(*unwrap(M));
521645
}

0 commit comments

Comments
 (0)