diff options
| author | Stepan Koltsov <stepan.koltsov@gmail.com> | 2017-06-29 17:52:43 +0300 |
|---|---|---|
| committer | Stepan Koltsov <stepan.koltsov@gmail.com> | 2017-07-01 03:16:43 +0300 |
| commit | b62bdaafe038b8933fac5df5fa0fa5ddbaf176b7 (patch) | |
| tree | 49c307dc988def19093d3af845ca037c9458c048 /src | |
| parent | 37849a002ed91ac2b80aeb2172364b4e19250e05 (diff) | |
| download | rust-b62bdaafe038b8933fac5df5fa0fa5ddbaf176b7.tar.gz rust-b62bdaafe038b8933fac5df5fa0fa5ddbaf176b7.zip | |
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
Diffstat (limited to 'src')
| -rw-r--r-- | src/Cargo.lock | 1 | ||||
| -rw-r--r-- | src/librustc_llvm/ffi.rs | 8 | ||||
| -rw-r--r-- | src/librustc_trans/Cargo.toml | 1 | ||||
| -rw-r--r-- | src/librustc_trans/back/write.rs | 39 | ||||
| -rw-r--r-- | src/librustc_trans/lib.rs | 1 | ||||
| -rw-r--r-- | src/rustllvm/PassWrapper.cpp | 128 |
6 files changed, 173 insertions, 5 deletions
diff --git a/src/Cargo.lock b/src/Cargo.lock index 386450f4a65..50608ca2d04 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -1407,6 +1407,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", diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs index 312b5a38d6e..770d16e5c02 100644 --- a/src/librustc_llvm/ffi.rs +++ b/src/librustc_llvm/ffi.rs @@ -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); diff --git a/src/librustc_trans/Cargo.toml b/src/librustc_trans/Cargo.toml index 86590bff4ff..a512cf2f02a 100644 --- a/src/librustc_trans/Cargo.toml +++ b/src/librustc_trans/Cargo.toml @@ -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" } diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 7e99ea0ee19..562d7171156 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -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); }) } diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index d480f249b44..6acd10cb887 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -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; diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index fdbe4e5f7ad..7fb1eafb30d 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -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)); } |
