[llvm] [VPlan] Fix m_c_LogicalAnd/Or commuting select operands (PR #213248)
Luke Lau via llvm-commits
llvm-commits at lists.llvm.org
Fri Jul 31 04:18:07 PDT 2026
https://github.com/lukel97 created https://github.com/llvm/llvm-project/pull/213248
We use m_c_Select in m_c_LogicalAnd and m_c_LogicalOr, since a logical and is
select(x, y, false), and a logical or is select(x, true, y).
m_c_Select(x, y, z) matches either m_Select(x, y, z) or m_Select(!x, z, y) though, so we don't actually end up matching select(y, x, false) or select(y, true, x).
This fixes it by just manually commuting the operands. We likely don't want to match on select(!x, false, y) as logical and.
We're missing a combine for x || (x || y) -> x || y, which is why the logical-or test doesn't have any diff.
>From b4fb3b0962b64f88ac891ab9289cd0a0f2a7416c Mon Sep 17 00:00:00 2001
From: Luke Lau <luke at igalia.com>
Date: Fri, 31 Jul 2026 19:05:41 +0800
Subject: [PATCH 1/2] Precommit tests
---
.../LoopVectorize/simplify-logical-and.ll | 122 ++++++++++++++++++
1 file changed, 122 insertions(+)
create mode 100644 llvm/test/Transforms/LoopVectorize/simplify-logical-and.ll
diff --git a/llvm/test/Transforms/LoopVectorize/simplify-logical-and.ll b/llvm/test/Transforms/LoopVectorize/simplify-logical-and.ll
new file mode 100644
index 0000000000000..807efaa84158a
--- /dev/null
+++ b/llvm/test/Transforms/LoopVectorize/simplify-logical-and.ll
@@ -0,0 +1,122 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals none --filter-out-after "^scalar.ph" --version 6
+; RUN: opt < %s -p loop-vectorize -force-vector-width=4 -S | FileCheck %s
+
+; x && (y && x) -> y && x
+define void @logical_and(ptr noalias %p, ptr noalias %a, ptr noalias %b, i32 %n) {
+; CHECK-LABEL: define void @logical_and(
+; CHECK-SAME: ptr noalias [[P:%.*]], ptr noalias [[A:%.*]], ptr noalias [[B:%.*]], i32 [[N:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[MIN_ITERS_CHECK:%.*]] = icmp ult i32 [[N]], 4
+; CHECK-NEXT: br i1 [[MIN_ITERS_CHECK]], label %[[SCALAR_PH:.*]], label %[[VECTOR_SCEVCHECK:.*]]
+; CHECK: [[VECTOR_SCEVCHECK]]:
+; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[N]], -1
+; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i32 [[TMP0]], 0
+; CHECK-NEXT: br i1 [[TMP1]], label %[[SCALAR_PH]], label %[[VECTOR_PH:.*]]
+; CHECK: [[VECTOR_PH]]:
+; CHECK-NEXT: [[N_MOD_VF:%.*]] = urem i32 [[N]], 4
+; CHECK-NEXT: [[N_VEC:%.*]] = sub i32 [[N]], [[N_MOD_VF]]
+; CHECK-NEXT: br label %[[VECTOR_BODY:.*]]
+; CHECK: [[VECTOR_BODY]]:
+; CHECK-NEXT: [[INDEX:%.*]] = phi i32 [ 0, %[[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], %[[VECTOR_BODY]] ]
+; CHECK-NEXT: [[TMP2:%.*]] = getelementptr i32, ptr [[A]], i32 [[INDEX]]
+; CHECK-NEXT: [[TMP3:%.*]] = getelementptr i32, ptr [[B]], i32 [[INDEX]]
+; CHECK-NEXT: [[WIDE_LOAD:%.*]] = load <4 x i32>, ptr [[TMP2]], align 4
+; CHECK-NEXT: [[WIDE_LOAD1:%.*]] = load <4 x i32>, ptr [[TMP3]], align 4
+; CHECK-NEXT: [[TMP4:%.*]] = trunc <4 x i32> [[WIDE_LOAD]] to <4 x i1>
+; CHECK-NEXT: [[TMP5:%.*]] = trunc <4 x i32> [[WIDE_LOAD1]] to <4 x i1>
+; CHECK-NEXT: [[TMP6:%.*]] = select <4 x i1> [[TMP4]], <4 x i1> [[TMP5]], <4 x i1> zeroinitializer
+; CHECK-NEXT: [[TMP7:%.*]] = select <4 x i1> [[TMP6]], <4 x i1> [[TMP4]], <4 x i1> zeroinitializer
+; CHECK-NEXT: [[TMP8:%.*]] = zext <4 x i1> [[TMP7]] to <4 x i32>
+; CHECK-NEXT: [[TMP9:%.*]] = getelementptr i32, ptr [[P]], i32 [[INDEX]]
+; CHECK-NEXT: store <4 x i32> [[TMP8]], ptr [[TMP9]], align 4
+; CHECK-NEXT: [[INDEX_NEXT]] = add nuw i32 [[INDEX]], 4
+; CHECK-NEXT: [[TMP10:%.*]] = icmp eq i32 [[INDEX_NEXT]], [[N_VEC]]
+; CHECK-NEXT: br i1 [[TMP10]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP0:![0-9]+]]
+; CHECK: [[MIDDLE_BLOCK]]:
+; CHECK-NEXT: [[CMP_N:%.*]] = icmp eq i32 [[N]], [[N_VEC]]
+; CHECK-NEXT: br i1 [[CMP_N]], [[EXIT:label %.*]], label %[[SCALAR_PH]]
+; CHECK: [[SCALAR_PH]]:
+;
+entry:
+ br label %loop
+
+loop:
+ %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
+ %pa = getelementptr i32, ptr %a, i32 %iv
+ %pb = getelementptr i32, ptr %b, i32 %iv
+ %la = load i32, ptr %pa
+ %lb = load i32, ptr %pb
+ %x = trunc i32 %la to i1
+ %y = trunc i32 %lb to i1
+ %inner = select i1 %y, i1 %x, i1 false
+ %outer = select i1 %x, i1 %inner, i1 false
+ %z = zext i1 %outer to i32
+ %pp = getelementptr i32, ptr %p, i32 %iv
+ store i32 %z, ptr %pp
+ %iv.next = add i32 %iv, 1
+ %ec = icmp eq i32 %iv.next, %n
+ br i1 %ec, label %exit, label %loop
+
+exit:
+ ret void
+}
+
+; x || (y || x) -> y || x
+define void @logical_or(ptr noalias %p, ptr noalias %a, ptr noalias %b, i32 %n) {
+; CHECK-LABEL: define void @logical_or(
+; CHECK-SAME: ptr noalias [[P:%.*]], ptr noalias [[A:%.*]], ptr noalias [[B:%.*]], i32 [[N:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[MIN_ITERS_CHECK:%.*]] = icmp ult i32 [[N]], 4
+; CHECK-NEXT: br i1 [[MIN_ITERS_CHECK]], label %[[SCALAR_PH:.*]], label %[[VECTOR_SCEVCHECK:.*]]
+; CHECK: [[VECTOR_SCEVCHECK]]:
+; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[N]], -1
+; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i32 [[TMP0]], 0
+; CHECK-NEXT: br i1 [[TMP1]], label %[[SCALAR_PH]], label %[[VECTOR_PH:.*]]
+; CHECK: [[VECTOR_PH]]:
+; CHECK-NEXT: [[N_MOD_VF:%.*]] = urem i32 [[N]], 4
+; CHECK-NEXT: [[N_VEC:%.*]] = sub i32 [[N]], [[N_MOD_VF]]
+; CHECK-NEXT: br label %[[VECTOR_BODY:.*]]
+; CHECK: [[VECTOR_BODY]]:
+; CHECK-NEXT: [[INDEX:%.*]] = phi i32 [ 0, %[[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], %[[VECTOR_BODY]] ]
+; CHECK-NEXT: [[TMP2:%.*]] = getelementptr i32, ptr [[A]], i32 [[INDEX]]
+; CHECK-NEXT: [[TMP3:%.*]] = getelementptr i32, ptr [[B]], i32 [[INDEX]]
+; CHECK-NEXT: [[WIDE_LOAD:%.*]] = load <4 x i32>, ptr [[TMP2]], align 4
+; CHECK-NEXT: [[WIDE_LOAD1:%.*]] = load <4 x i32>, ptr [[TMP3]], align 4
+; CHECK-NEXT: [[TMP4:%.*]] = trunc <4 x i32> [[WIDE_LOAD]] to <4 x i1>
+; CHECK-NEXT: [[TMP5:%.*]] = trunc <4 x i32> [[WIDE_LOAD1]] to <4 x i1>
+; CHECK-NEXT: [[TMP6:%.*]] = select <4 x i1> [[TMP5]], <4 x i1> splat (i1 true), <4 x i1> [[TMP4]]
+; CHECK-NEXT: [[TMP7:%.*]] = select <4 x i1> [[TMP4]], <4 x i1> splat (i1 true), <4 x i1> [[TMP6]]
+; CHECK-NEXT: [[TMP8:%.*]] = zext <4 x i1> [[TMP7]] to <4 x i32>
+; CHECK-NEXT: [[TMP9:%.*]] = getelementptr i32, ptr [[P]], i32 [[INDEX]]
+; CHECK-NEXT: store <4 x i32> [[TMP8]], ptr [[TMP9]], align 4
+; CHECK-NEXT: [[INDEX_NEXT]] = add nuw i32 [[INDEX]], 4
+; CHECK-NEXT: [[TMP10:%.*]] = icmp eq i32 [[INDEX_NEXT]], [[N_VEC]]
+; CHECK-NEXT: br i1 [[TMP10]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP4:![0-9]+]]
+; CHECK: [[MIDDLE_BLOCK]]:
+; CHECK-NEXT: [[CMP_N:%.*]] = icmp eq i32 [[N]], [[N_VEC]]
+; CHECK-NEXT: br i1 [[CMP_N]], [[EXIT:label %.*]], label %[[SCALAR_PH]]
+; CHECK: [[SCALAR_PH]]:
+;
+entry:
+ br label %loop
+
+loop:
+ %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
+ %pa = getelementptr i32, ptr %a, i32 %iv
+ %pb = getelementptr i32, ptr %b, i32 %iv
+ %la = load i32, ptr %pa
+ %lb = load i32, ptr %pb
+ %x = trunc i32 %la to i1
+ %y = trunc i32 %lb to i1
+ %inner = select i1 %y, i1 true, i1 %x
+ %outer = select i1 %x, i1 true, i1 %inner
+ %z = zext i1 %outer to i32
+ %pp = getelementptr i32, ptr %p, i32 %iv
+ store i32 %z, ptr %pp
+ %iv.next = add i32 %iv, 1
+ %ec = icmp eq i32 %iv.next, %n
+ br i1 %ec, label %exit, label %loop
+
+exit:
+ ret void
+}
>From 343c974433308cf688217fea22950c466bdd55dc Mon Sep 17 00:00:00 2001
From: Luke Lau <luke at igalia.com>
Date: Fri, 31 Jul 2026 19:12:04 +0800
Subject: [PATCH 2/2] [VPlan] Fix m_c_LogicalAnd/Or commuting select operands
We use m_c_Select in m_c_LogicalAnd and m_c_LogicalOr, since a logical and is
select(x, y, false), and a logical or is select(x, true, y).
m_c_Select(x, y, z) matches either m_Select(x, y, z) or m_Select(!x, z, y) though, so we don't actually end up matching select(y, x, false) or select(y, true, x).
This fixes it by just manually commuting the operands. We likely don't want to match on select(!x, false, y) as logical and.
We're missing a combine for x || (x || y) -> x || y, which is why the logical-or test doesn't have any diff.
---
llvm/lib/Transforms/Vectorize/VPlanPatternMatch.h | 5 +++--
llvm/test/Transforms/LoopVectorize/simplify-logical-and.ll | 3 +--
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/llvm/lib/Transforms/Vectorize/VPlanPatternMatch.h b/llvm/lib/Transforms/Vectorize/VPlanPatternMatch.h
index d575d1f150e7a..f7c478ecdc070 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanPatternMatch.h
+++ b/llvm/lib/Transforms/Vectorize/VPlanPatternMatch.h
@@ -861,7 +861,7 @@ template <typename Op0_t, typename Op1_t>
inline auto m_c_LogicalAnd(const Op0_t &Op0, const Op1_t &Op1) {
return m_CombineOr(
m_c_VPInstruction<VPInstruction::LogicalAnd, Op0_t, Op1_t>(Op0, Op1),
- m_c_Select(Op0, Op1, m_False()));
+ m_Select(Op0, Op1, m_False()), m_Select(Op1, Op0, m_False()));
}
template <typename Op0_t, typename Op1_t>
@@ -873,7 +873,8 @@ inline auto m_LogicalOr(const Op0_t &Op0, const Op1_t &Op1) {
template <typename Op0_t, typename Op1_t>
inline auto m_c_LogicalOr(const Op0_t &Op0, const Op1_t &Op1) {
- return m_c_Select(Op0, m_True(), Op1);
+ return m_CombineOr(m_Select(Op0, m_True(), Op1),
+ m_Select(Op1, m_True(), Op0));
}
/// Match the canonical induction variable (IV) of any loop region.
diff --git a/llvm/test/Transforms/LoopVectorize/simplify-logical-and.ll b/llvm/test/Transforms/LoopVectorize/simplify-logical-and.ll
index 807efaa84158a..64cc6e0a560c8 100644
--- a/llvm/test/Transforms/LoopVectorize/simplify-logical-and.ll
+++ b/llvm/test/Transforms/LoopVectorize/simplify-logical-and.ll
@@ -24,8 +24,7 @@ define void @logical_and(ptr noalias %p, ptr noalias %a, ptr noalias %b, i32 %n)
; CHECK-NEXT: [[WIDE_LOAD1:%.*]] = load <4 x i32>, ptr [[TMP3]], align 4
; CHECK-NEXT: [[TMP4:%.*]] = trunc <4 x i32> [[WIDE_LOAD]] to <4 x i1>
; CHECK-NEXT: [[TMP5:%.*]] = trunc <4 x i32> [[WIDE_LOAD1]] to <4 x i1>
-; CHECK-NEXT: [[TMP6:%.*]] = select <4 x i1> [[TMP4]], <4 x i1> [[TMP5]], <4 x i1> zeroinitializer
-; CHECK-NEXT: [[TMP7:%.*]] = select <4 x i1> [[TMP6]], <4 x i1> [[TMP4]], <4 x i1> zeroinitializer
+; CHECK-NEXT: [[TMP7:%.*]] = select <4 x i1> [[TMP5]], <4 x i1> [[TMP4]], <4 x i1> zeroinitializer
; CHECK-NEXT: [[TMP8:%.*]] = zext <4 x i1> [[TMP7]] to <4 x i32>
; CHECK-NEXT: [[TMP9:%.*]] = getelementptr i32, ptr [[P]], i32 [[INDEX]]
; CHECK-NEXT: store <4 x i32> [[TMP8]], ptr [[TMP9]], align 4
More information about the llvm-commits
mailing list