@@ -40,6 +40,70 @@ using namespace cling;
40
40
using namespace clang ;
41
41
using namespace llvm ;
42
42
43
+ namespace {
44
+ class WorkAroundConstructorPriorityBugPass
45
+ : public PassInfoMixin<WorkAroundConstructorPriorityBugPass> {
46
+ public:
47
+ PreservedAnalyses run (llvm::Module& M, ModuleAnalysisManager& AM) {
48
+ llvm::GlobalVariable* GlobalCtors = M.getNamedGlobal (" llvm.global_ctors" );
49
+ if (!GlobalCtors)
50
+ return PreservedAnalyses::all ();
51
+
52
+ auto * OldCtors = llvm::dyn_cast_or_null<llvm::ConstantArray>(
53
+ GlobalCtors->getInitializer ());
54
+ if (!OldCtors)
55
+ return PreservedAnalyses::all ();
56
+
57
+ // LLVM had a bug where constructors with the same priority would not be
58
+ // stably sorted. This has been fixed upstream by
59
+ // https://github.com/llvm/llvm-project/pull/95532, but to avoid relying
60
+ // on a backport this pass works around the issue: The idea is that we
61
+ // lower the default priority of concerned constructors to make them sort
62
+ // correctly.
63
+ static constexpr uint64_t DefaultPriority = 65535 ;
64
+
65
+ unsigned NumCtors = OldCtors->getNumOperands ();
66
+ const uint64_t NewDefaultPriorityStart = DefaultPriority - NumCtors;
67
+ uint64_t NewDefaultPriority = NewDefaultPriorityStart;
68
+
69
+ llvm::SmallVector<Constant*> NewCtors;
70
+ for (unsigned I = 0 ; I < NumCtors; I++) {
71
+ auto * Ctor =
72
+ llvm::dyn_cast<llvm::ConstantStruct>(OldCtors->getOperand (I));
73
+ auto * PriorityC = llvm::cast<llvm::ConstantInt>(Ctor->getOperand (0 ));
74
+ uint64_t Priority = PriorityC->getZExtValue ();
75
+ if (Priority >= NewDefaultPriorityStart && Priority < DefaultPriority) {
76
+ llvm::errs () << " Found priority " << Priority
77
+ << " , not changing anything\n " ;
78
+ return PreservedAnalyses::all ();
79
+ }
80
+
81
+ if (Priority == DefaultPriority) {
82
+ Priority = NewDefaultPriority;
83
+ NewDefaultPriority++;
84
+ }
85
+
86
+ llvm::SmallVector<Constant*> NewCtorArgs;
87
+ NewCtorArgs.push_back (
88
+ llvm::ConstantInt::get (PriorityC->getIntegerType (), Priority));
89
+ // Copy the function and data Constant, if present.
90
+ NewCtorArgs.push_back (Ctor->getOperand (1 ));
91
+ if (Ctor->getNumOperands () >= 3 ) {
92
+ NewCtorArgs.push_back (Ctor->getOperand (2 ));
93
+ }
94
+
95
+ NewCtors.push_back (
96
+ llvm::ConstantStruct::get (Ctor->getType (), NewCtorArgs));
97
+ }
98
+
99
+ GlobalCtors->setInitializer (
100
+ llvm::ConstantArray::get (OldCtors->getType (), NewCtors));
101
+
102
+ return PreservedAnalyses::none ();
103
+ }
104
+ };
105
+ } // namespace
106
+
43
107
namespace {
44
108
class KeepLocalGVPass : public PassInfoMixin <KeepLocalGVPass> {
45
109
bool runOnGlobal (GlobalValue& GV) {
@@ -350,6 +414,8 @@ void BackendPasses::CreatePasses(int OptLevel, llvm::ModulePassManager& MPM,
350
414
PassInstrumentationCallbacks& PIC,
351
415
StandardInstrumentations& SI) {
352
416
417
+ // TODO: Remove this pass once we upgrade past LLVM 19 that includes the fix.
418
+ MPM.addPass (WorkAroundConstructorPriorityBugPass ());
353
419
MPM.addPass (KeepLocalGVPass ());
354
420
MPM.addPass (WeakTypeinfoVTablePass ());
355
421
MPM.addPass (ReuseExistingWeakSymbols (m_JIT));
0 commit comments