diff --git a/src/aotcompile.cpp b/src/aotcompile.cpp index 96364d9904816..cb22bd8077341 100644 --- a/src/aotcompile.cpp +++ b/src/aotcompile.cpp @@ -5,11 +5,11 @@ // target support #include +#include +#include +#include #include #include -#include -#include -#include // analysis passes #include @@ -36,19 +36,11 @@ #endif #endif -// for outputting assembly +// for outputting code #include #include #include "llvm/Object/ArchiveWriter.h" #include -#include -#include -#include -#include -#include -#include -#include -#include #include #include @@ -494,10 +486,10 @@ void jl_dump_native(void *native_code, addTargetPasses(&PM, TM.get()); // set up optimization passes - SmallVector bc_Buffer; - SmallVector obj_Buffer; - SmallVector asm_Buffer; - SmallVector unopt_bc_Buffer; + SmallVector bc_Buffer; + SmallVector obj_Buffer; + SmallVector asm_Buffer; + SmallVector unopt_bc_Buffer; raw_svector_ostream bc_OS(bc_Buffer); raw_svector_ostream obj_OS(obj_Buffer); raw_svector_ostream asm_OS(asm_Buffer); @@ -864,7 +856,7 @@ void jl_add_optimization_passes(LLVMPassManagerRef PM, int opt_level, int lower_ // --- native code info, and dump function to IR and ASM --- // Get pointer to llvm::Function instance, compiling if necessary // for use in reflection from Julia. -// this is paired with jl_dump_function_ir, jl_dump_method_asm, jl_dump_llvm_asm in particular ways: +// this is paired with jl_dump_function_ir, jl_dump_function_asm, jl_dump_method_asm in particular ways: // misuse will leak memory or cause read-after-free extern "C" JL_DLLEXPORT void *jl_get_llvmf_defn(jl_method_instance_t *mi, size_t world, char getwrapper, char optimize, const jl_cgparams_t params) @@ -952,74 +944,3 @@ void *jl_get_llvmf_defn(jl_method_instance_t *mi, size_t world, char getwrapper, const char *mname = name_from_method_instance(mi); jl_errorf("unable to compile source for function %s", mname); } - -/// addPassesToX helper drives creation and initialization of TargetPassConfig. -static MCContext * -addPassesToGenerateCode(LLVMTargetMachine *TM, PassManagerBase &PM) { - TargetPassConfig *PassConfig = TM->createPassConfig(PM); - PassConfig->setDisableVerify(false); - PM.add(PassConfig); - MachineModuleInfoWrapperPass *MMIWP = - new MachineModuleInfoWrapperPass(TM); - PM.add(MMIWP); - if (PassConfig->addISelPasses()) - return NULL; - PassConfig->addMachinePasses(); - PassConfig->setInitialized(); - return &MMIWP->getMMI().getContext(); -} - -void jl_strip_llvm_debug(Module *m); - - -// get a native assembly for llvm::Function -// TODO: implement debuginfo handling -extern "C" JL_DLLEXPORT -jl_value_t *jl_dump_llvm_asm(void *F, const char* asm_variant, const char *debuginfo) -{ - // precise printing via IR assembler - SmallVector ObjBufferSV; - { // scope block - Function *f = (Function*)F; - llvm::raw_svector_ostream asmfile(ObjBufferSV); - assert(!f->isDeclaration()); - std::unique_ptr m(f->getParent()); - for (auto &f2 : m->functions()) { - if (f != &f2 && !f->isDeclaration()) - f2.deleteBody(); - } - jl_strip_llvm_debug(m.get()); - legacy::PassManager PM; - LLVMTargetMachine *TM = static_cast(jl_TargetMachine); - MCContext *Context = addPassesToGenerateCode(TM, PM); - if (Context) { - const MCSubtargetInfo &STI = *TM->getMCSubtargetInfo(); - const MCAsmInfo &MAI = *TM->getMCAsmInfo(); - const MCRegisterInfo &MRI = *TM->getMCRegisterInfo(); - const MCInstrInfo &MII = *TM->getMCInstrInfo(); - unsigned OutputAsmDialect = MAI.getAssemblerDialect(); - if (!strcmp(asm_variant, "att")) - OutputAsmDialect = 0; - if (!strcmp(asm_variant, "intel")) - OutputAsmDialect = 1; - MCInstPrinter *InstPrinter = TM->getTarget().createMCInstPrinter( - TM->getTargetTriple(), OutputAsmDialect, MAI, MII, MRI); - std::unique_ptr MAB(TM->getTarget().createMCAsmBackend( - STI, MRI, TM->Options.MCOptions)); - std::unique_ptr MCE; - auto FOut = std::make_unique(asmfile); - std::unique_ptr S(TM->getTarget().createAsmStreamer( - *Context, std::move(FOut), true, - true, InstPrinter, - std::move(MCE), std::move(MAB), - false)); - std::unique_ptr Printer( - TM->getTarget().createAsmPrinter(*TM, std::move(S))); - if (Printer) { - PM.add(Printer.release()); - PM.run(*m); - } - } - } - return jl_pchar_to_string(ObjBufferSV.data(), ObjBufferSV.size()); -} diff --git a/src/disasm.cpp b/src/disasm.cpp index dfc1e32b56eeb..afcd8d65659e9 100644 --- a/src/disasm.cpp +++ b/src/disasm.cpp @@ -22,43 +22,53 @@ #include #include "llvm-version.h" -#include -#include + +// for outputting disassembly +#include +#include #include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include +#include #include -#include -#include #include +#include +#include #include +#include +#include #include +#include +#include +#include +#include +#include #include -#include -#include -#include -#include +#include +#include #include +#include #include #include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include + +// for outputting assembly +#include +#include +#include +#include +#include +#include #include #include "julia.h" @@ -279,20 +289,26 @@ void DILineInfoPrinter::emit_lineinfo(raw_ostream &Out, std::vector // adaptor class for printing line numbers before llvm IR lines class LineNumberAnnotatedWriter : public AssemblyAnnotationWriter { - DILocation *InstrLoc = nullptr; - DILineInfoPrinter LinePrinter{"; ", false}; + const DILocation *InstrLoc = nullptr; + DILineInfoPrinter LinePrinter; DenseMap DebugLoc; DenseMap Subprogram; public: - LineNumberAnnotatedWriter(const char *debuginfo) - { + LineNumberAnnotatedWriter(const char *LineStart, bool bracket_outer, const char *debuginfo) + : LinePrinter(LineStart, bracket_outer) { LinePrinter.SetVerbosity(debuginfo); } virtual void emitFunctionAnnot(const Function *, formatted_raw_ostream &); virtual void emitInstructionAnnot(const Instruction *, formatted_raw_ostream &); + virtual void emitInstructionAnnot(const DILocation *, formatted_raw_ostream &); virtual void emitBasicBlockEndAnnot(const BasicBlock *, formatted_raw_ostream &); // virtual void printInfoComment(const Value &, formatted_raw_ostream &) {} + void emitEnd(formatted_raw_ostream &Out) { + LinePrinter.emit_finish(Out); + InstrLoc = nullptr; + } + void addSubprogram(const Function *F, DISubprogram *SP) { Subprogram[F] = SP; @@ -327,12 +343,19 @@ void LineNumberAnnotatedWriter::emitFunctionAnnot( void LineNumberAnnotatedWriter::emitInstructionAnnot( const Instruction *I, formatted_raw_ostream &Out) { - DILocation *NewInstrLoc = I->getDebugLoc(); + const DILocation *NewInstrLoc = I->getDebugLoc(); if (!NewInstrLoc) { auto Loc = DebugLoc.find(I); if (Loc != DebugLoc.end()) NewInstrLoc = Loc->second; } + emitInstructionAnnot(NewInstrLoc, Out); + Out << LinePrinter.inlining_indent(" "); +} + +void LineNumberAnnotatedWriter::emitInstructionAnnot( + const DILocation *NewInstrLoc, formatted_raw_ostream &Out) +{ if (NewInstrLoc && NewInstrLoc != InstrLoc) { InstrLoc = NewInstrLoc; std::vector DIvec; @@ -348,14 +371,13 @@ void LineNumberAnnotatedWriter::emitInstructionAnnot( } while (NewInstrLoc); LinePrinter.emit_lineinfo(Out, DIvec); } - Out << LinePrinter.inlining_indent(" "); } void LineNumberAnnotatedWriter::emitBasicBlockEndAnnot( const BasicBlock *BB, formatted_raw_ostream &Out) { if (BB == &BB->getParent()->back()) - LinePrinter.emit_finish(Out); + emitEnd(Out); } static void jl_strip_llvm_debug(Module *m, bool all_meta, LineNumberAnnotatedWriter *AAW) @@ -435,7 +457,7 @@ jl_value_t *jl_dump_function_ir(void *f, char strip_ir_metadata, char dump_modul jl_error("jl_dump_function_ir: Expected Function* in a temporary Module"); JL_LOCK(&codegen_lock); // Might GC - LineNumberAnnotatedWriter AAW{debuginfo}; + LineNumberAnnotatedWriter AAW{"; ", false, debuginfo}; if (!llvmf->getParent()) { // print the function declaration as-is llvmf->print(stream, &AAW); @@ -507,7 +529,7 @@ static uint64_t compute_obj_symsize(object::SectionRef Section, uint64_t offset) // print a native disassembly for the function starting at fptr extern "C" JL_DLLEXPORT -jl_value_t *jl_dump_fptr_asm(uint64_t fptr, int raw_mc, const char* asm_variant, const char *debuginfo, char binary) +jl_value_t *jl_dump_fptr_asm(uint64_t fptr, char raw_mc, const char* asm_variant, const char *debuginfo, char binary) { assert(fptr != 0); std::string code; @@ -1046,6 +1068,138 @@ static void jl_dump_asm_internal( } } +/// addPassesToX helper drives creation and initialization of TargetPassConfig. +static MCContext * +addPassesToGenerateCode(LLVMTargetMachine *TM, PassManagerBase &PM) { + TargetPassConfig *PassConfig = TM->createPassConfig(PM); + PassConfig->setDisableVerify(false); + PM.add(PassConfig); + MachineModuleInfoWrapperPass *MMIWP = + new MachineModuleInfoWrapperPass(TM); + PM.add(MMIWP); + if (PassConfig->addISelPasses()) + return NULL; + PassConfig->addMachinePasses(); + PassConfig->setInitialized(); + return &MMIWP->getMMI().getContext(); +} + +class LineNumberPrinterHandler : public AsmPrinterHandler { + MCStreamer &S; + LineNumberAnnotatedWriter LinePrinter; + std::string Buffer; + llvm::raw_string_ostream RawStream; + llvm::formatted_raw_ostream Stream; + +public: + LineNumberPrinterHandler(AsmPrinter &Printer, const char *debuginfo) + : S(*Printer.OutStreamer), + LinePrinter("; ", true, debuginfo), + RawStream(Buffer), + Stream(RawStream) {} + + void emitAndReset() { + Stream.flush(); + RawStream.flush(); + if (Buffer.empty()) + return; + S.emitRawText(Buffer); + Buffer.clear(); + } + + virtual void setSymbolSize(const MCSymbol *Sym, uint64_t Size) override {} + //virtual void beginModule(Module *M) override {} + virtual void endModule() override {} + /// note that some AsmPrinter implementations may not call beginFunction at all + virtual void beginFunction(const MachineFunction *MF) override { + LinePrinter.emitFunctionAnnot(&MF->getFunction(), Stream); + emitAndReset(); + } + //virtual void markFunctionEnd() override {} + virtual void endFunction(const MachineFunction *MF) override { + LinePrinter.emitEnd(Stream); + emitAndReset(); + } + //virtual void beginFragment(const MachineBasicBlock *MBB, + // ExceptionSymbolProvider ESP) override {} + //virtual void endFragment() override {} + //virtual void beginFunclet(const MachineBasicBlock &MBB, + // MCSymbol *Sym = nullptr) override {} + //virtual void endFunclet() override {} + virtual void beginInstruction(const MachineInstr *MI) override { + LinePrinter.emitInstructionAnnot(MI->getDebugLoc(), Stream); + emitAndReset(); + } + virtual void endInstruction() override {} +}; + +// get a native assembly for llvm::Function +extern "C" JL_DLLEXPORT +jl_value_t *jl_dump_function_asm(void *F, char raw_mc, const char* asm_variant, const char *debuginfo, char binary) +{ + // precise printing via IR assembler + SmallVector ObjBufferSV; + { // scope block + Function *f = (Function*)F; + llvm::raw_svector_ostream asmfile(ObjBufferSV); + assert(!f->isDeclaration()); + std::unique_ptr m(f->getParent()); + for (auto &f2 : m->functions()) { + if (f != &f2 && !f->isDeclaration()) + f2.deleteBody(); + } + LLVMTargetMachine *TM = static_cast(jl_TargetMachine); + legacy::PassManager PM; + addTargetPasses(&PM, TM); + if (raw_mc) { + raw_svector_ostream obj_OS(ObjBufferSV); + if (TM->addPassesToEmitFile(PM, obj_OS, nullptr, CGFT_ObjectFile, false, nullptr)) + return jl_an_empty_string; + PM.run(*m); + } + else { + MCContext *Context = addPassesToGenerateCode(TM, PM); + if (!Context) + return jl_an_empty_string; + Context->setGenDwarfForAssembly(false); + // Duplicate LLVMTargetMachine::addAsmPrinter here so we can set the asm dialect and add the custom annotation printer + const MCSubtargetInfo &STI = *TM->getMCSubtargetInfo(); + const MCAsmInfo &MAI = *TM->getMCAsmInfo(); + const MCRegisterInfo &MRI = *TM->getMCRegisterInfo(); + const MCInstrInfo &MII = *TM->getMCInstrInfo(); + unsigned OutputAsmDialect = MAI.getAssemblerDialect(); + if (!strcmp(asm_variant, "att")) + OutputAsmDialect = 0; + if (!strcmp(asm_variant, "intel")) + OutputAsmDialect = 1; + MCInstPrinter *InstPrinter = TM->getTarget().createMCInstPrinter( + TM->getTargetTriple(), OutputAsmDialect, MAI, MII, MRI); + std::unique_ptr MAB(TM->getTarget().createMCAsmBackend( + STI, MRI, TM->Options.MCOptions)); + std::unique_ptr MCE; + if (binary) // enable MCAsmStreamer::AddEncodingComment printing + MCE.reset(TM->getTarget().createMCCodeEmitter(MII, MRI, *Context)); + auto FOut = std::make_unique(asmfile); + std::unique_ptr S(TM->getTarget().createAsmStreamer( + *Context, std::move(FOut), true, + true, InstPrinter, + std::move(MCE), std::move(MAB), + false)); + std::unique_ptr Printer( + TM->getTarget().createAsmPrinter(*TM, std::move(S))); + Printer->addAsmPrinterHandler(AsmPrinter::HandlerInfo( + std::unique_ptr(new LineNumberPrinterHandler(*Printer, debuginfo)), + "emit", "Debug Info Emission", "Julia", "Julia::LineNumberPrinterHandler Markup")); + if (!Printer) + return jl_an_empty_string; + PM.add(Printer.release()); + PM.add(createFreeMachineFunctionPass()); + PM.run(*m); + } + } + return jl_pchar_to_string(ObjBufferSV.data(), ObjBufferSV.size()); +} + extern "C" JL_DLLEXPORT LLVMDisasmContextRef jl_LLVMCreateDisasm( const char *TripleName, void *DisInfo, int TagType, diff --git a/src/jitlayers.cpp b/src/jitlayers.cpp index e86d6109ff427..92af6ae460004 100644 --- a/src/jitlayers.cpp +++ b/src/jitlayers.cpp @@ -181,7 +181,7 @@ static jl_callptr_t _jl_compile_codeinst( jl_atomic_store_release(&this_code->invoke, addr); } else if (this_code->invoke == jl_fptr_const_return && !decls.specFunctionObject.empty()) { - // hack to export this pointer value to jl_dump_method_asm + // hack to export this pointer value to jl_dump_method_disasm this_code->specptr.fptr = (void*)getAddressForFunction(decls.specFunctionObject); } if (this_code== codeinst) @@ -407,7 +407,7 @@ void jl_generate_fptr_for_unspecialized(jl_code_instance_t *unspec) // get a native disassembly for a compiled method extern "C" JL_DLLEXPORT jl_value_t *jl_dump_method_asm(jl_method_instance_t *mi, size_t world, - int raw_mc, char getwrapper, const char* asm_variant, const char *debuginfo, char binary) + char raw_mc, char getwrapper, const char* asm_variant, const char *debuginfo, char binary) { // printing via disassembly jl_code_instance_t *codeinst = jl_generate_fptr(mi, world); @@ -457,9 +457,10 @@ jl_value_t *jl_dump_method_asm(jl_method_instance_t *mi, size_t world, } // whatever, that didn't work - use the assembler output instead - if (raw_mc) // eh, give up, this flag doesn't really work anyways normally - return (jl_value_t*)jl_pchar_to_array("", 0); - return jl_dump_llvm_asm(jl_get_llvmf_defn(mi, world, getwrapper, true, jl_default_cgparams), asm_variant, debuginfo); + void *F = jl_get_llvmf_defn(mi, world, getwrapper, true, jl_default_cgparams); + if (!F) + return jl_an_empty_string; + return jl_dump_function_asm(F, raw_mc, asm_variant, debuginfo, binary); } // A simple forwarding class, since OrcJIT v2 needs a unique_ptr, while we have a shared_ptr diff --git a/src/jl_exported_funcs.inc b/src/jl_exported_funcs.inc index 8e2c21fb6dfec..c85b1a48e2ba4 100644 --- a/src/jl_exported_funcs.inc +++ b/src/jl_exported_funcs.inc @@ -120,9 +120,9 @@ XX(jl_dlsym) \ XX(jl_dump_compiles) \ XX(jl_dump_fptr_asm) \ + XX(jl_dump_function_asm) \ XX(jl_dump_function_ir) \ XX(jl_dump_host_cpu) \ - XX(jl_dump_llvm_asm) \ XX(jl_dump_method_asm) \ XX(jl_egal) \ XX(jl_egal__bits) \ diff --git a/src/julia_internal.h b/src/julia_internal.h index b997ad0d1214a..8f2f87acca3fe 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -798,11 +798,11 @@ static inline void jl_set_gc_and_wait(void) void jl_gc_set_permalloc_region(void *start, void *end); JL_DLLEXPORT jl_value_t *jl_dump_method_asm(jl_method_instance_t *linfo, size_t world, - int raw_mc, char getwrapper, const char* asm_variant, const char *debuginfo, char binary); + char raw_mc, char getwrapper, const char* asm_variant, const char *debuginfo, char binary); JL_DLLEXPORT void *jl_get_llvmf_defn(jl_method_instance_t *linfo, size_t world, char getwrapper, char optimize, const jl_cgparams_t params); -JL_DLLEXPORT jl_value_t *jl_dump_fptr_asm(uint64_t fptr, int raw_mc, const char* asm_variant, const char *debuginfo, char binary); -JL_DLLEXPORT jl_value_t *jl_dump_llvm_asm(void *F, const char* asm_variant, const char *debuginfo); +JL_DLLEXPORT jl_value_t *jl_dump_fptr_asm(uint64_t fptr, char raw_mc, const char* asm_variant, const char *debuginfo, char binary); JL_DLLEXPORT jl_value_t *jl_dump_function_ir(void *f, char strip_ir_metadata, char dump_module, const char *debuginfo); +JL_DLLEXPORT jl_value_t *jl_dump_function_asm(void *F, char raw_mc, const char* asm_variant, const char *debuginfo, char binary); void *jl_create_native(jl_array_t *methods, const jl_cgparams_t cgparams, int policy); void jl_dump_native(void *native_code, diff --git a/stdlib/InteractiveUtils/src/codeview.jl b/stdlib/InteractiveUtils/src/codeview.jl index d6f7cd9daa24d..b292324a17134 100644 --- a/stdlib/InteractiveUtils/src/codeview.jl +++ b/stdlib/InteractiveUtils/src/codeview.jl @@ -143,7 +143,7 @@ import Base.CodegenParams function _dump_function(@nospecialize(f), @nospecialize(t), native::Bool, wrapper::Bool, strip_ir_metadata::Bool, dump_module::Bool, syntax::Symbol, optimize::Bool, debuginfo::Symbol, binary::Bool, - params::CodegenParams=CodegenParams()) + params::CodegenParams=CodegenParams(debug_info_kind=Cint(0))) ccall(:jl_is_in_pure_context, Bool, ()) && error("code reflection cannot be used from generated functions") if isa(f, Core.Builtin) throw(ArgumentError("argument is not a generic function")) @@ -153,8 +153,20 @@ function _dump_function(@nospecialize(f), @nospecialize(t), native::Bool, wrappe match = Base._which(signature_type(f, t), world) linfo = Core.Compiler.specialize_method(match) # get the code for it + if debuginfo === :default + debuginfo = :source + elseif debuginfo !== :source && debuginfo !== :none + throw(ArgumentError("'debuginfo' must be either :source or :none")) + end if native - str = _dump_function_linfo_native(linfo, world, wrapper, syntax, debuginfo, binary) + if syntax !== :att && syntax !== :intel + throw(ArgumentError("'syntax' must be either :intel or :att")) + end + if dump_module + str = _dump_function_linfo_native(linfo, world, wrapper, syntax, debuginfo, binary, params) + else + str = _dump_function_linfo_native(linfo, world, wrapper, syntax, debuginfo, binary) + end else str = _dump_function_linfo_llvm(linfo, world, wrapper, strip_ir_metadata, dump_module, optimize, debuginfo, params) end @@ -164,17 +176,18 @@ function _dump_function(@nospecialize(f), @nospecialize(t), native::Bool, wrappe end function _dump_function_linfo_native(linfo::Core.MethodInstance, world::UInt, wrapper::Bool, syntax::Symbol, debuginfo::Symbol, binary::Bool) - if syntax !== :att && syntax !== :intel - throw(ArgumentError("'syntax' must be either :intel or :att")) - end - if debuginfo === :default - debuginfo = :source - elseif debuginfo !== :source && debuginfo !== :none - throw(ArgumentError("'debuginfo' must be either :source or :none")) - end str = ccall(:jl_dump_method_asm, Ref{String}, - (Any, UInt, Cint, Bool, Ptr{UInt8}, Ptr{UInt8}, Bool), - linfo, world, 0, wrapper, syntax, debuginfo, binary) + (Any, UInt, Bool, Bool, Ptr{UInt8}, Ptr{UInt8}, Bool), + linfo, world, false, wrapper, syntax, debuginfo, binary) + return str +end + +function _dump_function_linfo_native(linfo::Core.MethodInstance, world::UInt, wrapper::Bool, syntax::Symbol, debuginfo::Symbol, binary::Bool, params::CodegenParams) + llvmf = ccall(:jl_get_llvmf_defn, Ptr{Cvoid}, (Any, UInt, Bool, Bool, CodegenParams), linfo, world, wrapper, true, params) + llvmf == C_NULL && error("could not compile the specified method") + str = ccall(:jl_dump_function_asm, Ref{String}, + (Ptr{Cvoid}, Bool, Ptr{UInt8}, Ptr{UInt8}, Bool), + llvmf, false, syntax, debuginfo, binary) return str end @@ -183,11 +196,6 @@ function _dump_function_linfo_llvm( strip_ir_metadata::Bool, dump_module::Bool, optimize::Bool, debuginfo::Symbol, params::CodegenParams) - if debuginfo === :default - debuginfo = :source - elseif debuginfo !== :source && debuginfo !== :none - throw(ArgumentError("'debuginfo' must be either :source or :none")) - end llvmf = ccall(:jl_get_llvmf_defn, Ptr{Cvoid}, (Any, UInt, Bool, Bool, CodegenParams), linfo, world, wrapper, optimize, params) llvmf == C_NULL && error("could not compile the specified method") str = ccall(:jl_dump_function_ir, Ref{String}, @@ -219,11 +227,11 @@ end code_llvm(io::IO, @nospecialize(f), @nospecialize(types=Tuple); raw::Bool=false, dump_module::Bool=false, optimize::Bool=true, debuginfo::Symbol=:default) = code_llvm(io, f, types, raw, dump_module, optimize, debuginfo) code_llvm(@nospecialize(f), @nospecialize(types=Tuple); raw=false, dump_module=false, optimize=true, debuginfo::Symbol=:default) = - code_llvm(stdout, f, types; raw=raw, dump_module=dump_module, optimize=optimize, debuginfo=debuginfo) + code_llvm(stdout, f, types; raw, dump_module, optimize, debuginfo) """ - code_native([io=stdout,], f, types; syntax=:att, debuginfo=:default, binary=false) + code_native([io=stdout,], f, types; syntax=:att, debuginfo=:default, binary=false, dump_module=true) Prints the native assembly instructions generated for running the method matching the given generic function and type signature to `io`. @@ -232,17 +240,17 @@ Keyword argument `debuginfo` may be one of source (default) or none, to specify If `binary` is `true`, it also prints the binary machine code for each instruction precedented by an abbreviated address. """ function code_native(io::IO, @nospecialize(f), @nospecialize(types=Tuple); - syntax::Symbol=:att, debuginfo::Symbol=:default, binary::Bool=false) - d = _dump_function(f, types, true, false, false, false, syntax, true, debuginfo, binary) + dump_module::Bool=true, syntax::Symbol=:att, debuginfo::Symbol=:default, binary::Bool=false) + d = _dump_function(f, types, true, false, false, dump_module, syntax, true, debuginfo, binary) if highlighting[:native] && get(io, :color, false) print_native(io, d) else print(io, d) end end -code_native(@nospecialize(f), @nospecialize(types=Tuple); syntax::Symbol=:att, debuginfo::Symbol=:default, binary::Bool=false) = - code_native(stdout, f, types; syntax=syntax, debuginfo=debuginfo, binary=binary) -code_native(::IO, ::Any, ::Symbol) = error("illegal code_native call") # resolve ambiguous call +code_native(@nospecialize(f), @nospecialize(types=Tuple); dump_module::Bool=true, syntax::Symbol=:att, debuginfo::Symbol=:default, binary::Bool=false) = + code_native(stdout, f, types; dump_module, syntax, debuginfo, binary) +code_native(::IO, ::Any, ::Symbol) = error("invalid code_native call") # resolve ambiguous call ## colorized IR and assembly printing diff --git a/stdlib/InteractiveUtils/test/runtests.jl b/stdlib/InteractiveUtils/test/runtests.jl index 8770de8797f04..8258881f56711 100644 --- a/stdlib/InteractiveUtils/test/runtests.jl +++ b/stdlib/InteractiveUtils/test/runtests.jl @@ -331,7 +331,7 @@ let err = tempname(), redirect_stderr(new_stderr) println(new_stderr, "start") flush(new_stderr) - @eval @test occursin("h_broken_code", sprint(code_native, h_broken_code, ())) + @test occursin("h_broken_code", sprint(code_native, h_broken_code, ())) Libc.flush_cstdio() println(new_stderr, "end") flush(new_stderr) @@ -341,10 +341,11 @@ let err = tempname(), close(new_stderr) let errstr = read(err, String) @test startswith(errstr, """start + end Internal error: encountered unexpected error during compilation of f_broken_code: ErrorException(\"unsupported or misplaced expression \"invalid\" in function f_broken_code\") """) || errstr - @test endswith(errstr, "\nend\n") || errstr + @test !endswith(errstr, "\nend\n") || errstr end rm(err) end @@ -444,12 +445,12 @@ if Sys.ARCH === :x86_64 || occursin(ix86, string(Sys.ARCH)) buf = IOBuffer() #test that the string output is at&t syntax by checking for occurrences of '%'s code_native(buf, linear_foo, (), syntax = :att, debuginfo = :none) - output = String(take!(buf)) + output = replace(String(take!(buf)), r"#[^\r\n]+" => "") @test occursin(rgx, output) #test that the code output is intel syntax by checking it has no occurrences of '%' code_native(buf, linear_foo, (), syntax = :intel, debuginfo = :none) - output = String(take!(buf)) + output = replace(String(take!(buf)), r"#[^\r\n]+" => "") @test !occursin(rgx, output) code_native(buf, linear_foo, ()) @@ -461,13 +462,13 @@ if Sys.ARCH === :x86_64 || occursin(ix86, string(Sys.ARCH)) ret = r"^; [0-9a-f]{4}: c3$"m # without binary flag (default) - code_native(buf, linear_foo, ()) + code_native(buf, linear_foo, (), dump_module=false) output = String(take!(buf)) @test !occursin(ret, output) # with binary flag for binary in false:true - code_native(buf, linear_foo, (), binary = binary) + code_native(buf, linear_foo, (); binary, dump_module=false) output = String(take!(buf)) @test occursin(ret, output) == binary end