Skip to content

Commit 9c58e4b

Browse files
committed
[patternmatch] Add InstructionOperand_match to support for matching against instructions with misc number of operands.
NOTE: 1. To test this I changed UnaryOp_match to use this under the hood. 2. These types of m_##ID##Inst matchers now will only accept compound types and I added a static assert to verify that this mistake doesn't happen. We previously had matchers that would take an int or the like to match tuple extract patterns. I converted those to use TupleExtractOperation that also properly handles destructures.
1 parent 6818eef commit 9c58e4b

File tree

6 files changed

+121
-188
lines changed

6 files changed

+121
-188
lines changed

include/swift/Basic/STLExtras.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -862,6 +862,17 @@ Iterator removeAdjacentIf(const Iterator first, const Iterator last,
862862
return insertionPoint;
863863
}
864864

865+
namespace detail {
866+
template <bool...> struct bool_pack;
867+
} // namespace detail
868+
869+
template <bool... b>
870+
using all_true =
871+
std::is_same<detail::bool_pack<b..., true>, detail::bool_pack<true, b...>>;
872+
873+
/// traits class for checking whether Ts consists only of compound types.
874+
template <class... Ts>
875+
using are_all_compound = all_true<std::is_compound<Ts>::value...>;
865876

866877
} // end namespace swift
867878

include/swift/SIL/PatternMatch.h

Lines changed: 71 additions & 146 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ template<typename Class>
6868
struct class_match {
6969
template<typename ITy>
7070
bool match(ITy *V) { return isa<Class>(V); }
71+
72+
bool match(SILValue v) { return isa<Class>(&*v); }
7173
};
7274

7375
template<typename Class>
@@ -83,6 +85,8 @@ struct bind_ty {
8385
}
8486
return false;
8587
}
88+
89+
bool match(SILValue v) { return match(&*v); }
8690
};
8791

8892
//===----------------------------------------------------------------------===//
@@ -104,6 +108,8 @@ struct match_combine_or {
104108
return true;
105109
return false;
106110
}
111+
112+
bool match(SILValue v) { return match(&*v); }
107113
};
108114

