Skip to content

Conversation

alanzhao1
Copy link
Contributor

Logical booleans in LLVM are represented by select statements - e.g. the statement

A && B

is represented as

select i1 %A, i1 %B, i1 false

When LLVM folds two of the same logical booleans into a logical boolean and a bitwise boolean (e.g. A && B && C -> A && (B & C)), the first logical boolean is a select statement that retains the original condition from the first logical boolean of the original statement. This means that the new select statement has the branch weights as the original select statement.

Tracking issue: #147390

@alanzhao1 alanzhao1 requested a review from mtrofin September 29, 2025 23:04
@alanzhao1 alanzhao1 requested a review from nikic as a code owner September 29, 2025 23:04
@llvmbot llvmbot added llvm:instcombine Covers the InstCombine, InstSimplify and AggressiveInstCombine passes llvm:ir llvm:transforms labels Sep 29, 2025
@llvmbot
Copy link
Member

llvmbot commented Sep 29, 2025

@llvm/pr-subscribers-llvm-transforms

@llvm/pr-subscribers-llvm-ir

Author: Alan Zhao (alanzhao1)

Changes

Logical booleans in LLVM are represented by select statements - e.g. the statement

A && B

is represented as

select i1 %A, i1 %B, i1 false

When LLVM folds two of the same logical booleans into a logical boolean and a bitwise boolean (e.g. A && B && C -> A && (B & C)), the first logical boolean is a select statement that retains the original condition from the first logical boolean of the original statement. This means that the new select statement has the branch weights as the original select statement.

Tracking issue: #147390


Patch is 25.60 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/161293.diff

3 Files Affected:

  • (modified) llvm/include/llvm/IR/IRBuilder.h (+7-4)
  • (modified) llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp (+9-2)
  • (modified) llvm/test/Transforms/InstCombine/select-safe-bool-transforms.ll (+156-146)
diff --git a/llvm/include/llvm/IR/IRBuilder.h b/llvm/include/llvm/IR/IRBuilder.h
index 783f8f6d2478c..041a4ce112275 100644
--- a/llvm/include/llvm/IR/IRBuilder.h
+++ b/llvm/include/llvm/IR/IRBuilder.h
@@ -1722,16 +1722,19 @@ class IRBuilderBase {
     return Insert(BinOp, Name);
   }
 
-  Value *CreateLogicalAnd(Value *Cond1, Value *Cond2, const Twine &Name = "") {
+  Value *CreateLogicalAnd(Value *Cond1, Value *Cond2, const Twine &Name = "",
+                          Instruction *MDFrom = nullptr) {
     assert(Cond2->getType()->isIntOrIntVectorTy(1));
     return CreateSelect(Cond1, Cond2,
-                        ConstantInt::getNullValue(Cond2->getType()), Name);
+                        ConstantInt::getNullValue(Cond2->getType()), Name,
+                        MDFrom);
   }
 
-  Value *CreateLogicalOr(Value *Cond1, Value *Cond2, const Twine &Name = "") {
+  Value *CreateLogicalOr(Value *Cond1, Value *Cond2, const Twine &Name = "",
+                         Instruction *MDFrom = nullptr) {
     assert(Cond2->getType()->isIntOrIntVectorTy(1));
     return CreateSelect(Cond1, ConstantInt::getAllOnesValue(Cond2->getType()),
-                        Cond2, Name);
+                        Cond2, Name, MDFrom);
   }
 
   Value *CreateLogicalOp(Instruction::BinaryOps Opc, Value *Cond1, Value *Cond2,
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index b6b3a95f35c76..459c7e02254fe 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -50,6 +50,7 @@
 using namespace llvm;
 using namespace PatternMatch;
 
+extern cl::opt<bool> ProfcheckDisableMetadataFixes;
 
 /// Replace a select operand based on an equality comparison with the identity
 /// constant of a binop.
@@ -3369,7 +3370,10 @@ Instruction *InstCombinerImpl::foldSelectOfBools(SelectInst &SI) {
         impliesPoisonOrCond(FalseVal, B, /*Expected=*/false)) {
       // (A || B) || C --> A || (B | C)
       return replaceInstUsesWith(
-          SI, Builder.CreateLogicalOr(A, Builder.CreateOr(B, FalseVal)));
+          SI, Builder.CreateLogicalOr(A, Builder.CreateOr(B, FalseVal), "",
+                                      ProfcheckDisableMetadataFixes
+                                          ? nullptr
+                                          : cast<SelectInst>(CondVal)));
     }
 
     // (A && B) || (C && B) --> (A || C) && B
@@ -3411,7 +3415,10 @@ Instruction *InstCombinerImpl::foldSelectOfBools(SelectInst &SI) {
         impliesPoisonOrCond(TrueVal, B, /*Expected=*/true)) {
       // (A && B) && C --> A && (B & C)
       return replaceInstUsesWith(
-          SI, Builder.CreateLogicalAnd(A, Builder.CreateAnd(B, TrueVal)));
+          SI, Builder.CreateLogicalAnd(A, Builder.CreateAnd(B, TrueVal), "",
+                                       ProfcheckDisableMetadataFixes
+                                           ? nullptr
+                                           : cast<SelectInst>(CondVal)));
     }
 
     // (A || B) && (C || B) --> (A && C) || B
diff --git a/llvm/test/Transforms/InstCombine/select-safe-bool-transforms.ll b/llvm/test/Transforms/InstCombine/select-safe-bool-transforms.ll
index 9de9150f62ed4..4ac61f65862b1 100644
--- a/llvm/test/Transforms/InstCombine/select-safe-bool-transforms.ll
+++ b/llvm/test/Transforms/InstCombine/select-safe-bool-transforms.ll
@@ -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 < %s -passes=instcombine -S | FileCheck %s
 
 ; TODO: All of these should be optimized to less than or equal to a single
@@ -7,502 +7,512 @@
 ; --- (A op B) op' A   /   (B op A) op' A ---
 
 ; (A land B) land A
-define i1 @land_land_left1(i1 %A, i1 %B) {
+define i1 @land_land_left1(i1 %A, i1 %B) !prof !0 {
 ; CHECK-LABEL: @land_land_left1(
-; CHECK-NEXT:    [[C:%.*]] = select i1 [[A:%.*]], i1 [[B:%.*]], i1 false
+; CHECK-NEXT:    [[C:%.*]] = select i1 [[A:%.*]], i1 [[B:%.*]], i1 false, !prof [[PROF1:![0-9]+]]
 ; CHECK-NEXT:    ret i1 [[C]]
 ;
-  %c = select i1 %A, i1 %B, i1 false
-  %res = select i1 %c, i1 %A, i1 false
+  %c = select i1 %A, i1 %B, i1 false, !prof !1
+  %res = select i1 %c, i1 %A, i1 false, !prof !2
   ret i1 %res
 }
-define i1 @land_land_left2(i1 %A, i1 %B) {
+define i1 @land_land_left2(i1 %A, i1 %B) !prof !0 {
 ; CHECK-LABEL: @land_land_left2(
-; CHECK-NEXT:    [[RES:%.*]] = select i1 [[B:%.*]], i1 [[A:%.*]], i1 false
+; CHECK-NEXT:    [[RES:%.*]] = select i1 [[B:%.*]], i1 [[A:%.*]], i1 false, !prof [[PROF2:![0-9]+]]
 ; CHECK-NEXT:    ret i1 [[RES]]
 ;
-  %c = select i1 %B, i1 %A, i1 false
-  %res = select i1 %c, i1 %A, i1 false
+  %c = select i1 %B, i1 %A, i1 false, !prof !3
+  %res = select i1 %c, i1 %A, i1 false, !prof !2
   ret i1 %res
 }
 
 ; (A land B) band A
-define i1 @land_band_left1(i1 %A, i1 %B) {
+define i1 @land_band_left1(i1 %A, i1 %B) !prof !0 {
 ; CHECK-LABEL: @land_band_left1(
-; CHECK-NEXT:    [[C:%.*]] = select i1 [[A:%.*]], i1 [[B:%.*]], i1 false
+; CHECK-NEXT:    [[C:%.*]] = select i1 [[A:%.*]], i1 [[B:%.*]], i1 false, !prof [[PROF1]]
 ; CHECK-NEXT:    ret i1 [[C]]
 ;
-  %c = select i1 %A, i1 %B, i1 false
+  %c = select i1 %A, i1 %B, i1 false, !prof !1
   %res = and i1 %c, %A
   ret i1 %res
 }
-define i1 @land_band_left2(i1 %A, i1 %B) {
+define i1 @land_band_left2(i1 %A, i1 %B) !prof !0 {
 ; CHECK-LABEL: @land_band_left2(
-; CHECK-NEXT:    [[C:%.*]] = select i1 [[B:%.*]], i1 [[A:%.*]], i1 false
+; CHECK-NEXT:    [[C:%.*]] = select i1 [[B:%.*]], i1 [[A:%.*]], i1 false, !prof [[PROF2]]
 ; CHECK-NEXT:    ret i1 [[C]]
 ;
-  %c = select i1 %B, i1 %A, i1 false
+  %c = select i1 %B, i1 %A, i1 false, !prof !3
   %res = and i1 %c, %A
   ret i1 %res
 }
 
 ; (A land B) lor A
-define i1 @land_lor_left1(i1 %A, i1 %B) {
+define i1 @land_lor_left1(i1 %A, i1 %B) !prof !0 {
 ; CHECK-LABEL: @land_lor_left1(
 ; CHECK-NEXT:    ret i1 [[A:%.*]]
 ;
-  %c = select i1 %A, i1 %B, i1 false
-  %res = select i1 %c, i1 true, i1 %A
+  %c = select i1 %A, i1 %B, i1 false, !prof !1
+  %res = select i1 %c, i1 true, i1 %A, !prof !2
   ret i1 %res
 }
-define i1 @land_lor_left2(i1 %A, i1 %B) {
+define i1 @land_lor_left2(i1 %A, i1 %B) !prof !0 {
 ; CHECK-LABEL: @land_lor_left2(
 ; CHECK-NEXT:    ret i1 [[A:%.*]]
 ;
-  %c = select i1 %B, i1 %A, i1 false
-  %res = select i1 %c, i1 true, i1 %A
+  %c = select i1 %B, i1 %A, i1 false, !prof !3
+  %res = select i1 %c, i1 true, i1 %A, !prof !2
   ret i1 %res
 }
 
 ; (A land B) bor A
-define i1 @land_bor_left1(i1 %A, i1 %B) {
+define i1 @land_bor_left1(i1 %A, i1 %B) !prof !0 {
 ; CHECK-LABEL: @land_bor_left1(
 ; CHECK-NEXT:    ret i1 [[A:%.*]]
 ;
-  %c = select i1 %A, i1 %B, i1 false
+  %c = select i1 %A, i1 %B, i1 false, !prof !1
   %res = or i1 %c, %A
   ret i1 %res
 }
-define i1 @land_bor_left2(i1 %A, i1 %B) {
+define i1 @land_bor_left2(i1 %A, i1 %B) !prof !0 {
 ; CHECK-LABEL: @land_bor_left2(
 ; CHECK-NEXT:    ret i1 [[A:%.*]]
 ;
-  %c = select i1 %B, i1 %A, i1 false
+  %c = select i1 %B, i1 %A, i1 false, !prof !3
   %res = or i1 %c, %A
   ret i1 %res
 }
 
 ; (A band B) land A
-define i1 @band_land_left1(i1 %A, i1 %B) {
+define i1 @band_land_left1(i1 %A, i1 %B) !prof !0 {
 ; CHECK-LABEL: @band_land_left1(
 ; CHECK-NEXT:    [[C:%.*]] = and i1 [[A:%.*]], [[B:%.*]]
 ; CHECK-NEXT:    ret i1 [[C]]
 ;
   %c = and i1 %A, %B
-  %res = select i1 %c, i1 %A, i1 false
+  %res = select i1 %c, i1 %A, i1 false, !prof !2
   ret i1 %res
 }
-define i1 @band_land_left2(i1 %A, i1 %B) {
+define i1 @band_land_left2(i1 %A, i1 %B) !prof !0 {
 ; CHECK-LABEL: @band_land_left2(
 ; CHECK-NEXT:    [[C:%.*]] = and i1 [[B:%.*]], [[A:%.*]]
 ; CHECK-NEXT:    ret i1 [[C]]
 ;
   %c = and i1 %B, %A
-  %res = select i1 %c, i1 %A, i1 false
+  %res = select i1 %c, i1 %A, i1 false, !prof !2
   ret i1 %res
 }
 
 ; (A band B) lor A
-define i1 @band_lor_left1(i1 %A, i1 %B) {
+define i1 @band_lor_left1(i1 %A, i1 %B) !prof !0 {
 ; CHECK-LABEL: @band_lor_left1(
 ; CHECK-NEXT:    ret i1 [[A:%.*]]
 ;
   %c = and i1 %A, %B
-  %res = select i1 %c, i1 true, i1 %A
+  %res = select i1 %c, i1 true, i1 %A, !prof !2
   ret i1 %res
 }
-define i1 @band_lor_left2(i1 %A, i1 %B) {
+define i1 @band_lor_left2(i1 %A, i1 %B) !prof !0 {
 ; CHECK-LABEL: @band_lor_left2(
 ; CHECK-NEXT:    ret i1 [[A:%.*]]
 ;
   %c = and i1 %B, %A
-  %res = select i1 %c, i1 true, i1 %A
+  %res = select i1 %c, i1 true, i1 %A, !prof !2
   ret i1 %res
 }
 
 ; (A lor B) land A
-define i1 @lor_land_left1(i1 %A, i1 %B) {
+define i1 @lor_land_left1(i1 %A, i1 %B) !prof !0 {
 ; CHECK-LABEL: @lor_land_left1(
 ; CHECK-NEXT:    ret i1 [[A:%.*]]
 ;
-  %c = select i1 %A, i1 true, i1 %B
-  %res = select i1 %c, i1 %A, i1 false
+  %c = select i1 %A, i1 true, i1 %B, !prof !1
+  %res = select i1 %c, i1 %A, i1 false, !prof !2
   ret i1 %res
 }
-define i1 @lor_land_left2(i1 %A, i1 %B) {
+define i1 @lor_land_left2(i1 %A, i1 %B) !prof !0 {
 ; CHECK-LABEL: @lor_land_left2(
 ; CHECK-NEXT:    ret i1 [[A:%.*]]
 ;
-  %c = select i1 %B, i1 true, i1 %A
-  %res = select i1 %c, i1 %A, i1 false
+  %c = select i1 %B, i1 true, i1 %A, !prof !3
+  %res = select i1 %c, i1 %A, i1 false, !prof !2
   ret i1 %res
 }
 
 ; (A lor B) band A
-define i1 @lor_band_left1(i1 %A, i1 %B) {
+define i1 @lor_band_left1(i1 %A, i1 %B) !prof !0 {
 ; CHECK-LABEL: @lor_band_left1(
 ; CHECK-NEXT:    ret i1 [[A:%.*]]
 ;
-  %c = select i1 %A, i1 true, i1 %B
+  %c = select i1 %A, i1 true, i1 %B, !prof !1
   %res = and i1 %c, %A
   ret i1 %res
 }
-define i1 @lor_band_left2(i1 %A, i1 %B) {
+define i1 @lor_band_left2(i1 %A, i1 %B) !prof !0 {
 ; CHECK-LABEL: @lor_band_left2(
 ; CHECK-NEXT:    ret i1 [[A:%.*]]
 ;
-  %c = select i1 %B, i1 true, i1 %A
+  %c = select i1 %B, i1 true, i1 %A, !prof !3
   %res = and i1 %c, %A
   ret i1 %res
 }
 
 ; (A lor B) lor A
-define i1 @lor_lor_left1(i1 %A, i1 %B) {
+define i1 @lor_lor_left1(i1 %A, i1 %B) !prof !0 {
 ; CHECK-LABEL: @lor_lor_left1(
-; CHECK-NEXT:    [[C:%.*]] = select i1 [[A:%.*]], i1 true, i1 [[B:%.*]]
+; CHECK-NEXT:    [[C:%.*]] = select i1 [[A:%.*]], i1 true, i1 [[B:%.*]], !prof [[PROF1]]
 ; CHECK-NEXT:    ret i1 [[C]]
 ;
-  %c = select i1 %A, i1 true, i1 %B
-  %res = select i1 %c, i1 true, i1 %A
+  %c = select i1 %A, i1 true, i1 %B, !prof !1
+  %res = select i1 %c, i1 true, i1 %A, !prof !2
   ret i1 %res
 }
-define i1 @lor_lor_left2(i1 %A, i1 %B) {
+define i1 @lor_lor_left2(i1 %A, i1 %B) !prof !0 {
 ; CHECK-LABEL: @lor_lor_left2(
-; CHECK-NEXT:    [[RES:%.*]] = select i1 [[B:%.*]], i1 true, i1 [[A:%.*]]
+; CHECK-NEXT:    [[RES:%.*]] = select i1 [[B:%.*]], i1 true, i1 [[A:%.*]], !prof [[PROF2]]
 ; CHECK-NEXT:    ret i1 [[RES]]
 ;
-  %c = select i1 %B, i1 true, i1 %A
-  %res = select i1 %c, i1 true, i1 %A
+  %c = select i1 %B, i1 true, i1 %A, !prof !3
+  %res = select i1 %c, i1 true, i1 %A, !prof !2
   ret i1 %res
 }
 
 ; (A lor B) bor A
-define i1 @lor_bor_left1(i1 %A, i1 %B) {
+define i1 @lor_bor_left1(i1 %A, i1 %B) !prof !0 {
 ; CHECK-LABEL: @lor_bor_left1(
-; CHECK-NEXT:    [[C:%.*]] = select i1 [[A:%.*]], i1 true, i1 [[B:%.*]]
+; CHECK-NEXT:    [[C:%.*]] = select i1 [[A:%.*]], i1 true, i1 [[B:%.*]], !prof [[PROF1]]
 ; CHECK-NEXT:    ret i1 [[C]]
 ;
-  %c = select i1 %A, i1 true, i1 %B
+  %c = select i1 %A, i1 true, i1 %B, !prof !1
   %res = or i1 %c, %A
   ret i1 %res
 }
-define i1 @lor_bor_left2(i1 %A, i1 %B) {
+define i1 @lor_bor_left2(i1 %A, i1 %B) !prof !0 {
 ; CHECK-LABEL: @lor_bor_left2(
-; CHECK-NEXT:    [[C:%.*]] = select i1 [[B:%.*]], i1 true, i1 [[A:%.*]]
+; CHECK-NEXT:    [[C:%.*]] = select i1 [[B:%.*]], i1 true, i1 [[A:%.*]], !prof [[PROF2]]
 ; CHECK-NEXT:    ret i1 [[C]]
 ;
-  %c = select i1 %B, i1 true, i1 %A
+  %c = select i1 %B, i1 true, i1 %A, !prof !3
   %res = or i1 %c, %A
   ret i1 %res
 }
 
 ; (A bor B) land A
-define i1 @bor_land_left1(i1 %A, i1 %B) {
+define i1 @bor_land_left1(i1 %A, i1 %B) !prof !0 {
 ; CHECK-LABEL: @bor_land_left1(
 ; CHECK-NEXT:    ret i1 [[A:%.*]]
 ;
   %c = or i1 %A, %B
-  %res = select i1 %c, i1 %A, i1 false
+  %res = select i1 %c, i1 %A, i1 false, !prof !2
   ret i1 %res
 }
-define i1 @bor_land_left2(i1 %A, i1 %B) {
+define i1 @bor_land_left2(i1 %A, i1 %B) !prof !0 {
 ; CHECK-LABEL: @bor_land_left2(
 ; CHECK-NEXT:    ret i1 [[A:%.*]]
 ;
   %c = or i1 %B, %A
-  %res = select i1 %c, i1 %A, i1 false
+  %res = select i1 %c, i1 %A, i1 false, !prof !2
   ret i1 %res
 }
 
 ; (A bor B) lor A
-define i1 @bor_lor_left1(i1 %A, i1 %B) {
+define i1 @bor_lor_left1(i1 %A, i1 %B) !prof !0 {
 ; CHECK-LABEL: @bor_lor_left1(
 ; CHECK-NEXT:    [[C:%.*]] = or i1 [[A:%.*]], [[B:%.*]]
 ; CHECK-NEXT:    ret i1 [[C]]
 ;
   %c = or i1 %A, %B
-  %res = select i1 %c, i1 true, i1 %A
+  %res = select i1 %c, i1 true, i1 %A, !prof !2
   ret i1 %res
 }
-define i1 @bor_lor_left2(i1 %A, i1 %B) {
+define i1 @bor_lor_left2(i1 %A, i1 %B) !prof !0 {
 ; CHECK-LABEL: @bor_lor_left2(
 ; CHECK-NEXT:    [[C:%.*]] = or i1 [[B:%.*]], [[A:%.*]]
 ; CHECK-NEXT:    ret i1 [[C]]
 ;
   %c = or i1 %B, %A
-  %res = select i1 %c, i1 true, i1 %A
+  %res = select i1 %c, i1 true, i1 %A, !prof !2
   ret i1 %res
 }
 
 ; --- A op (A op' B)   /   A op (B op' A) ---
 
 ; A land (A land B)
-define i1 @land_land_right1(i1 %A, i1 %B) {
+define i1 @land_land_right1(i1 %A, i1 %B) !prof !0 {
 ; CHECK-LABEL: @land_land_right1(
-; CHECK-NEXT:    [[RES:%.*]] = select i1 [[A:%.*]], i1 [[B:%.*]], i1 false
+; CHECK-NEXT:    [[RES:%.*]] = select i1 [[A:%.*]], i1 [[B:%.*]], i1 false, !prof [[PROF1]]
 ; CHECK-NEXT:    ret i1 [[RES]]
 ;
-  %c = select i1 %A, i1 %B, i1 false
-  %res = select i1 %A, i1 %c, i1 false
+  %c = select i1 %A, i1 %B, i1 false, !prof !1
+  %res = select i1 %A, i1 %c, i1 false, !prof !1
   ret i1 %res
 }
-define i1 @land_land_right2(i1 %A, i1 %B) {
+define i1 @land_land_right2(i1 %A, i1 %B) !prof !0 {
 ; CHECK-LABEL: @land_land_right2(
-; CHECK-NEXT:    [[RES:%.*]] = select i1 [[A:%.*]], i1 [[B:%.*]], i1 false
+; CHECK-NEXT:    [[RES:%.*]] = select i1 [[A:%.*]], i1 [[B:%.*]], i1 false, !prof [[PROF1]]
 ; CHECK-NEXT:    ret i1 [[RES]]
 ;
-  %c = select i1 %B, i1 %A, i1 false
-  %res = select i1 %A, i1 %c, i1 false
+  %c = select i1 %B, i1 %A, i1 false, !prof !3
+  %res = select i1 %A, i1 %c, i1 false, !prof !1
   ret i1 %res
 }
 
 ; A band (A land B)
-define i1 @land_band_right1(i1 %A, i1 %B) {
+define i1 @land_band_right1(i1 %A, i1 %B) !prof !0 {
 ; CHECK-LABEL: @land_band_right1(
-; CHECK-NEXT:    [[C:%.*]] = select i1 [[A:%.*]], i1 [[B:%.*]], i1 false
+; CHECK-NEXT:    [[C:%.*]] = select i1 [[A:%.*]], i1 [[B:%.*]], i1 false, !prof [[PROF1]]
 ; CHECK-NEXT:    ret i1 [[C]]
 ;
-  %c = select i1 %A, i1 %B, i1 false
+  %c = select i1 %A, i1 %B, i1 false, !prof !1
   %res = and i1 %A, %c
   ret i1 %res
 }
-define i1 @land_band_right2(i1 %A, i1 %B) {
+define i1 @land_band_right2(i1 %A, i1 %B) !prof !0 {
 ; CHECK-LABEL: @land_band_right2(
-; CHECK-NEXT:    [[C:%.*]] = select i1 [[B:%.*]], i1 [[A:%.*]], i1 false
+; CHECK-NEXT:    [[C:%.*]] = select i1 [[B:%.*]], i1 [[A:%.*]], i1 false, !prof [[PROF2]]
 ; CHECK-NEXT:    ret i1 [[C]]
 ;
-  %c = select i1 %B, i1 %A, i1 false
+  %c = select i1 %B, i1 %A, i1 false, !prof !3
   %res = and i1 %A, %c
   ret i1 %res
 }
 
 ; A lor (A land B)
-define i1 @land_lor_right1(i1 %A, i1 %B) {
+define i1 @land_lor_right1(i1 %A, i1 %B) !prof !0 {
 ; CHECK-LABEL: @land_lor_right1(
 ; CHECK-NEXT:    ret i1 [[A:%.*]]
 ;
-  %c = select i1 %A, i1 %B, i1 false
-  %res = select i1 %A, i1 true, i1 %c
+  %c = select i1 %A, i1 %B, i1 false, !prof !1
+  %res = select i1 %A, i1 true, i1 %c, !prof !1
   ret i1 %res
 }
-define i1 @land_lor_right2(i1 %A, i1 %B) {
+define i1 @land_lor_right2(i1 %A, i1 %B) !prof !0 {
 ; CHECK-LABEL: @land_lor_right2(
 ; CHECK-NEXT:    ret i1 [[A:%.*]]
 ;
-  %c = select i1 %B, i1 %A, i1 false
-  %res = select i1 %A, i1 true, i1 %c
+  %c = select i1 %B, i1 %A, i1 false, !prof !3
+  %res = select i1 %A, i1 true, i1 %c, !prof !1
   ret i1 %res
 }
 
-define <2 x i1> @land_lor_right1_vec(<2 x i1> %A, <2 x i1> %B) {
+define <2 x i1> @land_lor_right1_vec(<2 x i1> %A, <2 x i1> %B) !prof !0 {
 ; CHECK-LABEL: @land_lor_right1_vec(
 ; CHECK-NEXT:    ret <2 x i1> [[A:%.*]]
 ;
-  %c = select <2 x i1> %A, <2 x i1> %B, <2 x i1> zeroinitializer
-  %res = select <2 x i1> %A, <2 x i1> <i1 true, i1 true>, <2 x i1> %c
+  %c = select <2 x i1> %A, <2 x i1> %B, <2 x i1> zeroinitializer, !prof !1
+  %res = select <2 x i1> %A, <2 x i1> <i1 true, i1 true>, <2 x i1> %c, !prof !1
   ret <2 x i1> %res
 }
-define <2 x i1> @land_lor_right2_vec(<2 x i1> %A, <2 x i1> %B) {
+define <2 x i1> @land_lor_right2_vec(<2 x i1> %A, <2 x i1> %B) !prof !0 {
 ; CHECK-LABEL: @land_lor_right2_vec(
 ; CHECK-NEXT:    ret <2 x i1> [[A:%.*]]
 ;
-  %c = select <2 x i1> %B, <2 x i1> %A, <2 x i1> zeroinitializer
-  %res = select <2 x i1> %A, <2 x i1> <i1 true, i1 true>, <2 x i1> %c
+  %c = select <2 x i1> %B, <2 x i1> %A, <2 x i1> zeroinitializer, !prof !3
+  %res = select <2 x i1> %A, <2 x i1> <i1 true, i1 true>, <2 x i1> %c, !prof !1
   ret <2 x i1> %res
 }
 
 ; A bor (A land B)
-define i1 @land_bor_right1(i1 %A, i1 %B) {
+define i1 @land_bor_right1(i1 %A, i1 %B) !prof !0 {
 ; CHECK-LABEL: @land_bor_right1(
 ; CHECK-NEXT:    ret i1 [[A:%.*]]
 ;
-  %c = select i1 %A, i1 %B, i1 false
+  %c = select i1 %A, i1 %B, i1 false, !prof !1
   %res = or i1 %A, %c
   ret i1 %res
 }
-define i1 @land_bor_right2(i1 %A, i1 %B) {
+define i1 @land_bor_right2(i1 %A, i1 %B) !prof !0 {
 ; CHECK-LABEL: @land_bor_right2(
 ; CHECK-NEXT:    ret i1 [[A:%.*]]
 ;
-  %c = select i1 %B, i1 %A, i1 false
+  %c = select i1 %B, i1 %A, i1 false, !prof !3
   %res = or i1 %A, %c
   ret i1 %res
 }
 
 ; A land (A band B)
-define i1 @band_land_right1(i1 %A, i1 %B) {
+define i1 @band_land_right1(i1 %A, i1 %B) !prof !0 {
 ; CHECK-LABEL: @band_land_right1(
-; CHECK-NEXT:    [[RES:%.*]] = select i1 [[A:%.*]], i1 [[B:%.*]], i1 false
+; CHECK-NEXT:    [[RES:%.*]] = select i1 [[A:%.*]], i1 [[B:%.*]], i1 false, !prof [[PROF1]]
 ; CHECK-NEXT:    ret i1 [[RES]]
 ;
   %c = and i1 %A, %B
-  %res = select i1 %A, i1 %c, i1 false
+  %res = select i1 %A, i1 %c, i1 false, !prof !1
   ret i1 %res
 }
-define i1 @band_land_right2(i1 %A, i1 %B) {
+define i1 @band_land_right2(i1 %A, i1 %B) !prof !0 {
 ; CHECK-LABEL: @band_land_right2(
-; CHECK-NEXT:    [[RES:%.*]] = select i1 [[A:%.*]], i1 [[B:%.*]], i1 false
+; CHECK-NEXT:    [[RES:%.*]] = select i1 [[A:%.*]], i1 [[B:%.*]], i1 false, !prof [[PROF1]]
 ; CHECK-NEXT:    ret i1 [[RES]]
 ;
   %c = and i1 %B, %A
-  %res = select i1 %A, i1 %c, i1 false
+  %res = select i1 %A, i1 %c, i1 false, !prof !1
   ret i1 %res
 }
 
 ; A lor (A band B)
-define i1 @band_lor_right1(i1 %A, i1 %B) {
+define i1 @band_lor_right1(i1 %A, i1 %B) !prof !0 {
 ; CHECK-LABEL: @band_lor_right1(
 ; CHECK-NEXT:    ret i1 [[A:%.*]]
 ;
   %c = and i1 %A, %B
-  %res = select i1 %A, i1 true, i1 %c
+  %res = select i1 %A, i1 true, i1 %c, !prof !1
   ret i1 %res
 }
-define i1 @band_lor_right2(i1 %A, i1 %B) {
+define i1 @band_lor_right2(i1 %A, i1 %B) !prof !0 {
 ; CHECK-LABEL: @band_lor_right2(
 ; CHECK-NEXT:    ret i1 [[A:%.*]]
 ;
   %c = and i1 %B, %A
-  %res = select i1 %A, i1 true, i1 %c
+  %res = select i1 %A, i1 true, i1 %c, !prof !1
   ret i1 %res
 }
 
 ; A land (A lor B)
-define i1 @lor_land_right1(i1 %A, i1 %B) {
+define i1 @lor_land_right1(i1 %A, i1 %B) !prof !0 {
 ; CHECK-LABEL: @lor_land_right1(
 ; CHECK-NEXT:    ret i1 [[A:%.*]]
 ;
-  %c = select i1 %A, i1 true, i1 %B
-  %res = select i1 %A, i1 %c, i1 false
+  %c = select i1 %A, i1 true, i1 %B, !prof !1
+  %res = select i1 %A, i1 %c, i1 false, !prof !1
   ret i1 %res
 }
-define i1 @lor_land_right2(i1 %A, i1 %B) {
+define i1 @lor_land_right2(i1 %A, i1 %B) !prof !0 {
 ; CHECK-LABEL: @lor_land_right2(
 ; CHECK-NEXT:    ret i1 [[A:%.*]]
 ;
-  %c = select i1 %B, i1 true, i1 %A
-  %res = select i1 %A, i1 %c, i1 false
+  %c = select i1 %B, i1 true, i1 %A, !prof !3
+  %res = select i1 %A, i1 %c, i1 false, !prof !1
   ret i1 %res
 }
 
 ; A band (A lor B)
-define i1 @lor_band_right1(i1 %A, i1 %B) {
+define i1 @lor_band_right1(i1 %A, i1 %B) !prof !0 {
 ; CHECK-LABEL: @lor_band_right1(
 ; CHECK-NEXT:    ret i1 [[A:%.*]]
 ;
-  %c = select i1 %A, i1 true, i1 %B
+  %c = select i1 %A, i1 true, i1 %B, !prof !1
   %res = and i1 %A, %c
   ret i1 %res
 }
-define i1 @lor_band_right2(i1 %A, i1 %B) {
+define i1 @lor_band_right2(i1 %A, i1 %B) !prof !0 {
 ; CHECK-LABEL: @lor_band_right2(
 ; CHECK-N...
[truncated]

@mtrofin
Copy link
Member

mtrofin commented Sep 29, 2025

Nit: in your commit message, is it (A && B && C -> A && (B && C)), correct? (B && C not B & C)

@alanzhao1
Copy link
Contributor Author

Nit: in your commit message, is it (A && B && C -> A && (B && C)), correct? (B && C not B & C)

It is supposed to be one ampersand (B & C) because we're converting a logical and to a bitwise and. See

// (A && B) && C --> A && (B & C)
return replaceInstUsesWith(
SI, Builder.CreateLogicalAnd(A, Builder.CreateAnd(B, TrueVal)));

…oleans

Logical booleans in LLVM are represented by select statements - e.g. the
statement

```
A && B
```

is represented as

```
select i1 %A, i1 %B, i1 false
```

When LLVM folds two of the same logical booleans into a logical boolean
and a bitwise boolean (e.g. `A && B && C` -> `A && (B & C)`), the first
logical boolean is a select statement that retains the original
condition from the first logical boolean of the original statement. This
means that the new select statement has the branch weights as the
original select statement.

Tracking issue: llvm#147390
@alanzhao1 alanzhao1 force-pushed the feature/logical-bool-preserve-weights branch from 3456186 to b87743c Compare October 6, 2025 18:17
@alanzhao1 alanzhao1 enabled auto-merge (squash) October 6, 2025 18:18
@alanzhao1 alanzhao1 merged commit fea9ef3 into llvm:main Oct 6, 2025
9 checks passed
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:ir llvm:transforms
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants