mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-26 16:54:01 +00:00
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 https://github.com/integer32llc/rust-playground/issues/15
This commit is contained in:
commit
d41b791c1a
1
src/Cargo.lock
generated
1
src/Cargo.lock
generated
@ -1398,6 +1398,7 @@ dependencies = [
|
||||
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc 0.0.0",
|
||||
"rustc-demangle 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc_back 0.0.0",
|
||||
"rustc_bitflags 0.0.0",
|
||||
"rustc_const_math 0.0.0",
|
||||
|
@ -1597,7 +1597,13 @@ extern "C" {
|
||||
Output: *const c_char,
|
||||
FileType: FileType)
|
||||
-> LLVMRustResult;
|
||||
pub fn LLVMRustPrintModule(PM: PassManagerRef, M: ModuleRef, Output: *const c_char);
|
||||
pub fn LLVMRustPrintModule(PM: PassManagerRef,
|
||||
M: ModuleRef,
|
||||
Output: *const c_char,
|
||||
Demangle: extern fn(*const c_char,
|
||||
size_t,
|
||||
*mut c_char,
|
||||
size_t) -> size_t);
|
||||
pub fn LLVMRustSetLLVMOptions(Argc: c_int, Argv: *const *const c_char);
|
||||
pub fn LLVMRustPrintPasses();
|
||||
pub fn LLVMRustSetNormalizedTarget(M: ModuleRef, triple: *const c_char);
|
||||
|
@ -15,6 +15,7 @@ flate2 = "0.2"
|
||||
jobserver = "0.1.5"
|
||||
log = "0.3"
|
||||
owning_ref = "0.3.3"
|
||||
rustc-demangle = "0.1.4"
|
||||
rustc = { path = "../librustc" }
|
||||
rustc_back = { path = "../librustc_back" }
|
||||
rustc_bitflags = { path = "../librustc_bitflags" }
|
||||
|
@ -29,15 +29,18 @@ use syntax_pos::MultiSpan;
|
||||
use context::{is_pie_binary, get_reloc_model};
|
||||
use jobserver::{Client, Acquired};
|
||||
use crossbeam::{scope, Scope};
|
||||
use rustc_demangle;
|
||||
|
||||
use std::cmp;
|
||||
use std::ffi::CString;
|
||||
use std::fs;
|
||||
use std::io;
|
||||
use std::io::Write;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::str;
|
||||
use std::sync::mpsc::{channel, Sender};
|
||||
use libc::{c_uint, c_void};
|
||||
use std::slice;
|
||||
use libc::{c_uint, c_void, c_char, size_t};
|
||||
|
||||
pub const RELOC_MODEL_ARGS : [(&'static str, llvm::RelocMode); 7] = [
|
||||
("pic", llvm::RelocMode::PIC),
|
||||
@ -510,8 +513,40 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext,
|
||||
if config.emit_ir {
|
||||
let out = output_names.temp_path(OutputType::LlvmAssembly, module_name);
|
||||
let out = path2cstr(&out);
|
||||
|
||||
extern "C" fn demangle_callback(input_ptr: *const c_char,
|
||||
input_len: size_t,
|
||||
output_ptr: *mut c_char,
|
||||
output_len: size_t) -> size_t {
|
||||
let input = unsafe {
|
||||
slice::from_raw_parts(input_ptr as *const u8, input_len as usize)
|
||||
};
|
||||
|
||||
let input = match str::from_utf8(input) {
|
||||
Ok(s) => s,
|
||||
Err(_) => return 0,
|
||||
};
|
||||
|
||||
let output = unsafe {
|
||||
slice::from_raw_parts_mut(output_ptr as *mut u8, output_len as usize)
|
||||
};
|
||||
let mut cursor = io::Cursor::new(output);
|
||||
|
||||
let demangled = match rustc_demangle::try_demangle(input) {
|
||||
Ok(d) => d,
|
||||
Err(_) => return 0,
|
||||
};
|
||||
|
||||
if let Err(_) = write!(cursor, "{:#}", demangled) {
|
||||
// Possible only if provided buffer is not big enough
|
||||
return 0;
|
||||
}
|
||||
|
||||
cursor.position() as size_t
|
||||
}
|
||||
|
||||
with_codegen(tm, llmod, config.no_builtins, |cpm| {
|
||||
llvm::LLVMRustPrintModule(cpm, llmod, out.as_ptr());
|
||||
llvm::LLVMRustPrintModule(cpm, llmod, out.as_ptr(), demangle_callback);
|
||||
llvm::LLVMDisposePassManager(cpm);
|
||||
})
|
||||
}
|
||||
|
@ -52,6 +52,7 @@ extern crate rustc_const_math;
|
||||
#[macro_use]
|
||||
#[no_link]
|
||||
extern crate rustc_bitflags;
|
||||
extern crate rustc_demangle;
|
||||
extern crate jobserver;
|
||||
|
||||
#[macro_use] extern crate log;
|
||||
|
@ -10,11 +10,14 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "rustllvm.h"
|
||||
|
||||
#include "llvm/Analysis/TargetLibraryInfo.h"
|
||||
#include "llvm/Analysis/TargetTransformInfo.h"
|
||||
#include "llvm/IR/AutoUpgrade.h"
|
||||
#include "llvm/IR/AssemblyAnnotationWriter.h"
|
||||
#include "llvm/Support/CBindingWrapping.h"
|
||||
#include "llvm/Support/FileSystem.h"
|
||||
#include "llvm/Support/Host.h"
|
||||
@ -503,8 +506,129 @@ LLVMRustWriteOutputFile(LLVMTargetMachineRef Target, LLVMPassManagerRef PMR,
|
||||
return LLVMRustResult::Success;
|
||||
}
|
||||
|
||||
|
||||
// Callback to demangle function name
|
||||
// Parameters:
|
||||
// * name to be demangled
|
||||
// * name len
|
||||
// * output buffer
|
||||
// * output buffer len
|
||||
// Returns len of demangled string, or 0 if demangle failed.
|
||||
typedef size_t (*DemangleFn)(const char*, size_t, char*, size_t);
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
class RustAssemblyAnnotationWriter : public AssemblyAnnotationWriter {
|
||||
DemangleFn Demangle;
|
||||
std::vector<char> Buf;
|
||||
|
||||
public:
|
||||
RustAssemblyAnnotationWriter(DemangleFn Demangle) : Demangle(Demangle) {}
|
||||
|
||||
// Return empty string if demangle failed
|
||||
// or if name does not need to be demangled
|
||||
StringRef CallDemangle(StringRef name) {
|
||||
if (!Demangle) {
|
||||
return StringRef();
|
||||
}
|
||||
|
||||
if (Buf.size() < name.size() * 2) {
|
||||
// Semangled name usually shorter than mangled,
|
||||
// but allocate twice as much memory just in case
|
||||
Buf.resize(name.size() * 2);
|
||||
}
|
||||
|
||||
auto R = Demangle(name.data(), name.size(), Buf.data(), Buf.size());
|
||||
if (!R) {
|
||||
// Demangle failed.
|
||||
return StringRef();
|
||||
}
|
||||
|
||||
auto Demangled = StringRef(Buf.data(), R);
|
||||
if (Demangled == name) {
|
||||
// Do not print anything if demangled name is equal to mangled.
|
||||
return StringRef();
|
||||
}
|
||||
|
||||
return Demangled;
|
||||
}
|
||||
|
||||
void emitFunctionAnnot(const Function *F,
|
||||
formatted_raw_ostream &OS) override {
|
||||
StringRef Demangled = CallDemangle(F->getName());
|
||||
if (Demangled.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
OS << "; " << Demangled << "\n";
|
||||
}
|
||||
|
||||
void emitInstructionAnnot(const Instruction *I,
|
||||
formatted_raw_ostream &OS) override {
|
||||
const char *Name;
|
||||
const Value *Value;
|
||||
if (const CallInst *CI = dyn_cast<CallInst>(I)) {
|
||||
Name = "call";
|
||||
Value = CI->getCalledValue();
|
||||
} else if (const InvokeInst* II = dyn_cast<InvokeInst>(I)) {
|
||||
Name = "invoke";
|
||||
Value = II->getCalledValue();
|
||||
} else {
|
||||
// Could demangle more operations, e. g.
|
||||
// `store %place, @function`.
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Value->hasName()) {
|
||||
return;
|
||||
}
|
||||
|
||||
StringRef Demangled = CallDemangle(Value->getName());
|
||||
if (Demangled.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
OS << "; " << Name << " " << Demangled << "\n";
|
||||
}
|
||||
};
|
||||
|
||||
class RustPrintModulePass : public ModulePass {
|
||||
raw_ostream* OS;
|
||||
DemangleFn Demangle;
|
||||
public:
|
||||
static char ID;
|
||||
RustPrintModulePass() : ModulePass(ID), OS(nullptr), Demangle(nullptr) {}
|
||||
RustPrintModulePass(raw_ostream &OS, DemangleFn Demangle)
|
||||
: ModulePass(ID), OS(&OS), Demangle(Demangle) {}
|
||||
|
||||
bool runOnModule(Module &M) override {
|
||||
RustAssemblyAnnotationWriter AW(Demangle);
|
||||
|
||||
M.print(*OS, &AW, false);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
||||
AU.setPreservesAll();
|
||||
}
|
||||
|
||||
static StringRef name() { return "RustPrintModulePass"; }
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace llvm {
|
||||
void initializeRustPrintModulePassPass(PassRegistry&);
|
||||
}
|
||||
|
||||
char RustPrintModulePass::ID = 0;
|
||||
INITIALIZE_PASS(RustPrintModulePass, "print-rust-module",
|
||||
"Print rust module to stderr", false, false)
|
||||
|
||||
extern "C" void LLVMRustPrintModule(LLVMPassManagerRef PMR, LLVMModuleRef M,
|
||||
const char *Path) {
|
||||
const char *Path, DemangleFn Demangle) {
|
||||
llvm::legacy::PassManager *PM = unwrap<llvm::legacy::PassManager>(PMR);
|
||||
std::string ErrorInfo;
|
||||
|
||||
@ -515,7 +639,7 @@ extern "C" void LLVMRustPrintModule(LLVMPassManagerRef PMR, LLVMModuleRef M,
|
||||
|
||||
formatted_raw_ostream FOS(OS);
|
||||
|
||||
PM->add(createPrintModulePass(FOS));
|
||||
PM->add(new RustPrintModulePass(FOS, Demangle));
|
||||
|
||||
PM->run(*unwrap(M));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user