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:
bors 2017-07-01 05:52:08 +00:00
commit d41b791c1a
6 changed files with 173 additions and 5 deletions

1
src/Cargo.lock generated
View File

@ -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",

View File

@ -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);

View File

@ -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" }

View File

@ -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);
})
}

View File

@ -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;

View File

@ -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));
}