Skip to content

Commit

Permalink
Merge pull request #10747 from ihnorton/dumper_cleanup2
Browse files Browse the repository at this point in the history
code_* cleanup, and strip IR metadata from code_llvm output
  • Loading branch information
ihnorton committed Apr 7, 2015
2 parents cd653bb + d593ac7 commit 2459f7f
Show file tree
Hide file tree
Showing 6 changed files with 118 additions and 49 deletions.
2 changes: 2 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,8 @@ Library improvements
* `lock` and `unlock` which operate on `ReentrantLock`. Useful to lock a stream during
concurrent writes from multiple tasks

* `code_llvm` now outputs stripped IR without debug info or other attached metadata.
Use `code_llvm_raw` for the unstripped output ([#10747]).

Deprecated or removed
---------------------
Expand Down
3 changes: 2 additions & 1 deletion base/interactiveutil.jl
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,8 @@ function gen_call_with_extracted_types(fcn, ex0)
exret
end

for fname in [:which, :less, :edit, :code_typed, :code_warntype, :code_lowered, :code_llvm, :code_native]
for fname in [:which, :less, :edit, :code_typed, :code_warntype,
:code_lowered, :code_llvm, :code_llvm_raw, :code_native]
@eval begin
macro ($fname)(ex0)
gen_call_with_extracted_types($(Expr(:quote,fname)), ex0)
Expand Down
25 changes: 19 additions & 6 deletions base/reflection.jl
Original file line number Diff line number Diff line change
Expand Up @@ -156,17 +156,30 @@ done(mt::MethodTable, i::()) = true
uncompressed_ast(l::LambdaStaticData) =
isa(l.ast,Expr) ? l.ast : ccall(:jl_uncompress_ast, Any, (Any,Any), l, l.ast)

function _dump_function(f, t::ANY, native, wrapper)
str = ccall(:jl_dump_function, Any, (Any,Any,Bool,Bool), f, t, native, wrapper)::ByteString
if str == ""
# Printing code representations in IR and assembly
function _dump_function(f, t::ANY, native, wrapper, strip_ir_metadata)
llvmf = ccall(:jl_get_llvmf, Ptr{Void}, (Any, Any, Bool), f, t, wrapper)

if llvmf == C_NULL
error("no method found for the specified argument types")
end
str

if (native)
str = ccall(:jl_dump_function_asm, Any, (Ptr{Void},), llvmf)::ByteString
else
str = ccall(:jl_dump_function_ir, Any,
(Ptr{Void}, Bool), llvmf, strip_ir_metadata)::ByteString
end

return str
end

code_llvm(io::IO, f::Function, types::(Type...)) = print(io, _dump_function(f, types, false, false))
code_llvm(io::IO, f::Function, types::(Type...), strip_ir_metadata = true) =
print(io, _dump_function(f, types, false, false, strip_ir_metadata))
code_llvm(f::Function, types::(Type...)) = code_llvm(STDOUT, f, types)
code_native(io::IO, f::Function, types::(Type...)) = print(io, _dump_function(f, types, true, false))
code_llvm_raw(f::Function, types::(Type...)) = code_llvm(STDOUT, f, types, false)

code_native(io::IO, f::Function, types::(Type...)) = print(io, _dump_function(f, types, true, false, false))
code_native(f::Function, types::(Type...)) = code_native(STDOUT, f, types)

function which(f::ANY, t::(Type...))
Expand Down
2 changes: 2 additions & 0 deletions doc/stdlib/base.rst
Original file line number Diff line number Diff line change
Expand Up @@ -985,6 +985,8 @@ Internals

Prints the LLVM bitcodes generated for running the method matching the given generic function and type signature to :const:`STDOUT`.

All metadata and dbg.* calls are removed from the printed bitcode. Use code_llvm_raw for the full IR.

.. function:: @code_llvm

Evaluates the arguments to the function call, determines their types, and calls :func:`code_llvm` on the resulting expression
Expand Down
133 changes: 92 additions & 41 deletions src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "llvm-version.h"
#include <llvm/ExecutionEngine/ExecutionEngine.h>
#include <llvm/ExecutionEngine/JITEventListener.h>
#include <llvm/IR/IntrinsicInst.h>
#ifdef LLVM37
#include "llvm/IR/LegacyPassManager.h"
#else
Expand Down Expand Up @@ -862,6 +863,12 @@ void *jl_function_ptr(jl_function_t *f, jl_value_t *rt, jl_value_t *argt)
#endif
}


extern "C" DLLEXPORT
void *jl_function_ptr_by_llvm_name(char* name) {
return (void*)(intptr_t)jl_ExecutionEngine->FindFunctionNamed(name);
}

// export a C-callable entry point for a function, with a given name
extern "C" DLLEXPORT
void jl_extern_c(jl_function_t *f, jl_value_t *rt, jl_value_t *argt, char *name)
Expand All @@ -888,43 +895,8 @@ extern int jl_get_llvmf_info(uint64_t fptr, uint64_t *symsize, uint64_t *slide,
#endif
);

extern "C"
void jl_dump_function_asm(uintptr_t Fptr, size_t Fsize, size_t slide,
#ifdef USE_MCJIT
const object::ObjectFile *objectfile,
#else
std::vector<JITEvent_EmittedFunctionDetails::LineStart> lineinfo,
#endif
formatted_raw_ostream &stream);

const jl_value_t *jl_dump_llvmf(void *f, bool dumpasm)
{
std::string code;
llvm::raw_string_ostream stream(code);
llvm::formatted_raw_ostream fstream(stream);
Function *llvmf = (Function*)f;
if (dumpasm == false) {
llvmf->print(stream);
}
else {
uint64_t symsize, slide;
#ifdef USE_MCJIT
uint64_t fptr = jl_ExecutionEngine->getFunctionAddress(llvmf->getName());
const object::ObjectFile *object;
#else
uint64_t fptr = (uintptr_t)jl_ExecutionEngine->getPointerToFunction(llvmf);
std::vector<JITEvent_EmittedFunctionDetails::LineStart> object;
#endif
assert(fptr != 0);
if (jl_get_llvmf_info(fptr, &symsize, &slide, &object))
jl_dump_function_asm(fptr, symsize, slide, object, fstream);
else
jl_printf(JL_STDERR, "Warning: Unable to find function pointer\n");
fstream.flush();
}
return jl_cstr_to_string(const_cast<char*>(stream.str().c_str()));
}

// Get pointer to llvm::Function instance, compiling if necessary
extern "C" DLLEXPORT
void *jl_get_llvmf(jl_function_t *f, jl_tuple_t *types, bool getwrapper)
{
Expand Down Expand Up @@ -964,13 +936,92 @@ void *jl_get_llvmf(jl_function_t *f, jl_tuple_t *types, bool getwrapper)
return llvmf;
}

// Pre-declaration. Definition in disasm.cpp
extern "C"
void jl_dump_asm_internal(uintptr_t Fptr, size_t Fsize, size_t slide,
#ifdef USE_MCJIT
const object::ObjectFile *objectfile,
#else
std::vector<JITEvent_EmittedFunctionDetails::LineStart> lineinfo,
#endif
formatted_raw_ostream &stream);

extern "C" DLLEXPORT
const jl_value_t *jl_dump_function_ir(void *f, bool strip_ir_metadata)
{
std::string code;
llvm::raw_string_ostream stream(code);

Function *llvmf = dyn_cast<Function>((Function*)f);
if (!llvmf)
jl_error("jl_dump_function_ir: Expected Function*");

if (!strip_ir_metadata) {
// print the function IR as-is
llvmf->print(stream);
} else {
// make a copy of the function and strip metadata from the copy
llvm::ValueToValueMapTy VMap;
Function* f2 = llvm::CloneFunction(llvmf, VMap, false);
Function::BasicBlockListType::iterator f2_bb = f2->getBasicBlockList().begin();
// iterate over all basic blocks in the function
for (; f2_bb != f2->getBasicBlockList().end(); ++f2_bb) {
BasicBlock::InstListType::iterator f2_il = (*f2_bb).getInstList().begin();
// iterate over instructions in basic block
for (; f2_il != (*f2_bb).getInstList().end(); ) {
Instruction *inst = f2_il++;
// remove dbg.declare and dbg.value calls
if (isa<DbgDeclareInst>(inst) || isa<DbgValueInst>(inst)) {
inst->eraseFromParent();
continue;
}

SmallVector<std::pair<unsigned, MDNode*>, 4> MDForInst;
inst->getAllMetadata(MDForInst);
SmallVector<std::pair<unsigned, MDNode*>, 4>::iterator md_iter = MDForInst.begin();

// iterate over all metadata kinds and set to NULL to remove
for (; md_iter != MDForInst.end(); ++md_iter) {
inst->setMetadata((*md_iter).first, NULL);
}
}
}
f2->print(stream);
delete f2;
}

return jl_cstr_to_string(const_cast<char*>(stream.str().c_str()));
}

extern "C" DLLEXPORT
const jl_value_t *jl_dump_function(jl_function_t *f, jl_tuple_t *types, bool dumpasm, bool dumpwrapper)
const jl_value_t *jl_dump_function_asm(void *f)
{
void *llvmf = jl_get_llvmf(f,types,dumpwrapper);
if (llvmf == NULL)
return jl_cstr_to_string(const_cast<char*>(""));
return jl_dump_llvmf(llvmf,dumpasm);
std::string code;
llvm::raw_string_ostream stream(code);
llvm::formatted_raw_ostream fstream(stream);

Function *llvmf = dyn_cast<Function>((Function*)f);
if (!llvmf)
jl_error("jl_dump_function_asm: Expected Function*");

// Dump assembly code
uint64_t symsize, slide;
#ifdef USE_MCJIT
uint64_t fptr = jl_ExecutionEngine->getFunctionAddress(llvmf->getName());
const object::ObjectFile *object;
#else
uint64_t fptr = (uintptr_t)jl_ExecutionEngine->getPointerToFunction(llvmf);
std::vector<JITEvent_EmittedFunctionDetails::LineStart> object;
#endif
assert(fptr != 0);
if (jl_get_llvmf_info(fptr, &symsize, &slide, &object)) {
jl_dump_asm_internal(fptr, symsize, slide, object, fstream);
} else {
jl_printf(JL_STDERR, "Warning: Unable to find function pointer\n");
}
fstream.flush();

return jl_cstr_to_string(const_cast<char*>(stream.str().c_str()));
}

// Code coverage
Expand Down
2 changes: 1 addition & 1 deletion src/disasm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ int OpInfoLookup(void *DisInfo, uint64_t PC,
} // namespace

extern "C"
void jl_dump_function_asm(uintptr_t Fptr, size_t Fsize, size_t slide,
void jl_dump_asm_internal(uintptr_t Fptr, size_t Fsize, size_t slide,
#ifndef USE_MCJIT
std::vector<JITEvent_EmittedFunctionDetails::LineStart> lineinfo,
#else
Expand Down

0 comments on commit 2459f7f

Please sign in to comment.