|
41 | 41 | #include <llvm/Bitcode/BitcodeWriterPass.h> |
42 | 42 | #include "llvm/Object/ArchiveWriter.h" |
43 | 43 | #include <llvm/IR/IRPrintingPasses.h> |
| 44 | +#include <llvm/CodeGen/MachineModuleInfo.h> |
| 45 | +#include <llvm/CodeGen/TargetPassConfig.h> |
| 46 | +#if JL_LLVM_VERSION < 50000 |
| 47 | +#include <llvm/CodeGen/Passes.h> |
| 48 | +#include <llvm/CodeGen/AsmPrinter.h> |
| 49 | +#endif |
44 | 50 |
|
45 | 51 | #include <llvm/IR/LegacyPassManagers.h> |
46 | 52 | #include <llvm/Transforms/Utils/Cloning.h> |
@@ -721,3 +727,199 @@ extern "C" JL_DLLEXPORT |
721 | 727 | void jl_add_optimization_passes(LLVMPassManagerRef PM, int opt_level) { |
722 | 728 | addOptimizationPasses(unwrap(PM), opt_level); |
723 | 729 | } |
| 730 | + |
| 731 | +// --- native code info, and dump function to IR and ASM --- |
| 732 | +// Get pointer to llvm::Function instance, compiling if necessary |
| 733 | +// for use in reflection from Julia. |
| 734 | +// this is paired with jl_dump_function_ir, jl_dump_method_asm, jl_dump_llvm_asm in particular ways: |
| 735 | +// misuse will leak memory or cause read-after-free |
| 736 | +extern "C" JL_DLLEXPORT |
| 737 | +void *jl_get_llvmf_defn(jl_method_instance_t *linfo, size_t world, char getwrapper, char optimize, const jl_cgparams_t params) |
| 738 | +{ |
| 739 | + if (jl_is_method(linfo->def.method) && linfo->def.method->source == NULL && |
| 740 | + linfo->def.method->generator == NULL) { |
| 741 | + // not a generic function |
| 742 | + return NULL; |
| 743 | + } |
| 744 | + |
| 745 | + static legacy::PassManager *PM; |
| 746 | + if (!PM) { |
| 747 | + PM = new legacy::PassManager(); |
| 748 | + addTargetPasses(PM, jl_TargetMachine); |
| 749 | + addOptimizationPasses(PM, jl_options.opt_level); |
| 750 | + } |
| 751 | + |
| 752 | + // get the source code for this function |
| 753 | + jl_code_info_t *src = (jl_code_info_t*)linfo->inferred; |
| 754 | + JL_GC_PUSH1(&src); |
| 755 | + if (!src || (jl_value_t*)src == jl_nothing) { |
| 756 | + src = jl_type_infer(&linfo, world, 0); |
| 757 | + if (!src && jl_is_method(linfo->def.method)) |
| 758 | + src = linfo->def.method->generator ? jl_code_for_staged(linfo) : (jl_code_info_t*)linfo->def.method->source; |
| 759 | + } |
| 760 | + if ((jl_value_t*)src == jl_nothing) |
| 761 | + src = NULL; |
| 762 | + if (src && !jl_is_code_info(src) && jl_is_method(linfo->def.method)) |
| 763 | + src = jl_uncompress_ast(linfo->def.method, (jl_array_t*)src); |
| 764 | + |
| 765 | + // emit this function into a new module |
| 766 | + if (src && jl_is_code_info(src)) { |
| 767 | + jl_codegen_params_t output; |
| 768 | + output.world = world; |
| 769 | + output.params = ¶ms; |
| 770 | + std::unique_ptr<Module> m; |
| 771 | + jl_llvm_functions_t decls; |
| 772 | + jl_value_t *rettype; |
| 773 | + uint8_t api; |
| 774 | + JL_LOCK(&codegen_lock); |
| 775 | + std::tie(m, decls, rettype, api) = jl_compile_linfo1(linfo, src, output); |
| 776 | + |
| 777 | + Function *F = NULL; |
| 778 | + if (m) { |
| 779 | + // if compilation succeeded, prepare to return the result |
| 780 | + const std::string *fname; |
| 781 | + if (!getwrapper && !decls.specFunctionObject.empty()) |
| 782 | + fname = &decls.specFunctionObject; |
| 783 | + else |
| 784 | + fname = &decls.functionObject; |
| 785 | + if (optimize) |
| 786 | + PM->run(*m.get()); |
| 787 | + F = cast<Function>(m->getNamedValue(*fname)); |
| 788 | + m.release(); // the return object `llvmf` will be the owning pointer |
| 789 | + } |
| 790 | + JL_GC_POP(); |
| 791 | + JL_UNLOCK(&codegen_lock); // Might GC |
| 792 | + if (F) |
| 793 | + return F; |
| 794 | + } |
| 795 | + |
| 796 | + const char *mname = name_from_method_instance(linfo); |
| 797 | + jl_errorf("unable to compile source for function %s", mname); |
| 798 | +} |
| 799 | + |
| 800 | +/// addPassesToX helper drives creation and initialization of TargetPassConfig. |
| 801 | +#if JL_LLVM_VERSION >= 50000 |
| 802 | +static MCContext * |
| 803 | +addPassesToGenerateCode(LLVMTargetMachine *TM, PassManagerBase &PM) { |
| 804 | + TargetPassConfig *PassConfig = TM->createPassConfig(PM); |
| 805 | +#if JL_LLVM_VERSION < 60000 |
| 806 | + PassConfig->setStartStopPasses(nullptr, nullptr, nullptr, nullptr); |
| 807 | +#endif |
| 808 | + PassConfig->setDisableVerify(false); |
| 809 | + PM.add(PassConfig); |
| 810 | + MachineModuleInfo *MMI = new MachineModuleInfo(TM); |
| 811 | + PM.add(MMI); |
| 812 | + if (PassConfig->addISelPasses()) |
| 813 | + return NULL; |
| 814 | + PassConfig->addMachinePasses(); |
| 815 | + PassConfig->setInitialized(); |
| 816 | + return &MMI->getContext(); |
| 817 | +} |
| 818 | +#else |
| 819 | +static MCContext * |
| 820 | +addPassesToGenerateCode(LLVMTargetMachine *TM, PassManagerBase &PM) { |
| 821 | + // When in emulated TLS mode, add the LowerEmuTLS pass. |
| 822 | + if (TM->Options.EmulatedTLS) |
| 823 | + PM.add(createLowerEmuTLSPass(TM)); |
| 824 | + |
| 825 | + PM.add(createPreISelIntrinsicLoweringPass()); |
| 826 | + |
| 827 | + // Add internal analysis passes from the target machine. |
| 828 | + PM.add(createTargetTransformInfoWrapperPass(TM->getTargetIRAnalysis())); |
| 829 | + |
| 830 | + // Targets may override createPassConfig to provide a target-specific |
| 831 | + // subclass. |
| 832 | + TargetPassConfig *PassConfig = TM->createPassConfig(PM); |
| 833 | + PassConfig->setStartStopPasses(nullptr, nullptr, nullptr); |
| 834 | + |
| 835 | + // Set PassConfig options provided by TargetMachine. |
| 836 | + PassConfig->setDisableVerify(false); |
| 837 | + |
| 838 | + PM.add(PassConfig); |
| 839 | + |
| 840 | + PassConfig->addIRPasses(); |
| 841 | + |
| 842 | + PassConfig->addCodeGenPrepare(); |
| 843 | + |
| 844 | + PassConfig->addPassesToHandleExceptions(); |
| 845 | + |
| 846 | + PassConfig->addISelPrepare(); |
| 847 | + |
| 848 | + MachineModuleInfo &MMI = TM->addMachineModuleInfo(PM); |
| 849 | + TM->addMachineFunctionAnalysis(PM, nullptr); |
| 850 | + |
| 851 | + // Disable FastISel with -O0 |
| 852 | + TM->setO0WantsFastISel(false); |
| 853 | + |
| 854 | + if (PassConfig->addInstSelector()) |
| 855 | + return nullptr; |
| 856 | + |
| 857 | + PassConfig->addMachinePasses(); |
| 858 | + |
| 859 | + PassConfig->setInitialized(); |
| 860 | + |
| 861 | + return &MMI.getContext(); |
| 862 | +} |
| 863 | +#endif |
| 864 | + |
| 865 | +void jl_strip_llvm_debug(Module *m); |
| 866 | + |
| 867 | + |
| 868 | +// get a native assembly for llvm::Function |
| 869 | +extern "C" JL_DLLEXPORT |
| 870 | +jl_value_t *jl_dump_llvm_asm(void *F, const char* asm_variant) |
| 871 | +{ |
| 872 | + // precise printing via IR assembler |
| 873 | + SmallVector<char, 4096> ObjBufferSV; |
| 874 | + { // scope block |
| 875 | + Function *f = (Function*)F; |
| 876 | + llvm::raw_svector_ostream asmfile(ObjBufferSV); |
| 877 | + assert(!f->isDeclaration()); |
| 878 | + std::unique_ptr<Module> m(f->getParent()); |
| 879 | + for (auto &f2 : m->functions()) { |
| 880 | + if (f != &f2 && !f->isDeclaration()) |
| 881 | + f2.deleteBody(); |
| 882 | + } |
| 883 | + jl_strip_llvm_debug(m.get()); |
| 884 | + legacy::PassManager PM; |
| 885 | + LLVMTargetMachine *TM = static_cast<LLVMTargetMachine*>(jl_TargetMachine); |
| 886 | + MCContext *Context = addPassesToGenerateCode(TM, PM); |
| 887 | + if (Context) { |
| 888 | +#if JL_LLVM_VERSION >= 60000 |
| 889 | + const MCSubtargetInfo &STI = *TM->getMCSubtargetInfo(); |
| 890 | +#endif |
| 891 | + const MCAsmInfo &MAI = *TM->getMCAsmInfo(); |
| 892 | + const MCRegisterInfo &MRI = *TM->getMCRegisterInfo(); |
| 893 | + const MCInstrInfo &MII = *TM->getMCInstrInfo(); |
| 894 | + unsigned OutputAsmDialect = MAI.getAssemblerDialect(); |
| 895 | + if (!strcmp(asm_variant, "att")) |
| 896 | + OutputAsmDialect = 0; |
| 897 | + if (!strcmp(asm_variant, "intel")) |
| 898 | + OutputAsmDialect = 1; |
| 899 | + MCInstPrinter *InstPrinter = TM->getTarget().createMCInstPrinter( |
| 900 | + TM->getTargetTriple(), OutputAsmDialect, MAI, MII, MRI); |
| 901 | + MCAsmBackend *MAB = TM->getTarget().createMCAsmBackend( |
| 902 | +#if JL_LLVM_VERSION >= 60000 |
| 903 | + STI, MRI, TM->Options.MCOptions |
| 904 | +#elif JL_LLVM_VERSION >= 40000 |
| 905 | + MRI, TM->getTargetTriple().str(), TM->getTargetCPU(), TM->Options.MCOptions |
| 906 | +#else |
| 907 | + MRI, TM->getTargetTriple().str(), TM->getTargetCPU() |
| 908 | +#endif |
| 909 | + ); |
| 910 | + auto FOut = llvm::make_unique<formatted_raw_ostream>(asmfile); |
| 911 | + MCCodeEmitter *MCE = nullptr; |
| 912 | + std::unique_ptr<MCStreamer> S(TM->getTarget().createAsmStreamer( |
| 913 | + *Context, std::move(FOut), true, |
| 914 | + true, InstPrinter, MCE, MAB, false)); |
| 915 | + AsmPrinter *Printer = |
| 916 | + TM->getTarget().createAsmPrinter(*TM, std::move(S)); |
| 917 | + if (Printer) { |
| 918 | + PM.add(Printer); |
| 919 | + PM.run(*m); |
| 920 | + } |
| 921 | + } |
| 922 | + delete f; |
| 923 | + } |
| 924 | + return jl_pchar_to_string(ObjBufferSV.data(), ObjBufferSV.size()); |
| 925 | +} |
0 commit comments