[llvm] 2223b93 - [VPlan] Introduce m_c_Logical(And|Or) (#180048)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Feb 12 05:14:13 PST 2026
Author: Ramkumar Ramachandra
Date: 2026-02-12T13:14:08Z
New Revision: 2223b931c5c350cdac38e377f166d69760a15676
URL: https://github.com/llvm/llvm-project/commit/2223b931c5c350cdac38e377f166d69760a15676
DIFF: https://github.com/llvm/llvm-project/commit/2223b931c5c350cdac38e377f166d69760a15676.diff
LOG: [VPlan] Introduce m_c_Logical(And|Or) (#180048)
Added:
llvm/test/Transforms/LoopVectorize/constant-fold-commutative-and.ll
Modified:
llvm/lib/Transforms/Vectorize/VPlanPatternMatch.h
llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
Removed:
################################################################################
diff --git a/llvm/lib/Transforms/Vectorize/VPlanPatternMatch.h b/llvm/lib/Transforms/Vectorize/VPlanPatternMatch.h
index c0b736de1bc51..34cb5a8b48f78 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanPatternMatch.h
+++ b/llvm/lib/Transforms/Vectorize/VPlanPatternMatch.h
@@ -364,12 +364,23 @@ template <unsigned Opcode, typename... OpTys>
using VPInstruction_match = Recipe_match<std::tuple<OpTys...>, Opcode,
/*Commutative*/ false, VPInstruction>;
+template <unsigned Opcode, typename... OpTys>
+using VPInstruction_commutative_match =
+ Recipe_match<std::tuple<OpTys...>, Opcode,
+ /*Commutative*/ true, VPInstruction>;
+
template <unsigned Opcode, typename... OpTys>
inline VPInstruction_match<Opcode, OpTys...>
m_VPInstruction(const OpTys &...Ops) {
return VPInstruction_match<Opcode, OpTys...>(Ops...);
}
+template <unsigned Opcode, typename Op0_t, typename Op1_t>
+inline VPInstruction_commutative_match<Opcode, Op0_t, Op1_t>
+m_c_VPInstruction(const Op0_t &Op0, const Op1_t &Op1) {
+ return VPInstruction_commutative_match<Opcode, Op0_t, Op1_t>(Op0, Op1);
+}
+
/// BuildVector is matches only its opcode, w/o matching its operands as the
/// number of operands is not fixed.
inline VPInstruction_match<VPInstruction::BuildVector> m_BuildVector() {
@@ -799,6 +810,11 @@ m_Not(const Op0_t &Op0) {
m_c_Binary<Instruction::Xor>(m_AllOnes(), Op0));
}
+template <typename Op0_t, typename Op1_t, typename Op2_t>
+inline auto m_c_Select(const Op0_t &Op0, const Op1_t &Op1, const Op2_t &Op2) {
+ return m_CombineOr(m_Select(Op0, Op1, Op2), m_Select(m_Not(Op0), Op2, Op1));
+}
+
template <typename Op0_t, typename Op1_t>
inline match_combine_or<
VPInstruction_match<VPInstruction::LogicalAnd, Op0_t, Op1_t>,
@@ -809,12 +825,24 @@ m_LogicalAnd(const Op0_t &Op0, const Op1_t &Op1) {
m_Select(Op0, Op1, m_False()));
}
+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()));
+}
+
template <typename Op0_t, typename Op1_t>
inline AllRecipe_match<Instruction::Select, Op0_t, specific_intval<1>, Op1_t>
m_LogicalOr(const Op0_t &Op0, const Op1_t &Op1) {
return m_Select(Op0, m_True(), 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);
+}
+
template <typename Op0_t, typename Op1_t, typename Op2_t>
using VPScalarIVSteps_match = Recipe_match<std::tuple<Op0_t, Op1_t, Op2_t>, 0,
false, VPScalarIVStepsRecipe>;
diff --git a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
index 5708abfaf6f5b..89a270d1219e7 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
@@ -1064,8 +1064,9 @@ InstructionCost VPRecipeWithIRFlags::getCostForRecipeWithOpcode(
VPValue *Op0, *Op1;
bool IsLogicalAnd =
- match(this, m_LogicalAnd(m_VPValue(Op0), m_VPValue(Op1)));
- bool IsLogicalOr = match(this, m_LogicalOr(m_VPValue(Op0), m_VPValue(Op1)));
+ match(this, m_c_LogicalAnd(m_VPValue(Op0), m_VPValue(Op1)));
+ bool IsLogicalOr =
+ match(this, m_c_LogicalOr(m_VPValue(Op0), m_VPValue(Op1)));
// Also match the inverted forms:
// select x, false, y --> !x & y (still AND)
// select x, y, true --> !x | y (still OR)
diff --git a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
index 2245a7e0f004f..d49cbfadcf079 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
@@ -1295,11 +1295,11 @@ static void simplifyRecipe(VPSingleDefRecipe *Def, VPTypeAnalysis &TypeInfo) {
return Def->replaceAllUsesWith(X);
// x && false -> false
- if (match(Def, m_LogicalAnd(m_VPValue(X), m_False())))
- return Def->replaceAllUsesWith(Def->getOperand(1));
+ if (match(Def, m_c_LogicalAnd(m_VPValue(X), m_False())))
+ return Def->replaceAllUsesWith(Plan->getFalse());
- // true && x -> x
- if (match(Def, m_LogicalAnd(m_True(), m_VPValue(X))))
+ // x && true -> x
+ if (match(Def, m_c_LogicalAnd(m_VPValue(X), m_True())))
return Def->replaceAllUsesWith(X);
// (x && y) | (x && z) -> x && (y | z)
diff --git a/llvm/test/Transforms/LoopVectorize/constant-fold-commutative-and.ll b/llvm/test/Transforms/LoopVectorize/constant-fold-commutative-and.ll
new file mode 100644
index 0000000000000..97c54fa5a06c2
--- /dev/null
+++ b/llvm/test/Transforms/LoopVectorize/constant-fold-commutative-and.ll
@@ -0,0 +1,83 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals none --version 6
+; RUN: opt -passes=loop-vectorize -force-vector-width=2 \
+; RUN: -prefer-predicate-over-epilogue=predicate-else-scalar-epilogue -S %s \
+; RUN: | FileCheck %s
+
+; Test that we constant fold logical and with swapped operand order.
+
+define void @constant_fold_commutative_and(ptr %ptr.n, ptr noalias %p, i1 %cond) {
+; CHECK-LABEL: define void @constant_fold_commutative_and(
+; CHECK-SAME: ptr [[PTR_N:%.*]], ptr noalias [[P:%.*]], i1 [[COND:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: br label %[[VECTOR_PH:.*]]
+; CHECK: [[VECTOR_PH]]:
+; CHECK-NEXT: [[BROADCAST_SPLATINSERT:%.*]] = insertelement <2 x i1> poison, i1 [[COND]], i64 0
+; CHECK-NEXT: [[BROADCAST_SPLAT:%.*]] = shufflevector <2 x i1> [[BROADCAST_SPLATINSERT]], <2 x i1> poison, <2 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP0:%.*]] = xor <2 x i1> [[BROADCAST_SPLAT]], splat (i1 true)
+; CHECK-NEXT: br label %[[VECTOR_BODY:.*]]
+; CHECK: [[VECTOR_BODY]]:
+; CHECK-NEXT: [[INDEX:%.*]] = phi i64 [ 0, %[[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], %[[PRED_STORE_CONTINUE5:.*]] ]
+; CHECK-NEXT: [[VEC_IND:%.*]] = phi <2 x i8> [ <i8 0, i8 1>, %[[VECTOR_PH]] ], [ [[VEC_IND_NEXT:%.*]], %[[PRED_STORE_CONTINUE5]] ]
+; CHECK-NEXT: [[TMP1:%.*]] = icmp ule <2 x i8> [[VEC_IND]], splat (i8 16)
+; CHECK-NEXT: [[TMP2:%.*]] = load i64, ptr [[PTR_N]], align 4
+; CHECK-NEXT: [[BROADCAST_SPLATINSERT1:%.*]] = insertelement <2 x i64> poison, i64 [[TMP2]], i64 0
+; CHECK-NEXT: [[BROADCAST_SPLAT2:%.*]] = shufflevector <2 x i64> [[BROADCAST_SPLATINSERT1]], <2 x i64> poison, <2 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP3:%.*]] = icmp ult <2 x i64> [[BROADCAST_SPLAT2]], splat (i64 4)
+; CHECK-NEXT: [[TMP4:%.*]] = icmp ult <2 x i64> [[BROADCAST_SPLAT2]], splat (i64 7)
+; CHECK-NEXT: [[TMP5:%.*]] = select <2 x i1> [[TMP0]], <2 x i1> [[TMP3]], <2 x i1> zeroinitializer
+; CHECK-NEXT: [[PREDPHI:%.*]] = select <2 x i1> [[TMP5]], <2 x i1> splat (i1 true), <2 x i1> [[TMP4]]
+; CHECK-NEXT: [[PREDPHI3:%.*]] = select i1 [[COND]], <2 x i1> zeroinitializer, <2 x i1> [[PREDPHI]]
+; CHECK-NEXT: [[TMP6:%.*]] = extractelement <2 x i1> [[TMP1]], i32 0
+; CHECK-NEXT: br i1 [[TMP6]], label %[[PRED_STORE_IF:.*]], label %[[PRED_STORE_CONTINUE:.*]]
+; CHECK: [[PRED_STORE_IF]]:
+; CHECK-NEXT: [[TMP7:%.*]] = add i64 [[INDEX]], 0
+; CHECK-NEXT: [[TMP8:%.*]] = getelementptr i8, ptr [[P]], i64 [[TMP7]]
+; CHECK-NEXT: [[TMP9:%.*]] = extractelement <2 x i1> [[PREDPHI3]], i32 0
+; CHECK-NEXT: store i1 [[TMP9]], ptr [[TMP8]], align 1
+; CHECK-NEXT: br label %[[PRED_STORE_CONTINUE]]
+; CHECK: [[PRED_STORE_CONTINUE]]:
+; CHECK-NEXT: [[TMP10:%.*]] = extractelement <2 x i1> [[TMP1]], i32 1
+; CHECK-NEXT: br i1 [[TMP10]], label %[[PRED_STORE_IF4:.*]], label %[[PRED_STORE_CONTINUE5]]
+; CHECK: [[PRED_STORE_IF4]]:
+; CHECK-NEXT: [[TMP11:%.*]] = add i64 [[INDEX]], 1
+; CHECK-NEXT: [[TMP20:%.*]] = getelementptr i8, ptr [[P]], i64 [[TMP11]]
+; CHECK-NEXT: [[TMP21:%.*]] = extractelement <2 x i1> [[PREDPHI3]], i32 1
+; CHECK-NEXT: store i1 [[TMP21]], ptr [[TMP20]], align 1
+; CHECK-NEXT: br label %[[PRED_STORE_CONTINUE5]]
+; CHECK: [[PRED_STORE_CONTINUE5]]:
+; CHECK-NEXT: [[INDEX_NEXT]] = add nuw i64 [[INDEX]], 2
+; CHECK-NEXT: [[VEC_IND_NEXT]] = add <2 x i8> [[VEC_IND]], splat (i8 2)
+; CHECK-NEXT: [[TMP15:%.*]] = icmp eq i64 [[INDEX_NEXT]], 18
+; CHECK-NEXT: br i1 [[TMP15]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP0:![0-9]+]]
+; CHECK: [[MIDDLE_BLOCK]]:
+; CHECK-NEXT: br label %[[EXIT:.*]]
+; CHECK: [[EXIT]]:
+; CHECK-NEXT: ret void
+;
+entry:
+ br label %ph
+
+ph:
+ %iv = phi i64 [ 0, %entry ], [ %iv.next, %latch ]
+ %n = load i64, ptr %ptr.n
+ br i1 %cond, label %latch, label %pred.1
+
+pred.1:
+ %cmp = icmp ult i64 %n, 4
+ br i1 %cmp, label %latch, label %pred.2
+
+pred.2:
+ %cmp.2 = icmp ult i64 %n, 7
+ br label %latch
+
+latch:
+ %merge.val = phi i1 [ 0, %ph ], [ 1, %pred.1 ], [ %cmp.2, %pred.2 ]
+ %gep = getelementptr i8, ptr %p, i64 %iv
+ store i1 %merge.val, ptr %gep
+ %iv.next = add i64 %iv, 1
+ %ec = icmp eq i64 %iv, 16
+ br i1 %ec, label %exit, label %ph
+
+exit:
+ ret void
+}
More information about the llvm-commits
mailing list