LCOV - code coverage report
Current view: top level - src - aotcompile.cpp (source / functions) Hit Total Coverage
Test: [test only] commit 0f242327d2cc9bd130497f44b6350c924185606a Lines: 422 546 77.3 %
Date: 2022-07-16 23:42:53 Functions: 17 56 30.4 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 179 290 61.7 %

           Branch data     Line data    Source code
       1                 :            : // This file is a part of Julia. License is MIT: https://julialang.org/license
       2                 :            : 
       3                 :            : #include "llvm-version.h"
       4                 :            : #include "platform.h"
       5                 :            : 
       6                 :            : // target support
       7                 :            : #include <llvm/ADT/Triple.h>
       8                 :            : #include <llvm/Analysis/TargetLibraryInfo.h>
       9                 :            : #include <llvm/Analysis/TargetTransformInfo.h>
      10                 :            : #include <llvm/IR/DataLayout.h>
      11                 :            : #if JL_LLVM_VERSION >= 140000
      12                 :            : #include <llvm/MC/TargetRegistry.h>
      13                 :            : #else
      14                 :            : #include <llvm/Support/TargetRegistry.h>
      15                 :            : #endif
      16                 :            : #include <llvm/Target/TargetMachine.h>
      17                 :            : 
      18                 :            : // analysis passes
      19                 :            : #include <llvm/Analysis/Passes.h>
      20                 :            : #include <llvm/Analysis/BasicAliasAnalysis.h>
      21                 :            : #include <llvm/Analysis/TypeBasedAliasAnalysis.h>
      22                 :            : #include <llvm/Analysis/ScopedNoAliasAA.h>
      23                 :            : #include <llvm/IR/PassManager.h>
      24                 :            : #include <llvm/IR/Verifier.h>
      25                 :            : #include <llvm/Transforms/IPO.h>
      26                 :            : #include <llvm/Transforms/Scalar.h>
      27                 :            : #include <llvm/Transforms/Vectorize.h>
      28                 :            : #include <llvm/Transforms/Instrumentation/AddressSanitizer.h>
      29                 :            : #include <llvm/Transforms/Instrumentation/ThreadSanitizer.h>
      30                 :            : #include <llvm/Transforms/Scalar/GVN.h>
      31                 :            : #include <llvm/Transforms/IPO/AlwaysInliner.h>
      32                 :            : #include <llvm/Transforms/InstCombine/InstCombine.h>
      33                 :            : #include <llvm/Transforms/Scalar/InstSimplifyPass.h>
      34                 :            : #include <llvm/Transforms/Utils/SimplifyCFGOptions.h>
      35                 :            : #include <llvm/Passes/PassBuilder.h>
      36                 :            : #include <llvm/Passes/PassPlugin.h>
      37                 :            : #if defined(USE_POLLY)
      38                 :            : #include <polly/RegisterPasses.h>
      39                 :            : #include <polly/LinkAllPasses.h>
      40                 :            : #include <polly/CodeGen/CodegenCleanup.h>
      41                 :            : #if defined(USE_POLLY_ACC)
      42                 :            : #include <polly/Support/LinkGPURuntime.h>
      43                 :            : #endif
      44                 :            : #endif
      45                 :            : 
      46                 :            : // for outputting code
      47                 :            : #include <llvm/Bitcode/BitcodeWriter.h>
      48                 :            : #include <llvm/Bitcode/BitcodeWriterPass.h>
      49                 :            : #include "llvm/Object/ArchiveWriter.h"
      50                 :            : #include <llvm/IR/IRPrintingPasses.h>
      51                 :            : 
      52                 :            : #include <llvm/IR/LegacyPassManagers.h>
      53                 :            : #include <llvm/Transforms/Utils/Cloning.h>
      54                 :            : 
      55                 :            : 
      56                 :            : using namespace llvm;
      57                 :            : 
      58                 :            : #include "julia.h"
      59                 :            : #include "julia_internal.h"
      60                 :            : #include "jitlayers.h"
      61                 :            : #include "julia_assert.h"
      62                 :            : 
      63                 :            : template<class T> // for GlobalObject's
      64                 :      81720 : static T *addComdat(T *G)
      65                 :            : {
      66                 :            : #if defined(_OS_WINDOWS_)
      67                 :            :     if (!G->isDeclaration()) {
      68                 :            :         // add __declspec(dllexport) to everything marked for export
      69                 :            :         if (G->getLinkage() == GlobalValue::ExternalLinkage)
      70                 :            :             G->setDLLStorageClass(GlobalValue::DLLExportStorageClass);
      71                 :            :         else
      72                 :            :             G->setDLLStorageClass(GlobalValue::DefaultStorageClass);
      73                 :            :     }
      74                 :            : #endif
      75                 :      81720 :     return G;
      76                 :            : }
      77                 :            : 
      78                 :            : 
      79                 :            : typedef struct {
      80                 :            :     orc::ThreadSafeModule M;
      81                 :            :     std::vector<GlobalValue*> jl_sysimg_fvars;
      82                 :            :     std::vector<GlobalValue*> jl_sysimg_gvars;
      83                 :            :     std::map<jl_code_instance_t*, std::tuple<uint32_t, uint32_t>> jl_fvar_map;
      84                 :            :     std::map<void*, int32_t> jl_value_to_llvm; // uses 1-based indexing
      85                 :            : } jl_native_code_desc_t;
      86                 :            : 
      87                 :            : extern "C" JL_DLLEXPORT
      88                 :     111997 : void jl_get_function_id_impl(void *native_code, jl_code_instance_t *codeinst,
      89                 :            :         int32_t *func_idx, int32_t *specfunc_idx)
      90                 :            : {
      91                 :     111997 :     jl_native_code_desc_t *data = (jl_native_code_desc_t*)native_code;
      92         [ +  + ]:     111997 :     if (data) {
      93                 :            :         // get the function index in the fvar lookup table
      94                 :      68290 :         auto it = data->jl_fvar_map.find(codeinst);
      95         [ +  + ]:      68290 :         if (it != data->jl_fvar_map.end()) {
      96                 :      14900 :             std::tie(*func_idx, *specfunc_idx) = it->second;
      97                 :            :         }
      98                 :            :     }
      99                 :     111997 : }
     100                 :            : 
     101                 :            : extern "C" JL_DLLEXPORT
     102                 :    2278290 : int32_t jl_get_llvm_gv_impl(void *native_code, jl_value_t *p)
     103                 :            : {
     104                 :            :     // map a jl_value_t memory location to a GlobalVariable
     105                 :    2278290 :     jl_native_code_desc_t *data = (jl_native_code_desc_t*)native_code;
     106         [ +  + ]:    2278290 :     if (data) {
     107                 :    1228330 :         auto it = data->jl_value_to_llvm.find(p);
     108         [ +  + ]:    1228330 :         if (it != data->jl_value_to_llvm.end()) {
     109                 :      18372 :             return it->second;
     110                 :            :         }
     111                 :            :     }
     112                 :    2259920 :     return 0;
     113                 :            : }
     114                 :            : 
     115                 :            : extern "C" JL_DLLEXPORT
     116                 :          0 : LLVMOrcThreadSafeModuleRef jl_get_llvm_module_impl(void *native_code)
     117                 :            : {
     118                 :          0 :     jl_native_code_desc_t *data = (jl_native_code_desc_t*)native_code;
     119         [ #  # ]:          0 :     if (data)
     120                 :          0 :         return wrap(&data->M);
     121                 :            :     else
     122                 :          0 :         return NULL;
     123                 :            : }
     124                 :            : 
     125                 :            : extern "C" JL_DLLEXPORT
     126                 :          0 : GlobalValue* jl_get_llvm_function_impl(void *native_code, uint32_t idx)
     127                 :            : {
     128                 :          0 :     jl_native_code_desc_t *data = (jl_native_code_desc_t*)native_code;
     129         [ #  # ]:          0 :     if (data)
     130                 :          0 :         return data->jl_sysimg_fvars[idx];
     131                 :            :     else
     132                 :          0 :         return NULL;
     133                 :            : }
     134                 :            : 
     135                 :            : 
     136                 :          2 : static void emit_offset_table(Module &mod, const std::vector<GlobalValue*> &vars, StringRef name, Type *T_psize)
     137                 :            : {
     138                 :            :     // Emit a global variable with all the variable addresses.
     139                 :            :     // The cloning pass will convert them into offsets.
     140         [ -  + ]:          2 :     assert(!vars.empty());
     141                 :          2 :     size_t nvars = vars.size();
     142                 :          2 :     std::vector<Constant*> addrs(nvars);
     143         [ +  + ]:      43963 :     for (size_t i = 0; i < nvars; i++) {
     144                 :      43961 :         Constant *var = vars[i];
     145                 :      43961 :         addrs[i] = ConstantExpr::getBitCast(var, T_psize);
     146                 :            :     }
     147                 :          2 :     ArrayType *vars_type = ArrayType::get(T_psize, nvars);
     148                 :          2 :     new GlobalVariable(mod, vars_type, true,
     149                 :            :                        GlobalVariable::ExternalLinkage,
     150                 :          4 :                        ConstantArray::get(vars_type, addrs),
     151                 :          2 :                        name);
     152                 :          2 : }
     153                 :            : 
     154                 :    1734410 : static bool is_safe_char(unsigned char c)
     155                 :            : {
     156   [ +  +  +  + ]:    1734410 :     return ('0' <= c && c <= '9') ||
     157   [ +  +  +  + ]:    1338500 :            ('A' <= c && c <= 'Z') ||
     158   [ +  +  +  + ]:    1274250 :            ('a' <= c && c <= 'z') ||
     159   [ +  +  +  + ]:    3537590 :            (c == '_' || c == '$') ||
     160   [ +  +  +  - ]:    1803180 :            (c >= 128 && c < 255);
     161                 :            : }
     162                 :            : 
     163                 :            : static const char hexchars[16] = {
     164                 :            :     '0', '1', '2', '3', '4', '5', '6', '7',
     165                 :            :     '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
     166                 :            : 
     167                 :            : static const char *const common_names[256] = {
     168                 :            : //  0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f
     169                 :            :     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x00
     170                 :            :     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x10
     171                 :            :     "SP", "NOT", "DQT", "YY", 0, "REM", "AND", "SQT", // 0x20
     172                 :            :       "LPR", "RPR", "MUL", "SUM", 0, "SUB", "DOT", "DIV", // 0x28
     173                 :            :     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "COL", 0, "LT", "EQ", "GT", "QQ", // 0x30
     174                 :            :     "AT", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x40
     175                 :            :     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "LBR", "RDV", "RBR", "POW", 0, // 0x50
     176                 :            :     "TIC", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x60
     177                 :            :     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "LCR", "OR", "RCR", "TLD", "DEL", // 0x70
     178                 :            :     0 }; // remainder is filled with zeros, though are also all safe characters
     179                 :            : 
     180                 :            : // reversibly removes special characters from the name of GlobalObjects,
     181                 :            : // which might cause them to be treated special by LLVM or the system linker
     182                 :            : // the only non-identifier characters we allow to appear are '.' and '$',
     183                 :            : // and all of UTF-8 above code-point 128 (except 255)
     184                 :            : // most are given "friendly" abbreviations
     185                 :            : // the remaining few will print as hex
     186                 :            : // e.g. mangles "llvm.a≠a$a!a##" as "llvmDOT.a≠a$aNOT.aYY.YY."
     187                 :      81717 : static void makeSafeName(GlobalObject &G)
     188                 :            : {
     189                 :      81717 :     StringRef Name = G.getName();
     190                 :     163434 :     SmallVector<char, 32> SafeName;
     191         [ +  + ]:    1816130 :     for (unsigned char c : Name.bytes()) {
     192         [ +  + ]:    1734410 :         if (is_safe_char(c)) {
     193                 :    1665750 :             SafeName.push_back(c);
     194                 :            :         }
     195                 :            :         else {
     196         [ +  - ]:      68662 :             if (common_names[c]) {
     197                 :      68662 :                 SafeName.push_back(common_names[c][0]);
     198                 :      68662 :                 SafeName.push_back(common_names[c][1]);
     199         [ +  + ]:      68662 :                 if (common_names[c][2])
     200                 :      46704 :                     SafeName.push_back(common_names[c][2]);
     201                 :            :             }
     202                 :            :             else {
     203                 :          0 :                 SafeName.push_back(hexchars[(c >> 4) & 0xF]);
     204                 :          0 :                 SafeName.push_back(hexchars[c & 0xF]);
     205                 :            :             }
     206                 :      68662 :             SafeName.push_back('.');
     207                 :            :         }
     208                 :            :     }
     209         [ +  + ]:      81717 :     if (SafeName.size() != Name.size())
     210                 :      39228 :         G.setName(StringRef(SafeName.data(), SafeName.size()));
     211                 :      81717 : }
     212                 :            : 
     213                 :      38025 : static void jl_ci_cache_lookup(const jl_cgparams_t &cgparams, jl_method_instance_t *mi, size_t world, jl_code_instance_t **ci_out, jl_code_info_t **src_out)
     214                 :            : {
     215                 :      38025 :     jl_value_t *ci = cgparams.lookup(mi, world, world);
     216                 :            :     JL_GC_PROMISE_ROOTED(ci);
     217                 :      38025 :     jl_code_instance_t *codeinst = NULL;
     218         [ +  + ]:      38025 :     if (ci != jl_nothing) {
     219                 :      37875 :         codeinst = (jl_code_instance_t*)ci;
     220                 :      37875 :         *src_out = (jl_code_info_t*)codeinst->inferred;
     221                 :      37875 :         jl_method_t *def = codeinst->def->def.method;
     222         [ +  + ]:      37875 :         if ((jl_value_t*)*src_out == jl_nothing)
     223                 :       1312 :             *src_out = NULL;
     224   [ +  +  +  - ]:      37875 :         if (*src_out && jl_is_method(def))
     225                 :      36563 :             *src_out = jl_uncompress_ir(def, codeinst, (jl_array_t*)*src_out);
     226                 :            :     }
     227   [ +  +  -  + ]:      38025 :     if (*src_out == NULL || !jl_is_code_info(*src_out)) {
     228         [ -  + ]:       1462 :         if (cgparams.lookup != jl_rettype_inferred) {
     229                 :          0 :             jl_error("Refusing to automatically run type inference with custom cache lookup.");
     230                 :            :         }
     231                 :            :         else {
     232                 :       1462 :             *src_out = jl_type_infer(mi, world, 0);
     233         [ +  - ]:       1462 :             if (*src_out) {
     234                 :       1462 :                 codeinst = jl_get_method_inferred(mi, (*src_out)->rettype, (*src_out)->min_world, (*src_out)->max_world);
     235   [ +  -  +  + ]:       1462 :                 if ((*src_out)->inferred && !codeinst->inferred)
     236                 :          7 :                     codeinst->inferred = jl_nothing;
     237                 :            :             }
     238                 :            :         }
     239                 :            :     }
     240                 :      38025 :     *ci_out = codeinst;
     241                 :      38025 : }
     242                 :            : 
     243                 :            : // takes the running content that has collected in the shadow module and dump it to disk
     244                 :            : // this builds the object file portion of the sysimage files for fast startup, and can
     245                 :            : // also be used be extern consumers like GPUCompiler.jl to obtain a module containing
     246                 :            : // all reachable & inferrrable functions. The `policy` flag switches between the default
     247                 :            : // mode `0`, the extern mode `1`, and imaging mode `2`.
     248                 :            : extern "C" JL_DLLEXPORT
     249                 :          3 : void *jl_create_native_impl(jl_array_t *methods, LLVMOrcThreadSafeModuleRef llvmmod, const jl_cgparams_t *cgparams, int _policy)
     250                 :            : {
     251         [ +  - ]:          3 :     if (cgparams == NULL)
     252                 :          3 :         cgparams = &jl_default_cgparams;
     253                 :          3 :     jl_native_code_desc_t *data = new jl_native_code_desc_t;
     254                 :          3 :     CompilationPolicy policy = (CompilationPolicy) _policy;
     255   [ -  +  -  - ]:          3 :     bool imaging = imaging_default() || policy == CompilationPolicy::ImagingMode;
     256                 :          6 :     jl_workqueue_t emitted;
     257                 :          3 :     jl_method_instance_t *mi = NULL;
     258                 :          3 :     jl_code_info_t *src = NULL;
     259                 :          3 :     JL_GC_PUSH1(&src);
     260                 :          3 :     JL_LOCK(&jl_codegen_lock);
     261                 :          3 :     orc::ThreadSafeContext ctx;
     262                 :          3 :     orc::ThreadSafeModule backing;
     263         [ +  - ]:          3 :     if (!llvmmod) {
     264                 :          3 :         ctx = jl_ExecutionEngine->acquireContext();
     265                 :          3 :         backing = jl_create_llvm_module("text", ctx, imaging);
     266                 :            :     }
     267         [ -  + ]:          3 :     orc::ThreadSafeModule &clone = llvmmod ? *unwrap(llvmmod) : backing;
     268                 :          6 :     auto ctxt = clone.getContext();
     269                 :          6 :     jl_codegen_params_t params(ctxt);
     270                 :          3 :     params.params = cgparams;
     271                 :          3 :     uint64_t compiler_start_time = 0;
     272                 :          3 :     uint8_t measure_compile_time_enabled = jl_atomic_load_relaxed(&jl_measure_compile_time_enabled);
     273         [ -  + ]:          3 :     if (measure_compile_time_enabled)
     274                 :          0 :         compiler_start_time = jl_hrtime();
     275                 :            : 
     276                 :          3 :     params.imaging = imaging;
     277                 :            : 
     278                 :            :     // compile all methods for the current world and type-inference world
     279                 :          3 :     size_t compile_for[] = { jl_typeinf_world, jl_atomic_load_acquire(&jl_world_counter) };
     280         [ +  + ]:          9 :     for (int worlds = 0; worlds < 2; worlds++) {
     281                 :          6 :         params.world = compile_for[worlds];
     282         [ -  + ]:          6 :         if (!params.world)
     283                 :          0 :             continue;
     284                 :            :         // Don't emit methods for the typeinf_world with extern policy
     285   [ -  +  -  - ]:          6 :         if (policy != CompilationPolicy::Default && params.world == jl_typeinf_world)
     286                 :          0 :             continue;
     287                 :            :         size_t i, l;
     288         [ +  + ]:      53548 :         for (i = 0, l = jl_array_len(methods); i < l; i++) {
     289                 :            :             // each item in this list is either a MethodInstance indicating something
     290                 :            :             // to compile, or an svec(rettype, sig) describing a C-callable alias to create.
     291                 :      53542 :             jl_value_t *item = jl_array_ptr_ref(methods, i);
     292         [ -  + ]:      53542 :             if (jl_is_simplevector(item)) {
     293         [ #  # ]:          0 :                 if (worlds == 1)
     294                 :          0 :                     jl_compile_extern_c(wrap(&clone), &params, NULL, jl_svecref(item, 0), jl_svecref(item, 1));
     295                 :          0 :                 continue;
     296                 :            :             }
     297                 :      53542 :             mi = (jl_method_instance_t*)item;
     298                 :      53542 :             src = NULL;
     299                 :            :             // if this method is generally visible to the current compilation world,
     300                 :            :             // and this is either the primary world, or not applicable in the primary world
     301                 :            :             // then we want to compile and emit this
     302   [ +  +  +  + ]:      53542 :             if (mi->def.method->primary_world <= params.world && params.world <= mi->def.method->deleted_world) {
     303                 :            :                 // find and prepare the source code to compile
     304                 :      38025 :                 jl_code_instance_t *codeinst = NULL;
     305                 :      38025 :                 jl_ci_cache_lookup(*cgparams, mi, params.world, &codeinst, &src);
     306   [ +  -  +  +  :      38025 :                 if (src && !emitted.count(codeinst)) {
                   +  + ]
     307                 :            :                     // now add it to our compilation results
     308                 :            :                     JL_GC_PROMISE_ROOTED(codeinst->rettype);
     309                 :            :                     orc::ThreadSafeModule result_m = jl_create_llvm_module(name_from_method_instance(codeinst->def),
     310                 :      27198 :                             params.tsctx, params.imaging,
     311                 :            :                             clone.getModuleUnlocked()->getDataLayout(),
     312                 :      54396 :                             Triple(clone.getModuleUnlocked()->getTargetTriple()));
     313                 :      54396 :                     jl_llvm_functions_t decls = jl_emit_code(result_m, mi, src, codeinst->rettype, params);
     314         [ +  - ]:      27198 :                     if (result_m)
     315                 :      27198 :                         emitted[codeinst] = {std::move(result_m), std::move(decls)};
     316                 :            :                 }
     317                 :            :             }
     318                 :            :         }
     319                 :            : 
     320                 :            :         // finally, make sure all referenced methods also get compiled or fixed up
     321                 :          6 :         jl_compile_workqueue(emitted, *clone.getModuleUnlocked(), params, policy);
     322                 :            :     }
     323                 :          3 :     JL_GC_POP();
     324                 :            : 
     325                 :            :     // process the globals array, before jl_merge_module destroys them
     326                 :          3 :     std::vector<std::string> gvars;
     327                 :            : 
     328         [ +  + ]:      25271 :     for (auto &global : params.globals) {
     329                 :      25268 :         gvars.push_back(std::string(global.second->getName()));
     330                 :      25268 :         data->jl_value_to_llvm[global.first] = gvars.size();
     331                 :            :     }
     332                 :            : 
     333                 :            :     // clones the contents of the module `m` to the shadow_output collector
     334                 :            :     // while examining and recording what kind of function pointer we have
     335         [ +  + ]:      27336 :     for (auto &def : emitted) {
     336                 :      27333 :         jl_merge_module(clone, std::move(std::get<0>(def.second)));
     337                 :      27333 :         jl_code_instance_t *this_code = def.first;
     338                 :      27333 :         jl_llvm_functions_t decls = std::get<1>(def.second);
     339                 :      27333 :         StringRef func = decls.functionObject;
     340                 :      27333 :         StringRef cfunc = decls.specFunctionObject;
     341                 :      27333 :         uint32_t func_id = 0;
     342                 :      27333 :         uint32_t cfunc_id = 0;
     343         [ +  + ]:      27333 :         if (func == "jl_fptr_args") {
     344                 :       2790 :             func_id = -1;
     345                 :            :         }
     346         [ -  + ]:      24543 :         else if (func == "jl_fptr_sparam") {
     347                 :          0 :             func_id = -2;
     348                 :            :         }
     349                 :            :         else {
     350                 :            :             //Safe b/c context is locked by params
     351                 :      24543 :             data->jl_sysimg_fvars.push_back(cast<Function>(clone.getModuleUnlocked()->getNamedValue(func)));
     352                 :      24543 :             func_id = data->jl_sysimg_fvars.size();
     353                 :            :         }
     354         [ +  - ]:      27333 :         if (!cfunc.empty()) {
     355                 :            :             //Safe b/c context is locked by params
     356                 :      27333 :             data->jl_sysimg_fvars.push_back(cast<Function>(clone.getModuleUnlocked()->getNamedValue(cfunc)));
     357                 :      27333 :             cfunc_id = data->jl_sysimg_fvars.size();
     358                 :            :         }
     359                 :      27333 :         data->jl_fvar_map[this_code] = std::make_tuple(func_id, cfunc_id);
     360                 :            :     }
     361         [ +  - ]:          3 :     if (params._shared_module) {
     362                 :          3 :         jl_merge_module(clone, std::move(params._shared_module));
     363                 :            :     }
     364                 :            : 
     365                 :            :     // now get references to the globals in the merged module
     366                 :            :     // and set them to be internalized and initialized at startup
     367         [ +  + ]:      25271 :     for (auto &global : gvars) {
     368                 :            :         //Safe b/c context is locked by params
     369                 :      25268 :         GlobalVariable *G = cast<GlobalVariable>(clone.getModuleUnlocked()->getNamedValue(global));
     370                 :      25268 :         G->setInitializer(ConstantPointerNull::get(cast<PointerType>(G->getValueType())));
     371                 :      25268 :         G->setLinkage(GlobalVariable::InternalLinkage);
     372                 :      25268 :         data->jl_sysimg_gvars.push_back(G);
     373                 :            :     }
     374                 :            : 
     375                 :            :     //Safe b/c context is locked by params
     376                 :            : #if defined(_OS_WINDOWS_) && defined(_CPU_X86_64_)
     377                 :            :     // setting the function personality enables stack unwinding and catching exceptions
     378                 :            :     // so make sure everything has something set
     379                 :            :     Type *T_int32 = Type::getInt32Ty(clone.getModuleUnlocked()->getContext());
     380                 :            :     Function *juliapersonality_func =
     381                 :            :        Function::Create(FunctionType::get(T_int32, true),
     382                 :            :            Function::ExternalLinkage, "__julia_personality", clone.getModuleUnlocked());
     383                 :            :     juliapersonality_func->setDLLStorageClass(GlobalValue::DLLImportStorageClass);
     384                 :            : #endif
     385                 :            : 
     386                 :            :     // move everything inside, now that we've merged everything
     387                 :            :     // (before adding the exported headers)
     388         [ +  - ]:          3 :     if (policy == CompilationPolicy::Default) {
     389                 :            :         //Safe b/c context is locked by params
     390         [ +  + ]:      82050 :         for (GlobalObject &G : clone.getModuleUnlocked()->global_objects()) {
     391         [ +  + ]:      82047 :             if (!G.isDeclaration()) {
     392                 :      81717 :                 G.setLinkage(Function::InternalLinkage);
     393                 :      81717 :                 makeSafeName(G);
     394                 :      81717 :                 addComdat(&G);
     395                 :            : #if defined(_OS_WINDOWS_) && defined(_CPU_X86_64_)
     396                 :            :                 // Add unwind exception personalities to functions to handle async exceptions
     397                 :            :                 if (Function *F = dyn_cast<Function>(&G))
     398                 :            :                     F->setPersonalityFn(juliapersonality_func);
     399                 :            : #endif
     400                 :            :             }
     401                 :            :         }
     402                 :            :     }
     403                 :            : 
     404                 :          3 :     data->M = std::move(clone);
     405         [ -  + ]:          3 :     if (measure_compile_time_enabled)
     406                 :          0 :         jl_atomic_fetch_add_relaxed(&jl_cumulative_compile_time, (jl_hrtime() - compiler_start_time));
     407         [ +  - ]:          3 :     if (ctx.getContext()) {
     408                 :          3 :         jl_ExecutionEngine->releaseContext(std::move(ctx));
     409                 :            :     }
     410                 :          3 :     JL_UNLOCK(&jl_codegen_lock); // Might GC
     411                 :          3 :     return (void*)data;
     412                 :            : }
     413                 :            : 
     414                 :            : 
     415                 :          2 : static void emit_result(std::vector<NewArchiveMember> &Archive, SmallVectorImpl<char> &OS,
     416                 :            :         StringRef Name, std::vector<std::string> &outputs)
     417                 :            : {
     418                 :          2 :     outputs.push_back({ OS.data(), OS.size() });
     419                 :          2 :     Archive.push_back(NewArchiveMember(MemoryBufferRef(outputs.back(), Name)));
     420                 :          2 :     OS.clear();
     421                 :          2 : }
     422                 :            : 
     423                 :          1 : static object::Archive::Kind getDefaultForHost(Triple &triple)
     424                 :            : {
     425         [ -  + ]:          1 :       if (triple.isOSDarwin())
     426                 :          0 :           return object::Archive::K_DARWIN;
     427                 :          1 :       return object::Archive::K_GNU;
     428                 :            : }
     429                 :            : 
     430                 :            : typedef Error ArchiveWriterError;
     431                 :          0 : static void reportWriterError(const ErrorInfoBase &E)
     432                 :            : {
     433                 :          0 :     std::string err = E.message();
     434                 :          0 :     jl_safe_printf("ERROR: failed to emit output file %s\n", err.c_str());
     435                 :          0 : }
     436                 :            : 
     437                 :            : 
     438                 :            : // takes the running content that has collected in the shadow module and dump it to disk
     439                 :            : // this builds the object file portion of the sysimage files for fast startup
     440                 :            : extern "C" JL_DLLEXPORT
     441                 :          1 : void jl_dump_native_impl(void *native_code,
     442                 :            :         const char *bc_fname, const char *unopt_bc_fname, const char *obj_fname,
     443                 :            :         const char *asm_fname,
     444                 :            :         const char *sysimg_data, size_t sysimg_len)
     445                 :            : {
     446                 :            :     JL_TIMING(NATIVE_DUMP);
     447                 :          1 :     jl_native_code_desc_t *data = (jl_native_code_desc_t*)native_code;
     448                 :          2 :     auto TSCtx = data->M.getContext();
     449                 :          2 :     auto lock = TSCtx.getLock();
     450                 :          1 :     LLVMContext &Context = *TSCtx.getContext();
     451                 :            :     // We don't want to use MCJIT's target machine because
     452                 :            :     // it uses the large code model and we may potentially
     453                 :            :     // want less optimizations there.
     454                 :          2 :     Triple TheTriple = Triple(jl_ExecutionEngine->getTargetTriple());
     455                 :            :     // make sure to emit the native object format, even if FORCE_ELF was set in codegen
     456                 :            : #if defined(_OS_WINDOWS_)
     457                 :            :     TheTriple.setObjectFormat(Triple::COFF);
     458                 :            : #elif defined(_OS_DARWIN_)
     459                 :            :     TheTriple.setObjectFormat(Triple::MachO);
     460                 :            :     TheTriple.setOS(llvm::Triple::MacOSX);
     461                 :            : #endif
     462                 :            :     std::unique_ptr<TargetMachine> TM(
     463                 :          1 :         jl_ExecutionEngine->getTarget().createTargetMachine(
     464                 :            :             TheTriple.getTriple(),
     465                 :            :             jl_ExecutionEngine->getTargetCPU(),
     466                 :            :             jl_ExecutionEngine->getTargetFeatureString(),
     467                 :            :             jl_ExecutionEngine->getTargetOptions(),
     468                 :            : #if defined(_OS_LINUX_) || defined(_OS_FREEBSD_)
     469                 :          2 :             Reloc::PIC_,
     470                 :            : #else
     471                 :            :             Optional<Reloc::Model>(),
     472                 :            : #endif
     473                 :            : #if defined(_CPU_PPC_) || defined(_CPU_PPC64_)
     474                 :            :             // On PPC the small model is limited to 16bit offsets
     475                 :            :             CodeModel::Medium,
     476                 :            : #else
     477                 :            :             // Use small model so that we can use signed 32bits offset in the function and GV tables
     478                 :          2 :             CodeModel::Small,
     479                 :            : #endif
     480                 :            :             CodeGenOpt::Aggressive // -O3 TODO: respect command -O0 flag?
     481                 :          2 :             ));
     482                 :            : 
     483                 :            : 
     484                 :            :     // set up optimization passes
     485                 :          2 :     SmallVector<char, 0> bc_Buffer;
     486                 :          2 :     SmallVector<char, 0> obj_Buffer;
     487                 :          2 :     SmallVector<char, 0> asm_Buffer;
     488                 :          2 :     SmallVector<char, 0> unopt_bc_Buffer;
     489                 :          2 :     raw_svector_ostream bc_OS(bc_Buffer);
     490                 :          2 :     raw_svector_ostream obj_OS(obj_Buffer);
     491                 :          2 :     raw_svector_ostream asm_OS(asm_Buffer);
     492                 :          2 :     raw_svector_ostream unopt_bc_OS(unopt_bc_Buffer);
     493                 :          2 :     std::vector<NewArchiveMember> bc_Archive;
     494                 :          2 :     std::vector<NewArchiveMember> obj_Archive;
     495                 :          2 :     std::vector<NewArchiveMember> asm_Archive;
     496                 :          2 :     std::vector<NewArchiveMember> unopt_bc_Archive;
     497                 :          2 :     std::vector<std::string> outputs;
     498                 :            : 
     499                 :          2 :     legacy::PassManager preopt, postopt;
     500                 :            : 
     501         [ -  + ]:          1 :     if (unopt_bc_fname)
     502                 :          0 :         preopt.add(createBitcodeWriterPass(unopt_bc_OS));
     503                 :            : 
     504                 :            :     //Is this necessary for TM?
     505                 :            :     // addTargetPasses(&postopt, TM->getTargetTriple(), TM->getTargetIRAnalysis());
     506         [ -  + ]:          1 :     if (bc_fname)
     507                 :          0 :         postopt.add(createBitcodeWriterPass(bc_OS));
     508         [ +  - ]:          1 :     if (obj_fname)
     509         [ -  + ]:          1 :         if (TM->addPassesToEmitFile(postopt, obj_OS, nullptr, CGFT_ObjectFile, false))
     510                 :          0 :             jl_safe_printf("ERROR: target does not support generation of object files\n");
     511         [ -  + ]:          1 :     if (asm_fname)
     512         [ #  # ]:          0 :         if (TM->addPassesToEmitFile(postopt, asm_OS, nullptr, CGFT_AssemblyFile, false))
     513                 :          0 :             jl_safe_printf("ERROR: target does not support generation of object files\n");
     514                 :            : 
     515                 :          2 :     legacy::PassManager optimizer;
     516   [ +  -  -  +  :          1 :     if (bc_fname || obj_fname || asm_fname) {
                   -  - ]
     517                 :          1 :         addTargetPasses(&optimizer, TM->getTargetTriple(), TM->getTargetIRAnalysis());
     518                 :          1 :         addOptimizationPasses(&optimizer, jl_options.opt_level, true, true);
     519                 :          1 :         addMachinePasses(&optimizer, jl_options.opt_level);
     520                 :            :     }
     521                 :            : 
     522                 :            :     // Reset the target triple to make sure it matches the new target machine
     523                 :          1 :     auto dataM = data->M.getModuleUnlocked();
     524                 :          1 :     dataM->setTargetTriple(TM->getTargetTriple().str());
     525                 :          1 :     dataM->setDataLayout(jl_create_datalayout(*TM));
     526                 :            :     Type *T_size;
     527                 :            :     if (sizeof(size_t) == 8)
     528                 :          1 :         T_size = Type::getInt64Ty(Context);
     529                 :            :     else
     530                 :            :         T_size = Type::getInt32Ty(Context);
     531                 :          1 :     Type *T_psize = T_size->getPointerTo();
     532                 :            : 
     533                 :            :     // add metadata information
     534         [ +  - ]:          1 :     if (imaging_default()) {
     535                 :          1 :         emit_offset_table(*dataM, data->jl_sysimg_gvars, "jl_sysimg_gvars", T_psize);
     536                 :          1 :         emit_offset_table(*dataM, data->jl_sysimg_fvars, "jl_sysimg_fvars", T_psize);
     537                 :            : 
     538                 :            :         // reflect the address of the jl_RTLD_DEFAULT_handle variable
     539                 :            :         // back to the caller, so that we can check for consistency issues
     540                 :          1 :         GlobalValue *jlRTLD_DEFAULT_var = jl_emit_RTLD_DEFAULT_var(dataM);
     541                 :          2 :         addComdat(new GlobalVariable(*dataM,
     542                 :          1 :                                      jlRTLD_DEFAULT_var->getType(),
     543                 :            :                                      true,
     544                 :            :                                      GlobalVariable::ExternalLinkage,
     545                 :            :                                      jlRTLD_DEFAULT_var,
     546                 :          1 :                                      "jl_RTLD_DEFAULT_handle_pointer"));
     547                 :            :     }
     548                 :            : 
     549                 :            :     // do the actual work
     550                 :          2 :     auto add_output = [&] (Module &M, StringRef unopt_bc_Name, StringRef bc_Name, StringRef obj_Name, StringRef asm_Name) {
     551                 :          2 :         preopt.run(M);
     552                 :          2 :         optimizer.run(M);
     553                 :          2 :         postopt.run(M);
     554         [ -  + ]:          2 :         if (unopt_bc_fname)
     555                 :          0 :             emit_result(unopt_bc_Archive, unopt_bc_Buffer, unopt_bc_Name, outputs);
     556         [ -  + ]:          2 :         if (bc_fname)
     557                 :          0 :             emit_result(bc_Archive, bc_Buffer, bc_Name, outputs);
     558         [ +  - ]:          2 :         if (obj_fname)
     559                 :          2 :             emit_result(obj_Archive, obj_Buffer, obj_Name, outputs);
     560         [ -  + ]:          2 :         if (asm_fname)
     561                 :          0 :             emit_result(asm_Archive, asm_Buffer, asm_Name, outputs);
     562                 :          3 :     };
     563                 :            : 
     564                 :          1 :     add_output(*dataM, "unopt.bc", "text.bc", "text.o", "text.s");
     565                 :            : 
     566                 :          3 :     orc::ThreadSafeModule sysimage(std::make_unique<Module>("sysimage", Context), TSCtx);
     567                 :          1 :     auto sysimageM = sysimage.getModuleUnlocked();
     568                 :          1 :     sysimageM->setTargetTriple(dataM->getTargetTriple());
     569                 :          1 :     sysimageM->setDataLayout(dataM->getDataLayout());
     570                 :            : #if JL_LLVM_VERSION >= 130000
     571                 :          1 :     sysimageM->setStackProtectorGuard(dataM->getStackProtectorGuard());
     572                 :          1 :     sysimageM->setOverrideStackAlignment(dataM->getOverrideStackAlignment());
     573                 :            : #endif
     574                 :          1 :     data->M = orc::ThreadSafeModule(); // free memory for data->M
     575                 :            : 
     576         [ +  - ]:          1 :     if (sysimg_data) {
     577                 :          1 :         Constant *data = ConstantDataArray::get(Context,
     578                 :            :             ArrayRef<uint8_t>((const unsigned char*)sysimg_data, sysimg_len));
     579                 :          2 :         addComdat(new GlobalVariable(*sysimageM, data->getType(), false,
     580                 :            :                                      GlobalVariable::ExternalLinkage,
     581                 :          2 :                                      data, "jl_system_image_data"))->setAlignment(Align(64));
     582                 :          1 :         Constant *len = ConstantInt::get(T_size, sysimg_len);
     583                 :          2 :         addComdat(new GlobalVariable(*sysimageM, len->getType(), true,
     584                 :            :                                      GlobalVariable::ExternalLinkage,
     585                 :          1 :                                      len, "jl_system_image_size"));
     586                 :            :     }
     587                 :          1 :     add_output(*sysimageM, "data.bc", "data.bc", "data.o", "data.s");
     588                 :            : 
     589                 :          1 :     object::Archive::Kind Kind = getDefaultForHost(TheTriple);
     590         [ -  + ]:          1 :     if (unopt_bc_fname)
     591                 :          0 :         handleAllErrors(writeArchive(unopt_bc_fname, unopt_bc_Archive, true,
     592                 :            :                     Kind, true, false), reportWriterError);
     593         [ -  + ]:          1 :     if (bc_fname)
     594                 :          0 :         handleAllErrors(writeArchive(bc_fname, bc_Archive, true,
     595                 :            :                     Kind, true, false), reportWriterError);
     596         [ +  - ]:          1 :     if (obj_fname)
     597                 :          1 :         handleAllErrors(writeArchive(obj_fname, obj_Archive, true,
     598                 :            :                     Kind, true, false), reportWriterError);
     599         [ -  + ]:          1 :     if (asm_fname)
     600                 :          0 :         handleAllErrors(writeArchive(asm_fname, asm_Archive, true,
     601                 :            :                     Kind, true, false), reportWriterError);
     602                 :            : 
     603         [ +  - ]:          1 :     delete data;
     604                 :          1 : }
     605                 :            : 
     606                 :       1076 : void addTargetPasses(legacy::PassManagerBase *PM, const Triple &triple, TargetIRAnalysis analysis)
     607                 :            : {
     608                 :       1076 :     PM->add(new TargetLibraryInfoWrapperPass(triple));
     609                 :       1076 :     PM->add(createTargetTransformInfoWrapperPass(std::move(analysis)));
     610                 :       1076 : }
     611                 :            : 
     612                 :            : 
     613                 :       1052 : void addMachinePasses(legacy::PassManagerBase *PM, int optlevel)
     614                 :            : {
     615                 :            :     // TODO: don't do this on CPUs that natively support Float16
     616                 :       1052 :     PM->add(createDemoteFloat16Pass());
     617         [ +  + ]:       1052 :     if (optlevel > 1)
     618                 :        574 :         PM->add(createGVNPass());
     619                 :       1052 : }
     620                 :            : 
     621                 :            : // this defines the set of optimization passes defined for Julia at various optimization levels.
     622                 :            : // it assumes that the TLI and TTI wrapper passes have already been added.
     623                 :       1052 : void addOptimizationPasses(legacy::PassManagerBase *PM, int opt_level,
     624                 :            :                            bool lower_intrinsics, bool dump_native,
     625                 :            :                            bool external_use)
     626                 :            : {
     627                 :            :     // Note: LLVM 12 disabled the hoisting of common instruction
     628                 :            :     //       before loop vectorization (https://reviews.llvm.org/D84108).
     629                 :            :     //
     630                 :            :     // TODO: CommonInstruction hoisting/sinking enables AllocOpt
     631                 :            :     //       to merge allocations and sometimes eliminate them,
     632                 :            :     //       since AllocOpt does not handle PhiNodes.
     633                 :            :     //       Enable this instruction hoisting because of this and Union benchmarks.
     634                 :       1052 :     auto basicSimplifyCFGOptions = SimplifyCFGOptions()
     635                 :       1052 :         .convertSwitchRangeToICmp(true)
     636                 :       1052 :         .convertSwitchToLookupTable(true)
     637                 :       1052 :         .forwardSwitchCondToPhi(true);
     638                 :       1052 :     auto aggressiveSimplifyCFGOptions = SimplifyCFGOptions()
     639                 :       1052 :         .convertSwitchRangeToICmp(true)
     640                 :       1052 :         .convertSwitchToLookupTable(true)
     641                 :       1052 :         .forwardSwitchCondToPhi(true)
     642                 :            :         //These mess with loop rotation, so only do them after that
     643                 :       1052 :         .hoistCommonInsts(true)
     644                 :            :         // Causes an SRET assertion error in late-gc-lowering
     645                 :            :         // .sinkCommonInsts(true)
     646                 :            :         ;
     647                 :            : #ifdef JL_DEBUG_BUILD
     648                 :       1052 :     PM->add(createGCInvariantVerifierPass(true));
     649                 :       1052 :     PM->add(createVerifierPass());
     650                 :            : #endif
     651                 :            : 
     652                 :       1052 :     PM->add(createConstantMergePass());
     653         [ +  + ]:       1052 :     if (opt_level < 2) {
     654         [ +  + ]:        478 :         if (!dump_native) {
     655                 :            :             // we won't be multiversioning, so lower CPU feature checks early on
     656                 :            :             // so that we can avoid an additional CFG simplification pass at the end.
     657                 :        477 :             PM->add(createCPUFeaturesPass());
     658         [ +  + ]:        477 :             if (opt_level == 1)
     659                 :        418 :                 PM->add(createInstSimplifyLegacyPass());
     660                 :            :         }
     661                 :        478 :         PM->add(createCFGSimplificationPass(basicSimplifyCFGOptions));
     662         [ +  + ]:        478 :         if (opt_level == 1) {
     663                 :        418 :             PM->add(createSROAPass());
     664                 :        418 :             PM->add(createInstructionCombiningPass());
     665                 :        418 :             PM->add(createEarlyCSEPass());
     666                 :            :             // maybe add GVN?
     667                 :            :             // also try GVNHoist and GVNSink
     668                 :            :         }
     669                 :        478 :         PM->add(createMemCpyOptPass());
     670                 :        478 :         PM->add(createAlwaysInlinerLegacyPass()); // Respect always_inline
     671                 :        478 :         PM->add(createLowerSimdLoopPass()); // Annotate loop marked with "loopinfo" as LLVM parallel loop
     672         [ +  - ]:        478 :         if (lower_intrinsics) {
     673                 :        478 :             PM->add(createBarrierNoopPass());
     674                 :        478 :             PM->add(createLowerExcHandlersPass());
     675                 :        478 :             PM->add(createGCInvariantVerifierPass(false));
     676                 :        478 :             PM->add(createRemoveNIPass());
     677                 :        478 :             PM->add(createLateLowerGCFramePass());
     678                 :        478 :             PM->add(createFinalLowerGCPass());
     679                 :        478 :             PM->add(createLowerPTLSPass(dump_native));
     680                 :            :         }
     681                 :            :         else {
     682                 :          0 :             PM->add(createRemoveNIPass());
     683                 :            :         }
     684                 :        478 :         PM->add(createLowerSimdLoopPass()); // Annotate loop marked with "loopinfo" as LLVM parallel loop
     685         [ +  + ]:        478 :         if (dump_native) {
     686                 :          1 :             PM->add(createMultiVersioningPass(external_use));
     687                 :          1 :             PM->add(createCPUFeaturesPass());
     688                 :            :             // minimal clean-up to get rid of CPU feature checks
     689         [ -  + ]:          1 :             if (opt_level == 1) {
     690                 :          0 :                 PM->add(createInstSimplifyLegacyPass());
     691                 :          0 :                 PM->add(createCFGSimplificationPass(basicSimplifyCFGOptions));
     692                 :            :             }
     693                 :            :         }
     694                 :            : #if defined(_COMPILER_ASAN_ENABLED_)
     695                 :            :         PM->add(createAddressSanitizerFunctionPass());
     696                 :            : #endif
     697                 :            : #if defined(_COMPILER_MSAN_ENABLED_)
     698                 :            :         PM->add(createMemorySanitizerPass(true));
     699                 :            : #endif
     700                 :            : #if defined(_COMPILER_TSAN_ENABLED_)
     701                 :            :         PM->add(createThreadSanitizerLegacyPassPass());
     702                 :            : #endif
     703                 :        478 :         return;
     704                 :            :     }
     705                 :        574 :     PM->add(createPropagateJuliaAddrspaces());
     706                 :        574 :     PM->add(createScopedNoAliasAAWrapperPass());
     707                 :        574 :     PM->add(createTypeBasedAAWrapperPass());
     708         [ +  + ]:        574 :     if (opt_level >= 3) {
     709                 :          2 :         PM->add(createBasicAAWrapperPass());
     710                 :            :     }
     711                 :            : 
     712                 :        574 :     PM->add(createCFGSimplificationPass(basicSimplifyCFGOptions));
     713                 :        574 :     PM->add(createDeadCodeEliminationPass());
     714                 :        574 :     PM->add(createSROAPass());
     715                 :            : 
     716                 :            :     //PM->add(createMemCpyOptPass());
     717                 :            : 
     718                 :        574 :     PM->add(createAlwaysInlinerLegacyPass()); // Respect always_inline
     719                 :            : 
     720                 :            :     // Running `memcpyopt` between this and `sroa` seems to give `sroa` a hard time
     721                 :            :     // merging the `alloca` for the unboxed data and the `alloca` created by the `alloc_opt`
     722                 :            :     // pass.
     723                 :        574 :     PM->add(createAllocOptPass());
     724                 :            :     // consider AggressiveInstCombinePass at optlevel > 2
     725                 :        574 :     PM->add(createInstructionCombiningPass());
     726                 :        574 :     PM->add(createCFGSimplificationPass(basicSimplifyCFGOptions));
     727         [ -  + ]:        574 :     if (dump_native)
     728                 :          0 :         PM->add(createMultiVersioningPass(external_use));
     729                 :        574 :     PM->add(createCPUFeaturesPass());
     730                 :        574 :     PM->add(createSROAPass());
     731                 :        574 :     PM->add(createInstSimplifyLegacyPass());
     732                 :        574 :     PM->add(createJumpThreadingPass());
     733                 :        574 :     PM->add(createCorrelatedValuePropagationPass());
     734                 :            : 
     735                 :        574 :     PM->add(createReassociatePass());
     736                 :            : 
     737                 :        574 :     PM->add(createEarlyCSEPass());
     738                 :            : 
     739                 :            :     // Load forwarding above can expose allocations that aren't actually used
     740                 :            :     // remove those before optimizing loops.
     741                 :        574 :     PM->add(createAllocOptPass());
     742                 :        574 :     PM->add(createLoopRotatePass());
     743                 :            :     // moving IndVarSimplify here prevented removing the loop in perf_sumcartesian(10:-1:1)
     744                 :            : #ifdef USE_POLLY
     745                 :            :     // LCSSA (which has already run at this point due to the dependencies of the
     746                 :            :     // above passes) introduces redundant phis that hinder Polly. Therefore we
     747                 :            :     // run InstCombine here to remove them.
     748                 :            :     PM->add(createInstructionCombiningPass());
     749                 :            :     PM->add(polly::createCodePreparationPass());
     750                 :            :     polly::registerPollyPasses(*PM);
     751                 :            :     PM->add(polly::createCodegenCleanupPass());
     752                 :            : #endif
     753                 :            :     // LoopRotate strips metadata from terminator, so run LowerSIMD afterwards
     754                 :        574 :     PM->add(createLowerSimdLoopPass()); // Annotate loop marked with "loopinfo" as LLVM parallel loop
     755                 :        574 :     PM->add(createLICMPass());
     756                 :        574 :     PM->add(createJuliaLICMPass());
     757                 :        574 :     PM->add(createLoopUnswitchPass());
     758                 :        574 :     PM->add(createLICMPass());
     759                 :        574 :     PM->add(createJuliaLICMPass());
     760                 :        574 :     PM->add(createInductiveRangeCheckEliminationPass()); // Must come before indvars
     761                 :            :     // Subsequent passes not stripping metadata from terminator
     762                 :        574 :     PM->add(createInstSimplifyLegacyPass());
     763                 :        574 :     PM->add(createLoopIdiomPass());
     764                 :        574 :     PM->add(createIndVarSimplifyPass());
     765                 :        574 :     PM->add(createLoopDeletionPass());
     766                 :        574 :     PM->add(createSimpleLoopUnrollPass());
     767                 :            : 
     768                 :            :     // Run our own SROA on heap objects before LLVM's
     769                 :        574 :     PM->add(createAllocOptPass());
     770                 :            :     // Re-run SROA after loop-unrolling (useful for small loops that operate,
     771                 :            :     // over the structure of an aggregate)
     772                 :        574 :     PM->add(createSROAPass());
     773                 :            :     // might not be necessary:
     774                 :        574 :     PM->add(createInstSimplifyLegacyPass());
     775                 :            : 
     776                 :        574 :     PM->add(createGVNPass());
     777                 :        574 :     PM->add(createMemCpyOptPass());
     778                 :        574 :     PM->add(createSCCPPass());
     779                 :            : 
     780                 :            :     //These next two passes must come before IRCE to eliminate the bounds check in #43308
     781                 :        574 :     PM->add(createCorrelatedValuePropagationPass());
     782                 :        574 :     PM->add(createDeadCodeEliminationPass());
     783                 :            : 
     784                 :        574 :     PM->add(createInductiveRangeCheckEliminationPass()); // Must come between the two GVN passes
     785                 :            : 
     786                 :            :     // Run instcombine after redundancy elimination to exploit opportunities
     787                 :            :     // opened up by them.
     788                 :            :     // This needs to be InstCombine instead of InstSimplify to allow
     789                 :            :     // loops over Union-typed arrays to vectorize.
     790                 :        574 :     PM->add(createInstructionCombiningPass());
     791                 :        574 :     PM->add(createJumpThreadingPass());
     792         [ +  + ]:        574 :     if (opt_level >= 3) {
     793                 :          2 :         PM->add(createGVNPass()); // Must come after JumpThreading and before LoopVectorize
     794                 :            :     }
     795                 :        574 :     PM->add(createDeadStoreEliminationPass());
     796                 :            :     // see if all of the constant folding has exposed more loops
     797                 :            :     // to simplification and deletion
     798                 :            :     // this helps significantly with cleaning up iteration
     799                 :        574 :     PM->add(createCFGSimplificationPass(aggressiveSimplifyCFGOptions));
     800                 :            : 
     801                 :            :     // More dead allocation (store) deletion before loop optimization
     802                 :            :     // consider removing this:
     803                 :            :     // Moving this after aggressive CFG simplification helps deallocate when allocations are hoisted
     804                 :        574 :     PM->add(createAllocOptPass());
     805                 :        574 :     PM->add(createLoopDeletionPass());
     806                 :        574 :     PM->add(createInstructionCombiningPass());
     807                 :        574 :     PM->add(createLoopVectorizePass());
     808                 :        574 :     PM->add(createLoopLoadEliminationPass());
     809                 :            :     // Cleanup after LV pass
     810                 :        574 :     PM->add(createInstructionCombiningPass());
     811                 :        574 :     PM->add(createCFGSimplificationPass( // Aggressive CFG simplification
     812                 :            :         aggressiveSimplifyCFGOptions
     813                 :        574 :     ));
     814                 :        574 :     PM->add(createSLPVectorizerPass());
     815                 :            :     // might need this after LLVM 11:
     816                 :            :     //PM->add(createVectorCombinePass());
     817                 :            : 
     818                 :        574 :     PM->add(createAggressiveDCEPass());
     819                 :            : 
     820         [ +  - ]:        574 :     if (lower_intrinsics) {
     821                 :            :         // LowerPTLS removes an indirect call. As a result, it is likely to trigger
     822                 :            :         // LLVM's devirtualization heuristics, which would result in the entire
     823                 :            :         // pass pipeline being re-executed. Prevent this by inserting a barrier.
     824                 :        574 :         PM->add(createBarrierNoopPass());
     825                 :        574 :         PM->add(createLowerExcHandlersPass());
     826                 :        574 :         PM->add(createGCInvariantVerifierPass(false));
     827                 :            :         // Needed **before** LateLowerGCFrame on LLVM < 12
     828                 :            :         // due to bug in `CreateAlignmentAssumption`.
     829                 :        574 :         PM->add(createRemoveNIPass());
     830                 :        574 :         PM->add(createLateLowerGCFramePass());
     831                 :        574 :         PM->add(createFinalLowerGCPass());
     832                 :            :         // We need these two passes and the instcombine below
     833                 :            :         // after GC lowering to let LLVM do some constant propagation on the tags.
     834                 :            :         // and remove some unnecessary write barrier checks.
     835                 :        574 :         PM->add(createGVNPass());
     836                 :        574 :         PM->add(createSCCPPass());
     837                 :            :         // Remove dead use of ptls
     838                 :        574 :         PM->add(createDeadCodeEliminationPass());
     839                 :        574 :         PM->add(createLowerPTLSPass(dump_native));
     840                 :        574 :         PM->add(createInstructionCombiningPass());
     841                 :            :         // Clean up write barrier and ptls lowering
     842                 :        574 :         PM->add(createCFGSimplificationPass());
     843                 :            :     }
     844                 :            :     else {
     845                 :          0 :         PM->add(createRemoveNIPass());
     846                 :            :     }
     847                 :        574 :     PM->add(createCombineMulAddPass());
     848                 :        574 :     PM->add(createDivRemPairsPass());
     849                 :            : #if defined(_COMPILER_ASAN_ENABLED_)
     850                 :            :     PM->add(createAddressSanitizerFunctionPass());
     851                 :            : #endif
     852                 :            : #if defined(_COMPILER_MSAN_ENABLED_)
     853                 :            :     PM->add(createMemorySanitizerPass(true));
     854                 :            : #endif
     855                 :            : #if defined(_COMPILER_TSAN_ENABLED_)
     856                 :            :     PM->add(createThreadSanitizerLegacyPassPass());
     857                 :            : #endif
     858                 :            : }
     859                 :            : 
     860                 :            : // An LLVM module pass that just runs all julia passes in order. Useful for
     861                 :            : // debugging
     862                 :            : template <int OptLevel, bool dump_native>
     863                 :            : class JuliaPipeline : public Pass {
     864                 :            : public:
     865                 :            :     static char ID;
     866                 :            :     // A bit of a hack, but works
     867                 :            :     struct TPMAdapter : public PassManagerBase {
     868                 :            :         PMTopLevelManager *TPM;
     869                 :          0 :         TPMAdapter(PMTopLevelManager *TPM) : TPM(TPM) {}
     870                 :          0 :         void add(Pass *P) { TPM->schedulePass(P); }
     871                 :            :     };
     872                 :          0 :     void preparePassManager(PMStack &Stack) override {
     873                 :          0 :         (void)jl_init_llvm();
     874                 :          0 :         PMTopLevelManager *TPM = Stack.top()->getTopLevelManager();
     875                 :          0 :         TPMAdapter Adapter(TPM);
     876                 :          0 :         addTargetPasses(&Adapter, jl_ExecutionEngine->getTargetTriple(), jl_ExecutionEngine->getTargetIRAnalysis());
     877                 :          0 :         addOptimizationPasses(&Adapter, OptLevel, true, dump_native, true);
     878                 :          0 :         addMachinePasses(&Adapter, OptLevel);
     879                 :          0 :     }
     880                 :          0 :     JuliaPipeline() : Pass(PT_PassManager, ID) {}
     881                 :          0 :     Pass *createPrinterPass(raw_ostream &O, const std::string &Banner) const override {
     882                 :          0 :         return createPrintModulePass(O, Banner);
     883                 :            :     }
     884                 :            : };
     885                 :            : template<> char JuliaPipeline<0,false>::ID = 0;
     886                 :            : template<> char JuliaPipeline<2,false>::ID = 0;
     887                 :            : template<> char JuliaPipeline<3,false>::ID = 0;
     888                 :            : template<> char JuliaPipeline<0,true>::ID = 0;
     889                 :            : template<> char JuliaPipeline<2,true>::ID = 0;
     890                 :            : template<> char JuliaPipeline<3,true>::ID = 0;
     891                 :            : static RegisterPass<JuliaPipeline<0,false>> X("juliaO0", "Runs the entire julia pipeline (at -O0)", false, false);
     892                 :            : static RegisterPass<JuliaPipeline<2,false>> Y("julia", "Runs the entire julia pipeline (at -O2)", false, false);
     893                 :            : static RegisterPass<JuliaPipeline<3,false>> Z("juliaO3", "Runs the entire julia pipeline (at -O3)", false, false);
     894                 :            : 
     895                 :            : static RegisterPass<JuliaPipeline<0,true>> XS("juliaO0-sysimg", "Runs the entire julia pipeline (at -O0/sysimg mode)", false, false);
     896                 :            : static RegisterPass<JuliaPipeline<2,true>> YS("julia-sysimg", "Runs the entire julia pipeline (at -O2/sysimg mode)", false, false);
     897                 :            : static RegisterPass<JuliaPipeline<3,true>> ZS("juliaO3-sysimg", "Runs the entire julia pipeline (at -O3/sysimg mode)", false, false);
     898                 :            : 
     899                 :            : extern "C" JL_DLLEXPORT
     900                 :          0 : void jl_add_optimization_passes_impl(LLVMPassManagerRef PM, int opt_level, int lower_intrinsics) {
     901                 :          0 :     addOptimizationPasses(unwrap(PM), opt_level, lower_intrinsics);
     902                 :          0 : }
     903                 :            : 
     904                 :            : // new pass manager plugin
     905                 :            : 
     906                 :            : // NOTE: Instead of exporting all the constructors in passes.h we could
     907                 :            : // forward the callbacks to the respective passes. LLVM seems to prefer this,
     908                 :            : // and when we add the full pass builder having them directly will be helpful.
     909                 :          0 : static void registerCallbacks(PassBuilder &PB) {
     910                 :          0 :     PB.registerPipelineParsingCallback(
     911                 :          0 :         [](StringRef Name, FunctionPassManager &PM,
     912                 :            :            ArrayRef<PassBuilder::PipelineElement> InnerPipeline) {
     913         [ #  # ]:          0 :             if (Name == "DemoteFloat16") {
     914                 :          0 :                 PM.addPass(DemoteFloat16());
     915                 :          0 :                 return true;
     916                 :            :             }
     917         [ #  # ]:          0 :             if (Name == "CombineMulAdd") {
     918                 :          0 :               PM.addPass(CombineMulAdd());
     919                 :          0 :               return true;
     920                 :            :             }
     921         [ #  # ]:          0 :             if (Name == "LateLowerGCFrame") {
     922                 :          0 :                 PM.addPass(LateLowerGC());
     923                 :          0 :                 return true;
     924                 :            :             }
     925         [ #  # ]:          0 :             if (Name == "AllocOpt") {
     926                 :          0 :                 PM.addPass(AllocOptPass());
     927                 :          0 :                 return true;
     928                 :            :             }
     929         [ #  # ]:          0 :             if (Name == "PropagateJuliaAddrspaces") {
     930                 :          0 :                 PM.addPass(PropagateJuliaAddrspacesPass());
     931                 :          0 :                 return true;
     932                 :            :             }
     933         [ #  # ]:          0 :             if (Name == "LowerExcHandlers") {
     934                 :          0 :                 PM.addPass(LowerExcHandlers());
     935                 :          0 :                 return true;
     936                 :            :             }
     937         [ #  # ]:          0 :             if (Name == "GCInvariantVerifier") {
     938                 :            :                 // TODO: Parse option and allow users to set `Strong`
     939                 :          0 :                 PM.addPass(GCInvariantVerifierPass());
     940                 :          0 :                 return true;
     941                 :            :             }
     942                 :          0 :             return false;
     943                 :            :         });
     944                 :            : 
     945                 :          0 :     PB.registerPipelineParsingCallback(
     946                 :          0 :         [](StringRef Name, ModulePassManager &PM,
     947                 :            :            ArrayRef<PassBuilder::PipelineElement> InnerPipeline) {
     948         [ #  # ]:          0 :             if (Name == "CPUFeatures") {
     949                 :          0 :               PM.addPass(CPUFeatures());
     950                 :          0 :               return true;
     951                 :            :             }
     952         [ #  # ]:          0 :             if (Name == "RemoveNI") {
     953                 :          0 :               PM.addPass(RemoveNI());
     954                 :          0 :               return true;
     955                 :            :             }
     956         [ #  # ]:          0 :             if (Name == "LowerSIMDLoop") {
     957                 :          0 :               PM.addPass(LowerSIMDLoop());
     958                 :          0 :               return true;
     959                 :            :             }
     960         [ #  # ]:          0 :             if (Name == "FinalLowerGC") {
     961                 :          0 :                 PM.addPass(FinalLowerGCPass());
     962                 :          0 :                 return true;
     963                 :            :             }
     964         [ #  # ]:          0 :             if (Name == "RemoveJuliaAddrspaces") {
     965                 :          0 :                 PM.addPass(RemoveJuliaAddrspacesPass());
     966                 :          0 :                 return true;
     967                 :            :             }
     968         [ #  # ]:          0 :             if (Name == "MultiVersioning") {
     969                 :          0 :                 PM.addPass(MultiVersioning());
     970                 :          0 :                 return true;
     971                 :            :             }
     972         [ #  # ]:          0 :             if (Name == "LowerPTLS") {
     973                 :          0 :                 PM.addPass(LowerPTLSPass());
     974                 :          0 :                 return true;
     975                 :            :             }
     976                 :          0 :             return false;
     977                 :            :         });
     978                 :            : 
     979                 :          0 :     PB.registerPipelineParsingCallback(
     980                 :          0 :         [](StringRef Name, LoopPassManager &PM,
     981                 :            :            ArrayRef<PassBuilder::PipelineElement> InnerPipeline) {
     982         [ #  # ]:          0 :             if (Name == "JuliaLICM") {
     983                 :          0 :                 PM.addPass(JuliaLICMPass());
     984                 :          0 :                 return true;
     985                 :            :             }
     986                 :          0 :             return false;
     987                 :            :         });
     988                 :          0 : }
     989                 :            : 
     990                 :            : extern "C" JL_DLLEXPORT ::llvm::PassPluginLibraryInfo
     991                 :          0 : llvmGetPassPluginInfo() {
     992                 :          0 :       return {LLVM_PLUGIN_API_VERSION, "Julia", "1", registerCallbacks};
     993                 :            : }
     994                 :            : 
     995                 :            : // --- native code info, and dump function to IR and ASM ---
     996                 :            : // Get pointer to llvm::Function instance, compiling if necessary
     997                 :            : // for use in reflection from Julia.
     998                 :            : // this is paired with jl_dump_function_ir, jl_dump_function_asm, jl_dump_method_asm in particular ways:
     999                 :            : // misuse will leak memory or cause read-after-free
    1000                 :            : extern "C" JL_DLLEXPORT
    1001                 :        106 : void jl_get_llvmf_defn_impl(jl_llvmf_dump_t* dump, jl_method_instance_t *mi, size_t world, char getwrapper, char optimize, const jl_cgparams_t params)
    1002                 :            : {
    1003   [ +  -  +  + ]:        106 :     if (jl_is_method(mi->def.method) && mi->def.method->source == NULL &&
    1004         [ -  + ]:          2 :             mi->def.method->generator == NULL) {
    1005                 :            :         // not a generic function
    1006                 :          0 :         dump->F = NULL;
    1007                 :          0 :         return;
    1008                 :            :     }
    1009                 :            : 
    1010                 :            :     // get the source code for this function
    1011                 :        106 :     jl_value_t *jlrettype = (jl_value_t*)jl_any_type;
    1012                 :        106 :     jl_code_info_t *src = NULL;
    1013                 :        106 :     JL_GC_PUSH2(&src, &jlrettype);
    1014   [ +  -  +  +  :        106 :     if (jl_is_method(mi->def.method) && mi->def.method->source != NULL && jl_ir_flag_inferred((jl_array_t*)mi->def.method->source)) {
             +  +  +  + ]
    1015                 :          2 :         src = (jl_code_info_t*)mi->def.method->source;
    1016   [ +  -  +  - ]:          2 :         if (src && !jl_is_code_info(src))
    1017                 :          2 :             src = jl_uncompress_ir(mi->def.method, NULL, (jl_array_t*)src);
    1018                 :            :     } else {
    1019                 :        104 :         jl_value_t *ci = jl_rettype_inferred(mi, world, world);
    1020         [ +  + ]:        104 :         if (ci != jl_nothing) {
    1021                 :         53 :             jl_code_instance_t *codeinst = (jl_code_instance_t*)ci;
    1022                 :         53 :             src = (jl_code_info_t*)codeinst->inferred;
    1023   [ +  +  +  -  :         53 :             if ((jl_value_t*)src != jl_nothing && !jl_is_code_info(src) && jl_is_method(mi->def.method))
                   +  - ]
    1024                 :         33 :                 src = jl_uncompress_ir(mi->def.method, codeinst, (jl_array_t*)src);
    1025                 :         53 :             jlrettype = codeinst->rettype;
    1026                 :            :         }
    1027   [ +  +  +  + ]:        104 :         if (!src || (jl_value_t*)src == jl_nothing) {
    1028                 :         71 :             src = jl_type_infer(mi, world, 0);
    1029         [ +  + ]:         71 :             if (src)
    1030                 :         70 :                 jlrettype = src->rettype;
    1031         [ +  - ]:          1 :             else if (jl_is_method(mi->def.method)) {
    1032         [ -  + ]:          1 :                 src = mi->def.method->generator ? jl_code_for_staged(mi) : (jl_code_info_t*)mi->def.method->source;
    1033   [ +  -  +  -  :          1 :                 if (src && !jl_is_code_info(src) && jl_is_method(mi->def.method))
                   +  - ]
    1034                 :          1 :                     src = jl_uncompress_ir(mi->def.method, NULL, (jl_array_t*)src);
    1035                 :            :             }
    1036                 :            :             // TODO: use mi->uninferred
    1037                 :            :         }
    1038                 :            :     }
    1039                 :            : 
    1040                 :            :     // emit this function into a new llvm module
    1041   [ +  -  +  - ]:        106 :     if (src && jl_is_code_info(src)) {
    1042                 :        106 :         JL_LOCK(&jl_codegen_lock);
    1043                 :        106 :         auto ctx = jl_ExecutionEngine->getContext();
    1044                 :        106 :         jl_codegen_params_t output(*ctx);
    1045                 :        106 :         output.world = world;
    1046                 :        106 :         output.params = &params;
    1047                 :        106 :         orc::ThreadSafeModule m = jl_create_llvm_module(name_from_method_instance(mi), output.tsctx, output.imaging);
    1048                 :        106 :         uint64_t compiler_start_time = 0;
    1049                 :        106 :         uint8_t measure_compile_time_enabled = jl_atomic_load_relaxed(&jl_measure_compile_time_enabled);
    1050         [ -  + ]:        106 :         if (measure_compile_time_enabled)
    1051                 :          0 :             compiler_start_time = jl_hrtime();
    1052                 :        106 :         auto decls = jl_emit_code(m, mi, src, jlrettype, output);
    1053                 :            : 
    1054                 :        106 :         Function *F = NULL;
    1055         [ +  - ]:        106 :         if (m) {
    1056                 :            :             // if compilation succeeded, prepare to return the result
    1057                 :            :             // For imaging mode, global constants are currently private without initializer
    1058                 :            :             // which isn't legal. Convert them to extern linkage so that the code can compile
    1059                 :            :             // and will better match what's actually in sysimg.
    1060         [ -  + ]:        106 :             for (auto &global : output.globals)
    1061                 :          0 :                 global.second->setLinkage(GlobalValue::ExternalLinkage);
    1062         [ +  + ]:        106 :             if (optimize) {
    1063                 :        198 :                 legacy::PassManager PM;
    1064                 :         99 :                 addTargetPasses(&PM, jl_ExecutionEngine->getTargetTriple(), jl_ExecutionEngine->getTargetIRAnalysis());
    1065                 :         99 :                 addOptimizationPasses(&PM, jl_options.opt_level);
    1066                 :         99 :                 addMachinePasses(&PM, jl_options.opt_level);
    1067                 :            :                 //Safe b/c context lock is held by output
    1068                 :         99 :                 PM.run(*m.getModuleUnlocked());
    1069                 :            :             }
    1070                 :            :             const std::string *fname;
    1071   [ +  +  +  +  :        106 :             if (decls.functionObject == "jl_fptr_args" || decls.functionObject == "jl_fptr_sparam")
                   +  + ]
    1072                 :          8 :                 getwrapper = false;
    1073         [ +  - ]:        106 :             if (!getwrapper)
    1074                 :        106 :                 fname = &decls.specFunctionObject;
    1075                 :            :             else
    1076                 :          0 :                 fname = &decls.functionObject;
    1077                 :        106 :             F = cast<Function>(m.getModuleUnlocked()->getNamedValue(*fname));
    1078                 :            :         }
    1079                 :        106 :         JL_GC_POP();
    1080         [ -  + ]:        106 :         if (measure_compile_time_enabled)
    1081                 :          0 :             jl_atomic_fetch_add_relaxed(&jl_cumulative_compile_time, (jl_hrtime() - compiler_start_time));
    1082                 :        106 :         JL_UNLOCK(&jl_codegen_lock); // Might GC
    1083         [ +  - ]:        106 :         if (F) {
    1084                 :        106 :             dump->TSM = wrap(new orc::ThreadSafeModule(std::move(m)));
    1085                 :        106 :             dump->F = wrap(F);
    1086                 :        106 :             return;
    1087                 :            :         }
    1088                 :            :     }
    1089                 :            : 
    1090                 :          0 :     const char *mname = name_from_method_instance(mi);
    1091                 :          0 :     jl_errorf("unable to compile source for function %s", mname);
    1092                 :            : }

Generated by: LCOV version 1.14