[llvm] 4c3ef83 - [NFC][SPIR-V] Use PatternMatch combinators in SPIRVEmitIntrinsics (#189554)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Apr 13 03:55:27 PDT 2026
Author: Arseniy Obolenskiy
Date: 2026-04-13T12:55:21+02:00
New Revision: 4c3ef83e5b235359d557c68c4a3c81cd42e7525d
URL: https://github.com/llvm/llvm-project/commit/4c3ef83e5b235359d557c68c4a3c81cd42e7525d
DIFF: https://github.com/llvm/llvm-project/commit/4c3ef83e5b235359d557c68c4a3c81cd42e7525d.diff
LOG: [NFC][SPIR-V] Use PatternMatch combinators in SPIRVEmitIntrinsics (#189554)
Replace `dyn_cast<IntrinsicInst> + getIntrinsicID()` chains with
PatternMatch combinators where applicable
Added:
Modified:
llvm/include/llvm/IR/PatternMatch.h
llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
llvm/unittests/IR/PatternMatch.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/IR/PatternMatch.h b/llvm/include/llvm/IR/PatternMatch.h
index a29c1d3bba0c2..8399c252f1c2d 100644
--- a/llvm/include/llvm/IR/PatternMatch.h
+++ b/llvm/include/llvm/IR/PatternMatch.h
@@ -2805,6 +2805,18 @@ struct IntrinsicID_match {
}
};
+/// Match intrinsic calls with any of the given IDs.
+template <Intrinsic::ID... IntrIDs> struct IntrinsicIDs_match {
+ template <typename OpTy> bool match(OpTy *V) const {
+ if (const auto *CI = dyn_cast<CallInst>(V))
+ if (const auto *F = dyn_cast_or_null<Function>(CI->getCalledOperand())) {
+ Intrinsic::ID ID = F->getIntrinsicID();
+ return ((ID == IntrIDs) || ...);
+ }
+ return false;
+ }
+};
+
/// Intrinsic matches are combinations of ID matchers, and argument
/// matchers. Higher arity matcher are defined recursively in terms of and-ing
/// them with lower arity matchers. Here's some convenient typedefs for up to
@@ -2851,6 +2863,15 @@ template <Intrinsic::ID IntrID> inline IntrinsicID_match m_Intrinsic() {
return IntrinsicID_match(IntrID);
}
+/// Match intrinsic calls with any of the given IDs like this:
+/// m_AnyIntrinsic<Intrinsic::fptosi_sat, Intrinsic::fptoui_sat>()
+/// This is more efficient than using nested m_CombineOr with m_Intrinsic
+/// because it performs the CallInst/Function cast only once.
+template <Intrinsic::ID... IntrIDs>
+inline IntrinsicIDs_match<IntrIDs...> m_AnyIntrinsic() {
+ return IntrinsicIDs_match<IntrIDs...>();
+}
+
/// Matches MaskedLoad Intrinsic.
template <typename Opnd0, typename Opnd1, typename Opnd2>
inline typename m_Intrinsic_Ty<Opnd0, Opnd1, Opnd2>::Ty
diff --git a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
index 9c2af100ad64e..7600b3a695a4e 100644
--- a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
@@ -53,6 +53,7 @@
// TODO: consider removing spv.track.constant in favor of spv.assign.type.
using namespace llvm;
+using namespace llvm::PatternMatch;
static cl::opt<bool>
SpirvEmitOpNames("spirv-emit-op-names",
@@ -375,37 +376,22 @@ class SPIRVEmitIntrinsics
};
bool isConvergenceIntrinsic(const Instruction *I) {
- const auto *II = dyn_cast<IntrinsicInst>(I);
- if (!II)
- return false;
-
- return II->getIntrinsicID() == Intrinsic::experimental_convergence_entry ||
- II->getIntrinsicID() == Intrinsic::experimental_convergence_loop ||
- II->getIntrinsicID() == Intrinsic::experimental_convergence_anchor;
+ return match(I, m_AnyIntrinsic<Intrinsic::experimental_convergence_entry,
+ Intrinsic::experimental_convergence_loop,
+ Intrinsic::experimental_convergence_anchor>());
}
bool expectIgnoredInIRTranslation(const Instruction *I) {
- const auto *II = dyn_cast<IntrinsicInst>(I);
- if (!II)
- return false;
- switch (II->getIntrinsicID()) {
- case Intrinsic::invariant_start:
- case Intrinsic::spv_resource_handlefrombinding:
- case Intrinsic::spv_resource_getpointer:
- return true;
- default:
- return false;
- }
+ return match(I, m_AnyIntrinsic<Intrinsic::invariant_start,
+ Intrinsic::spv_resource_handlefrombinding,
+ Intrinsic::spv_resource_getpointer>());
}
// Returns the source pointer from `I` ignoring intermediate ptrcast.
Value *getPointerRoot(Value *I) {
- if (auto *II = dyn_cast<IntrinsicInst>(I)) {
- if (II->getIntrinsicID() == Intrinsic::spv_ptrcast) {
- Value *V = II->getArgOperand(0);
- return getPointerRoot(V);
- }
- }
+ Value *V;
+ if (match(I, m_Intrinsic<Intrinsic::spv_ptrcast>(m_Value(V))))
+ return getPointerRoot(V);
return I;
}
@@ -417,8 +403,7 @@ INITIALIZE_PASS(SPIRVEmitIntrinsics, "spirv-emit-intrinsics",
"SPIRV emit intrinsics", false, false)
static inline bool isAssignTypeInstr(const Instruction *I) {
- return isa<IntrinsicInst>(I) &&
- cast<IntrinsicInst>(I)->getIntrinsicID() == Intrinsic::spv_assign_type;
+ return match(I, m_Intrinsic<Intrinsic::spv_assign_type>());
}
static bool isMemInstrToReplace(Instruction *I) {
@@ -450,14 +435,9 @@ static void setInsertPointAfterDef(IRBuilder<> &B, Instruction *I) {
}
static bool requireAssignType(Instruction *I) {
- if (const auto *Intr = dyn_cast<IntrinsicInst>(I)) {
- switch (Intr->getIntrinsicID()) {
- case Intrinsic::invariant_start:
- case Intrinsic::invariant_end:
- return false;
- }
- }
- return true;
+ return !match(
+ I,
+ m_AnyIntrinsic<Intrinsic::invariant_start, Intrinsic::invariant_end>());
}
static inline void reportFatalOnTokenType(const Instruction *I) {
@@ -1640,21 +1620,8 @@ static void createSaturatedConversionDecoration(Instruction *I,
}
static void addSaturatedDecorationToIntrinsic(Instruction *I, IRBuilder<> &B) {
- if (auto *CI = dyn_cast<CallInst>(I)) {
- if (Function *Fu = CI->getCalledFunction()) {
- if (Fu->isIntrinsic()) {
- unsigned const int IntrinsicId = Fu->getIntrinsicID();
- switch (IntrinsicId) {
- case Intrinsic::fptosi_sat:
- case Intrinsic::fptoui_sat:
- createSaturatedConversionDecoration(I, B);
- break;
- default:
- break;
- }
- }
- }
- }
+ if (match(I, m_AnyIntrinsic<Intrinsic::fptosi_sat, Intrinsic::fptoui_sat>()))
+ createSaturatedConversionDecoration(I, B);
}
Instruction *SPIRVEmitIntrinsics::visitCallInst(CallInst &Call) {
@@ -1745,12 +1712,7 @@ Instruction *SPIRVEmitIntrinsics::visitSwitchInst(SwitchInst &I) {
}
static bool isFirstIndexZero(const GetElementPtrInst *GEP) {
- if (GEP->getNumIndices() == 0)
- return false;
- if (const auto *CI = dyn_cast<ConstantInt>(GEP->getOperand(1))) {
- return CI->getZExtValue() == 0;
- }
- return false;
+ return GEP->getNumIndices() > 0 && match(GEP->getOperand(1), m_Zero());
}
Instruction *SPIRVEmitIntrinsics::visitIntrinsicInst(IntrinsicInst &I) {
@@ -2496,19 +2458,14 @@ bool SPIRVEmitIntrinsics::shouldTryToAddMemAliasingDecoration(
// Add aliasing decorations to internal load and store intrinsics
// and atomic instructions, skipping atomic store as it won't have ID to
// attach the decoration.
- CallInst *CI = dyn_cast<CallInst>(Inst);
+ if (match(Inst, m_AnyIntrinsic<Intrinsic::spv_load, Intrinsic::spv_store>()))
+ return true;
+ auto *CI = dyn_cast<CallInst>(Inst);
if (!CI)
return false;
if (Function *Fun = CI->getCalledFunction()) {
- if (Fun->isIntrinsic()) {
- switch (Fun->getIntrinsicID()) {
- case Intrinsic::spv_load:
- case Intrinsic::spv_store:
- return true;
- default:
- return false;
- }
- }
+ if (Fun->isIntrinsic())
+ return false;
std::string Name = getOclOrSpirvBuiltinDemangledName(Fun->getName());
const std::string Prefix = "__spirv_Atomic";
const bool IsAtomic = Name.find(Prefix) == 0;
@@ -3074,8 +3031,7 @@ SPIRVEmitIntrinsics::simplifyZeroLengthArrayGepInst(GetElementPtrInst *GEP) {
Type *SrcTy = GEP->getSourceElementType();
SmallVector<Value *, 8> Indices(GEP->indices());
ArrayType *ArrTy = dyn_cast<ArrayType>(SrcTy);
- if (ArrTy && ArrTy->getNumElements() == 0 &&
- PatternMatch::match(Indices[0], PatternMatch::m_Zero())) {
+ if (ArrTy && ArrTy->getNumElements() == 0 && match(Indices[0], m_Zero())) {
Indices.erase(Indices.begin());
SrcTy = ArrTy->getElementType();
return GetElementPtrInst::Create(SrcTy, GEP->getPointerOperand(), Indices,
diff --git a/llvm/unittests/IR/PatternMatch.cpp b/llvm/unittests/IR/PatternMatch.cpp
index 8cbec2cba8392..3f81739ef3c7b 100644
--- a/llvm/unittests/IR/PatternMatch.cpp
+++ b/llvm/unittests/IR/PatternMatch.cpp
@@ -2105,6 +2105,38 @@ TEST_F(PatternMatchTest, IntrinsicMatcher) {
m_SpecificInt(10))));
}
+TEST_F(PatternMatchTest, AnyIntrinsicMatcher) {
+ Value *Ops0[] = {IRB.getInt32(0)};
+ Value *Ops1[] = {IRB.getInt32(0)};
+ Module *M = BB->getParent()->getParent();
+
+ Function *BswapFn =
+ Intrinsic::getOrInsertDeclaration(M, Intrinsic::bswap, IRB.getInt32Ty());
+ Value *BswapCall = CallInst::Create(BswapFn, Ops0, "", BB);
+
+ Function *CtpopFn =
+ Intrinsic::getOrInsertDeclaration(M, Intrinsic::ctpop, IRB.getInt32Ty());
+ Value *CtpopCall = CallInst::Create(CtpopFn, Ops1, "", BB);
+
+ // Match any of the listed intrinsic IDs.
+ EXPECT_TRUE(
+ match(BswapCall, m_AnyIntrinsic<Intrinsic::bswap, Intrinsic::ctpop>()));
+ EXPECT_TRUE(
+ match(CtpopCall, m_AnyIntrinsic<Intrinsic::bswap, Intrinsic::ctpop>()));
+
+ // Should not match an unlisted intrinsic.
+ EXPECT_FALSE(match(
+ BswapCall, m_AnyIntrinsic<Intrinsic::ctpop, Intrinsic::bitreverse>()));
+
+ // Single ID should work like m_Intrinsic.
+ EXPECT_TRUE(match(BswapCall, m_AnyIntrinsic<Intrinsic::bswap>()));
+ EXPECT_FALSE(match(CtpopCall, m_AnyIntrinsic<Intrinsic::bswap>()));
+
+ // Non-intrinsic call should not match.
+ EXPECT_FALSE(match(IRB.getInt32(0),
+ m_AnyIntrinsic<Intrinsic::bswap, Intrinsic::ctpop>()));
+}
+
namespace {
struct is_unsigned_zero_pred {
More information about the llvm-commits
mailing list