-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[PatternMatch] Add m_c_XorLike
matcher; NFC
#122642
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
`m_c_XorLike` matches either: `(xor L, R)`, `(xor R, L)`, or `(sub nuw R, L)` iff `R.isMask()`. This is in preperation for dropping the fold from: `(sub C_Mask, X)` -> `(xor X, C_Mask)`
@llvm/pr-subscribers-llvm-ir Author: None (goldsteinn) Changes
This is in preperation for dropping the fold from: Full diff: https://github.com/llvm/llvm-project/pull/122642.diff 2 Files Affected:
diff --git a/llvm/include/llvm/IR/PatternMatch.h b/llvm/include/llvm/IR/PatternMatch.h
index cd9a36029e6dbd..e50459716fe0eb 100644
--- a/llvm/include/llvm/IR/PatternMatch.h
+++ b/llvm/include/llvm/IR/PatternMatch.h
@@ -1430,6 +1430,34 @@ m_NUWAddLike(const LHS &L, const RHS &R) {
return m_CombineOr(m_NUWAdd(L, R), m_DisjointOr(L, R));
}
+template <typename LHS, typename RHS>
+struct XorLike_match {
+ LHS L;
+ RHS R;
+
+ XorLike_match(const LHS &L, const RHS &R) : L(L), R(R) {}
+
+ template <typename OpTy> bool match(OpTy *V) {
+ if (auto *Op = dyn_cast<BinaryOperator>(V)) {
+ if (Op->getOpcode() == Instruction::Sub && Op->hasNoUnsignedWrap() &&
+ PatternMatch::match(Op->getOperand(0), m_LowBitMask()))
+ ; // Pass
+ else if (Op->getOpcode() != Instruction::Xor)
+ return false;
+ return (L.match(Op->getOperand(0)) && R.match(Op->getOperand(1))) ||
+ (L.match(Op->getOperand(1)) && R.match(Op->getOperand(0)));
+ }
+ return false;
+ }
+};
+
+// Match either `(xor L, R)`, `(xor R, L)` or `(sub nuw R, L)` iff `R.isMask()`
+// Only commutative matcher as the `sub` will need to swap the L and R.
+template <typename LHS, typename RHS>
+inline auto m_c_XorLike(const LHS &L, const RHS &R) {
+ return XorLike_match<LHS, RHS>(L, R);
+}
+
//===----------------------------------------------------------------------===//
// Class that matches a group of binary opcodes.
//
diff --git a/llvm/unittests/IR/PatternMatch.cpp b/llvm/unittests/IR/PatternMatch.cpp
index 47fde5782a13bc..da2c09ea199290 100644
--- a/llvm/unittests/IR/PatternMatch.cpp
+++ b/llvm/unittests/IR/PatternMatch.cpp
@@ -533,6 +533,72 @@ TEST_F(PatternMatchTest, BitWise) {
EXPECT_FALSE(m_c_BitwiseLogic(m_Zero(), m_Zero()).match(Xor));
}
+TEST_F(PatternMatchTest, XorLike) {
+ Value *AllocaX = IRB.CreateAlloca(IRB.getInt32Ty());
+ Value *X = IRB.CreateLoad(IRB.getInt32Ty(), AllocaX);
+ Value *AllocaY = IRB.CreateAlloca(IRB.getInt32Ty());
+ Value *Y = IRB.CreateLoad(IRB.getInt32Ty(), AllocaY);
+ Value *MaskC = IRB.getInt32(31);
+ Value *NonMaskC = IRB.getInt32(32);
+
+ Value *OpA, *OpB;
+ {
+ Value *Xor = IRB.CreateXor(X, Y);
+ Value *Sub = IRB.CreateNUWSub(X, Y);
+ OpA = nullptr;
+ OpB = nullptr;
+ EXPECT_TRUE(m_c_XorLike(m_Value(OpA), m_Value(OpB)).match(Xor));
+ EXPECT_TRUE(OpA != OpB && (OpA == X || OpB == X) && (OpA == Y || OpB == Y));
+ OpA = nullptr;
+ OpB = nullptr;
+ EXPECT_FALSE(m_c_XorLike(m_Value(OpA), m_Value(OpB)).match(Sub));
+ }
+ {
+ Value *Xor = IRB.CreateXor(X, MaskC);
+ Value *Sub = IRB.CreateNUWSub(MaskC, X);
+ OpA = nullptr;
+ OpB = nullptr;
+ EXPECT_TRUE(m_c_XorLike(m_Value(OpA), m_Value(OpB)).match(Xor));
+ EXPECT_TRUE(OpA != OpB && (OpA == X || OpB == X) &&
+ (OpA == MaskC || OpB == MaskC));
+ OpA = nullptr;
+ OpB = nullptr;
+ EXPECT_TRUE(m_c_XorLike(m_Value(OpA), m_Value(OpB)).match(Sub));
+ EXPECT_TRUE(OpA != OpB && (OpA == X || OpB == X) &&
+ (OpA == MaskC || OpB == MaskC));
+ }
+ {
+ Value *Xor = IRB.CreateXor(X, MaskC);
+ Value *Sub = IRB.CreateNSWSub(MaskC, X);
+ OpA = nullptr;
+ OpB = nullptr;
+ EXPECT_TRUE(m_c_XorLike(m_Value(OpA), m_Value(OpB)).match(Xor));
+ EXPECT_TRUE(OpA != OpB && (OpA == X || OpB == X) &&
+ (OpA == MaskC || OpB == MaskC));
+ OpA = nullptr;
+ OpB = nullptr;
+ EXPECT_FALSE(m_c_XorLike(m_Value(OpA), m_Value(OpB)).match(Sub));
+ }
+ {
+ Value *Sub = IRB.CreateNUWSub(X, MaskC);
+ OpA = nullptr;
+ OpB = nullptr;
+ EXPECT_FALSE(m_c_XorLike(m_Value(OpA), m_Value(OpB)).match(Sub));
+ }
+ {
+ Value *Xor = IRB.CreateXor(X, NonMaskC);
+ Value *Sub = IRB.CreateNUWSub(NonMaskC, X);
+ OpA = nullptr;
+ OpB = nullptr;
+ EXPECT_TRUE(m_c_XorLike(m_Value(OpA), m_Value(OpB)).match(Xor));
+ EXPECT_TRUE(OpA != OpB && (OpA == X || OpB == X) &&
+ (OpA == NonMaskC || OpB == NonMaskC));
+ OpA = nullptr;
+ OpB = nullptr;
+ EXPECT_FALSE(m_c_XorLike(m_Value(OpA), m_Value(OpB)).match(Sub));
+ }
+}
+
TEST_F(PatternMatchTest, ZExtSExtSelf) {
LLVMContext &Ctx = IRB.getContext();
|
You can test this locally with the following command:git-clang-format --diff b91d5af1ac3ad2c18b1dfde2061a6ac1d638e6e4 e192d736e366bb5508da6eb33a43d104b084441c --extensions cpp,h -- llvm/include/llvm/IR/PatternMatch.h llvm/unittests/IR/PatternMatch.cpp View the diff from clang-format here.diff --git a/llvm/include/llvm/IR/PatternMatch.h b/llvm/include/llvm/IR/PatternMatch.h
index b3eeb1d7ba..cd2bf4be6d 100644
--- a/llvm/include/llvm/IR/PatternMatch.h
+++ b/llvm/include/llvm/IR/PatternMatch.h
@@ -1430,8 +1430,7 @@ m_NUWAddLike(const LHS &L, const RHS &R) {
return m_CombineOr(m_NUWAdd(L, R), m_DisjointOr(L, R));
}
-template <typename LHS, typename RHS>
-struct XorLike_match {
+template <typename LHS, typename RHS> struct XorLike_match {
LHS L;
RHS R;
@@ -1441,7 +1440,7 @@ struct XorLike_match {
if (auto *Op = dyn_cast<BinaryOperator>(V)) {
if (Op->getOpcode() == Instruction::Sub && Op->hasNoUnsignedWrap() &&
PatternMatch::match(Op->getOperand(0), m_LowBitMask()))
- ; // Pass
+ ; // Pass
else if (Op->getOpcode() != Instruction::Xor)
return false;
return (L.match(Op->getOperand(0)) && R.match(Op->getOperand(1))) ||
|
if (auto *Op = dyn_cast<BinaryOperator>(V)) { | ||
if (Op->getOpcode() == Instruction::Sub && Op->hasNoUnsignedWrap() && | ||
PatternMatch::match(Op->getOperand(0), m_LowBitMask())) | ||
; // Pass |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this case, only L.match(Op->getOperand(1)) && R.match(Op->getOperand(0))
is needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably assuming canonicalization. But IMO at least letting sub
case fall through is simpler codes and could theoretically handle cases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LG
llvm/include/llvm/IR/PatternMatch.h
Outdated
// Match either `(xor L, R)`, `(xor R, L)` or `(sub nuw R, L)` iff `R.isMask()` | ||
// Only commutative matcher as the `sub` will need to swap the L and R. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// Match either `(xor L, R)`, `(xor R, L)` or `(sub nuw R, L)` iff `R.isMask()` | |
// Only commutative matcher as the `sub` will need to swap the L and R. | |
/// Match either `(xor L, R)`, `(xor R, L)` or `(sub nuw R, L)` iff `R.isMask()` | |
/// Only commutative matcher as the `sub` will need to swap the L and R. |
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/73/builds/11958 Here is the relevant piece of the build log for the reference
|
m_c_XorLike
matches either:(xor L, R)
,(xor R, L)
, or(sub nuw R, L)
iffR.isMask()
.This is in preperation for dropping the fold from:
(sub C_Mask, X)
->(xor X, C_Mask)