about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorStepan Koltsov <stepan.koltsov@gmail.com>2017-06-29 17:52:43 +0300
committerStepan Koltsov <stepan.koltsov@gmail.com>2017-07-01 03:16:43 +0300
commitb62bdaafe038b8933fac5df5fa0fa5ddbaf176b7 (patch)
tree49c307dc988def19093d3af845ca037c9458c048 /src
parent37849a002ed91ac2b80aeb2172364b4e19250e05 (diff)
downloadrust-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.lock1
-rw-r--r--src/librustc_llvm/ffi.rs8
-rw-r--r--src/librustc_trans/Cargo.toml1
-rw-r--r--src/librustc_trans/back/write.rs39
-rw-r--r--src/librustc_trans/lib.rs1
-rw-r--r--src/rustllvm/PassWrapper.cpp128
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));
 }