Skip to content

Commit 7db43f7

Browse files
committed
[cling] Work around constructor priority bug
LLVM had a bug where constructors with the same priority would not be stably sorted. This has been fixed upstream by llvm/llvm-project#95532, but to avoid relying on a backport this commit works around the issue: The idea is that we lower the default priority of concerned constructors to make them sort correctly.
1 parent 67ff470 commit 7db43f7

File tree

1 file changed

+66
-0
lines changed

1 file changed

+66
-0
lines changed

interpreter/cling/lib/Interpreter/BackendPasses.cpp

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,70 @@ using namespace cling;
4040
using namespace clang;
4141
using namespace llvm;
4242

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+
43107
namespace {
44108
class KeepLocalGVPass : public PassInfoMixin<KeepLocalGVPass> {
45109
bool runOnGlobal(GlobalValue& GV) {
@@ -350,6 +414,8 @@ void BackendPasses::CreatePasses(int OptLevel, llvm::ModulePassManager& MPM,
350414
PassInstrumentationCallbacks& PIC,
351415
StandardInstrumentations& SI) {
352416

417+
// TODO: Remove this pass once we upgrade past LLVM 19 that includes the fix.
418+
MPM.addPass(WorkAroundConstructorPriorityBugPass());
353419
MPM.addPass(KeepLocalGVPass());
354420
MPM.addPass(WeakTypeinfoVTablePass());
355421
MPM.addPass(ReuseExistingWeakSymbols(m_JIT));

0 commit comments

Comments
 (0)