[InstCombine] Propagate profile metadata when combining selects (#177883)

When we simplify a pair of selects, we want to propagate profile
information when the condition remains the same and drop it when it does
not. Before this patch, we were keeping incorrect profile data in
addition to not annotating any new select instructions that had the same
value as a previous one.

Noticed by looking at 80d9df6b054cebfbe97d709195be4e61a7acc694.
This commit is contained in:
Aiden Grossman 2026-01-26 11:25:06 -10:00 committed by GitHub
parent cd79290926
commit 16c8a02f2d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 49 additions and 25 deletions

View File

@ -35,6 +35,7 @@
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/Operator.h"
#include "llvm/IR/PatternMatch.h"
#include "llvm/IR/ProfDataUtils.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/User.h"
#include "llvm/IR/Value.h"
@ -4546,18 +4547,24 @@ Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) {
Value *And = nullptr, *OtherVal = nullptr;
// select(C0, select(C1, a, b), b) -> select(C0&&C1, a, b)
if (TrueSI->getFalseValue() == FalseVal) {
And = Builder.CreateLogicalAnd(CondVal, TrueSI->getCondition());
And = Builder.CreateLogicalAnd(CondVal, TrueSI->getCondition(), "",
ProfcheckDisableMetadataFixes ? nullptr
: &SI);
OtherVal = TrueSI->getTrueValue();
}
// select(C0, select(C1, b, a), b) -> select(C0&&!C1, a, b)
else if (TrueSI->getTrueValue() == FalseVal) {
Value *InvertedCond = Builder.CreateNot(TrueSI->getCondition());
And = Builder.CreateLogicalAnd(CondVal, InvertedCond);
And = Builder.CreateLogicalAnd(CondVal, InvertedCond, "",
ProfcheckDisableMetadataFixes ? nullptr
: &SI);
OtherVal = TrueSI->getFalseValue();
}
if (And && OtherVal) {
replaceOperand(SI, 0, And);
replaceOperand(SI, 1, OtherVal);
if (!ProfcheckDisableMetadataFixes)
setExplicitlyUnknownBranchWeightsIfProfiled(SI, DEBUG_TYPE);
return &SI;
}
}
@ -4575,18 +4582,24 @@ Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) {
Value *Or = nullptr, *OtherVal = nullptr;
// select(C0, a, select(C1, a, b)) -> select(C0||C1, a, b)
if (FalseSI->getTrueValue() == TrueVal) {
Or = Builder.CreateLogicalOr(CondVal, FalseSI->getCondition());
Or = Builder.CreateLogicalOr(CondVal, FalseSI->getCondition(), "",
ProfcheckDisableMetadataFixes ? nullptr
: &SI);
OtherVal = FalseSI->getFalseValue();
}
// select(C0, a, select(C1, b, a)) -> select(C0||!C1, a, b)
else if (FalseSI->getFalseValue() == TrueVal) {
Value *InvertedCond = Builder.CreateNot(FalseSI->getCondition());
Or = Builder.CreateLogicalOr(CondVal, InvertedCond);
Or = Builder.CreateLogicalOr(CondVal, InvertedCond, "",
ProfcheckDisableMetadataFixes ? nullptr
: &SI);
OtherVal = FalseSI->getTrueValue();
}
if (Or && OtherVal) {
replaceOperand(SI, 0, Or);
replaceOperand(SI, 2, OtherVal);
if (!ProfcheckDisableMetadataFixes)
setExplicitlyUnknownBranchWeightsIfProfiled(SI, DEBUG_TYPE);
return &SI;
}
}

View File

