Skip to content

Conversation

alanzhao1
Copy link
Contributor

For transforms of the form:

(X == C) && (Y Pred1 X) --> (X == C) && (Y Pred1 C)
(X != C) || (Y Pred1 X) --> (X != C) || (Y Pred1 C)

we can preserve the profile branch weights of the select statement because the first condition is unchanged.

Tracking issue: #147390

…e equivalences

 For transforms of the form:

 ```
 (X == C) && (Y Pred1 X) --> (X == C) && (Y Pred1 C)
 (X != C) || (Y Pred1 X) --> (X != C) || (Y Pred1 C)
 ```

we can preserve the profile branch weights of the select statement
because the first condition is unchanged.

Tracking issue: llvm#147390
@alanzhao1 alanzhao1 requested a review from mtrofin October 9, 2025 21:10
@alanzhao1 alanzhao1 requested a review from nikic as a code owner October 9, 2025 21:10
@llvmbot llvmbot added llvm:instcombine Covers the InstCombine, InstSimplify and AggressiveInstCombine passes llvm:transforms labels Oct 9, 2025
@llvmbot
Copy link
Member

llvmbot commented Oct 9, 2025

@llvm/pr-subscribers-llvm-transforms

Author: Alan Zhao (alanzhao1)

Changes

For transforms of the form:

(X == C) && (Y Pred1 X) --> (X == C) && (Y Pred1 C)
(X != C) || (Y Pred1 X) --> (X != C) || (Y Pred1 C)

we can preserve the profile branch weights of the select statement because the first condition is unchanged.

Tracking issue: #147390


Full diff: https://github.com/llvm/llvm-project/pull/162736.diff

2 Files Affected:

  • (modified) llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp (+16-8)
  • (modified) llvm/test/Transforms/InstCombine/select-safe-transforms.ll (+17-7)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
index 9b272c4721cbd..3ddf182149e57 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
@@ -28,6 +28,10 @@ using namespace PatternMatch;
 
 #define DEBUG_TYPE "instcombine"
 
+namespace llvm {
+extern cl::opt<bool> ProfcheckDisableMetadataFixes;
+}
+
 /// This is the complement of getICmpCode, which turns an opcode and two
 /// operands into either a constant true or false, or a brand new ICmp
 /// instruction. The sign is passed in to determine which kind of predicate to
@@ -1272,7 +1276,8 @@ Value *InstCombinerImpl::foldEqOfParts(Value *Cmp0, Value *Cmp1, bool IsAnd) {
 static Value *foldAndOrOfICmpsWithConstEq(ICmpInst *Cmp0, ICmpInst *Cmp1,
                                           bool IsAnd, bool IsLogical,
                                           InstCombiner::BuilderTy &Builder,
-                                          const SimplifyQuery &Q) {
+                                          const SimplifyQuery &Q,
+                                          Instruction &I) {
   // Match an equality compare with a non-poison constant as Cmp0.
   // Also, give up if the compare can be constant-folded to avoid looping.
   CmpPredicate Pred0;
@@ -1306,9 +1311,12 @@ static Value *foldAndOrOfICmpsWithConstEq(ICmpInst *Cmp0, ICmpInst *Cmp1,
       return nullptr;
     SubstituteCmp = Builder.CreateICmp(Pred1, Y, C);
   }
-  if (IsLogical)
-    return IsAnd ? Builder.CreateLogicalAnd(Cmp0, SubstituteCmp)
-                 : Builder.CreateLogicalOr(Cmp0, SubstituteCmp);
+  if (IsLogical) {
+    Instruction *MDFrom =
+        ProfcheckDisableMetadataFixes && isa<SelectInst>(I) ? nullptr : &I;
+    return IsAnd ? Builder.CreateLogicalAnd(Cmp0, SubstituteCmp, "", MDFrom)
+                 : Builder.CreateLogicalOr(Cmp0, SubstituteCmp, "", MDFrom);
+  }
   return Builder.CreateBinOp(IsAnd ? Instruction::And : Instruction::Or, Cmp0,
                              SubstituteCmp);
 }
@@ -3396,13 +3404,13 @@ Value *InstCombinerImpl::foldAndOrOfICmps(ICmpInst *LHS, ICmpInst *RHS,
                                                   /*IsLogical*/ false, Builder))
     return V;
 
