From 618dd254d219597ec5daf5905e89fe2e3f648732 Mon Sep 17 00:00:00 2001 From: Peter Waller Date: Mon, 29 Dec 2025 17:20:56 +0000 Subject: [PATCH] [CHR] Fix crash when marking merged condition unknown CHR builds the merged hot-path predicate with IRBuilder::CreateLogicalAnd. That helper is implemented as a select and can constant-fold to a non- Instruction (e.g. i1 true). The pass then attempted to mark the merged condition as having explicitly unknown branch weights when profile data is present, but it unconditionally did cast(MergedCondition), which can crash in release builds. Guard the metadata update with dyn_cast and pass the containing Function explicitly to avoid calling Instruction::getFunction when the value is not attached yet. Add a regression test that exercises the constant-folding case. Crashing stack: ``` 2. Running pass "chr" on function "repro_crash" #0 0x0000000003be00a4 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (bin/opt+0x3be00a4) #1 0x0000000003bdd9e8 llvm::sys::RunSignalHandlers() (bin/opt+0x3bdd9e8) #2 0x0000000003be1300 SignalHandler(int, siginfo_t*, void*) Signals.cpp:0:0 #3 0x0000ffffa8e1d840 (linux-vdso.so.1+0x840) #4 0x0000000003c815e0 llvm::Instruction::getFunction() const (bin/opt+0x3c815e0) #5 0x0000000003dcd35c llvm::setExplicitlyUnknownBranchWeightsIfProfiled(llvm::Instruction&, llvm::StringRef, llvm::Function const*) (bin/opt+0x3dcd35c) #6 0x0000000004fb3670 (anonymous namespace)::CHR::addToMergedCondition(bool, llvm::Value*, llvm::Instruction*, (anonymous namespace)::CHRScope*, llvm::IRBuilder&, llvm::Value*&) ControlHeightReduction.cpp:0:0 #7 0x0000000004fa7d88 (anonymous namespace)::CHR::run() ControlHeightReduction.cpp:0:0 #8 0x0000000004fa3618 llvm::ControlHeightReductionPass::run(llvm::Function&, llvm::AnalysisManager&) (bin/opt+0x4fa3618) ``` Tests: opt < llvm/test/Transforms/PGOProfile/chr-unknown-profdata-crash.ll -passes='require,function(chr)' -force-chr -chr-merge-threshold=1 -disable-output --- .../ControlHeightReduction.cpp | 4 +-- .../PGOProfile/chr-unknown-profdata-crash.ll | 33 +++++++++++++++++++ 2 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 llvm/test/Transforms/PGOProfile/chr-unknown-profdata-crash.ll diff --git a/llvm/lib/Transforms/Instrumentation/ControlHeightReduction.cpp b/llvm/lib/Transforms/Instrumentation/ControlHeightReduction.cpp index 726d94b27a7f2..c7b941319f8b9 100644 --- a/llvm/lib/Transforms/Instrumentation/ControlHeightReduction.cpp +++ b/llvm/lib/Transforms/Instrumentation/ControlHeightReduction.cpp @@ -1992,8 +1992,8 @@ void CHR::addToMergedCondition(bool IsTrueBiased, Value *Cond, // Use logical and to avoid propagating poison from later conditions. MergedCondition = IRB.CreateLogicalAnd(MergedCondition, Cond); - setExplicitlyUnknownBranchWeightsIfProfiled( - *cast(MergedCondition), DEBUG_TYPE); + if (auto *MergedInst = dyn_cast(MergedCondition)) + setExplicitlyUnknownBranchWeightsIfProfiled(*MergedInst, DEBUG_TYPE, &F); } void CHR::transformScopes(SmallVectorImpl &CHRScopes) { diff --git a/llvm/test/Transforms/PGOProfile/chr-unknown-profdata-crash.ll b/llvm/test/Transforms/PGOProfile/chr-unknown-profdata-crash.ll new file mode 100644 index 0000000000000..220f442a6b681 --- /dev/null +++ b/llvm/test/Transforms/PGOProfile/chr-unknown-profdata-crash.ll @@ -0,0 +1,33 @@ +; RUN: opt < %s -passes='require,function(chr)' -force-chr -chr-merge-threshold=1 -disable-output + +; Regression test for a crash in CHR when setting unknown profdata on the +; merged condition. IRBuilder::CreateLogicalAnd is implemented as a select and +; can constant-fold to a non-Instruction value (e.g. `i1 true`). The buggy code +; assumed it always produced an Instruction and did `cast(V)`, +; which can segfault in release builds. +define void @repro_crash() { +entry: + br i1 true, label %then, label %exit, !prof !15 + +then: + br label %exit + +exit: + ret void +} + +!llvm.module.flags = !{!0} +!0 = !{i32 1, !"ProfileSummary", !1} +!1 = !{!2, !3, !4, !5, !6, !7, !8, !9} +!2 = !{!"ProfileFormat", !"InstrProf"} +!3 = !{!"TotalCount", i64 10000} +!4 = !{!"MaxCount", i64 10} +!5 = !{!"MaxInternalCount", i64 1} +!6 = !{!"MaxFunctionCount", i64 1000} +!7 = !{!"NumCounts", i64 1} +!8 = !{!"NumFunctions", i64 1} +!9 = !{!"DetailedSummary", !10} +!10 = !{!11} +!11 = !{i32 999999, i64 1, i32 1} + +!15 = !{!"branch_weights", i32 100, i32 1}