109115
template<typename LTy, typename RTy>
@@ -113,6 +119,8 @@ struct match_combine_and {
113119

114120
match_combine_and(const LTy &Left, const RTy &Right) : L(Left), R(Right) { }
115121

122+
bool match(SILValue v) { return match(&*v); }
123+
116124
template<typename ITy>
117125
bool match(ITy *V) {
118126
if (L.match(V))
@@ -257,10 +265,10 @@ static inline bool isSameAPIntValue(const APInt &I1, const APInt &I2,
257265
}
258266

259267
// Builtin Integer Matcher
260-
struct integerliteral_ty {
268+
struct specificintegerliteral_ty {
261269
APInt Value;
262270
bool isSigned;
263-
integerliteral_ty(APInt V, bool S) : Value(V), isSigned(S) { }
271+
specificintegerliteral_ty(APInt V, bool S) : Value(V), isSigned(S) {}
264272

265273
template<typename ITy>
266274
bool match(ITy *V) {
@@ -274,7 +282,8 @@ struct integerliteral_ty {
274282
}
275283
};
276284

277-
static inline integerliteral_ty m_IntegerLiteralInst(APInt V, bool isSigned) {
285+
static inline specificintegerliteral_ty
286+
m_SpecificIntegerLiteral(APInt V, bool isSigned) {
278287
return {V, isSigned};
279288
}
280289

@@ -293,187 +302,103 @@ using m_Zero = match_integer<0>;
293302
using m_One = match_integer<1>;
294303

295304
//===----------------------------------------------------------------------===//
296-
// Unary Instructions
305+
// Instruction Operand Matchers
297306
//===----------------------------------------------------------------------===//
298307

299-
template<typename OpMatchTy, SILInstructionKind Kind>
300-
struct UnaryOp_match {
301-
OpMatchTy OpMatch;
308+
namespace detail {
302309

303-
UnaryOp_match(const OpMatchTy &Op) : OpMatch(Op) { }
310+
struct GetOperandsFunctor {
311+
template <size_t... Idx>
312+
std::array<SILValue, sizeof...(Idx)>
313+
operator()(SILInstruction *i, llvm::index_sequence<Idx...> seq) const {
314+
return {i->getOperand(Idx)...};
315+
}
316+
};
304317

305-
bool match(SILNode *node) {
306-
if (node->getKind() != SILNodeKind(Kind))
307-
return false;
318+
template <typename... MatcherTys> struct MatcherFunctor {
319+
std::tuple<MatcherTys...> matchers;
308320

309-
return match(cast<SILInstruction>(node));
310-
}
321+
MatcherFunctor(const MatcherTys &... matchers) : matchers(matchers...) {}
311322

312-
bool match(SILInstruction *I) {
313-
if (I->getKind() != Kind)
314-
return false;
323+
template <typename MatcherTy> bool individual(MatcherTy matcher, SILValue v) {
324+
return matcher.match(v);
325+
}
315326

316-
if (I->getNumOperands() != 1)
317-
return false;
327+
template <size_t... Idx>
328+
std::array<bool, sizeof...(MatcherTys)>
329+
matchHelper(const std::array<SILValue, sizeof...(MatcherTys)> &operands,
330+
llvm::index_sequence<Idx...> seq) {
331+
return {individual(std::get<Idx>(matchers), std::get<Idx>(operands))...};
332+
}
318333

319-
return OpMatch.match(I->getOperand(0));
334+
bool match(SILInstruction *i) {
335+
std::array<SILValue, sizeof...(MatcherTys)> operands =
336+
GetOperandsFunctor{}(i, llvm::index_sequence_for<MatcherTys...>{});
337+
auto tmpResult =
338+
matchHelper(operands, llvm::index_sequence_for<MatcherTys...>{});
339+
for (unsigned i : indices(tmpResult)) {
340+
if (!tmpResult[i])
341+
return false;
342+
}
343+
return true;
320344
}
321345
};
322346

323-
// XMacro for generating a matcher for unary op instructions that can apply
324-
// further matchers to the operands of the unary operation.
325-
#define UNARY_OP_MATCH_WITH_ARG_MATCHER(Class) \
326-
template <typename Ty> \
327-
UnaryOp_match<Ty, SILInstructionKind::Class> \
328-
m_##Class(const Ty &T) { \
329-
return T; \
330-
}
331-
UNARY_OP_MATCH_WITH_ARG_MATCHER(AllocRefDynamicInst)
332-
UNARY_OP_MATCH_WITH_ARG_MATCHER(ConvertFunctionInst)
333-
UNARY_OP_MATCH_WITH_ARG_MATCHER(UpcastInst)
334-
UNARY_OP_MATCH_WITH_ARG_MATCHER(PointerToAddressInst)
335-
UNARY_OP_MATCH_WITH_ARG_MATCHER(AddressToPointerInst)
336-
UNARY_OP_MATCH_WITH_ARG_MATCHER(UncheckedRefCastInst)
337-
UNARY_OP_MATCH_WITH_ARG_MATCHER(UncheckedAddrCastInst)
338-
UNARY_OP_MATCH_WITH_ARG_MATCHER(UncheckedTrivialBitCastInst)
339-
UNARY_OP_MATCH_WITH_ARG_MATCHER(UncheckedBitwiseCastInst)
340-
UNARY_OP_MATCH_WITH_ARG_MATCHER(RawPointerToRefInst)
341-
UNARY_OP_MATCH_WITH_ARG_MATCHER(ThinToThickFunctionInst)
342-
UNARY_OP_MATCH_WITH_ARG_MATCHER(ThickToObjCMetatypeInst)
343-
UNARY_OP_MATCH_WITH_ARG_MATCHER(ObjCToThickMetatypeInst)
344-
UNARY_OP_MATCH_WITH_ARG_MATCHER(ObjCMetatypeToObjectInst)
345-
UNARY_OP_MATCH_WITH_ARG_MATCHER(ObjCExistentialMetatypeToObjectInst)
346-
UNARY_OP_MATCH_WITH_ARG_MATCHER(RetainValueInst)
347-
UNARY_OP_MATCH_WITH_ARG_MATCHER(RetainValueAddrInst)
348-
UNARY_OP_MATCH_WITH_ARG_MATCHER(ReleaseValueInst)
349-
UNARY_OP_MATCH_WITH_ARG_MATCHER(ReleaseValueAddrInst)
350-
UNARY_OP_MATCH_WITH_ARG_MATCHER(AutoreleaseValueInst)
351-
UNARY_OP_MATCH_WITH_ARG_MATCHER(UncheckedEnumDataInst)
352-
UNARY_OP_MATCH_WITH_ARG_MATCHER(InitEnumDataAddrInst)
353-
UNARY_OP_MATCH_WITH_ARG_MATCHER(InjectEnumAddrInst)
354-
UNARY_OP_MATCH_WITH_ARG_MATCHER(UncheckedTakeEnumDataAddrInst)
355-
UNARY_OP_MATCH_WITH_ARG_MATCHER(ValueMetatypeInst)
356-
UNARY_OP_MATCH_WITH_ARG_MATCHER(ExistentialMetatypeInst)
357-
UNARY_OP_MATCH_WITH_ARG_MATCHER(TupleExtractInst)
358-
UNARY_OP_MATCH_WITH_ARG_MATCHER(TupleElementAddrInst)
359-
UNARY_OP_MATCH_WITH_ARG_MATCHER(StructExtractInst)
360-
UNARY_OP_MATCH_WITH_ARG_MATCHER(StructElementAddrInst)
361-
UNARY_OP_MATCH_WITH_ARG_MATCHER(LoadInst)
362-
UNARY_OP_MATCH_WITH_ARG_MATCHER(RefElementAddrInst)
363-
UNARY_OP_MATCH_WITH_ARG_MATCHER(ClassMethodInst)
364-
UNARY_OP_MATCH_WITH_ARG_MATCHER(ObjCMethodInst)
365-
UNARY_OP_MATCH_WITH_ARG_MATCHER(SuperMethodInst)
366-
UNARY_OP_MATCH_WITH_ARG_MATCHER(ObjCSuperMethodInst)
367-
UNARY_OP_MATCH_WITH_ARG_MATCHER(OpenExistentialAddrInst)
368-
UNARY_OP_MATCH_WITH_ARG_MATCHER(OpenExistentialRefInst)
369-
UNARY_OP_MATCH_WITH_ARG_MATCHER(OpenExistentialValueInst)
370-
UNARY_OP_MATCH_WITH_ARG_MATCHER(InitExistentialAddrInst)
371-
UNARY_OP_MATCH_WITH_ARG_MATCHER(InitExistentialValueInst)
372-
UNARY_OP_MATCH_WITH_ARG_MATCHER(InitExistentialRefInst)
373-
UNARY_OP_MATCH_WITH_ARG_MATCHER(DeinitExistentialAddrInst)
374-
UNARY_OP_MATCH_WITH_ARG_MATCHER(DeinitExistentialValueInst)
375-
UNARY_OP_MATCH_WITH_ARG_MATCHER(ProjectBlockStorageInst)
376-
UNARY_OP_MATCH_WITH_ARG_MATCHER(StrongRetainInst)
377-
UNARY_OP_MATCH_WITH_ARG_MATCHER(StrongReleaseInst)
378-
UNARY_OP_MATCH_WITH_ARG_MATCHER(ClassifyBridgeObjectInst)
379-
UNARY_OP_MATCH_WITH_ARG_MATCHER(ValueToBridgeObjectInst)
380-
UNARY_OP_MATCH_WITH_ARG_MATCHER(FixLifetimeInst)
381-
UNARY_OP_MATCH_WITH_ARG_MATCHER(CopyBlockInst)
382-
UNARY_OP_MATCH_WITH_ARG_MATCHER(DeallocStackInst)
383-
UNARY_OP_MATCH_WITH_ARG_MATCHER(DeallocRefInst)
384-
UNARY_OP_MATCH_WITH_ARG_MATCHER(DeallocPartialRefInst)
385-
UNARY_OP_MATCH_WITH_ARG_MATCHER(DeallocBoxInst)
386-
UNARY_OP_MATCH_WITH_ARG_MATCHER(DestroyAddrInst)
387-
UNARY_OP_MATCH_WITH_ARG_MATCHER(CondFailInst)
388-
UNARY_OP_MATCH_WITH_ARG_MATCHER(ReturnInst)
389-
#define LOADABLE_REF_STORAGE_HELPER(Name) \
390-
UNARY_OP_MATCH_WITH_ARG_MATCHER(RefTo##Name##Inst) \
391-
UNARY_OP_MATCH_WITH_ARG_MATCHER(Name##ToRefInst)
392-
#define NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \
393-
UNARY_OP_MATCH_WITH_ARG_MATCHER(Load##Name##Inst)
394-
#define ALWAYS_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \
395-
LOADABLE_REF_STORAGE_HELPER(Name) \
396-
UNARY_OP_MATCH_WITH_ARG_MATCHER(Name##RetainInst) \
397-
UNARY_OP_MATCH_WITH_ARG_MATCHER(Name##ReleaseInst) \
398-
UNARY_OP_MATCH_WITH_ARG_MATCHER(StrongRetain##Name##Inst)
399-
#define SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \
400-
NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, "...") \
401-
ALWAYS_LOADABLE_CHECKED_REF_STORAGE(Name, "...")
402-
#define UNCHECKED_REF_STORAGE(Name, ...) \
403-
LOADABLE_REF_STORAGE_HELPER(Name)
404-
#include "swift/AST/ReferenceStorage.def"
405-
#undef LOADABLE_REF_STORAGE_HELPER
406-
407-
#undef UNARY_OP_MATCH_WITH_ARG_MATCHER
347+
} // namespace detail
408348

409-
//===----------------------------------------------------------------------===//
410-
// Binary Instructions
411-
//===----------------------------------------------------------------------===//
349+
// NOTE: These matchers only can accept compound, non-fundamental
350+
// types. This prevents by mistake passing in int, float, etc to these
351+
// matchers.
352+
template <SILInstructionKind Kind, typename... MatcherTys>
353+
struct InstructionOperand_match {
354+
// This just makes sure that we catch common mistakes passing
355+
// fundamental types (i.e. int, float, etc) to this API.
356+
static_assert(
357+
are_all_compound<MatcherTys...>::value,
358+
"Expected all matcher tys to be non-fundamental compound types?!");
359+
detail::MatcherFunctor<MatcherTys...> matcherFunctor;
412360

413-
template<typename LHSTy, typename RHSTy, SILInstructionKind Kind>
414-
struct BinaryOp_match {
415-
LHSTy L;
416-
RHSTy R;
361+
static constexpr unsigned NumMatchers = sizeof...(MatcherTys);
417362

418-
BinaryOp_match(const LHSTy &LHS, const RHSTy &RHS) : L(LHS), R(RHS) {}
363+
// Only allow for these to be constructed from non-fundamental types.
364+
InstructionOperand_match(const MatcherTys &... matchers)
365+
: matcherFunctor(matchers...) {}
419366

420367
bool match(SILNode *node) {
421368
if (node->getKind() != SILNodeKind(Kind))
422369
return false;
423-
424370
return match(cast<SILInstruction>(node));
425371
}
426372

427-
bool match(SILInstruction *I) {
428-
if (I->getKind() != Kind)
373+
bool match(SILInstruction *i) {
374+
if (i->getKind() != Kind || !(i->getNumOperands() <= NumMatchers))
429375
return false;
430376

431-
if (I->getNumOperands() != 2)
432-
return false;
433-
434-
return L.match((ValueBase *)I->getOperand(0)) &&
435-
R.match((ValueBase *)I->getOperand(1));
377+
return matcherFunctor.match(i);
436378
}
437379
};
438380

439-
template <typename LTy, typename RTy>
440-
BinaryOp_match<LTy, RTy, SILInstructionKind::IndexRawPointerInst>
441-
m_IndexRawPointerInst(const LTy &Left, const RTy &Right) {
442-
return {Left, Right};
443-
}
381+
#define FULL_INST(ID, NAME, PARENT, MEMBEHAVIOR, MAYRELEASE) \
382+
template <typename... MatcherTys> \
383+
InstructionOperand_match<SILInstructionKind::ID, MatcherTys...> m_##ID( \
384+
const MatcherTys &... matchers) { \
385+
return {matchers...}; \
386+
}
387+
#include "swift/SIL/SILNodes.def"
444388

445389
//===----------------------------------------------------------------------===//
446390
// Address/Struct Projections
447391
//===----------------------------------------------------------------------===//
448392

449-
template <typename LTy>
450-
struct tupleextract_ty {
451-
LTy L;
452-
unsigned index;
453-
tupleextract_ty(const LTy &Left, unsigned i) : L(Left), index(i) { }
454-
455-
template <typename ITy>
456-
bool match(ITy *V) {
457-
auto *TEI = dyn_cast<TupleExtractInst>(V);
458-
if (!TEI)
459-
return false;
460-
461-
return TEI->getFieldNo() == index && L.match((ValueBase *)TEI->getOperand());
462-
}
463-
};
464-
465-
template <typename LTy>
466-
tupleextract_ty<LTy> m_TupleExtractInst(const LTy &Left, unsigned Index) {
467-
return tupleextract_ty<LTy>(Left, Index);
468-
}
469-
470393
/// Match either a tuple_extract that the index field from a tuple or the
471394
/// indexth destructure_tuple result.
472395
template <typename LTy> struct tupleextractoperation_ty {
473396
LTy L;
474397
unsigned index;
475398
tupleextractoperation_ty(const LTy &Left, unsigned i) : L(Left), index(i) {}
476399

400+
bool match(SILValue v) { return match(v->getDefiningInstruction()); }
401+
477402
template <typename ITy> bool match(ITy *V) {
478403
if (auto *TEI = dyn_cast<TupleExtractInst>(V)) {
479404
return TEI->getFieldNo() == index &&

lib/SILOptimizer/LoopTransforms/ArrayBoundsCheckOpts.cpp

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,7 @@ static CondFailInst *hasCondFailUse(SILValue V) {
458458
/// a cond_fail on the second result.
459459
static CondFailInst *isOverflowChecked(BuiltinInst *AI) {
460460
for (auto *Op : AI->getUses()) {
461-
if (!match(Op->getUser(), m_TupleExtractInst(m_ValueBase(), 1)))
461+
if (!match(Op->getUser(), m_TupleExtractOperation(m_ValueBase(), 1)))
462462
continue;
463463

464464
TupleExtractInst *TEI = cast<TupleExtractInst>(Op->getUser());
@@ -474,11 +474,10 @@ static bool isSignedLessEqual(SILValue Start, SILValue End, SILBasicBlock &BB) {
474474
// If we have an inclusive range "low...up" the loop exit count will be
475475
// "up + 1" but the overflow check is on "up".
476476
SILValue PreInclusiveEnd;
477-
if (!match(
478-
End,
479-
m_TupleExtractInst(m_ApplyInst(BuiltinValueKind::SAddOver,
480-
m_SILValue(PreInclusiveEnd), m_One()),
481-
0)))
477+
if (!match(End, m_TupleExtractOperation(
478+
m_ApplyInst(BuiltinValueKind::SAddOver,
479+
m_SILValue(PreInclusiveEnd), m_One()),
480+
0)))
482481
PreInclusiveEnd = SILValue();
483482

484483
bool IsPreInclusiveEndLEQ = false;
@@ -811,11 +810,11 @@ class InductionAnalysis {
811810
// Look for a compare of induction variable + 1.
812811
// TODO: obviously we need to handle many more patterns.
813812
if (!match(Cond, m_ApplyInst(BuiltinValueKind::ICMP_EQ,
814-
m_TupleExtractInst(m_Specific(Inc), 0),
813+
m_TupleExtractOperation(m_Specific(Inc), 0),
815814
m_SILValue(End))) &&
816815
!match(Cond,
817816
m_ApplyInst(BuiltinValueKind::ICMP_EQ, m_SILValue(End),
818-
m_TupleExtractInst(m_Specific(Inc), 0)))) {
817+
m_TupleExtractOperation(m_Specific(Inc), 0)))) {
819818
LLVM_DEBUG(llvm::dbgs() << " found no exit condition\n");
820819
return nullptr;
821820
}
@@ -1075,7 +1074,7 @@ static bool isComparisonKnownFalse(BuiltinInst *Builtin,
10751074
// Iteration count + 1 < 0 (start)
10761075
// Iteration count + 1 == 0 (start)
10771076
auto MatchIndVarHeader = m_Specific(IndVar.HeaderVal);
1078-
auto MatchIncrementIndVar = m_TupleExtractInst(
1077+
auto MatchIncrementIndVar = m_TupleExtractOperation(
10791078
m_ApplyInst(BuiltinValueKind::SAddOver, MatchIndVarHeader, m_One()), 0);
10801079
auto MatchIndVarStart = m_Specific(IndVar.Start);
10811080

lib/SILOptimizer/LoopTransforms/LoopUnroll.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -135,10 +135,10 @@ static Optional<uint64_t> getMaxLoopTripCount(SILLoop *Loop,
135135

136136
SILValue RecNext = Cmp->getArguments()[0];
137137
SILPhiArgument *RecArg;
138-
if (!match(RecNext,
139-
m_TupleExtractInst(m_ApplyInst(BuiltinValueKind::SAddOver,
140-
m_SILPhiArgument(RecArg), m_One()),
141-
0)))
138+
if (!match(RecNext, m_TupleExtractOperation(
139+
m_ApplyInst(BuiltinValueKind::SAddOver,
140+
m_SILPhiArgument(RecArg), m_One()),
141+
0)))
142142
return None;
143143

144144
if (RecArg->getParent() != Header)

0 commit comments

Comments
 (0)