[llvm] Fix profile metadata propagation in InstCombine select folding (PR #179743)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Feb 19 23:50:42 PST 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-transforms
Author: Snehasish Kumar (snehasish)
<details>
<summary>Changes</summary>
Propagate profile metadata when folding select instructions with logical AND/OR conditions and when canonicalizing SPF to intrinsics. This fixes profile verification failures in Transforms/InstCombine/select-and-or.ll.
1. Select Pattern Factor (SPF) Canonicalization
When canonicalizing SPF patterns (like umax/umin), InstCombine transforms sequences like select i1 %cond,(select i1 %cmp, %x, %y), %z into intrinsic calls wrapped in a new select. The new outer select directly replaces the original select instruction, and its condition (%cond) remains structurally identical. Because the condition and its evaluated true/false semantics are unchanged, it is ok to copy the original !prof branch weight metadata to the newly created select.
2. Logical Boolean Folds (foldSelectOfBools)
For logical boolean folds (e.g., transforming select (~a | c), a, b into select a, (select c, true, b), false), InstCombine restructures complex conditions into nested selects. In this scenario, blindly copying the !prof metadata from the original select to both the newly created inner and outer selects is imprecise. The original profile data represented the aggregate probability of the complex condition (~a | c), not the isolated probabilities of a or c.
---
Full diff: https://github.com/llvm/llvm-project/pull/179743.diff
3 Files Affected:
- (modified) llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp (+16-10)
- (modified) llvm/test/Transforms/InstCombine/select-and-or.ll (+25-24)
- (modified) llvm/utils/profcheck-xfail.txt (-1)
``````````diff
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index 3eb0b1d767727..a63cf6a85628c 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -3717,28 +3717,32 @@ Instruction *InstCombinerImpl::foldSelectOfBools(SelectInst &SI) {
// select (~a | c), a, b -> select a, (select c, true, b), false
if (match(CondVal,
m_OneUse(m_c_Or(m_Not(m_Specific(TrueVal)), m_Value(C))))) {
- Value *OrV = Builder.CreateSelect(C, One, FalseVal);
- return SelectInst::Create(TrueVal, OrV, Zero);
+ Instruction *MDFrom = ProfcheckDisableMetadataFixes ? nullptr : &SI;
+ Value *OrV = Builder.CreateSelect(C, One, FalseVal, "", MDFrom);
+ return SelectInst::Create(TrueVal, OrV, Zero, "", nullptr, MDFrom);
}
// select (c & b), a, b -> select b, (select ~c, true, a), false
if (match(CondVal, m_OneUse(m_c_And(m_Value(C), m_Specific(FalseVal))))) {
if (Value *NotC = getFreelyInverted(C, C->hasOneUse(), &Builder)) {
- Value *OrV = Builder.CreateSelect(NotC, One, TrueVal);
- return SelectInst::Create(FalseVal, OrV, Zero);
+ Instruction *MDFrom = ProfcheckDisableMetadataFixes ? nullptr : &SI;
+ Value *OrV = Builder.CreateSelect(NotC, One, TrueVal, "", MDFrom);
+ return SelectInst::Create(FalseVal, OrV, Zero, "", nullptr, MDFrom);
}
}
// select (a | c), a, b -> select a, true, (select ~c, b, false)
if (match(CondVal, m_OneUse(m_c_Or(m_Specific(TrueVal), m_Value(C))))) {
if (Value *NotC = getFreelyInverted(C, C->hasOneUse(), &Builder)) {
- Value *AndV = Builder.CreateSelect(NotC, FalseVal, Zero);
- return SelectInst::Create(TrueVal, One, AndV);
+ Instruction *MDFrom = ProfcheckDisableMetadataFixes ? nullptr : &SI;
+ Value *AndV = Builder.CreateSelect(NotC, FalseVal, Zero, "", MDFrom);
+ return SelectInst::Create(TrueVal, One, AndV, "", nullptr, MDFrom);
}
}
// select (c & ~b), a, b -> select b, true, (select c, a, false)
if (match(CondVal,
m_OneUse(m_c_And(m_Value(C), m_Not(m_Specific(FalseVal)))))) {
- Value *AndV = Builder.CreateSelect(C, TrueVal, Zero);
- return SelectInst::Create(FalseVal, One, AndV);
+ Instruction *MDFrom = ProfcheckDisableMetadataFixes ? nullptr : &SI;
+ Value *AndV = Builder.CreateSelect(C, TrueVal, Zero, "", MDFrom);
+ return SelectInst::Create(FalseVal, One, AndV, "", nullptr, MDFrom);
}
if (match(FalseVal, m_Zero()) || match(TrueVal, m_One())) {
@@ -4843,9 +4847,11 @@ Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) {
// Is (select B, T, F) a SPF?
if (CondVal->hasOneUse() && SelType->isIntOrIntVectorTy()) {
if (ICmpInst *Cmp = dyn_cast<ICmpInst>(B))
- if (Value *V = canonicalizeSPF(*Cmp, TrueVal, FalseVal, *this))
+ if (Value *V = canonicalizeSPF(*Cmp, TrueVal, FalseVal, *this)) {
+ Instruction *MDFrom = ProfcheckDisableMetadataFixes ? nullptr : &SI;
return SelectInst::Create(A, IsAnd ? V : TrueVal,
- IsAnd ? FalseVal : V);
+ IsAnd ? FalseVal : V, "", nullptr, MDFrom);
+ }
}
return nullptr;
diff --git a/llvm/test/Transforms/InstCombine/select-and-or.ll b/llvm/test/Transforms/InstCombine/select-and-or.ll
index 7ae250f04f29e..33701e8ab5a38 100644
--- a/llvm/test/Transforms/InstCombine/select-and-or.ll
+++ b/llvm/test/Transforms/InstCombine/select-and-or.ll
@@ -490,27 +490,27 @@ define i1 @demorgan_select_infloop2(i1 %L) {
ret i1 %C15
}
-define i1 @and_or1(i1 %a, i1 %b, i1 %c) {
+define i1 @and_or1(i1 %a, i1 %b, i1 %c) !prof !0 {
; CHECK-LABEL: @and_or1(
-; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[C:%.*]], i1 true, i1 [[B:%.*]]
-; CHECK-NEXT: [[R:%.*]] = select i1 [[A:%.*]], i1 [[TMP1]], i1 false
+; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[C:%.*]], i1 true, i1 [[B:%.*]], !prof [[PROF2:![0-9]+]]
+; CHECK-NEXT: [[R:%.*]] = select i1 [[A:%.*]], i1 [[TMP1]], i1 false, !prof [[PROF2]]
; CHECK-NEXT: ret i1 [[R]]
;
%nota = xor i1 %a, true
%cond = or i1 %nota, %c
- %r = select i1 %cond, i1 %a, i1 %b
+ %r = select i1 %cond, i1 %a, i1 %b, !prof !1
ret i1 %r
}
-define i1 @and_or2(i1 %a, i1 %b, i1 %c) {
+define i1 @and_or2(i1 %a, i1 %b, i1 %c) !prof !0 {
; CHECK-LABEL: @and_or2(
-; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[C:%.*]], i1 true, i1 [[A:%.*]]
-; CHECK-NEXT: [[R:%.*]] = select i1 [[B:%.*]], i1 [[TMP1]], i1 false
+; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[C:%.*]], i1 true, i1 [[A:%.*]], !prof [[PROF2]]
+; CHECK-NEXT: [[R:%.*]] = select i1 [[B:%.*]], i1 [[TMP1]], i1 false, !prof [[PROF2]]
; CHECK-NEXT: ret i1 [[R]]
;
%notc = xor i1 %c, true
%cond = and i1 %notc, %b
- %r = select i1 %cond, i1 %a, i1 %b
+ %r = select i1 %cond, i1 %a, i1 %b, !prof !1
ret i1 %r
}
@@ -741,27 +741,27 @@ define i1 @and_or3_wrong_operand(i1 %a, i1 %b, i32 %x, i32 %y, i1 %d) {
ret i1 %r
}
-define i1 @or_and1(i1 %a, i1 %b, i1 %c) {
+define i1 @or_and1(i1 %a, i1 %b, i1 %c) !prof !0 {
; CHECK-LABEL: @or_and1(
-; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[C:%.*]], i1 [[A:%.*]], i1 false
-; CHECK-NEXT: [[R:%.*]] = select i1 [[B:%.*]], i1 true, i1 [[TMP1]]
+; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[C:%.*]], i1 [[A:%.*]], i1 false, !prof [[PROF2]]
+; CHECK-NEXT: [[R:%.*]] = select i1 [[B:%.*]], i1 true, i1 [[TMP1]], !prof [[PROF2]]
; CHECK-NEXT: ret i1 [[R]]
;
%notb = xor i1 %b, true
%cond = and i1 %notb, %c
- %r = select i1 %cond, i1 %a, i1 %b
+ %r = select i1 %cond, i1 %a, i1 %b, !prof !1
ret i1 %r
}
-define i1 @or_and2(i1 %a, i1 %b, i1 %c) {
+define i1 @or_and2(i1 %a, i1 %b, i1 %c) !prof !0 {
; CHECK-LABEL: @or_and2(
-; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[C:%.*]], i1 [[B:%.*]], i1 false
-; CHECK-NEXT: [[R:%.*]] = select i1 [[A:%.*]], i1 true, i1 [[TMP1]]
+; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[C:%.*]], i1 [[B:%.*]], i1 false, !prof [[PROF2]]
+; CHECK-NEXT: [[R:%.*]] = select i1 [[A:%.*]], i1 true, i1 [[TMP1]], !prof [[PROF2]]
; CHECK-NEXT: ret i1 [[R]]
;
%notc = xor i1 %c, true
%cond = or i1 %notc, %a
- %r = select i1 %cond, i1 %a, i1 %b
+ %r = select i1 %cond, i1 %a, i1 %b, !prof !1
ret i1 %r
}
@@ -803,7 +803,7 @@ define i1 @fold_or_of_ands_with_select_to_logical1(i1 %a, i1 %b, i1 %c) !prof !0
define i1 @fold_or_of_ands_with_select_to_logical2(i1 %a, i1 %b, i1 %c) !prof !0 {
; CHECK-LABEL: @fold_or_of_ands_with_select_to_logical2(
-; CHECK-NEXT: [[OR1:%.*]] = select i1 [[C:%.*]], i1 [[A:%.*]], i1 [[B:%.*]], !prof [[PROF2:![0-9]+]]
+; CHECK-NEXT: [[OR1:%.*]] = select i1 [[C:%.*]], i1 [[A:%.*]], i1 [[B:%.*]], !prof [[PROF3:![0-9]+]]
; CHECK-NEXT: ret i1 [[OR1]]
;
%not = xor i1 %c, true
@@ -827,7 +827,7 @@ define i1 @fold_or_of_ands_with_select_to_logical3(i1 %a, i1 %b, i1 %c) !prof !0
define i1 @fold_or_of_ands_with_select_to_logical4(i1 %a, i1 %b, i1 %c) !prof !0 {
; CHECK-LABEL: @fold_or_of_ands_with_select_to_logical4(
-; CHECK-NEXT: [[OR1:%.*]] = select i1 [[C:%.*]], i1 [[A:%.*]], i1 [[B:%.*]], !prof [[PROF2]]
+; CHECK-NEXT: [[OR1:%.*]] = select i1 [[C:%.*]], i1 [[A:%.*]], i1 [[B:%.*]], !prof [[PROF3]]
; CHECK-NEXT: ret i1 [[OR1]]
;
%not = xor i1 %c, true
@@ -839,7 +839,7 @@ define i1 @fold_or_of_ands_with_select_to_logical4(i1 %a, i1 %b, i1 %c) !prof !0
define i1 @fold_or_of_ands_with_select_to_logical5(i1 %a, i1 %b, i1 %c) !prof !0 {
; CHECK-LABEL: @fold_or_of_ands_with_select_to_logical5(
-; CHECK-NEXT: [[OR1:%.*]] = select i1 [[C:%.*]], i1 [[A:%.*]], i1 [[B:%.*]], !prof [[PROF2]]
+; CHECK-NEXT: [[OR1:%.*]] = select i1 [[C:%.*]], i1 [[A:%.*]], i1 [[B:%.*]], !prof [[PROF3]]
; CHECK-NEXT: ret i1 [[OR1]]
;
%not = xor i1 %c, true
@@ -852,7 +852,7 @@ define i1 @fold_or_of_ands_with_select_to_logical5(i1 %a, i1 %b, i1 %c) !prof !0
define i1 @fold_or_of_ands_with_select_to_logical6(i1 %a, i1 %b, i1 %c) !prof !0 {
; CHECK-LABEL: @fold_or_of_ands_with_select_to_logical6(
; CHECK-NEXT: [[TMP1:%.*]] = freeze i1 [[C:%.*]]
-; CHECK-NEXT: [[OR1:%.*]] = select i1 [[TMP1]], i1 [[A:%.*]], i1 [[B:%.*]], !prof [[PROF2]]
+; CHECK-NEXT: [[OR1:%.*]] = select i1 [[TMP1]], i1 [[A:%.*]], i1 [[B:%.*]], !prof [[PROF3]]
; CHECK-NEXT: ret i1 [[OR1]]
;
%not = xor i1 %c, true
@@ -1117,15 +1117,15 @@ define i1 @or_and3_wrong_operand(i1 %a, i1 %b, i32 %x, i32 %y, i1 %d) {
ret i1 %r
}
-define i8 @test_or_umax(i8 %x, i8 %y, i1 %cond) {
+define i8 @test_or_umax(i8 %x, i8 %y, i1 %cond) !prof !0 {
; CHECK-LABEL: @test_or_umax(
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umax.i8(i8 [[X:%.*]], i8 [[Y:%.*]])
-; CHECK-NEXT: [[RET:%.*]] = select i1 [[COND:%.*]], i8 [[X]], i8 [[TMP1]]
+; CHECK-NEXT: [[RET:%.*]] = select i1 [[COND:%.*]], i8 [[X]], i8 [[TMP1]], !prof [[PROF2]]
; CHECK-NEXT: ret i8 [[RET]]
;
%cmp = icmp ugt i8 %x, %y
%or = select i1 %cond, i1 true, i1 %cmp
- %ret = select i1 %or, i8 %x, i8 %y
+ %ret = select i1 %or, i8 %x, i8 %y, !prof !1
ret i8 %ret
}
@@ -1473,5 +1473,6 @@ define i8 @test_logical_commuted_and_ne_a_b(i1 %other_cond, i8 %a, i8 %b) {
;.
; CHECK: [[META0:![0-9]+]] = !{!"function_entry_count", i64 1000}
; CHECK: [[PROF1]] = !{!"branch_weights", i32 3, i32 2}
-; CHECK: [[PROF2]] = !{!"unknown", !"instcombine"}
+; CHECK: [[PROF2]] = !{!"branch_weights", i32 2, i32 3}
+; CHECK: [[PROF3]] = !{!"unknown", !"instcombine"}
;.
diff --git a/llvm/utils/profcheck-xfail.txt b/llvm/utils/profcheck-xfail.txt
index 72bf53e751864..0052d557b8574 100644
--- a/llvm/utils/profcheck-xfail.txt
+++ b/llvm/utils/profcheck-xfail.txt
@@ -122,7 +122,6 @@ Transforms/InstCombine/pow-1.ll
Transforms/InstCombine/pow-3.ll
Transforms/InstCombine/pow-sqrt.ll
Transforms/InstCombine/pull-conditional-binop-through-shift.ll
-Transforms/InstCombine/select-and-or.ll
Transforms/InstCombine/select-factorize.ll
Transforms/InstCombine/select-min-max.ll
Transforms/InstCombine/select-of-symmetric-selects.ll
``````````
</details>
https://github.com/llvm/llvm-project/pull/179743
More information about the llvm-commits
mailing list