@@ -242,7 +242,7 @@ struct CloneCtx {
242
242
return cast<Function>(vmap->lookup (orig_f));
243
243
}
244
244
};
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 );
246
246
void clone_bases ();
247
247
void collect_func_infos ();
248
248
void clone_all_partials ();
@@ -292,10 +292,11 @@ struct CloneCtx {
292
292
std::set<uint32_t > alias_relocs;
293
293
bool has_veccall{false };
294
294
bool has_cloneall{false };
295
+ bool allow_bad_fvars{false };
295
296
};
296
297
297
298
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 )
299
300
{
300
301
// Get information about sysimg export functions from the two global variables.
301
302
// 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)
304
305
auto *ary = cast<ConstantArray>(gv->getInitializer ());
305
306
unsigned nele = ary->getNumOperands ();
306
307
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);
309
319
assert (gv->use_empty ());
310
320
gv->eraseFromParent ();
311
321
if (ary->use_empty ())
@@ -314,14 +324,15 @@ static inline std::vector<T*> consume_gv(Module &M, const char *name)
314
324
}
315
325
316
326
// 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 )
318
328
: tbaa_const(tbaa_make_child_with_context(M.getContext(), "jtbaa_const", nullptr, true).first),
319
329
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 )),
322
332
M(M),
323
333
GetLI(GetLI),
324
- GetCG(GetCG)
334
+ GetCG(GetCG),
335
+ allow_bad_fvars(allow_bad_fvars)
325
336
{
326
337
groups.emplace_back (0 , specs[0 ]);
327
338
uint32_t ntargets = specs.size ();
@@ -636,6 +647,12 @@ uint32_t CloneCtx::get_func_id(Function *F)
636
647
{
637
648
auto &ref = func_ids[F];
638
649
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
+ }
639
656
fvars.push_back (F);
640
657
ref = fvars.size ();
641
658
}
@@ -927,10 +944,15 @@ Constant *CloneCtx::emit_offset_table(const std::vector<T*> &vars, StringRef nam
927
944
928
945
void CloneCtx::emit_metadata ()
929
946
{
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
+
930
953
// Store back the information about exported functions.
931
954
auto fbase = emit_offset_table (fvars, " jl_sysimg_fvars" );
932
955
auto gbase = emit_offset_table (gvars, " jl_sysimg_gvars" );
933
- uint32_t nfvars = fvars.size ();
934
956
935
957
uint32_t ntargets = specs.size ();
936
958
SmallVector<Target*, 8 > targets (ntargets);
@@ -1057,7 +1079,7 @@ void CloneCtx::emit_metadata()
1057
1079
}
1058
1080
}
1059
1081
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 )
1061
1083
{
1062
1084
// Group targets and identify cloning bases.
1063
1085
// 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
1070
1092
if (M.getName () == " sysimage" )
1071
1093
return false ;
1072
1094
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);
1074
1102
1075
1103
// Collect a list of original functions and clone base functions
1076
1104
clone.clone_bases ();
@@ -1110,8 +1138,8 @@ static bool runMultiVersioning(Module &M, function_ref<LoopInfo&(Function&)> Get
1110
1138
1111
1139
struct MultiVersioningLegacy : public ModulePass {
1112
1140
static char ID;
1113
- MultiVersioningLegacy ()
1114
- : ModulePass(ID)
1141
+ MultiVersioningLegacy (bool allow_bad_fvars= false )
1142
+ : ModulePass(ID), allow_bad_fvars(allow_bad_fvars)
1115
1143
{}
1116
1144
1117
1145
private:
@@ -1122,6 +1150,7 @@ struct MultiVersioningLegacy: public ModulePass {
1122
1150
AU.addRequired <CallGraphWrapperPass>();
1123
1151
AU.addPreserved <LoopInfoWrapperPass>();
1124
1152
}
1153
+ bool allow_bad_fvars;
1125
1154
};
1126
1155
1127
1156
bool MultiVersioningLegacy::runOnModule (Module &M)
@@ -1132,7 +1161,7 @@ bool MultiVersioningLegacy::runOnModule(Module &M)
1132
1161
auto GetCG = [this ]() -> CallGraph & {
1133
1162
return getAnalysis<CallGraphWrapperPass>().getCallGraph ();
1134
1163
};
1135
- return runMultiVersioning (M, GetLI, GetCG);
1164
+ return runMultiVersioning (M, GetLI, GetCG, allow_bad_fvars );
1136
1165
}
1137
1166
1138
1167
@@ -1152,20 +1181,20 @@ PreservedAnalyses MultiVersioning::run(Module &M, ModuleAnalysisManager &AM)
1152
1181
auto GetCG = [&]() -> CallGraph & {
1153
1182
return AM.getResult <CallGraphAnalysis>(M);
1154
1183
};
1155
- if (runMultiVersioning (M, GetLI, GetCG)) {
1184
+ if (runMultiVersioning (M, GetLI, GetCG, false )) {
1156
1185
auto preserved = PreservedAnalyses::allInSet<CFGAnalyses>();
1157
1186
preserved.preserve <LoopAnalysis>();
1158
1187
return preserved;
1159
1188
}
1160
1189
return PreservedAnalyses::all ();
1161
1190
}
1162
1191
1163
- Pass *createMultiVersioningPass ()
1192
+ Pass *createMultiVersioningPass (bool allow_bad_fvars )
1164
1193
{
1165
- return new MultiVersioningLegacy ();
1194
+ return new MultiVersioningLegacy (allow_bad_fvars );
1166
1195
}
1167
1196
1168
1197
extern " C" JL_DLLEXPORT void LLVMExtraAddMultiVersioningPass_impl (LLVMPassManagerRef PM)
1169
1198
{
1170
- unwrap (PM)->add (createMultiVersioningPass ());
1199
+ unwrap (PM)->add (createMultiVersioningPass (false ));
1171
1200
}
0 commit comments