Skip to content

Commit 516a404

Browse files
authored
Merge pull request #44798 from JuliaLang/kf/bugpoint
Make julia bootstrap bugpointable
2 parents dab3019 + 1b3435b commit 516a404

File tree

4 files changed

+69
-31
lines changed

4 files changed

+69
-31
lines changed

src/aotcompile.cpp

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -605,7 +605,8 @@ void addMachinePasses(legacy::PassManagerBase *PM, TargetMachine *TM, int optlev
605605
// this defines the set of optimization passes defined for Julia at various optimization levels.
606606
// it assumes that the TLI and TTI wrapper passes have already been added.
607607
void addOptimizationPasses(legacy::PassManagerBase *PM, int opt_level,
608-
bool lower_intrinsics, bool dump_native)
608+
bool lower_intrinsics, bool dump_native,
609+
bool external_use)
609610
{
610611
// Note: LLVM 12 disabled the hoisting of common instruction
611612
// before loop vectorization (https://reviews.llvm.org/D84108).
@@ -654,7 +655,7 @@ void addOptimizationPasses(legacy::PassManagerBase *PM, int opt_level,
654655
}
655656
PM->add(createLowerSimdLoopPass()); // Annotate loop marked with "loopinfo" as LLVM parallel loop
656657
if (dump_native) {
657-
PM->add(createMultiVersioningPass());
658+
PM->add(createMultiVersioningPass(external_use));
658659
PM->add(createCPUFeaturesPass());
659660
// minimal clean-up to get rid of CPU feature checks
660661
if (opt_level == 1) {
@@ -696,7 +697,7 @@ void addOptimizationPasses(legacy::PassManagerBase *PM, int opt_level,
696697
PM->add(createInstructionCombiningPass());
697698
PM->add(createCFGSimplificationPass(simplifyCFGOptions));
698699
if (dump_native)
699-
PM->add(createMultiVersioningPass());
700+
PM->add(createMultiVersioningPass(external_use));
700701
PM->add(createCPUFeaturesPass());
701702
PM->add(createSROAPass());
702703
PM->add(createInstSimplifyLegacyPass());
@@ -834,7 +835,7 @@ void addOptimizationPasses(legacy::PassManagerBase *PM, int opt_level,
834835

835836
// An LLVM module pass that just runs all julia passes in order. Useful for
836837
// debugging
837-
template <int OptLevel>
838+
template <int OptLevel, bool dump_native>
838839
class JuliaPipeline : public Pass {
839840
public:
840841
static char ID;
@@ -849,20 +850,27 @@ class JuliaPipeline : public Pass {
849850
PMTopLevelManager *TPM = Stack.top()->getTopLevelManager();
850851
TPMAdapter Adapter(TPM);
851852
addTargetPasses(&Adapter, &jl_ExecutionEngine->getTargetMachine());
852-
addOptimizationPasses(&Adapter, OptLevel);
853+
addOptimizationPasses(&Adapter, OptLevel, true, dump_native, true);
853854
addMachinePasses(&Adapter, &jl_ExecutionEngine->getTargetMachine(), OptLevel);
854855
}
855856
JuliaPipeline() : Pass(PT_PassManager, ID) {}
856857
Pass *createPrinterPass(raw_ostream &O, const std::string &Banner) const override {
857858
return createPrintModulePass(O, Banner);
858859
}
859860
};
860-
template<> char JuliaPipeline<0>::ID = 0;
861-
template<> char JuliaPipeline<2>::ID = 0;
862-
template<> char JuliaPipeline<3>::ID = 0;
863-
static RegisterPass<JuliaPipeline<0>> X("juliaO0", "Runs the entire julia pipeline (at -O0)", false, false);
864-
static RegisterPass<JuliaPipeline<2>> Y("julia", "Runs the entire julia pipeline (at -O2)", false, false);
865-
static RegisterPass<JuliaPipeline<3>> Z("juliaO3", "Runs the entire julia pipeline (at -O3)", false, false);
861+
template<> char JuliaPipeline<0,false>::ID = 0;
862+
template<> char JuliaPipeline<2,false>::ID = 0;
863+
template<> char JuliaPipeline<3,false>::ID = 0;
864+
template<> char JuliaPipeline<0,true>::ID = 0;
865+
template<> char JuliaPipeline<2,true>::ID = 0;
866+
template<> char JuliaPipeline<3,true>::ID = 0;
867+
static RegisterPass<JuliaPipeline<0,false>> X("juliaO0", "Runs the entire julia pipeline (at -O0)", false, false);
868+
static RegisterPass<JuliaPipeline<2,false>> Y("julia", "Runs the entire julia pipeline (at -O2)", false, false);
869+
static RegisterPass<JuliaPipeline<3,false>> Z("juliaO3", "Runs the entire julia pipeline (at -O3)", false, false);
870+
871+
static RegisterPass<JuliaPipeline<0,true>> XS("juliaO0-sysimg", "Runs the entire julia pipeline (at -O0/sysimg mode)", false, false);
872+
static RegisterPass<JuliaPipeline<2,true>> YS("julia-sysimg", "Runs the entire julia pipeline (at -O2/sysimg mode)", false, false);
873+
static RegisterPass<JuliaPipeline<3,true>> ZS("juliaO3-sysimg", "Runs the entire julia pipeline (at -O3/sysimg mode)", false, false);
866874

867875
extern "C" JL_DLLEXPORT
868876
void jl_add_optimization_passes_impl(LLVMPassManagerRef PM, int opt_level, int lower_intrinsics) {

src/jitlayers.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <llvm/Support/raw_ostream.h>
1919
#include <llvm/Transforms/Utils/Cloning.h>
2020
#include <llvm/Transforms/Utils/ModuleUtils.h>
21+
#include <llvm/Bitcode/BitcodeWriter.h>
2122

2223
// target machine computation
2324
#include <llvm/CodeGen/TargetSubtargetInfo.h>

src/jitlayers.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ extern "C" jl_cgparams_t jl_default_cgparams;
5151
extern bool imaging_mode;
5252

5353
void addTargetPasses(legacy::PassManagerBase *PM, TargetMachine *TM);
54-
void addOptimizationPasses(legacy::PassManagerBase *PM, int opt_level, bool lower_intrinsics=true, bool dump_native=false);
54+
void addOptimizationPasses(legacy::PassManagerBase *PM, int opt_level, bool lower_intrinsics=true, bool dump_native=false, bool external_use=false);
5555
void addMachinePasses(legacy::PassManagerBase *PM, TargetMachine *TM, int optlevel);
5656
void jl_finalize_module(std::unique_ptr<Module> m);
5757
void jl_merge_module(Module *dest, std::unique_ptr<Module> src);
@@ -283,7 +283,7 @@ Pass *createPropagateJuliaAddrspaces();
283283
Pass *createRemoveJuliaAddrspacesPass();
284284
Pass *createRemoveNIPass();
285285
Pass *createJuliaLICMPass();
286-
Pass *createMultiVersioningPass();
286+
Pass *createMultiVersioningPass(bool external_use);
287287
Pass *createAllocOptPass();
288288
Pass *createDemoteFloat16Pass();
289289
Pass *createCPUFeaturesPass();

src/llvm-multiversioning.cpp

Lines changed: 47 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ struct CloneCtx {
242242
return cast<Function>(vmap->lookup(orig_f));
243243
}
244244
};
245-
CloneCtx(Module &M, function_ref<LoopInfo&(Function&)> GetLI, function_ref<CallGraph&()> GetCG);
245+
CloneCtx(Module &M, function_ref<LoopInfo&(Function&)> GetLI, function_ref<CallGraph&()> GetCG, bool allow_bad_fvars);
246246
void clone_bases();
247247
void collect_func_infos();
248248
void clone_all_partials();
@@ -292,10 +292,11 @@ struct CloneCtx {
292292
std::set<uint32_t> alias_relocs;
293293
bool has_veccall{false};
294294
bool has_cloneall{false};
295+
bool allow_bad_fvars{false};
295296
};
296297

297298
template<typename T>
298-
static inline std::vector<T*> consume_gv(Module &M, const char *name)
299+
static inline std::vector<T*> consume_gv(Module &M, const char *name, bool allow_bad_fvars)
299300
{
300301
// Get information about sysimg export functions from the two global variables.
301302
// Strip them from the Module so that it's easier to handle the uses.
@@ -304,8 +305,17 @@ static inline std::vector<T*> consume_gv(Module &M, const char *name)
304305
auto *ary = cast<ConstantArray>(gv->getInitializer());
305306
unsigned nele = ary->getNumOperands();
306307
std::vector<T*> res(nele);
307-
for (unsigned i = 0; i < nele; i++)
308-
res[i] = cast<T>(ary->getOperand(i)->stripPointerCasts());
308+
unsigned i = 0;
309+
while (i < nele) {
310+
llvm::Value *val = ary->getOperand(i)->stripPointerCasts();
311+
if (allow_bad_fvars && (!isa<T>(val) || (isa<Function>(val) && cast<Function>(val)->isDeclaration()))) {
312+
// Shouldn't happen in regular use, but can happen in bugpoint.
313+
nele--;
314+
continue;
315+
}
316+
res[i++] = cast<T>(val);
317+
}
318+
res.resize(nele);
309319
assert(gv->use_empty());
310320
gv->eraseFromParent();
311321
if (ary->use_empty())
@@ -314,14 +324,15 @@ static inline std::vector<T*> consume_gv(Module &M, const char *name)
314324
}
315325

316326
// Collect basic information about targets and functions.
317-
CloneCtx::CloneCtx(Module &M, function_ref<LoopInfo&(Function&)> GetLI, function_ref<CallGraph&()> GetCG)
327+
CloneCtx::CloneCtx(Module &M, function_ref<LoopInfo&(Function&)> GetLI, function_ref<CallGraph&()> GetCG, bool allow_bad_fvars)
318328
: tbaa_const(tbaa_make_child_with_context(M.getContext(), "jtbaa_const", nullptr, true).first),
319329
specs(jl_get_llvm_clone_targets()),
320-
fvars(consume_gv<Function>(M, "jl_sysimg_fvars")),
321-
gvars(consume_gv<Constant>(M, "jl_sysimg_gvars")),
330+
fvars(consume_gv<Function>(M, "jl_sysimg_fvars", allow_bad_fvars)),
331+
gvars(consume_gv<Constant>(M, "jl_sysimg_gvars", false)),
322332
M(M),
323333
GetLI(GetLI),
324-
GetCG(GetCG)
334+
GetCG(GetCG),
335+
allow_bad_fvars(allow_bad_fvars)
325336
{
326337
groups.emplace_back(0, specs[0]);
327338
uint32_t ntargets = specs.size();
@@ -636,6 +647,12 @@ uint32_t CloneCtx::get_func_id(Function *F)
636647
{
637648
auto &ref = func_ids[F];
638649
if (!ref) {
650+
if (allow_bad_fvars && F->isDeclaration()) {
651+
// This should never happen in regular use, but can happen if
652+
// bugpoint deletes the function. Just do something here to
653+
// allow bugpoint to proceed.
654+
return (uint32_t)-1;
655+
}
639656
fvars.push_back(F);
640657
ref = fvars.size();
641658
}
@@ -927,10 +944,15 @@ Constant *CloneCtx::emit_offset_table(const std::vector<T*> &vars, StringRef nam
927944

928945
void CloneCtx::emit_metadata()
929946
{
947+
uint32_t nfvars = fvars.size();
948+
if (allow_bad_fvars && nfvars == 0) {
949+
// Will result in a non-loadable sysimg, but `allow_bad_fvars` is for bugpoint only
950+
return;
951+
}
952+
930953
// Store back the information about exported functions.
931954
auto fbase = emit_offset_table(fvars, "jl_sysimg_fvars");
932955
auto gbase = emit_offset_table(gvars, "jl_sysimg_gvars");
933-
uint32_t nfvars = fvars.size();
934956

935957
uint32_t ntargets = specs.size();
936958
SmallVector<Target*, 8> targets(ntargets);
@@ -1057,7 +1079,7 @@ void CloneCtx::emit_metadata()
10571079
}
10581080
}
10591081

1060-
static bool runMultiVersioning(Module &M, function_ref<LoopInfo&(Function&)> GetLI, function_ref<CallGraph&()> GetCG)
1082+
static bool runMultiVersioning(Module &M, function_ref<LoopInfo&(Function&)> GetLI, function_ref<CallGraph&()> GetCG, bool allow_bad_fvars)
10611083
{
10621084
// Group targets and identify cloning bases.
10631085
// Also initialize function info maps (we'll update these maps as we go)
@@ -1070,7 +1092,13 @@ static bool runMultiVersioning(Module &M, function_ref<LoopInfo&(Function&)> Get
10701092
if (M.getName() == "sysimage")
10711093
return false;
10721094

1073-
CloneCtx clone(M, GetLI, GetCG);
1095+
GlobalVariable *fvars = M.getGlobalVariable("jl_sysimg_fvars");
1096+
GlobalVariable *gvars = M.getGlobalVariable("jl_sysimg_gvars");
1097+
if (allow_bad_fvars && (!fvars || !fvars->hasInitializer() || !isa<ConstantArray>(fvars->getInitializer()) ||
1098+
!gvars || !gvars->hasInitializer() || !isa<ConstantArray>(gvars->getInitializer())))
1099+
return false;
1100+
1101+
CloneCtx clone(M, GetLI, GetCG, allow_bad_fvars);
10741102

10751103
// Collect a list of original functions and clone base functions
10761104
clone.clone_bases();
@@ -1110,8 +1138,8 @@ static bool runMultiVersioning(Module &M, function_ref<LoopInfo&(Function&)> Get
11101138

11111139
struct MultiVersioningLegacy: public ModulePass {
11121140
static char ID;
1113-
MultiVersioningLegacy()
1114-
: ModulePass(ID)
1141+
MultiVersioningLegacy(bool allow_bad_fvars=false)
1142+
: ModulePass(ID), allow_bad_fvars(allow_bad_fvars)
11151143
{}
11161144

11171145
private:
@@ -1122,6 +1150,7 @@ struct MultiVersioningLegacy: public ModulePass {
11221150
AU.addRequired<CallGraphWrapperPass>();
11231151
AU.addPreserved<LoopInfoWrapperPass>();
11241152
}
1153+
bool allow_bad_fvars;
11251154
};
11261155

11271156
bool MultiVersioningLegacy::runOnModule(Module &M)
@@ -1132,7 +1161,7 @@ bool MultiVersioningLegacy::runOnModule(Module &M)
11321161
auto GetCG = [this]() -> CallGraph & {
11331162
return getAnalysis<CallGraphWrapperPass>().getCallGraph();
11341163
};
1135-
return runMultiVersioning(M, GetLI, GetCG);
1164+
return runMultiVersioning(M, GetLI, GetCG, allow_bad_fvars);
11361165
}
11371166

11381167

@@ -1152,20 +1181,20 @@ PreservedAnalyses MultiVersioning::run(Module &M, ModuleAnalysisManager &AM)
11521181
auto GetCG = [&]() -> CallGraph & {
11531182
return AM.getResult<CallGraphAnalysis>(M);
11541183
};
1155-
if (runMultiVersioning(M, GetLI, GetCG)) {
1184+
if (runMultiVersioning(M, GetLI, GetCG, false)) {
11561185
auto preserved = PreservedAnalyses::allInSet<CFGAnalyses>();
11571186
preserved.preserve<LoopAnalysis>();
11581187
return preserved;
11591188
}
11601189
return PreservedAnalyses::all();
11611190
}
11621191

1163-
Pass *createMultiVersioningPass()
1192+
Pass *createMultiVersioningPass(bool allow_bad_fvars)
11641193
{
1165-
return new MultiVersioningLegacy();
1194+
return new MultiVersioningLegacy(allow_bad_fvars);
11661195
}
11671196

11681197
extern "C" JL_DLLEXPORT void LLVMExtraAddMultiVersioningPass_impl(LLVMPassManagerRef PM)
11691198
{
1170-
unwrap(PM)->add(createMultiVersioningPass());
1199+
unwrap(PM)->add(createMultiVersioningPass(false));
11711200
}

0 commit comments

Comments
 (0)