-  if (Value *V =
-          foldAndOrOfICmpsWithConstEq(LHS, RHS, IsAnd, IsLogical, Builder, Q))
+  if (Value *V = foldAndOrOfICmpsWithConstEq(LHS, RHS, IsAnd, IsLogical,
+                                             Builder, Q, I))
     return V;
   // We can convert this case to bitwise and, because both operands are used
   // on the LHS, and as such poison from both will propagate.
-  if (Value *V = foldAndOrOfICmpsWithConstEq(RHS, LHS, IsAnd,
-                                             /*IsLogical=*/false, Builder, Q)) {
+  if (Value *V = foldAndOrOfICmpsWithConstEq(
+          RHS, LHS, IsAnd, /*IsLogical=*/false, Builder, Q, I)) {
     // If RHS is still used, we should drop samesign flag.
     if (IsLogical && RHS->hasSameSign() && !RHS->use_empty()) {
       RHS->setSameSign(false);
diff --git a/llvm/test/Transforms/InstCombine/select-safe-transforms.ll b/llvm/test/Transforms/InstCombine/select-safe-transforms.ll
index ebea5bf2eadf4..d88eaf8aa9ddc 100644
--- a/llvm/test/Transforms/InstCombine/select-safe-transforms.ll
+++ b/llvm/test/Transforms/InstCombine/select-safe-transforms.ll
@@ -1,8 +1,11 @@
-; 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 < %s -passes=instcombine -S | FileCheck %s
 
 declare i1 @gen1()
 
+;.
+; CHECK: @glb = global i8 0
+;.
 define i1 @cond_eq_and(i8 %X, i8 %Y, i8 noundef %C) {
 ; CHECK-LABEL: @cond_eq_and(
 ; CHECK-NEXT:    [[COND:%.*]] = icmp eq i8 [[X:%.*]], [[C:%.*]]
@@ -16,16 +19,16 @@ define i1 @cond_eq_and(i8 %X, i8 %Y, i8 noundef %C) {
   ret i1 %res
 }
 
-define i1 @cond_eq_and_const(i8 %X, i8 %Y) {
+define i1 @cond_eq_and_const(i8 %X, i8 %Y) !prof !0 {
 ; CHECK-LABEL: @cond_eq_and_const(
 ; CHECK-NEXT:    [[COND:%.*]] = icmp eq i8 [[X:%.*]], 10
 ; CHECK-NEXT:    [[TMP1:%.*]] = icmp ugt i8 [[Y:%.*]], 10
-; CHECK-NEXT:    [[RES:%.*]] = select i1 [[COND]], i1 [[TMP1]], i1 false
+; CHECK-NEXT:    [[RES:%.*]] = select i1 [[COND]], i1 [[TMP1]], i1 false, !prof [[PROF1:![0-9]+]]
 ; CHECK-NEXT:    ret i1 [[RES]]
 ;
   %cond = icmp eq i8 %X, 10
   %lhs = icmp ult i8 %X, %Y
-  %res = select i1 %cond, i1 %lhs, i1 false
+  %res = select i1 %cond, i1 %lhs, i1 false, !prof !1
   ret i1 %res
 }
 
@@ -42,16 +45,16 @@ define i1 @cond_eq_or(i8 %X, i8 %Y, i8 noundef %C) {
   ret i1 %res
 }
 
-define i1 @cond_eq_or_const(i8 %X, i8 %Y) {
+define i1 @cond_eq_or_const(i8 %X, i8 %Y) !prof !0 {
 ; CHECK-LABEL: @cond_eq_or_const(
 ; CHECK-NEXT:    [[COND:%.*]] = icmp ne i8 [[X:%.*]], 10
 ; CHECK-NEXT:    [[TMP1:%.*]] = icmp ugt i8 [[Y:%.*]], 10
-; CHECK-NEXT:    [[RES:%.*]] = select i1 [[COND]], i1 true, i1 [[TMP1]]
+; CHECK-NEXT:    [[RES:%.*]] = select i1 [[COND]], i1 true, i1 [[TMP1]], !prof [[PROF1]]
 ; CHECK-NEXT:    ret i1 [[RES]]
 ;
   %cond = icmp ne i8 %X, 10
   %lhs = icmp ult i8 %X, %Y
-  %res = select i1 %cond, i1 true, i1 %lhs
+  %res = select i1 %cond, i1 true, i1 %lhs, !prof !1
   ret i1 %res
 }
 
@@ -793,3 +796,10 @@ define <2 x i1> @not_logical_and2(i1 %b, <2 x i32> %a) {
   %or = select <2 x i1> %and, <2 x i1> <i1 true, i1 true>, <2 x i1> %implied
   ret <2 x i1> %or
 }
+
+!0 = !{!"function_entry_count", i64 1000}
+!1 = !{!"branch_weights", i32 2, i32 3}
+;.
+; CHECK: [[META0:![0-9]+]] = !{!"function_entry_count", i64 1000}
+; CHECK: [[PROF1]] = !{!"branch_weights", i32 2, i32 3}
+;.

@alanzhao1 alanzhao1 merged commit a1b5e97 into llvm:main Oct 10, 2025
13 checks passed
@alanzhao1 alanzhao1 deleted the feature/profcheck-const-eq-fold branch October 10, 2025 04:43
@llvm-ci
Copy link
Collaborator

llvm-ci commented Oct 10, 2025

LLVM Buildbot has detected a new failure on builder clang-aarch64-quick running on linaro-clang-aarch64-quick while building llvm at step 5 "ninja check 1".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/65/builds/23817

Here is the relevant piece of the build log for the reference
Step 5 (ninja check 1) failure: stage 1 checked (failure)
******************** TEST 'Clangd Unit Tests :: ./ClangdTests/245/333' FAILED ********************
Script(shard):
--
GTEST_OUTPUT=json:/home/tcwg-buildbot/worker/clang-aarch64-quick/stage1/tools/clang/tools/extra/clangd/unittests/./ClangdTests-Clangd Unit Tests-863987-245-333.json GTEST_SHUFFLE=0 GTEST_TOTAL_SHARDS=333 GTEST_SHARD_INDEX=245 /home/tcwg-buildbot/worker/clang-aarch64-quick/stage1/tools/clang/tools/extra/clangd/unittests/./ClangdTests
--

Note: This is test shard 246 of 333.
[==========] Running 4 tests from 4 test suites.
[----------] Global test environment set-up.
[----------] 1 test from CompletionStringTest
[ RUN      ] CompletionStringTest.GetDeclCommentBadUTF8
Built preamble of size 707708 for file /clangd-test/TestTU.cpp version null in 0.07 seconds
[       OK ] CompletionStringTest.GetDeclCommentBadUTF8 (88 ms)
[----------] 1 test from CompletionStringTest (88 ms total)

[----------] 1 test from FuzzyMatch
[ RUN      ] FuzzyMatch.Matches
[       OK ] FuzzyMatch.Matches (13 ms)
[----------] 1 test from FuzzyMatch (13 ms total)

[----------] 1 test from CrossFileRenameTests
[ RUN      ] CrossFileRenameTests.WithUpToDateIndex
ASTWorker building file /clangd-test/foo.h version null with command 
[/clangd-test]
clang -xobjective-c++ /clangd-test/foo.h
Driver produced command: cc1 -cc1 -triple aarch64-unknown-linux-gnu -fsyntax-only -disable-free -clear-ast-before-backend -main-file-name foo.h -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=non-leaf -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -enable-tlsdesc -target-cpu generic -target-feature +v8a -target-feature +fp-armv8 -target-feature +neon -target-abi aapcs -debugger-tuning=gdb -fdebug-compilation-dir=/clangd-test -fcoverage-compilation-dir=/clangd-test -resource-dir lib/clang/22 -internal-isystem lib/clang/22/include -internal-isystem /usr/local/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -fdeprecated-macro -ferror-limit 19 -fno-signed-char -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fobjc-runtime=gcc -fobjc-encode-cxx-class-template-spec -fobjc-exceptions -fcxx-exceptions -fexceptions -no-round-trip-args -target-feature -fmv -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -x objective-c++ /clangd-test/foo.h
Building first preamble for /clangd-test/foo.h version null
Built preamble of size 821120 for file /clangd-test/foo.h version null in 0.17 seconds
indexed preamble AST for /clangd-test/foo.h version null:
  symbol slab: 0 symbols, 120 bytes
  ref slab: 0 symbols, 0 refs, 128 bytes
  relations slab: 0 relations, 24 bytes
indexed file AST for /clangd-test/foo.h version null:
  symbol slab: 3 symbols, 4912 bytes
  ref slab: 3 symbols, 5 refs, 4320 bytes
  relations slab: 0 relations, 24 bytes
Build dynamic index for main-file symbols with estimated memory usage of 12648 bytes
ASTWorker building file /clangd-test/foo.cc version null with command 
[/clangd-test]
clang -xobjective-c++ /clangd-test/foo.cc
Driver produced command: cc1 -cc1 -triple aarch64-unknown-linux-gnu -fsyntax-only -disable-free -clear-ast-before-backend -main-file-name foo.cc -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=non-leaf -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -enable-tlsdesc -target-cpu generic -target-feature +v8a -target-feature +fp-armv8 -target-feature +neon -target-abi aapcs -debugger-tuning=gdb -fdebug-compilation-dir=/clangd-test -fcoverage-compilation-dir=/clangd-test -resource-dir lib/clang/22 -internal-isystem lib/clang/22/include -internal-isystem /usr/local/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -fdeprecated-macro -ferror-limit 19 -fno-signed-char -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fobjc-runtime=gcc -fobjc-encode-cxx-class-template-spec -fobjc-exceptions -fcxx-exceptions -fexceptions -no-round-trip-args -target-feature -fmv -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -x objective-c++ /clangd-test/foo.cc
Building first preamble for /clangd-test/foo.cc version null
Built preamble of size 824668 for file /clangd-test/foo.cc version null in 0.30 seconds
indexed preamble AST for /clangd-test/foo.cc version null:
  symbol slab: 3 symbols, 4912 bytes
  ref slab: 0 symbols, 0 refs, 128 bytes
  relations slab: 0 relations, 24 bytes
Build dynamic index for header symbols with estimated memory usage of 7444 bytes
indexed file AST for /clangd-test/foo.cc version null:
  symbol slab: 3 symbols, 4912 bytes
...

@llvm-ci
Copy link
Collaborator

llvm-ci commented Oct 10, 2025

LLVM Buildbot has detected a new failure on builder sanitizer-aarch64-linux running on sanitizer-buildbot7 while building llvm at step 2 "annotate".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/51/builds/25008

Here is the relevant piece of the build log for the reference
Step 2 (annotate) failure: 'python ../sanitizer_buildbot/sanitizers/zorg/buildbot/builders/sanitizers/buildbot_selector.py' (failure)
...
-- Performing Test C_WCOMMENT_ALLOWS_LINE_WRAP
-- Performing Test C_WCOMMENT_ALLOWS_LINE_WRAP - Success
-- Performing Test C_SUPPORTS_MISLEADING_INDENTATION_FLAG
-- Performing Test C_SUPPORTS_MISLEADING_INDENTATION_FLAG - Success
-- Performing Test CXX_SUPPORTS_MISLEADING_INDENTATION_FLAG
-- Performing Test CXX_SUPPORTS_MISLEADING_INDENTATION_FLAG - Success
-- Performing Test C_SUPPORTS_CTAD_MAYBE_UNSPPORTED_FLAG
-- Performing Test C_SUPPORTS_CTAD_MAYBE_UNSPPORTED_FLAG - Success
-- Performing Test CXX_SUPPORTS_CTAD_MAYBE_UNSPPORTED_FLAG
-- Performing Test CXX_SUPPORTS_CTAD_MAYBE_UNSPPORTED_FLAG - Success
-- Performing Test C_SUPPORTS_NO_PASS_FAILED_FLAG
-- Performing Test C_SUPPORTS_NO_PASS_FAILED_FLAG - Success
-- Performing Test CXX_SUPPORTS_NO_PASS_FAILED_FLAG
-- Performing Test CXX_SUPPORTS_NO_PASS_FAILED_FLAG - Success
-- Performing Test LINKER_SUPPORTS_COLOR_DIAGNOSTICS
-- Performing Test LINKER_SUPPORTS_COLOR_DIAGNOSTICS - Success
-- Looking for os_signpost_interval_begin
-- Looking for os_signpost_interval_begin - not found
-- Looking for flock
-- Looking for flock - found
-- Linker detection: LLD
-- Performing Test LLVM_LINKER_SUPPORTS_B_SYMBOLIC_FUNCTIONS
-- Performing Test LLVM_LINKER_SUPPORTS_B_SYMBOLIC_FUNCTIONS - Success
-- Performing Test HAS_WERROR_GLOBAL_CTORS
-- Performing Test HAS_WERROR_GLOBAL_CTORS - Success
-- Performing Test LLVM_HAS_NOGLOBAL_CTOR_MUTEX
-- Performing Test LLVM_HAS_NOGLOBAL_CTOR_MUTEX - Success
-- Looking for __x86_64__
-- Looking for __x86_64__ - not found
-- Found Git: /usr/bin/git (found version "2.48.1")
-- Looking for logf128
-- Looking for logf128 - found
-- Targeting AArch64
-- Targeting AMDGPU
-- Targeting ARM
-- Targeting AVR
-- Targeting BPF
-- Targeting Hexagon
-- Targeting Lanai
-- Targeting LoongArch
-- Targeting Mips
-- Targeting MSP430
-- Targeting NVPTX
-- Targeting PowerPC
-- Targeting RISCV
-- Targeting Sparc
-- Targeting SPIRV
-- Targeting SystemZ
-- Targeting VE
Step 11 (test compiler-rt debug) failure: test compiler-rt debug (failure)
...
-- Performing Test C_WCOMMENT_ALLOWS_LINE_WRAP
-- Performing Test C_WCOMMENT_ALLOWS_LINE_WRAP - Success
-- Performing Test C_SUPPORTS_MISLEADING_INDENTATION_FLAG
-- Performing Test C_SUPPORTS_MISLEADING_INDENTATION_FLAG - Success
-- Performing Test CXX_SUPPORTS_MISLEADING_INDENTATION_FLAG
-- Performing Test CXX_SUPPORTS_MISLEADING_INDENTATION_FLAG - Success
-- Performing Test C_SUPPORTS_CTAD_MAYBE_UNSPPORTED_FLAG
-- Performing Test C_SUPPORTS_CTAD_MAYBE_UNSPPORTED_FLAG - Success
-- Performing Test CXX_SUPPORTS_CTAD_MAYBE_UNSPPORTED_FLAG
-- Performing Test CXX_SUPPORTS_CTAD_MAYBE_UNSPPORTED_FLAG - Success
-- Performing Test C_SUPPORTS_NO_PASS_FAILED_FLAG
-- Performing Test C_SUPPORTS_NO_PASS_FAILED_FLAG - Success
-- Performing Test CXX_SUPPORTS_NO_PASS_FAILED_FLAG
-- Performing Test CXX_SUPPORTS_NO_PASS_FAILED_FLAG - Success
-- Performing Test LINKER_SUPPORTS_COLOR_DIAGNOSTICS
-- Performing Test LINKER_SUPPORTS_COLOR_DIAGNOSTICS - Failed
-- Looking for os_signpost_interval_begin
-- Looking for os_signpost_interval_begin - not found
-- Looking for flock
-- Looking for flock - found
-- Found Python3: /usr/bin/python3 (found version "3.13.3") found components: Interpreter
-- LLVM host triple: aarch64-unknown-linux-gnu
-- LLVM default target triple: aarch64-unknown-linux-gnu
-- Using libc++abi testing configuration: /home/b/sanitizer-aarch64-linux/build/llvm-project/libcxxabi/test/configs/llvm-libc++abi-static.cfg.in
-- Looking for fopen in c
-- Looking for fopen in c - found
-- Looking for __gcc_personality_v0 in gcc_s
-- Looking for __gcc_personality_v0 in gcc_s - found
-- Looking for __aeabi_uldivmod in gcc
-- Looking for __aeabi_uldivmod in gcc - found
-- Performing Test C_SUPPORTS_COMMENT_LIB_PRAGMA
-- Performing Test C_SUPPORTS_COMMENT_LIB_PRAGMA - Success
-- Looking for dladdr in dl
-- Looking for dladdr in dl - found
-- Looking for __cxa_thread_atexit_impl in c
-- Looking for __cxa_thread_atexit_impl in c - found
-- Performing Test CXX_SUPPORTS_FSTRICT_ALIASING_FLAG
-- Performing Test CXX_SUPPORTS_FSTRICT_ALIASING_FLAG - Success
-- Performing Test CXX_SUPPORTS_EHSC_FLAG
-- Performing Test CXX_SUPPORTS_EHSC_FLAG - Failed
-- Performing Test C_SUPPORTS_FUNWIND_TABLES_FLAG
-- Performing Test C_SUPPORTS_FUNWIND_TABLES_FLAG - Success
-- Performing Test CXX_SUPPORTS_WALL_FLAG
-- Performing Test CXX_SUPPORTS_WALL_FLAG - Success
-- Performing Test CXX_SUPPORTS_WEXTRA_FLAG
-- Performing Test CXX_SUPPORTS_WEXTRA_FLAG - Success
-- Performing Test CXX_SUPPORTS_WNEWLINE_EOF_FLAG
-- Performing Test CXX_SUPPORTS_WNEWLINE_EOF_FLAG - Success
-- Performing Test CXX_SUPPORTS_WSHADOW_FLAG

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

llvm:instcombine Covers the InstCombine, InstSimplify and AggressiveInstCombine passes llvm:transforms

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants