llvm-project/llvm/test/Transforms/InstCombine/select-safe-bool-transforms.ll
Alan Zhao fea9ef325b
[InstCombine] Preserve profile branch weights when folding logical booleans (#161293)
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
2025-10-06 18:58:35 +00:00

518 lines
13 KiB
LLVM

; 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
; instruction of select/and/or.
; --- (A op B) op' A / (B op A) op' A ---
; (A land B) land A
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, !prof [[PROF1:![0-9]+]]
; CHECK-NEXT: ret i1 [[C]]
;
%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) {
; CHECK-LABEL: @land_land_left2(
; CHECK-NEXT: [[RES:%.*]] = select i1 [[B:%.*]], i1 [[A:%.*]], i1 false
; CHECK-NEXT: ret i1 [[RES]]
;
%c = select i1 %B, i1 %A, i1 false
%res = select i1 %c, i1 %A, i1 false
ret i1 %res
}
; (A land B) band A
define i1 @land_band_left1(i1 %A, i1 %B) {
; CHECK-LABEL: @land_band_left1(
; CHECK-NEXT: [[C:%.*]] = select i1 [[A:%.*]], i1 [[B:%.*]], i1 false
; CHECK-NEXT: ret i1 [[C]]
;
%c = select i1 %A, i1 %B, i1 false
%res = and i1 %c, %A
ret i1 %res
}
define i1 @land_band_left2(i1 %A, i1 %B) {
; CHECK-LABEL: @land_band_left2(
; CHECK-NEXT: [[C:%.*]] = select i1 [[B:%.*]], i1 [[A:%.*]], i1 false
; CHECK-NEXT: ret i1 [[C]]
;
%c = select i1 %B, i1 %A, i1 false
%res = and i1 %c, %A
ret i1 %res
}
; (A land B) lor A
define i1 @land_lor_left1(i1 %A, i1 %B) {
; 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
ret i1 %res
}
define i1 @land_lor_left2(i1 %A, i1 %B) {
; 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
ret i1 %res
}
; (A land B) bor A
define i1 @land_bor_left1(i1 %A, i1 %B) {
; CHECK-LABEL: @land_bor_left1(
; CHECK-NEXT: ret i1 [[A:%.*]]
;
%c = select i1 %A, i1 %B, i1 false
%res = or i1 %c, %A
ret i1 %res
}
define i1 @land_bor_left2(i1 %A, i1 %B) {
; CHECK-LABEL: @land_bor_left2(
; CHECK-NEXT: ret i1 [[A:%.*]]
;
%c = select i1 %B, i1 %A, i1 false
%res = or i1 %c, %A
ret i1 %res
}
; (A band B) land A
define i1 @band_land_left1(i1 %A, i1 %B) {
; 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
ret i1 %res
}
define i1 @band_land_left2(i1 %A, i1 %B) {
; 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
ret i1 %res
}
; (A band B) lor A
define i1 @band_lor_left1(i1 %A, i1 %B) {
; CHECK-LABEL: @band_lor_left1(
; CHECK-NEXT: ret i1 [[A:%.*]]
;
%c = and i1 %A, %B
%res = select i1 %c, i1 true, i1 %A
ret i1 %res
}
define i1 @band_lor_left2(i1 %A, i1 %B) {
; CHECK-LABEL: @band_lor_left2(
; CHECK-NEXT: ret i1 [[A:%.*]]
;
%c = and i1 %B, %A
%res = select i1 %c, i1 true, i1 %A
ret i1 %res
}
; (A lor B) land A
define i1 @lor_land_left1(i1 %A, i1 %B) {
; 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
ret i1 %res
}
define i1 @lor_land_left2(i1 %A, i1 %B) {
; 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
ret i1 %res
}
; (A lor B) band A
define i1 @lor_band_left1(i1 %A, i1 %B) {
; CHECK-LABEL: @lor_band_left1(
; CHECK-NEXT: ret i1 [[A:%.*]]
;
%c = select i1 %A, i1 true, i1 %B
%res = and i1 %c, %A
ret i1 %res
}
define i1 @lor_band_left2(i1 %A, i1 %B) {
; CHECK-LABEL: @lor_band_left2(
; CHECK-NEXT: ret i1 [[A:%.*]]
;
%c = select i1 %B, i1 true, i1 %A
%res = and i1 %c, %A
ret i1 %res
}
; (A lor B) lor A
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:%.*]], !prof [[PROF1]]
; CHECK-NEXT: ret i1 [[C]]
;
%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) {
; CHECK-LABEL: @lor_lor_left2(
; CHECK-NEXT: [[RES:%.*]] = select i1 [[B:%.*]], i1 true, i1 [[A:%.*]]
; CHECK-NEXT: ret i1 [[RES]]
;
%c = select i1 %B, i1 true, i1 %A
%res = select i1 %c, i1 true, i1 %A
ret i1 %res
}
; (A lor B) bor A
define i1 @lor_bor_left1(i1 %A, i1 %B) {
; CHECK-LABEL: @lor_bor_left1(
; CHECK-NEXT: [[C:%.*]] = select i1 [[A:%.*]], i1 true, i1 [[B:%.*]]
; CHECK-NEXT: ret i1 [[C]]
;
%c = select i1 %A, i1 true, i1 %B
%res = or i1 %c, %A
ret i1 %res
}
define i1 @lor_bor_left2(i1 %A, i1 %B) {
; CHECK-LABEL: @lor_bor_left2(
; CHECK-NEXT: [[C:%.*]] = select i1 [[B:%.*]], i1 true, i1 [[A:%.*]]
; CHECK-NEXT: ret i1 [[C]]
;
%c = select i1 %B, i1 true, i1 %A
%res = or i1 %c, %A
ret i1 %res
}
; (A bor B) land A
define i1 @bor_land_left1(i1 %A, i1 %B) {
; CHECK-LABEL: @bor_land_left1(
; CHECK-NEXT: ret i1 [[A:%.*]]
;
%c = or i1 %A, %B
%res = select i1 %c, i1 %A, i1 false
ret i1 %res
}
define i1 @bor_land_left2(i1 %A, i1 %B) {
; CHECK-LABEL: @bor_land_left2(
; CHECK-NEXT: ret i1 [[A:%.*]]
;
%c = or i1 %B, %A
%res = select i1 %c, i1 %A, i1 false
ret i1 %res
}
; (A bor B) lor A
define i1 @bor_lor_left1(i1 %A, i1 %B) {
; 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
ret i1 %res
}
define i1 @bor_lor_left2(i1 %A, i1 %B) {
; 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
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) {
; CHECK-LABEL: @land_land_right1(
; CHECK-NEXT: [[RES:%.*]] = select i1 [[A:%.*]], i1 [[B:%.*]], i1 false
; CHECK-NEXT: ret i1 [[RES]]
;
%c = select i1 %A, i1 %B, i1 false
%res = select i1 %A, i1 %c, i1 false
ret i1 %res
}
define i1 @land_land_right2(i1 %A, i1 %B) {
; CHECK-LABEL: @land_land_right2(
; CHECK-NEXT: [[RES:%.*]] = select i1 [[A:%.*]], i1 [[B:%.*]], i1 false
; CHECK-NEXT: ret i1 [[RES]]
;
%c = select i1 %B, i1 %A, i1 false
%res = select i1 %A, i1 %c, i1 false
ret i1 %res
}
; A band (A land B)
define i1 @land_band_right1(i1 %A, i1 %B) {
; CHECK-LABEL: @land_band_right1(
; CHECK-NEXT: [[C:%.*]] = select i1 [[A:%.*]], i1 [[B:%.*]], i1 false
; CHECK-NEXT: ret i1 [[C]]
;
%c = select i1 %A, i1 %B, i1 false
%res = and i1 %A, %c
ret i1 %res
}
define i1 @land_band_right2(i1 %A, i1 %B) {
; CHECK-LABEL: @land_band_right2(
; CHECK-NEXT: [[C:%.*]] = select i1 [[B:%.*]], i1 [[A:%.*]], i1 false
; CHECK-NEXT: ret i1 [[C]]
;
%c = select i1 %B, i1 %A, i1 false
%res = and i1 %A, %c
ret i1 %res
}
; A lor (A land B)
define i1 @land_lor_right1(i1 %A, i1 %B) {
; 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
ret i1 %res
}
define i1 @land_lor_right2(i1 %A, i1 %B) {
; 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
ret i1 %res
}
define <2 x i1> @land_lor_right1_vec(<2 x i1> %A, <2 x i1> %B) {
; 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
ret <2 x i1> %res
}
define <2 x i1> @land_lor_right2_vec(<2 x i1> %A, <2 x i1> %B) {
; 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
ret <2 x i1> %res
}
; A bor (A land B)
define i1 @land_bor_right1(i1 %A, i1 %B) {
; CHECK-LABEL: @land_bor_right1(
; CHECK-NEXT: ret i1 [[A:%.*]]
;
%c = select i1 %A, i1 %B, i1 false
%res = or i1 %A, %c
ret i1 %res
}
define i1 @land_bor_right2(i1 %A, i1 %B) {
; CHECK-LABEL: @land_bor_right2(
; CHECK-NEXT: ret i1 [[A:%.*]]
;
%c = select i1 %B, i1 %A, i1 false
%res = or i1 %A, %c
ret i1 %res
}
; A land (A band B)
define i1 @band_land_right1(i1 %A, i1 %B) {
; CHECK-LABEL: @band_land_right1(
; CHECK-NEXT: [[RES:%.*]] = select i1 [[A:%.*]], i1 [[B:%.*]], i1 false
; CHECK-NEXT: ret i1 [[RES]]
;
%c = and i1 %A, %B
%res = select i1 %A, i1 %c, i1 false
ret i1 %res
}
define i1 @band_land_right2(i1 %A, i1 %B) {
; CHECK-LABEL: @band_land_right2(
; CHECK-NEXT: [[RES:%.*]] = select i1 [[A:%.*]], i1 [[B:%.*]], i1 false
; CHECK-NEXT: ret i1 [[RES]]
;
%c = and i1 %B, %A
%res = select i1 %A, i1 %c, i1 false
ret i1 %res
}
; A lor (A band B)
define i1 @band_lor_right1(i1 %A, i1 %B) {
; CHECK-LABEL: @band_lor_right1(
; CHECK-NEXT: ret i1 [[A:%.*]]
;
%c = and i1 %A, %B
%res = select i1 %A, i1 true, i1 %c
ret i1 %res
}
define i1 @band_lor_right2(i1 %A, i1 %B) {
; CHECK-LABEL: @band_lor_right2(
; CHECK-NEXT: ret i1 [[A:%.*]]
;
%c = and i1 %B, %A
%res = select i1 %A, i1 true, i1 %c
ret i1 %res
}
; A land (A lor B)
define i1 @lor_land_right1(i1 %A, i1 %B) {
; 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
ret i1 %res
}
define i1 @lor_land_right2(i1 %A, i1 %B) {
; 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
ret i1 %res
}
; A band (A lor B)
define i1 @lor_band_right1(i1 %A, i1 %B) {
; CHECK-LABEL: @lor_band_right1(
; CHECK-NEXT: ret i1 [[A:%.*]]
;
%c = select i1 %A, i1 true, i1 %B
%res = and i1 %A, %c
ret i1 %res
}
define i1 @lor_band_right2(i1 %A, i1 %B) {
; CHECK-LABEL: @lor_band_right2(
; CHECK-NEXT: ret i1 [[A:%.*]]
;
%c = select i1 %B, i1 true, i1 %A
%res = and i1 %A, %c
ret i1 %res
}
; A lor (A lor B)
define i1 @lor_lor_right1(i1 %A, i1 %B) {
; CHECK-LABEL: @lor_lor_right1(
; CHECK-NEXT: [[RES:%.*]] = select i1 [[A:%.*]], i1 true, i1 [[B:%.*]]
; CHECK-NEXT: ret i1 [[RES]]
;
%c = select i1 %A, i1 true, i1 %B
%res = select i1 %A, i1 true, i1 %c
ret i1 %res
}
define i1 @lor_lor_right2(i1 %A, i1 %B) {
; CHECK-LABEL: @lor_lor_right2(
; CHECK-NEXT: [[RES:%.*]] = select i1 [[A:%.*]], i1 true, i1 [[B:%.*]]
; CHECK-NEXT: ret i1 [[RES]]
;
%c = select i1 %B, i1 true, i1 %A
%res = select i1 %A, i1 true, i1 %c
ret i1 %res
}
; A bor (A lor B)
define i1 @lor_bor_right1(i1 %A, i1 %B) {
; CHECK-LABEL: @lor_bor_right1(
; CHECK-NEXT: [[C:%.*]] = select i1 [[A:%.*]], i1 true, i1 [[B:%.*]]
; CHECK-NEXT: ret i1 [[C]]
;
%c = select i1 %A, i1 true, i1 %B
%res = or i1 %A, %c
ret i1 %res
}
define i1 @lor_bor_right2(i1 %A, i1 %B) {
; CHECK-LABEL: @lor_bor_right2(
; CHECK-NEXT: [[C:%.*]] = select i1 [[B:%.*]], i1 true, i1 [[A:%.*]]
; CHECK-NEXT: ret i1 [[C]]
;
%c = select i1 %B, i1 true, i1 %A
%res = or i1 %A, %c
ret i1 %res
}
; A land (A bor B)
define i1 @bor_land_right1(i1 %A, i1 %B) {
; CHECK-LABEL: @bor_land_right1(
; CHECK-NEXT: ret i1 [[A:%.*]]
;
%c = or i1 %A, %B
%res = select i1 %A, i1 %c, i1 false
ret i1 %res
}
define i1 @bor_land_right2(i1 %A, i1 %B) {
; CHECK-LABEL: @bor_land_right2(
; CHECK-NEXT: ret i1 [[A:%.*]]
;
%c = or i1 %B, %A
%res = select i1 %A, i1 %c, i1 false
ret i1 %res
}
; A lor (A bor B)
define i1 @bor_lor_right1(i1 %A, i1 %B) {
; CHECK-LABEL: @bor_lor_right1(
; CHECK-NEXT: [[RES:%.*]] = select i1 [[A:%.*]], i1 true, i1 [[B:%.*]]
; CHECK-NEXT: ret i1 [[RES]]
;
%c = or i1 %A, %B
%res = select i1 %A, i1 true, i1 %c
ret i1 %res
}
define i1 @bor_lor_right2(i1 %A, i1 %B) {
; CHECK-LABEL: @bor_lor_right2(
; CHECK-NEXT: [[RES:%.*]] = select i1 [[A:%.*]], i1 true, i1 [[B:%.*]]
; CHECK-NEXT: ret i1 [[RES]]
;
%c = or i1 %B, %A
%res = select i1 %A, i1 true, i1 %c
ret i1 %res
}
; Value equivalence substitution does not account for vector
; transforms, so it needs a scalar condition operand.
; For example, this would miscompile if %a = {1, 0}.
define <2 x i1> @PR50500_trueval(<2 x i1> %a, <2 x i1> %b) {
; CHECK-LABEL: @PR50500_trueval(
; CHECK-NEXT: [[S:%.*]] = shufflevector <2 x i1> [[A:%.*]], <2 x i1> poison, <2 x i32> <i32 1, i32 0>
; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[A]], <2 x i1> [[S]], <2 x i1> [[B:%.*]]
; CHECK-NEXT: ret <2 x i1> [[R]]
;
%s = shufflevector <2 x i1> %a, <2 x i1> poison, <2 x i32> <i32 1, i32 0>
%r = select <2 x i1> %a, <2 x i1> %s, <2 x i1> %b
ret <2 x i1> %r
}
define <2 x i1> @PR50500_falseval(<2 x i1> %a, <2 x i1> %b) {
; CHECK-LABEL: @PR50500_falseval(
; CHECK-NEXT: [[S:%.*]] = shufflevector <2 x i1> [[A:%.*]], <2 x i1> poison, <2 x i32> <i32 1, i32 0>
; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[A]], <2 x i1> [[B:%.*]], <2 x i1> [[S]]
; CHECK-NEXT: ret <2 x i1> [[R]]
;
%s = shufflevector <2 x i1> %a, <2 x i1> poison, <2 x i32> <i32 1, i32 0>
%r = select <2 x i1> %a, <2 x i1> %b, <2 x i1> %s
ret <2 x i1> %r
}
!0 = !{!"function_entry_count", i64 1000}
!1 = !{!"branch_weights", i32 2, i32 3}
!2 = !{!"branch_weights", i32 5, i32 7}
;.
; CHECK: [[META0:![0-9]+]] = !{!"function_entry_count", i64 1000}
; CHECK: [[PROF1]] = !{!"branch_weights", i32 2, i32 3}
;.