Skip to content

Commit

Permalink
Merge pull request JuliaLang#44798 from JuliaLang/kf/bugpoint
Browse files Browse the repository at this point in the history
Make julia bootstrap bugpointable
  • Loading branch information
Keno authored Mar 30, 2022
2 parents dab3019 + 1b3435b commit 516a404
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 31 deletions.
30 changes: 19 additions & 11 deletions src/aotcompile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -605,7 +605,8 @@ void addMachinePasses(legacy::PassManagerBase *PM, TargetMachine *TM, int optlev
// this defines the set of optimization passes defined for Julia at various optimization levels.
// it assumes that the TLI and TTI wrapper passes have already been added.
void addOptimizationPasses(legacy::PassManagerBase *PM, int opt_level,
bool lower_intrinsics, bool dump_native)
bool lower_intrinsics, bool dump_native,
bool external_use)
{
// Note: LLVM 12 disabled the hoisting of common instruction
// before loop vectorization (https://reviews.llvm.org/D84108).
Expand Down Expand Up @@ -654,7 +655,7 @@ void addOptimizationPasses(legacy::PassManagerBase *PM, int opt_level,
}
PM->add(createLowerSimdLoopPass()); // Annotate loop marked with "loopinfo" as LLVM parallel loop
if (dump_native) {
PM->add(createMultiVersioningPass());
PM->add(createMultiVersioningPass(external_use));
PM->add(createCPUFeaturesPass());
// minimal clean-up to get rid of CPU feature checks
if (opt_level == 1) {
Expand Down Expand Up @@ -696,7 +697,7 @@ void addOptimizationPasses(legacy::PassManagerBase *PM, int opt_level,
PM->add(createInstructionCombiningPass());
PM->add(createCFGSimplificationPass(simplifyCFGOptions));
if (dump_native)
PM->add(createMultiVersioningPass());
PM->add(createMultiVersioningPass(external_use));
PM->add(createCPUFeaturesPass());
PM->add(createSROAPass());
PM->add(createInstSimplifyLegacyPass());
Expand Down Expand Up @@ -834,7 +835,7 @@ void addOptimizationPasses(legacy::PassManagerBase *PM, int opt_level,

// An LLVM module pass that just runs all julia passes in order. Useful for
// debugging
template <int OptLevel>
template <int OptLevel, bool dump_native>
class JuliaPipeline : public Pass {
public:
static char ID;
Expand All @@ -849,20 +850,27 @@ class JuliaPipeline : public Pass {
PMTopLevelManager *TPM = Stack.top()->getTopLevelManager();
TPMAdapter Adapter(TPM);
addTargetPasses(&Adapter, &jl_ExecutionEngine->getTargetMachine());
addOptimizationPasses(&Adapter, OptLevel);
addOptimizationPasses(&Adapter, OptLevel, true, dump_native, true);
addMachinePasses(&Adapter, &jl_ExecutionEngine->getTargetMachine(), OptLevel);
}
JuliaPipeline() : Pass(PT_PassManager, ID) {}
Pass *createPrinterPass(raw_ostream &O, const std::string &Banner) const override {
return createPrintModulePass(O, Banner);
}
};
template<> char JuliaPipeline<0>::ID = 0;
template<> char JuliaPipeline<2>::ID = 0;
template<> char JuliaPipeline<3>::ID = 0;
static RegisterPass<JuliaPipeline<0>> X("juliaO0", "Runs the entire julia pipeline (at -O0)", false, false);
static RegisterPass<JuliaPipeline<2>> Y("julia", "Runs the entire julia pipeline (at -O2)", false, false);
static RegisterPass<JuliaPipeline<3>> Z("juliaO3", "Runs the entire julia pipeline (at -O3)", false, false);
template<> char JuliaPipeline<0,false>::ID = 0;
template<> char JuliaPipeline<2,false>::ID = 0;
template<> char JuliaPipeline<3,false>::ID = 0;
template<> char JuliaPipeline<0,true>::ID = 0;
template<> char JuliaPipeline<2,true>::ID = 0;
template<> char JuliaPipeline<3,true>::ID = 0;
static RegisterPass<JuliaPipeline<0,false>> X("juliaO0", "Runs the entire julia pipeline (at -O0)", false, false);
static RegisterPass<JuliaPipeline<2,false>> Y("julia", "Runs the entire julia pipeline (at -O2)", false, false);
static RegisterPass<JuliaPipeline<3,false>> Z("juliaO3", "Runs the entire julia pipeline (at -O3)", false, false);

static RegisterPass<JuliaPipeline<0,true>> XS("juliaO0-sysimg", "Runs the entire julia pipeline (at -O0/sysimg mode)", false, false);
static RegisterPass<JuliaPipeline<2,true>> YS("julia-sysimg", "Runs the entire julia pipeline (at -O2/sysimg mode)", false, false);
static RegisterPass<JuliaPipeline<3,true>> ZS("juliaO3-sysimg", "Runs the entire julia pipeline (at -O3/sysimg mode)", false, false);

extern "C" JL_DLLEXPORT
void jl_add_optimization_passes_impl(LLVMPassManagerRef PM, int opt_level, int lower_intrinsics) {
Expand Down
1 change: 1 addition & 0 deletions src/jitlayers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <llvm/Support/raw_ostream.h>
#include <llvm/Transforms/Utils/Cloning.h>
#include <llvm/Transforms/Utils/ModuleUtils.h>
#include <llvm/Bitcode/BitcodeWriter.h>

// target machine computation
#include <llvm/CodeGen/TargetSubtargetInfo.h>
Expand Down
4 changes: 2 additions & 2 deletions src/jitlayers.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ extern "C" jl_cgparams_t jl_default_cgparams;
extern bool imaging_mode;

void addTargetPasses(legacy::PassManagerBase *PM, TargetMachine *TM);
void addOptimizationPasses(legacy::PassManagerBase *PM, int opt_level, bool lower_intrinsics=true, bool dump_native=false);
void addOptimizationPasses(legacy::PassManagerBase *PM, int opt_level, bool lower_intrinsics=true, bool dump_native=false, bool external_use=false);
void addMachinePasses(legacy::PassManagerBase *PM, TargetMachine *TM, int optlevel);
void jl_finalize_module(std::unique_ptr<Module> m);
void jl_merge_module(Module *dest, std::unique_ptr<Module> src);
Expand Down Expand Up @@ -283,7 +283,7 @@ Pass *createPropagateJuliaAddrspaces();
Pass *createRemoveJuliaAddrspacesPass();
Pass *createRemoveNIPass();
Pass *createJuliaLICMPass();
Pass *createMultiVersioningPass();
Pass *createMultiVersioningPass(bool external_use);
Pass *createAllocOptPass();
Pass *createDemoteFloat16Pass();
Pass *createCPUFeaturesPass();
Expand Down
65 changes: 47 additions & 18 deletions src/llvm-multiversioning.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ struct CloneCtx {
return cast<Function>(vmap->lookup(orig_f));
}
};
CloneCtx(Module &M, function_ref<LoopInfo&(Function&)> GetLI, function_ref<CallGraph&()> GetCG);
CloneCtx(Module &M, function_ref<LoopInfo&(Function&)> GetLI, function_ref<CallGraph&()> GetCG, bool allow_bad_fvars);
void clone_bases();
void collect_func_infos();
void clone_all_partials();
Expand Down Expand Up @@ -292,10 +292,11 @@ struct CloneCtx {
std::set<uint32_t> alias_relocs;
bool has_veccall{false};
bool has_cloneall{false};
bool allow_bad_fvars{false};
};

template<typename T>
static inline std::vector<T*> consume_gv(Module &M, const char *name)
static inline std::vector<T*> consume_gv(Module &M, const char *name, bool allow_bad_fvars)
{
// Get information about sysimg export functions from the two global variables.
// Strip them from the Module so that it's easier to handle the uses.
Expand All @@ -304,8 +305,17 @@ static inline std::vector<T*> consume_gv(Module &M, const char *name)
auto *ary = cast<ConstantArray>(gv->getInitializer());
unsigned nele = ary->getNumOperands();
std::vector<T*> res(nele);
for (unsigned i = 0; i < nele; i++)
res[i] = cast<T>(ary->getOperand(i)->stripPointerCasts());
unsigned i = 0;
while (i < nele) {
llvm::Value *val = ary->getOperand(i)->stripPointerCasts();
if (allow_bad_fvars && (!isa<T>(val) || (isa<Function>(val) && cast<Function>(val)->isDeclaration()))) {
// Shouldn't happen in regular use, but can happen in bugpoint.
nele--;
continue;
}
res[i++] = cast<T>(val);
}
res.resize(nele);
assert(gv->use_empty());
gv->eraseFromParent();
if (ary->use_empty())
Expand All @@ -314,14 +324,15 @@ static inline std::vector<T*> consume_gv(Module &M, const char *name)
}

// Collect basic information about targets and functions.
CloneCtx::CloneCtx(Module &M, function_ref<LoopInfo&(Function&)> GetLI, function_ref<CallGraph&()> GetCG)
CloneCtx::CloneCtx(Module &M, function_ref<LoopInfo&(Function&)> GetLI, function_ref<CallGraph&()> GetCG, bool allow_bad_fvars)
: tbaa_const(tbaa_make_child_with_context(M.getContext(), "jtbaa_const", nullptr, true).first),
specs(jl_get_llvm_clone_targets()),
fvars(consume_gv<Function>(M, "jl_sysimg_fvars")),
gvars(consume_gv<Constant>(M, "jl_sysimg_gvars")),
fvars(consume_gv<Function>(M, "jl_sysimg_fvars", allow_bad_fvars)),
gvars(consume_gv<Constant>(M, "jl_sysimg_gvars", false)),
M(M),
GetLI(GetLI),
GetCG(GetCG)
GetCG(GetCG),
allow_bad_fvars(allow_bad_fvars)
{
groups.emplace_back(0, specs[0]);
uint32_t ntargets = specs.size();
Expand Down Expand Up @@ -636,6 +647,12 @@ uint32_t CloneCtx::get_func_id(Function *F)
{
auto &ref = func_ids[F];
if (!ref) {
if (allow_bad_fvars && F->isDeclaration()) {
// This should never happen in regular use, but can happen if
// bugpoint deletes the function. Just do something here to
// allow bugpoint to proceed.
return (uint32_t)-1;
}
fvars.push_back(F);
ref = fvars.size();
}
Expand Down Expand Up @@ -927,10 +944,15 @@ Constant *CloneCtx::emit_offset_table(const std::vector<T*> &vars, StringRef nam

void CloneCtx::emit_metadata()
{
uint32_t nfvars = fvars.size();
if (allow_bad_fvars && nfvars == 0) {
// Will result in a non-loadable sysimg, but `allow_bad_fvars` is for bugpoint only
return;
}

// Store back the information about exported functions.
auto fbase = emit_offset_table(fvars, "jl_sysimg_fvars");
auto gbase = emit_offset_table(gvars, "jl_sysimg_gvars");
uint32_t nfvars = fvars.size();

uint32_t ntargets = specs.size();
SmallVector<Target*, 8> targets(ntargets);
Expand Down Expand Up @@ -1057,7 +1079,7 @@ void CloneCtx::emit_metadata()
}
}

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

CloneCtx clone(M, GetLI, GetCG);
GlobalVariable *fvars = M.getGlobalVariable("jl_sysimg_fvars");
GlobalVariable *gvars = M.getGlobalVariable("jl_sysimg_gvars");
if (allow_bad_fvars && (!fvars || !fvars->hasInitializer() || !isa<ConstantArray>(fvars->getInitializer()) ||
!gvars || !gvars->hasInitializer() || !isa<ConstantArray>(gvars->getInitializer())))
return false;

CloneCtx clone(M, GetLI, GetCG, allow_bad_fvars);

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

struct MultiVersioningLegacy: public ModulePass {
static char ID;
MultiVersioningLegacy()
: ModulePass(ID)
MultiVersioningLegacy(bool allow_bad_fvars=false)
: ModulePass(ID), allow_bad_fvars(allow_bad_fvars)
{}

private:
Expand All @@ -1122,6 +1150,7 @@ struct MultiVersioningLegacy: public ModulePass {
AU.addRequired<CallGraphWrapperPass>();
AU.addPreserved<LoopInfoWrapperPass>();
}
bool allow_bad_fvars;
};

bool MultiVersioningLegacy::runOnModule(Module &M)
Expand All @@ -1132,7 +1161,7 @@ bool MultiVersioningLegacy::runOnModule(Module &M)
auto GetCG = [this]() -> CallGraph & {
return getAnalysis<CallGraphWrapperPass>().getCallGraph();
};
return runMultiVersioning(M, GetLI, GetCG);
return runMultiVersioning(M, GetLI, GetCG, allow_bad_fvars);
}


Expand All @@ -1152,20 +1181,20 @@ PreservedAnalyses MultiVersioning::run(Module &M, ModuleAnalysisManager &AM)
auto GetCG = [&]() -> CallGraph & {
return AM.getResult<CallGraphAnalysis>(M);
};
if (runMultiVersioning(M, GetLI, GetCG)) {
if (runMultiVersioning(M, GetLI, GetCG, false)) {
auto preserved = PreservedAnalyses::allInSet<CFGAnalyses>();
preserved.preserve<LoopAnalysis>();
return preserved;
}
return PreservedAnalyses::all();
}

Pass *createMultiVersioningPass()
Pass *createMultiVersioningPass(bool allow_bad_fvars)
{
return new MultiVersioningLegacy();
return new MultiVersioningLegacy(allow_bad_fvars);
}

extern "C" JL_DLLEXPORT void LLVMExtraAddMultiVersioningPass_impl(LLVMPassManagerRef PM)
{
unwrap(PM)->add(createMultiVersioningPass());
unwrap(PM)->add(createMultiVersioningPass(false));
}

0 comments on commit 516a404

Please sign in to comment.