@ -1,4 +1,4 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals
; RUN: opt -passes=instcombine -S < %s | FileCheck %s
define float @foo1(float %a) {
@ -533,49 +533,49 @@ define <2 x i8> @strong_order_cmp_eq_ugt_vector_poison3(<2 x i32> %a, <2 x i32>
; Minimal code that triggers the optimizations.
define i32 @selectSelect11(i1 %cond1, i1 %cond2, i32 %var, i32 %defaultVal) {
define i32 @selectSelect11(i1 %cond1, i1 %cond2, i32 %var, i32 %defaultVal) !prof !0 {
; CHECK-LABEL: @selectSelect11(
; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[COND2:%.*]], i1 true, i1 [[COND1:%.*]]
; CHECK-NEXT: [[SEL2:%.*]] = select i1 [[TMP1]], i32 [[VAR:%.*]], i32 [[DEFAULTVAL:%.*]]
; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[COND2:%.*]], i1 true, i1 [[COND1:%.*]], !prof [[PROF1:![0-9]+]]
; CHECK-NEXT: [[SEL2:%.*]] = select i1 [[TMP1]], i32 [[DEFAULTVAL:%.*]], i32 [[VAR:%.*]], !prof [[PROF2:![0-9]+]]
; CHECK-NEXT: ret i32 [[SEL2]]
;
%sel1 = select i1 %cond1, i32 %defaultVal, i32 %var
%sel2 = select i1 %cond2, i32 %defaultVal, i32 %sel1
%sel1 = select i1 %cond1, i32 %defaultVal, i32 %var, !prof !1
%sel2 = select i1 %cond2, i32 %defaultVal, i32 %sel1, !prof !2
ret i32 %sel2
}
define i32 @selectSelect22(i1 %cond1, i1 %cond2, i32 %var, i32 %defaultVal) {
define i32 @selectSelect22(i1 %cond1, i1 %cond2, i32 %var, i32 %defaultVal) !prof !0 {
; CHECK-LABEL: @selectSelect22(
; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[COND2:%.*]], i1 [[COND1:%.*]], i1 false
; CHECK-NEXT: [[SEL2:%.*]] = select i1 [[TMP1]], i32 [[VAR:%.*]], i32 [[DEFAULTVAL:%.*]]
; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[COND2:%.*]], i1 [[COND1:%.*]], i1 false, !prof [[PROF1]]
; CHECK-NEXT: [[SEL2:%.*]] = select i1 [[TMP1]], i32 [[VAR:%.*]], i32 [[DEFAULTVAL:%.*]], !prof [[PROF2]]
; CHECK-NEXT: ret i32 [[SEL2]]
;
%sel1 = select i1 %cond1, i32 %var, i32 %defaultVal
%sel2 = select i1 %cond2, i32 %sel1, i32 %defaultVal
%sel1 = select i1 %cond1, i32 %var, i32 %defaultVal, !prof !1
%sel2 = select i1 %cond2, i32 %sel1, i32 %defaultVal, !prof !2
ret i32 %sel2
}
define i32 @selectSelect12(i1 %cond1, i1 %cond2, i32 %var, i32 %defaultVal) {
define i32 @selectSelect12(i1 %cond1, i1 %cond2, i32 %var, i32 %defaultVal) !prof !0 {
; CHECK-LABEL: @selectSelect12(
; CHECK-NEXT: [[TMP1:%.*]] = xor i1 [[COND1:%.*]], true
; CHECK-NEXT: [[COND2:%.*]] = select i1 [[COND3:%.*]], i1 [[TMP1]], i1 false
; CHECK-NEXT: [[SEL2:%.*]] = select i1 [[COND2]], i32 [[SEL3:%.*]], i32 [[DEFAULTVAL:%.*]]
; CHECK-NEXT: [[TMP2:%.*]] = select i1 [[COND2:%.*]], i1 [[TMP1]], i1 false, !prof [[PROF1]]
; CHECK-NEXT: [[SEL2:%.*]] = select i1 [[TMP2]], i32 [[VAR:%.*]], i32 [[DEFAULTVAL:%.*]], !prof [[PROF2]]
; CHECK-NEXT: ret i32 [[SEL2]]
;
%sel1 = select i1 %cond1, i32 %defaultVal,i32 %var
%sel2 = select i1 %cond2, i32 %sel1, i32 %defaultVal
%sel1 = select i1 %cond1, i32 %defaultVal,i32 %var, !prof !1
%sel2 = select i1 %cond2, i32 %sel1, i32 %defaultVal, !prof !2
ret i32 %sel2
}
define i32 @selectSelect21(i1 %cond1, i1 %cond2, i32 %var, i32 %defaultVal) {
define i32 @selectSelect21(i1 %cond1, i1 %cond2, i32 %var, i32 %defaultVal) !prof !0 {
; CHECK-LABEL: @selectSelect21(
; CHECK-NEXT: [[TMP1:%.*]] = xor i1 [[COND1:%.*]], true
; CHECK-NEXT: [[COND2:%.*]] = select i1 [[COND3:%.*]], i1 true, i1 [[TMP1]]
; CHECK-NEXT: [[SEL2:%.*]] = select i1 [[COND2]], i32 [[DEFAULTVAL1:%.*]], i32 [[DEFAULTVAL:%.*]]
; CHECK-NEXT: [[TMP2:%.*]] = select i1 [[COND2:%.*]], i1 true, i1 [[TMP1]], !prof [[PROF1]]
; CHECK-NEXT: [[SEL2:%.*]] = select i1 [[TMP2]], i32 [[DEFAULTVAL:%.*]], i32 [[VAR:%.*]], !prof [[PROF2]]
; CHECK-NEXT: ret i32 [[SEL2]]
;
%sel1 = select i1 %cond1, i32 %var, i32 %defaultVal
%sel2 = select i1 %cond2, i32 %defaultVal, i32 %sel1
%sel1 = select i1 %cond1, i32 %var, i32 %defaultVal, !prof !1
%sel2 = select i1 %cond2, i32 %defaultVal, i32 %sel1, !prof !2
ret i32 %sel2
}
@ -689,3 +689,14 @@ define i32 @gh82350(i32 %x, i32 %y, i32 %z, i1 %cmp1) {
declare void @use1(i1)
declare void @use8(i8)
declare void @use32(i32)
!0 = !{!"function_entry_count", i64 1000}
!1 = !{!"branch_weights", i32 2, i32 3}
!2 = !{!"branch_weights", i32 5, i32 3}
;.
; CHECK: attributes #[[ATTR0:[0-9]+]] = { nocallback nocreateundeforpoison nofree nosync nounwind speculatable willreturn memory(none) }
;.
; CHECK: [[META0:![0-9]+]] = !{!"function_entry_count", i64 1000}
; CHECK: [[PROF1]] = !{!"branch_weights", i32 5, i32 3}
; CHECK: [[PROF2]] = !{!"unknown", !"instcombine"}
;.