| //===- CodeGenDAGPatterns.cpp - Read DAG patterns from .td file -----------===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| // | |
| // This file implements the CodeGenDAGPatterns class, which is used to read and | |
| // represent the patterns present in a .td file for instructions. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "CodeGenDAGPatterns.h" | |
| #include "CodeGenInstruction.h" | |
| #include "CodeGenRegisters.h" | |
| #include "SubtargetFeatureInfo.h" | |
| #include "llvm/ADT/DenseSet.h" | |
| #include "llvm/ADT/MapVector.h" | |
| #include "llvm/ADT/STLExtras.h" | |
| #include "llvm/ADT/SmallSet.h" | |
| #include "llvm/ADT/SmallString.h" | |
| #include "llvm/ADT/StringExtras.h" | |
| #include "llvm/ADT/StringMap.h" | |
| #include "llvm/ADT/Twine.h" | |
| #include "llvm/Support/Debug.h" | |
| #include "llvm/Support/ErrorHandling.h" | |
| #include "llvm/Support/InterleavedRange.h" | |
| #include "llvm/Support/TypeSize.h" | |
| #include "llvm/TableGen/Error.h" | |
| #include "llvm/TableGen/Record.h" | |
| #include <algorithm> | |
| #include <cstdio> | |
| #include <iterator> | |
| #include <set> | |
| using namespace llvm; | |
| #define DEBUG_TYPE "dag-patterns" | |
| static inline bool isIntegerOrPtr(MVT VT) { | |
| return VT.isInteger() || VT == MVT::iPTR; | |
| } | |
| static inline bool isFloatingPoint(MVT VT) { return VT.isFloatingPoint(); } | |
| static inline bool isVector(MVT VT) { return VT.isVector(); } | |
| static inline bool isScalar(MVT VT) { return !VT.isVector(); } | |
| template <typename Predicate> | |
| static bool berase_if(MachineValueTypeSet &S, Predicate P) { | |
| bool Erased = false; | |
| // It is ok to iterate over MachineValueTypeSet and remove elements from it | |
| // at the same time. | |
| for (MVT T : S) { | |
| if (!P(T)) | |
| continue; | |
| Erased = true; | |
| S.erase(T); | |
| } | |
| return Erased; | |
| } | |
| void MachineValueTypeSet::writeToStream(raw_ostream &OS) const { | |
| SmallVector<MVT, 4> Types(begin(), end()); | |
| array_pod_sort(Types.begin(), Types.end()); | |
| OS << '['; | |
| ListSeparator LS(" "); | |
| for (const MVT &T : Types) | |
| OS << LS << ValueTypeByHwMode::getMVTName(T); | |
| OS << ']'; | |
| } | |
| // --- TypeSetByHwMode | |
| // This is a parameterized type-set class. For each mode there is a list | |
| // of types that are currently possible for a given tree node. Type | |
| // inference will apply to each mode separately. | |
| TypeSetByHwMode::TypeSetByHwMode(ArrayRef<ValueTypeByHwMode> VTList) { | |
| // Take the address space from the first type in the list. | |
| if (!VTList.empty()) | |
| PtrAddrSpace = VTList[0].PtrAddrSpace; | |
| for (const ValueTypeByHwMode &VVT : VTList) | |
| insert(VVT); | |
| } | |
| bool TypeSetByHwMode::isValueTypeByHwMode(bool AllowEmpty) const { | |
| for (const auto &I : *this) { | |
| if (I.second.size() > 1) | |
| return false; | |
| if (!AllowEmpty && I.second.empty()) | |
| return false; | |
| } | |
| return true; | |
| } | |
| ValueTypeByHwMode TypeSetByHwMode::getValueTypeByHwMode(bool SkipEmpty) const { | |
| assert(isValueTypeByHwMode(true) && | |
| "The type set has multiple types for at least one HW mode"); | |
| ValueTypeByHwMode VVT; | |
| VVT.PtrAddrSpace = PtrAddrSpace; | |
| for (const auto &I : *this) { | |
| if (SkipEmpty && I.second.empty()) | |
| continue; | |
| MVT T = I.second.empty() ? MVT::Other : *I.second.begin(); | |
| VVT.insertTypeForMode(I.first, T); | |
| } | |
| return VVT; | |
| } | |
| bool TypeSetByHwMode::isPossible() const { | |
| for (const auto &I : *this) | |
| if (!I.second.empty()) | |
| return true; | |
| return false; | |
| } | |
| bool TypeSetByHwMode::insert(const ValueTypeByHwMode &VVT) { | |
| bool Changed = false; | |
| bool ContainsDefault = false; | |
| MVT DT = MVT::Other; | |
| for (const auto &P : VVT) { | |
| unsigned M = P.first; | |
| // Make sure there exists a set for each specific mode from VVT. | |
| Changed |= getOrCreate(M).insert(P.second).second; | |
| // Cache VVT's default mode. | |
| if (DefaultMode == M) { | |
| ContainsDefault = true; | |
| DT = P.second; | |
| } | |
| } | |
| // If VVT has a default mode, add the corresponding type to all | |
| // modes in "this" that do not exist in VVT. | |
| if (ContainsDefault) | |
| for (auto &I : *this) | |
| if (!VVT.hasMode(I.first)) | |
| Changed |= I.second.insert(DT).second; | |
| return Changed; | |
| } | |
| // Constrain the type set to be the intersection with VTS. | |
| bool TypeSetByHwMode::constrain(const TypeSetByHwMode &VTS) { | |
| bool Changed = false; | |
| if (hasDefault()) { | |
| for (const auto &I : VTS) { | |
| unsigned M = I.first; | |
| if (M == DefaultMode || hasMode(M)) | |
| continue; | |
| Map.try_emplace(M, Map.at(DefaultMode)); | |
| Changed = true; | |
| } | |
| } | |
| for (auto &I : *this) { | |
| unsigned M = I.first; | |
| SetType &S = I.second; | |
| if (VTS.hasMode(M) || VTS.hasDefault()) { | |
| Changed |= intersect(I.second, VTS.get(M)); | |
| } else if (!S.empty()) { | |
| S.clear(); | |
| Changed = true; | |
| } | |
| } | |
| return Changed; | |
| } | |
| template <typename Predicate> bool TypeSetByHwMode::constrain(Predicate P) { | |
| bool Changed = false; | |
| for (auto &I : *this) | |
| Changed |= berase_if(I.second, [&P](MVT VT) { return !P(VT); }); | |
| return Changed; | |
| } | |
| template <typename Predicate> | |
| bool TypeSetByHwMode::assign_if(const TypeSetByHwMode &VTS, Predicate P) { | |
| assert(empty()); | |
| for (const auto &I : VTS) { | |
| SetType &S = getOrCreate(I.first); | |
| for (auto J : I.second) | |
| if (P(J)) | |
| S.insert(J); | |
| } | |
| return !empty(); | |
| } | |
| void TypeSetByHwMode::writeToStream(raw_ostream &OS) const { | |
| if (Map.empty()) { | |
| OS << "{}"; | |
| return; | |
| } | |
| OS << '{'; | |
| for (const auto &[Mode, Types] : Map) { | |
| OS << ' ' << getModeName(Mode) << ':'; | |
| Types.writeToStream(OS); | |
| } | |
| OS << " }"; | |
| } | |
| bool TypeSetByHwMode::operator==(const TypeSetByHwMode &VTS) const { | |
| // The isSimple call is much quicker than hasDefault - check this first. | |
| bool IsSimple = isSimple(); | |
| bool VTSIsSimple = VTS.isSimple(); | |
| if (IsSimple && VTSIsSimple) | |
| return getSimple() == VTS.getSimple(); | |
| // Speedup: We have a default if the set is simple. | |
| bool HaveDefault = IsSimple || hasDefault(); | |
| bool VTSHaveDefault = VTSIsSimple || VTS.hasDefault(); | |
| if (HaveDefault != VTSHaveDefault) | |
| return false; | |
| SmallSet<unsigned, 4> Modes; | |
| Modes.insert_range(llvm::make_first_range(*this)); | |
| Modes.insert_range(llvm::make_first_range(VTS)); | |
| if (HaveDefault) { | |
| // Both sets have default mode. | |
| for (unsigned M : Modes) { | |
| if (get(M) != VTS.get(M)) | |
| return false; | |
| } | |
| } else { | |
| // Neither set has default mode. | |
| for (unsigned M : Modes) { | |
| // If there is no default mode, an empty set is equivalent to not having | |
| // the corresponding mode. | |
| bool NoModeThis = !hasMode(M) || get(M).empty(); | |
| bool NoModeVTS = !VTS.hasMode(M) || VTS.get(M).empty(); | |
| if (NoModeThis != NoModeVTS) | |
| return false; | |
| if (!NoModeThis) | |
| if (get(M) != VTS.get(M)) | |
| return false; | |
| } | |
| } | |
| return true; | |
| } | |
| raw_ostream &llvm::operator<<(raw_ostream &OS, const MachineValueTypeSet &T) { | |
| T.writeToStream(OS); | |
| return OS; | |
| } | |
| raw_ostream &llvm::operator<<(raw_ostream &OS, const TypeSetByHwMode &T) { | |
| T.writeToStream(OS); | |
| return OS; | |
| } | |
| LLVM_DUMP_METHOD | |
| void TypeSetByHwMode::dump() const { dbgs() << *this << '\n'; } | |
| bool TypeSetByHwMode::intersect(SetType &Out, const SetType &In) { | |
| auto IntersectP = [&](std::optional<MVT> WildVT, function_ref<bool(MVT)> P) { | |
| // Complement of In within this partition. | |
| auto CompIn = [&](MVT T) -> bool { return !In.count(T) && P(T); }; | |
| if (!WildVT) | |
| return berase_if(Out, CompIn); | |
| bool OutW = Out.count(*WildVT), InW = In.count(*WildVT); | |
| if (OutW == InW) | |
| return berase_if(Out, CompIn); | |
| // Compute the intersection of scalars separately to account for only one | |
| // set containing WildVT. | |
| // The intersection of WildVT with a set of corresponding types that does | |
| // not include WildVT will result in the most specific type: | |
| // - WildVT is more specific than any set with two elements or more | |
| // - WildVT is less specific than any single type. | |
| // For example, for iPTR and scalar integer types | |
| // { iPTR } * { i32 } -> { i32 } | |
| // { iPTR } * { i32 i64 } -> { iPTR } | |
| // and | |
| // { iPTR i32 } * { i32 } -> { i32 } | |
| // { iPTR i32 } * { i32 i64 } -> { i32 i64 } | |
| // { iPTR i32 } * { i32 i64 i128 } -> { iPTR i32 } | |
| // Looking at just this partition, let In' = elements only in In, | |
| // Out' = elements only in Out, and IO = elements common to both. Normally | |
| // IO would be returned as the result of the intersection, but we need to | |
| // account for WildVT being a "wildcard" of sorts. Since elements in IO are | |
| // those that match both sets exactly, they will all belong to the output. | |
| // If any of the "leftovers" (i.e. In' or Out') contain WildVT, it means | |
| // that the other set doesn't have it, but it could have (1) a more | |
| // specific type, or (2) a set of types that is less specific. The | |
| // "leftovers" from the other set is what we want to examine more closely. | |
| auto Leftovers = [&](const SetType &A, const SetType &B) { | |
| SetType Diff = A; | |
| berase_if(Diff, [&](MVT T) { return B.count(T) || !P(T); }); | |
| return Diff; | |
| }; | |
| if (InW) { | |
| SetType OutLeftovers = Leftovers(Out, In); | |
| if (OutLeftovers.size() < 2) { | |
| // WildVT not added to Out. Keep the possible single leftover. | |
| return false; | |
| } | |
| // WildVT replaces the leftovers. | |
| berase_if(Out, CompIn); | |
| Out.insert(*WildVT); | |
| return true; | |
| } | |
| // OutW == true | |
| SetType InLeftovers = Leftovers(In, Out); | |
| unsigned SizeOut = Out.size(); | |
| berase_if(Out, CompIn); // This will remove at least the WildVT. | |
| if (InLeftovers.size() < 2) { | |
| // WildVT deleted from Out. Add back the possible single leftover. | |
| Out.insert(InLeftovers); | |
| return true; | |
| } | |
| // Keep the WildVT in Out. | |
| Out.insert(*WildVT); | |
| // If WildVT was the only element initially removed from Out, then Out | |
| // has not changed. | |
| return SizeOut != Out.size(); | |
| }; | |
| // Note: must be non-overlapping | |
| using WildPartT = std::pair<MVT, std::function<bool(MVT)>>; | |
| static const WildPartT WildParts[] = { | |
| {MVT::iPTR, [](MVT T) { return T.isScalarInteger() || T == MVT::iPTR; }}, | |
| {MVT::cPTR, | |
| [](MVT T) { return T.isCheriCapability() || T == MVT::cPTR; }}, | |
| }; | |
| bool Changed = false; | |
| for (const auto &I : WildParts) | |
| Changed |= IntersectP(I.first, I.second); | |
| Changed |= IntersectP(std::nullopt, [&](MVT T) { | |
| return !any_of(WildParts, [=](const WildPartT &I) { return I.second(T); }); | |
| }); | |
| return Changed; | |
| } | |
| bool TypeSetByHwMode::validate() const { | |
| if (empty()) | |
| return true; | |
| bool AllEmpty = true; | |
| for (const auto &I : *this) | |
| AllEmpty &= I.second.empty(); | |
| return !AllEmpty; | |
| } | |
| // --- TypeInfer | |
| bool TypeInfer::MergeInTypeInfo(TypeSetByHwMode &Out, | |
| const TypeSetByHwMode &In) const { | |
| ValidateOnExit _1(Out, *this); | |
| In.validate(); | |
| if (In.empty() || Out == In || TP.hasError()) | |
| return false; | |
| if (Out.empty()) { | |
| Out = In; | |
| return true; | |
| } | |
| bool Changed = Out.constrain(In); | |
| if (Changed && Out.empty()) | |
| TP.error("Type contradiction"); | |
| return Changed; | |
| } | |
| bool TypeInfer::forceArbitrary(TypeSetByHwMode &Out) { | |
| ValidateOnExit _1(Out, *this); | |
| if (TP.hasError()) | |
| return false; | |
| assert(!Out.empty() && "cannot pick from an empty set"); | |
| bool Changed = false; | |
| for (auto &I : Out) { | |
| TypeSetByHwMode::SetType &S = I.second; | |
| if (S.size() <= 1) | |
| continue; | |
| MVT T = *S.begin(); // Pick the first element. | |
| S.clear(); | |
| S.insert(T); | |
| Changed = true; | |
| } | |
| return Changed; | |
| } | |
| bool TypeInfer::EnforceInteger(TypeSetByHwMode &Out) { | |
| ValidateOnExit _1(Out, *this); | |
| if (TP.hasError()) | |
| return false; | |
| if (!Out.empty()) | |
| return Out.constrain(isIntegerOrPtr); | |
| return Out.assign_if(getLegalTypes(), isIntegerOrPtr); | |
| } | |
| bool TypeInfer::EnforceFloatingPoint(TypeSetByHwMode &Out) { | |
| ValidateOnExit _1(Out, *this); | |
| if (TP.hasError()) | |
| return false; | |
| if (!Out.empty()) | |
| return Out.constrain(isFloatingPoint); | |
| return Out.assign_if(getLegalTypes(), isFloatingPoint); | |
| } | |
| bool TypeInfer::EnforceScalar(TypeSetByHwMode &Out) { | |
| ValidateOnExit _1(Out, *this); | |
| if (TP.hasError()) | |
| return false; | |
| if (!Out.empty()) | |
| return Out.constrain(isScalar); | |
| return Out.assign_if(getLegalTypes(), isScalar); | |
| } | |
| bool TypeInfer::EnforceVector(TypeSetByHwMode &Out) { | |
| ValidateOnExit _1(Out, *this); | |
| if (TP.hasError()) | |
| return false; | |
| if (!Out.empty()) | |
| return Out.constrain(isVector); | |
| return Out.assign_if(getLegalTypes(), isVector); | |
| } | |
| bool TypeInfer::EnforceAny(TypeSetByHwMode &Out) { | |
| ValidateOnExit _1(Out, *this); | |
| if (TP.hasError() || !Out.empty()) | |
| return false; | |
| Out = getLegalTypes(); | |
| return true; | |
| } | |
| template <typename Iter, typename Pred, typename Less> | |
| static Iter min_if(Iter B, Iter E, Pred P, Less L) { | |
| if (B == E) | |
| return E; | |
| Iter Min = E; | |
| for (Iter I = B; I != E; ++I) { | |
| if (!P(*I)) | |
| continue; | |
| if (Min == E || L(*I, *Min)) | |
| Min = I; | |
| } | |
| return Min; | |
| } | |
| template <typename Iter, typename Pred, typename Less> | |
| static Iter max_if(Iter B, Iter E, Pred P, Less L) { | |
| if (B == E) | |
| return E; | |
| Iter Max = E; | |
| for (Iter I = B; I != E; ++I) { | |
| if (!P(*I)) | |
| continue; | |
| if (Max == E || L(*Max, *I)) | |
| Max = I; | |
| } | |
| return Max; | |
| } | |
| /// Make sure that for each type in Small, there exists a larger type in Big. | |
| bool TypeInfer::EnforceSmallerThan(TypeSetByHwMode &Small, TypeSetByHwMode &Big, | |
| bool SmallIsVT) { | |
| ValidateOnExit _1(Small, *this), _2(Big, *this); | |
| if (TP.hasError()) | |
| return false; | |
| bool Changed = false; | |
| assert((!SmallIsVT || !Small.empty()) && | |
| "Small should not be empty for SDTCisVTSmallerThanOp"); | |
| if (Small.empty()) | |
| Changed |= EnforceAny(Small); | |
| if (Big.empty()) | |
| Changed |= EnforceAny(Big); | |
| assert(Small.hasDefault() && Big.hasDefault()); | |
| SmallVector<unsigned, 4> Modes; | |
| union_modes(Small, Big, Modes); | |
| // 1. Only allow integer or floating point types and make sure that | |
| // both sides are both integer or both floating point. | |
| // 2. Make sure that either both sides have vector types, or neither | |
| // of them does. | |
| for (unsigned M : Modes) { | |
| TypeSetByHwMode::SetType &S = Small.get(M); | |
| TypeSetByHwMode::SetType &B = Big.get(M); | |
| assert((!SmallIsVT || !S.empty()) && "Expected non-empty type"); | |
| if (any_of(S, isIntegerOrPtr) && any_of(B, isIntegerOrPtr)) { | |
| auto NotInt = [](MVT VT) { return !isIntegerOrPtr(VT); }; | |
| Changed |= berase_if(S, NotInt); | |
| Changed |= berase_if(B, NotInt); | |
| } else if (any_of(S, isFloatingPoint) && any_of(B, isFloatingPoint)) { | |
| auto NotFP = [](MVT VT) { return !isFloatingPoint(VT); }; | |
| Changed |= berase_if(S, NotFP); | |
| Changed |= berase_if(B, NotFP); | |
| } else if (SmallIsVT && B.empty()) { | |
| // B is empty and since S is a specific VT, it will never be empty. Don't | |
| // report this as a change, just clear S and continue. This prevents an | |
| // infinite loop. | |
| S.clear(); | |
| } else if (S.empty() || B.empty()) { | |
| Changed = !S.empty() || !B.empty(); | |
| S.clear(); | |
| B.clear(); | |
| } else { | |
| TP.error("Incompatible types"); | |
| return Changed; | |
| } | |
| if (none_of(S, isVector) || none_of(B, isVector)) { | |
| Changed |= berase_if(S, isVector); | |
| Changed |= berase_if(B, isVector); | |
| } | |
| } | |
| auto LT = [](MVT A, MVT B) -> bool { | |
| // Always treat non-scalable MVTs as smaller than scalable MVTs for the | |
| // purposes of ordering. | |
| auto ASize = std::tuple(A.isScalableVector(), A.getScalarSizeInBits(), | |
| A.getSizeInBits().getKnownMinValue()); | |
| auto BSize = std::tuple(B.isScalableVector(), B.getScalarSizeInBits(), | |
| B.getSizeInBits().getKnownMinValue()); | |
| return ASize < BSize; | |
| }; | |
| auto SameKindLE = [](MVT A, MVT B) -> bool { | |
| // This function is used when removing elements: when a vector is compared | |
| // to a non-vector or a scalable vector to any non-scalable MVT, it should | |
| // return false (to avoid removal). | |
| if (std::tuple(A.isVector(), A.isScalableVector()) != | |
| std::tuple(B.isVector(), B.isScalableVector())) | |
| return false; | |
| return std::tuple(A.getScalarSizeInBits(), | |
| A.getSizeInBits().getKnownMinValue()) <= | |
| std::tuple(B.getScalarSizeInBits(), | |
| B.getSizeInBits().getKnownMinValue()); | |
| }; | |
| for (unsigned M : Modes) { | |
| TypeSetByHwMode::SetType &S = Small.get(M); | |
| TypeSetByHwMode::SetType &B = Big.get(M); | |
| // MinS = min scalar in Small, remove all scalars from Big that are | |
| // smaller-or-equal than MinS. | |
| auto MinS = min_if(S.begin(), S.end(), isScalar, LT); | |
| if (MinS != S.end()) | |
| Changed |= | |
| berase_if(B, std::bind(SameKindLE, std::placeholders::_1, *MinS)); | |
| // MaxS = max scalar in Big, remove all scalars from Small that are | |
| // larger than MaxS. | |
| auto MaxS = max_if(B.begin(), B.end(), isScalar, LT); | |
| if (MaxS != B.end()) | |
| Changed |= | |
| berase_if(S, std::bind(SameKindLE, *MaxS, std::placeholders::_1)); | |
| // MinV = min vector in Small, remove all vectors from Big that are | |
| // smaller-or-equal than MinV. | |
| auto MinV = min_if(S.begin(), S.end(), isVector, LT); | |
| if (MinV != S.end()) | |
| Changed |= | |
| berase_if(B, std::bind(SameKindLE, std::placeholders::_1, *MinV)); | |
| // MaxV = max vector in Big, remove all vectors from Small that are | |
| // larger than MaxV. | |
| auto MaxV = max_if(B.begin(), B.end(), isVector, LT); | |
| if (MaxV != B.end()) | |
| Changed |= | |
| berase_if(S, std::bind(SameKindLE, *MaxV, std::placeholders::_1)); | |
| } | |
| return Changed; | |
| } | |
| /// 1. Ensure that for each type T in Vec, T is a vector type, and that | |
| /// for each type U in Elem, U is a scalar type. | |
| /// 2. Ensure that for each (scalar) type U in Elem, there exists a (vector) | |
| /// type T in Vec, such that U is the element type of T. | |
| bool TypeInfer::EnforceVectorEltTypeIs(TypeSetByHwMode &Vec, | |
| TypeSetByHwMode &Elem) { | |
| ValidateOnExit _1(Vec, *this), _2(Elem, *this); | |
| if (TP.hasError()) | |
| return false; | |
| bool Changed = false; | |
| if (Vec.empty()) | |
| Changed |= EnforceVector(Vec); | |
| if (Elem.empty()) | |
| Changed |= EnforceScalar(Elem); | |
| SmallVector<unsigned, 4> Modes; | |
| union_modes(Vec, Elem, Modes); | |
| for (unsigned M : Modes) { | |
| TypeSetByHwMode::SetType &V = Vec.get(M); | |
| TypeSetByHwMode::SetType &E = Elem.get(M); | |
| Changed |= berase_if(V, isScalar); // Scalar = !vector | |
| Changed |= berase_if(E, isVector); // Vector = !scalar | |
| assert(!V.empty() && !E.empty()); | |
| MachineValueTypeSet VT, ST; | |
| // Collect element types from the "vector" set. | |
| for (MVT T : V) | |
| VT.insert(T.getVectorElementType()); | |
| // Collect scalar types from the "element" set. | |
| for (MVT T : E) | |
| ST.insert(T); | |
| // Remove from V all (vector) types whose element type is not in S. | |
| Changed |= berase_if(V, [&ST](MVT T) -> bool { | |
| return !ST.count(T.getVectorElementType()); | |
| }); | |
| // Remove from E all (scalar) types, for which there is no corresponding | |
| // type in V. | |
| Changed |= berase_if(E, [&VT](MVT T) -> bool { return !VT.count(T); }); | |
| } | |
| return Changed; | |
| } | |
| bool TypeInfer::EnforceVectorEltTypeIs(TypeSetByHwMode &Vec, | |
| const ValueTypeByHwMode &VVT) { | |
| TypeSetByHwMode Tmp(VVT); | |
| ValidateOnExit _1(Vec, *this), _2(Tmp, *this); | |
| return EnforceVectorEltTypeIs(Vec, Tmp); | |
| } | |
| /// Ensure that for each type T in Sub, T is a vector type, and there | |
| /// exists a type U in Vec such that U is a vector type with the same | |
| /// element type as T and at least as many elements as T. | |
| bool TypeInfer::EnforceVectorSubVectorTypeIs(TypeSetByHwMode &Vec, | |
| TypeSetByHwMode &Sub) { | |
| ValidateOnExit _1(Vec, *this), _2(Sub, *this); | |
| if (TP.hasError()) | |
| return false; | |
| /// Return true if B is a suB-vector of P, i.e. P is a suPer-vector of B. | |
| auto IsSubVec = [](MVT B, MVT P) -> bool { | |
| if (!B.isVector() || !P.isVector()) | |
| return false; | |
| // You cannot extract a scalable vector from a fixed length vector. | |
| // You cannot insert a scalable vector into a fixed length vector. | |
| if (B.isScalableVector() && !P.isScalableVector()) | |
| return false; | |
| if (B.getVectorElementType() != P.getVectorElementType()) | |
| return false; | |
| // If the subvector and vector are both fixed or both scalable, require | |
| // the minimum element count to be smaller. | |
| if (B.isScalableVector() == P.isScalableVector()) | |
| return B.getVectorMinNumElements() < P.getVectorMinNumElements(); | |
| // If the subvector is fixed and the vector is scalable, allow the | |
| // minimum number of elements to be less than or equal. Note, if vscale is | |
| // known to be greater than 1, the subvector could have more than the | |
| // minimum number of elements, but that would probably require custom isel. | |
| return B.getVectorMinNumElements() <= P.getVectorMinNumElements(); | |
| }; | |
| /// Return true if S has no element (vector type) that T is a sub-vector of, | |
| /// i.e. has the same element type as T and more elements. | |
| auto NoSubV = [&IsSubVec](const TypeSetByHwMode::SetType &S, MVT T) -> bool { | |
| for (auto I : S) | |
| if (IsSubVec(T, I)) | |
| return false; | |
| return true; | |
| }; | |
| /// Return true if S has no element (vector type) that T is a super-vector | |
| /// of, i.e. has the same element type as T and fewer elements. | |
| auto NoSupV = [&IsSubVec](const TypeSetByHwMode::SetType &S, MVT T) -> bool { | |
| for (auto I : S) | |
| if (IsSubVec(I, T)) | |
| return false; | |
| return true; | |
| }; | |
| bool Changed = false; | |
| if (Vec.empty()) | |
| Changed |= EnforceVector(Vec); | |
| if (Sub.empty()) | |
| Changed |= EnforceVector(Sub); | |
| SmallVector<unsigned, 4> Modes; | |
| union_modes(Vec, Sub, Modes); | |
| for (unsigned M : Modes) { | |
| TypeSetByHwMode::SetType &S = Sub.get(M); | |
| TypeSetByHwMode::SetType &V = Vec.get(M); | |
| Changed |= berase_if(S, isScalar); | |
| // Erase all types from S that are not sub-vectors of a type in V. | |
| Changed |= berase_if(S, std::bind(NoSubV, V, std::placeholders::_1)); | |
| // Erase all types from V that are not super-vectors of a type in S. | |
| Changed |= berase_if(V, std::bind(NoSupV, S, std::placeholders::_1)); | |
| } | |
| return Changed; | |
| } | |
| /// 1. Ensure that V has a scalar type iff W has a scalar type. | |
| /// 2. Ensure that for each vector type T in V, there exists a vector | |
| /// type U in W, such that T and U have the same number of elements. | |
| /// 3. Ensure that for each vector type U in W, there exists a vector | |
| /// type T in V, such that T and U have the same number of elements | |
| /// (reverse of 2). | |
| bool TypeInfer::EnforceSameNumElts(TypeSetByHwMode &V, TypeSetByHwMode &W) { | |
| ValidateOnExit _1(V, *this), _2(W, *this); | |
| if (TP.hasError()) | |
| return false; | |
| bool Changed = false; | |
| if (V.empty()) | |
| Changed |= EnforceAny(V); | |
| if (W.empty()) | |
| Changed |= EnforceAny(W); | |
| // An actual vector type cannot have 0 elements, so we can treat scalars | |
| // as zero-length vectors. This way both vectors and scalars can be | |
| // processed identically. | |
| auto NoLength = [](const SmallDenseSet<ElementCount> &Lengths, | |
| MVT T) -> bool { | |
| return !Lengths.contains(T.isVector() ? T.getVectorElementCount() | |
| : ElementCount()); | |
| }; | |
| SmallVector<unsigned, 4> Modes; | |
| union_modes(V, W, Modes); | |
| for (unsigned M : Modes) { | |
| TypeSetByHwMode::SetType &VS = V.get(M); | |
| TypeSetByHwMode::SetType &WS = W.get(M); | |
| SmallDenseSet<ElementCount> VN, WN; | |
| for (MVT T : VS) | |
| VN.insert(T.isVector() ? T.getVectorElementCount() : ElementCount()); | |
| for (MVT T : WS) | |
| WN.insert(T.isVector() ? T.getVectorElementCount() : ElementCount()); | |
| Changed |= berase_if(VS, std::bind(NoLength, WN, std::placeholders::_1)); | |
| Changed |= berase_if(WS, std::bind(NoLength, VN, std::placeholders::_1)); | |
| } | |
| return Changed; | |
| } | |
| namespace { | |
| struct TypeSizeComparator { | |
| bool operator()(const TypeSize &LHS, const TypeSize &RHS) const { | |
| return std::tuple(LHS.isScalable(), LHS.getKnownMinValue()) < | |
| std::tuple(RHS.isScalable(), RHS.getKnownMinValue()); | |
| } | |
| }; | |
| } // end anonymous namespace | |
| /// 1. Ensure that for each type T in A, there exists a type U in B, | |
| /// such that T and U have equal size in bits. | |
| /// 2. Ensure that for each type U in B, there exists a type T in A | |
| /// such that T and U have equal size in bits (reverse of 1). | |
| bool TypeInfer::EnforceSameSize(TypeSetByHwMode &A, TypeSetByHwMode &B) { | |
| ValidateOnExit _1(A, *this), _2(B, *this); | |
| if (TP.hasError()) | |
| return false; | |
| bool Changed = false; | |
| if (A.empty()) | |
| Changed |= EnforceAny(A); | |
| if (B.empty()) | |
| Changed |= EnforceAny(B); | |
| using TypeSizeSet = SmallSet<TypeSize, 2, TypeSizeComparator>; | |
| auto NoSize = [](const TypeSizeSet &Sizes, MVT T) -> bool { | |
| return !Sizes.contains(T.getSizeInBits()); | |
| }; | |
| SmallVector<unsigned, 4> Modes; | |
| union_modes(A, B, Modes); | |
| for (unsigned M : Modes) { | |
| TypeSetByHwMode::SetType &AS = A.get(M); | |
| TypeSetByHwMode::SetType &BS = B.get(M); | |
| TypeSizeSet AN, BN; | |
| for (MVT T : AS) | |
| AN.insert(T.getSizeInBits()); | |
| for (MVT T : BS) | |
| BN.insert(T.getSizeInBits()); | |
| Changed |= berase_if(AS, std::bind(NoSize, BN, std::placeholders::_1)); | |
| Changed |= berase_if(BS, std::bind(NoSize, AN, std::placeholders::_1)); | |
| } | |
| return Changed; | |
| } | |
| void TypeInfer::expandOverloads(TypeSetByHwMode &VTS) const { | |
| ValidateOnExit _1(VTS, *this); | |
| const TypeSetByHwMode &Legal = getLegalTypes(); | |
| assert(Legal.isSimple() && "Default-mode only expected"); | |
| const TypeSetByHwMode::SetType &LegalTypes = Legal.getSimple(); | |
| for (auto &I : VTS) | |
| expandOverloads(I.second, LegalTypes); | |
| } | |
| void TypeInfer::expandOverloads(TypeSetByHwMode::SetType &Out, | |
| const TypeSetByHwMode::SetType &Legal) const { | |
| if (Out.count(MVT::pAny)) { | |
| Out.erase(MVT::pAny); | |
| Out.insert(MVT::iPTR); | |
| for (MVT T : MVT::cheri_capability_valuetypes()) { | |
| if (Legal.count(T)) | |
| Out.insert(MVT::cPTR); | |
| } | |
| } else if (Out.count(MVT::iAny)) { | |
| Out.erase(MVT::iAny); | |
| for (MVT T : MVT::integer_valuetypes()) | |
| if (Legal.count(T)) | |
| Out.insert(T); | |
| for (MVT T : MVT::integer_fixedlen_vector_valuetypes()) | |
| if (Legal.count(T)) | |
| Out.insert(T); | |
| for (MVT T : MVT::integer_scalable_vector_valuetypes()) | |
| if (Legal.count(T)) | |
| Out.insert(T); | |
| } else if (Out.count(MVT::fAny)) { | |
| Out.erase(MVT::fAny); | |
| for (MVT T : MVT::fp_valuetypes()) | |
| if (Legal.count(T)) | |
| Out.insert(T); | |
| for (MVT T : MVT::fp_fixedlen_vector_valuetypes()) | |
| if (Legal.count(T)) | |
| Out.insert(T); | |
| for (MVT T : MVT::fp_scalable_vector_valuetypes()) | |
| if (Legal.count(T)) | |
| Out.insert(T); | |
| } else if (Out.count(MVT::vAny)) { | |
| Out.erase(MVT::vAny); | |
| for (MVT T : MVT::vector_valuetypes()) | |
| if (Legal.count(T)) | |
| Out.insert(T); | |
| } else if (Out.count(MVT::Any)) { | |
| Out.erase(MVT::Any); | |
| for (MVT T : MVT::all_valuetypes()) | |
| if (Legal.count(T)) | |
| Out.insert(T); | |
| } | |
| } | |
| const TypeSetByHwMode &TypeInfer::getLegalTypes() const { | |
| if (!LegalTypesCached) { | |
| TypeSetByHwMode::SetType &LegalTypes = LegalCache.getOrCreate(DefaultMode); | |
| // Stuff all types from all modes into the default mode. | |
| const TypeSetByHwMode <S = TP.getDAGPatterns().getLegalTypes(); | |
| for (const auto &I : LTS) | |
| LegalTypes.insert(I.second); | |
| LegalTypesCached = true; | |
| } | |
| assert(LegalCache.isSimple() && "Default-mode only expected"); | |
| return LegalCache; | |
| } | |
| TypeInfer::ValidateOnExit::~ValidateOnExit() { | |
| if (Infer.Validate && !VTS.validate()) { | |
| #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) | |
| errs() << "Type set is empty for each HW mode:\n" | |
| "possible type contradiction in the pattern below " | |
| "(use -print-records with llvm-tblgen to see all " | |
| "expanded records).\n"; | |
| Infer.TP.dump(); | |
| errs() << "Generated from record:\n"; | |
| Infer.TP.getRecord()->dump(); | |
| #endif | |
| PrintFatalError(Infer.TP.getRecord()->getLoc(), | |
| "Type set is empty for each HW mode in '" + | |
| Infer.TP.getRecord()->getName() + "'"); | |
| } | |
| } | |
| //===----------------------------------------------------------------------===// | |
| // ScopedName Implementation | |
| //===----------------------------------------------------------------------===// | |
| bool ScopedName::operator==(const ScopedName &o) const { | |
| return Scope == o.Scope && Identifier == o.Identifier; | |
| } | |
| bool ScopedName::operator!=(const ScopedName &o) const { return !(*this == o); } | |
| //===----------------------------------------------------------------------===// | |
| // TreePredicateFn Implementation | |
| //===----------------------------------------------------------------------===// | |
| /// TreePredicateFn constructor. Here 'N' is a subclass of PatFrag. | |
| TreePredicateFn::TreePredicateFn(TreePattern *N) : PatFragRec(N) { | |
| assert( | |
| (!hasPredCode() || !hasImmCode()) && | |
| ".td file corrupt: can't have a node predicate *and* an imm predicate"); | |
| if (hasGISelPredicateCode() && hasGISelLeafPredicateCode()) | |
| PrintFatalError(getOrigPatFragRecord()->getRecord()->getLoc(), | |
| ".td file corrupt: can't have GISelPredicateCode *and* " | |
| "GISelLeafPredicateCode"); | |
| } | |
| bool TreePredicateFn::hasPredCode() const { | |
| return isLoad() || isStore() || isAtomic() || hasNoUse() || hasOneUse() || | |
| !PatFragRec->getRecord()->getValueAsString("PredicateCode").empty(); | |
| } | |
| std::string TreePredicateFn::getPredCode() const { | |
| std::string Code; | |
| if (!isLoad() && !isStore() && !isAtomic() && getMemoryVT()) | |
| PrintFatalError(getOrigPatFragRecord()->getRecord()->getLoc(), | |
| "MemoryVT requires IsLoad or IsStore or IsAtomic"); | |
| if (!isLoad() && !isStore()) { | |
| if (isUnindexed()) | |
| PrintFatalError(getOrigPatFragRecord()->getRecord()->getLoc(), | |
| "IsUnindexed requires IsLoad or IsStore"); | |
| if (getScalarMemoryVT()) | |
| PrintFatalError(getOrigPatFragRecord()->getRecord()->getLoc(), | |
| "ScalarMemoryVT requires IsLoad or IsStore"); | |
| } | |
| if (isLoad() + isStore() + isAtomic() > 1) | |
| PrintFatalError(getOrigPatFragRecord()->getRecord()->getLoc(), | |
| "IsLoad, IsStore, and IsAtomic are mutually exclusive"); | |
| if (isLoad()) { | |
| if (!isUnindexed() && !isNonExtLoad() && !isAnyExtLoad() && | |
| !isSignExtLoad() && !isZeroExtLoad() && getMemoryVT() == nullptr && | |
| getScalarMemoryVT() == nullptr && getAddressSpaces() == nullptr && | |
| getMinAlignment() < 1) | |
| PrintFatalError(getOrigPatFragRecord()->getRecord()->getLoc(), | |
| "IsLoad cannot be used by itself"); | |
| } else if (!isAtomic()) { | |
| if (isNonExtLoad()) | |
| PrintFatalError(getOrigPatFragRecord()->getRecord()->getLoc(), | |
| "IsNonExtLoad requires IsLoad or IsAtomic"); | |
| if (isAnyExtLoad()) | |
| PrintFatalError(getOrigPatFragRecord()->getRecord()->getLoc(), | |
| "IsAnyExtLoad requires IsLoad or IsAtomic"); | |
| if (isSignExtLoad()) | |
| PrintFatalError(getOrigPatFragRecord()->getRecord()->getLoc(), | |
| "IsSignExtLoad requires IsLoad or IsAtomic"); | |
| if (isZeroExtLoad()) | |
| PrintFatalError(getOrigPatFragRecord()->getRecord()->getLoc(), | |
| "IsZeroExtLoad requires IsLoad or IsAtomic"); | |
| } | |
| if (isStore()) { | |
| if (!isUnindexed() && !isTruncStore() && !isNonTruncStore() && | |
| getMemoryVT() == nullptr && getScalarMemoryVT() == nullptr && | |
| getAddressSpaces() == nullptr && getMinAlignment() < 1) | |
| PrintFatalError(getOrigPatFragRecord()->getRecord()->getLoc(), | |
| "IsStore cannot be used by itself"); | |
| } else if (!isAtomic()) { | |
| if (isNonTruncStore()) { | |
| PrintFatalError(getOrigPatFragRecord()->getRecord()->getLoc(), | |
| "IsNonTruncStore requires IsStore or IsAtomic"); | |
| } | |
| if (isTruncStore()) { | |
| PrintFatalError(getOrigPatFragRecord()->getRecord()->getLoc(), | |
| "IsTruncStore requires IsStore or IsAtomic"); | |
| } | |
| } | |
| if (isAtomic()) { | |
| if (getMemoryVT() == nullptr && getAddressSpaces() == nullptr && | |
| // FIXME: Should atomic loads be IsLoad, IsAtomic, or both? | |
| !isNonExtLoad() && !isAnyExtLoad() && !isZeroExtLoad() && | |
| !isSignExtLoad() && !isNonTruncStore() && !isTruncStore() && | |
| !isAtomicOrderingMonotonic() && !isAtomicOrderingAcquire() && | |
| !isAtomicOrderingRelease() && !isAtomicOrderingAcquireRelease() && | |
| !isAtomicOrderingSequentiallyConsistent() && | |
| !isAtomicOrderingAcquireOrStronger() && | |
| !isAtomicOrderingReleaseOrStronger() && | |
| !isAtomicOrderingWeakerThanAcquire() && | |
| !isAtomicOrderingWeakerThanRelease()) | |
| PrintFatalError(getOrigPatFragRecord()->getRecord()->getLoc(), | |
| "IsAtomic cannot be used by itself"); | |
| } else { | |
| if (isAtomicOrderingMonotonic()) | |
| PrintFatalError(getOrigPatFragRecord()->getRecord()->getLoc(), | |
| "IsAtomicOrderingMonotonic requires IsAtomic"); | |
| if (isAtomicOrderingAcquire()) | |
| PrintFatalError(getOrigPatFragRecord()->getRecord()->getLoc(), | |
| "IsAtomicOrderingAcquire requires IsAtomic"); | |
| if (isAtomicOrderingRelease()) | |
| PrintFatalError(getOrigPatFragRecord()->getRecord()->getLoc(), | |
| "IsAtomicOrderingRelease requires IsAtomic"); | |
| if (isAtomicOrderingAcquireRelease()) | |
| PrintFatalError(getOrigPatFragRecord()->getRecord()->getLoc(), | |
| "IsAtomicOrderingAcquireRelease requires IsAtomic"); | |
| if (isAtomicOrderingSequentiallyConsistent()) | |
| PrintFatalError( | |
| getOrigPatFragRecord()->getRecord()->getLoc(), | |
| "IsAtomicOrderingSequentiallyConsistent requires IsAtomic"); | |
| if (isAtomicOrderingAcquireOrStronger()) | |
| PrintFatalError(getOrigPatFragRecord()->getRecord()->getLoc(), | |
| "IsAtomicOrderingAcquireOrStronger requires IsAtomic"); | |
| if (isAtomicOrderingReleaseOrStronger()) | |
| PrintFatalError(getOrigPatFragRecord()->getRecord()->getLoc(), | |
| "IsAtomicOrderingReleaseOrStronger requires IsAtomic"); | |
| if (isAtomicOrderingWeakerThanAcquire()) | |
| PrintFatalError(getOrigPatFragRecord()->getRecord()->getLoc(), | |
| "IsAtomicOrderingWeakerThanAcquire requires IsAtomic"); | |
| } | |
| if (isLoad() || isStore() || isAtomic()) { | |
| if (const ListInit *AddressSpaces = getAddressSpaces()) { | |
| Code += "unsigned AddrSpace = cast<MemSDNode>(N)->getAddressSpace();\n" | |
| " if ("; | |
| ListSeparator LS(" && "); | |
| for (const Init *Val : AddressSpaces->getElements()) { | |
| Code += LS; | |
| const IntInit *IntVal = dyn_cast<IntInit>(Val); | |
| if (!IntVal) { | |
| PrintFatalError(getOrigPatFragRecord()->getRecord()->getLoc(), | |
| "AddressSpaces element must be integer"); | |
| } | |
| Code += "AddrSpace != " + utostr(IntVal->getValue()); | |
| } | |
| Code += ")\nreturn false;\n"; | |
| } | |
| int64_t MinAlign = getMinAlignment(); | |
| if (MinAlign > 0) { | |
| Code += "if (cast<MemSDNode>(N)->getAlign() < Align("; | |
| Code += utostr(MinAlign); | |
| Code += "))\nreturn false;\n"; | |
| } | |
| if (const Record *MemoryVT = getMemoryVT()) | |
| Code += ("if (cast<MemSDNode>(N)->getMemoryVT() != MVT::" + | |
| MemoryVT->getName() + ") return false;\n") | |
| .str(); | |
| } | |
| if (isAtomic() && isAtomicOrderingMonotonic()) | |
| Code += "if (cast<AtomicSDNode>(N)->getMergedOrdering() != " | |
| "AtomicOrdering::Monotonic) return false;\n"; | |
| if (isAtomic() && isAtomicOrderingAcquire()) | |
| Code += "if (cast<AtomicSDNode>(N)->getMergedOrdering() != " | |
| "AtomicOrdering::Acquire) return false;\n"; | |
| if (isAtomic() && isAtomicOrderingRelease()) | |
| Code += "if (cast<AtomicSDNode>(N)->getMergedOrdering() != " | |
| "AtomicOrdering::Release) return false;\n"; | |
| if (isAtomic() && isAtomicOrderingAcquireRelease()) | |
| Code += "if (cast<AtomicSDNode>(N)->getMergedOrdering() != " | |
| "AtomicOrdering::AcquireRelease) return false;\n"; | |
| if (isAtomic() && isAtomicOrderingSequentiallyConsistent()) | |
| Code += "if (cast<AtomicSDNode>(N)->getMergedOrdering() != " | |
| "AtomicOrdering::SequentiallyConsistent) return false;\n"; | |
| if (isAtomic() && isAtomicOrderingAcquireOrStronger()) | |
| Code += | |
| "if (!isAcquireOrStronger(cast<AtomicSDNode>(N)->getMergedOrdering())) " | |
| "return false;\n"; | |
| if (isAtomic() && isAtomicOrderingWeakerThanAcquire()) | |
| Code += | |
| "if (isAcquireOrStronger(cast<AtomicSDNode>(N)->getMergedOrdering())) " | |
| "return false;\n"; | |
| if (isAtomic() && isAtomicOrderingReleaseOrStronger()) | |
| Code += | |
| "if (!isReleaseOrStronger(cast<AtomicSDNode>(N)->getMergedOrdering())) " | |
| "return false;\n"; | |
| if (isAtomic() && isAtomicOrderingWeakerThanRelease()) | |
| Code += | |
| "if (isReleaseOrStronger(cast<AtomicSDNode>(N)->getMergedOrdering())) " | |
| "return false;\n"; | |
| if (isAtomic()) { | |
| if ((isNonExtLoad() + isAnyExtLoad() + isSignExtLoad() + isZeroExtLoad()) > | |
| 1) | |
| PrintFatalError( | |
| getOrigPatFragRecord()->getRecord()->getLoc(), | |
| "IsNonExtLoad, IsAnyExtLoad, IsSignExtLoad, and IsZeroExtLoad are " | |
| "mutually exclusive"); | |
| if (isNonExtLoad()) | |
| Code += "if (cast<AtomicSDNode>(N)->getExtensionType() != " | |
| "ISD::NON_EXTLOAD) return false;\n"; | |
| if (isAnyExtLoad()) | |
| Code += "if (cast<AtomicSDNode>(N)->getExtensionType() != ISD::EXTLOAD) " | |
| "return false;\n"; | |
| if (isSignExtLoad()) | |
| Code += "if (cast<AtomicSDNode>(N)->getExtensionType() != ISD::SEXTLOAD) " | |
| "return false;\n"; | |
| if (isZeroExtLoad()) | |
| Code += "if (cast<AtomicSDNode>(N)->getExtensionType() != ISD::ZEXTLOAD) " | |
| "return false;\n"; | |
| if ((isNonTruncStore() + isTruncStore()) > 1) { | |
| PrintFatalError( | |
| getOrigPatFragRecord()->getRecord()->getLoc(), | |
| "IsNonTruncStore, and IsTruncStore are mutually exclusive"); | |
| } | |
| if (isNonTruncStore()) { | |
| Code += "if (cast<AtomicSDNode>(N)->getMemoryVT().getSizeInBits() != " | |
| "cast<AtomicSDNode>(N)->getVal().getValueSizeInBits()) " | |
| "return false;\n"; | |
| } | |
| if (isTruncStore()) { | |
| Code += "if (cast<AtomicSDNode>(N)->getMemoryVT().getSizeInBits() == " | |
| "cast<AtomicSDNode>(N)->getVal().getValueSizeInBits()) " | |
| "return false;\n"; | |
| } | |
| } | |
| if (isLoad() || isStore()) { | |
| StringRef SDNodeName = isLoad() ? "LoadSDNode" : "StoreSDNode"; | |
| if (isUnindexed()) | |
| Code += ("if (cast<" + SDNodeName + | |
| ">(N)->getAddressingMode() != ISD::UNINDEXED) " | |
| "return false;\n") | |
| .str(); | |
| if (isLoad()) { | |
| if ((isNonExtLoad() + isAnyExtLoad() + isSignExtLoad() + | |
| isZeroExtLoad()) > 1) | |
| PrintFatalError(getOrigPatFragRecord()->getRecord()->getLoc(), | |
| "IsNonExtLoad, IsAnyExtLoad, IsSignExtLoad, and " | |
| "IsZeroExtLoad are mutually exclusive"); | |
| if (isNonExtLoad()) | |
| Code += "if (cast<LoadSDNode>(N)->getExtensionType() != " | |
| "ISD::NON_EXTLOAD) return false;\n"; | |
| if (isAnyExtLoad()) | |
| Code += "if (cast<LoadSDNode>(N)->getExtensionType() != ISD::EXTLOAD) " | |
| "return false;\n"; | |
| if (isSignExtLoad()) | |
| Code += "if (cast<LoadSDNode>(N)->getExtensionType() != ISD::SEXTLOAD) " | |
| "return false;\n"; | |
| if (isZeroExtLoad()) | |
| Code += "if (cast<LoadSDNode>(N)->getExtensionType() != ISD::ZEXTLOAD) " | |
| "return false;\n"; | |
| } else { | |
| if ((isNonTruncStore() + isTruncStore()) > 1) | |
| PrintFatalError( | |
| getOrigPatFragRecord()->getRecord()->getLoc(), | |
| "IsNonTruncStore, and IsTruncStore are mutually exclusive"); | |
| if (isNonTruncStore()) | |
| Code += | |
| " if (cast<StoreSDNode>(N)->isTruncatingStore()) return false;\n"; | |
| if (isTruncStore()) | |
| Code += | |
| " if (!cast<StoreSDNode>(N)->isTruncatingStore()) return false;\n"; | |
| } | |
| if (const Record *ScalarMemoryVT = getScalarMemoryVT()) | |
| Code += ("if (cast<" + SDNodeName + | |
| ">(N)->getMemoryVT().getScalarType() != MVT::" + | |
| ScalarMemoryVT->getName() + ") return false;\n") | |
| .str(); | |
| } | |
| if (hasNoUse()) | |
| Code += "if (N->hasAnyUseOfValue(0)) return false;\n"; | |
| if (hasOneUse()) | |
| Code += "if (!N->hasNUsesOfValue(1, 0)) return false;\n"; | |
| std::string PredicateCode = | |
| PatFragRec->getRecord()->getValueAsString("PredicateCode").str(); | |
| Code += PredicateCode; | |
| if (PredicateCode.empty() && !Code.empty()) | |
| Code += "return true;\n"; | |
| return Code; | |
| } | |
| bool TreePredicateFn::hasImmCode() const { | |
| return !PatFragRec->getRecord()->getValueAsString("ImmediateCode").empty(); | |
| } | |
| std::string TreePredicateFn::getImmCode() const { | |
| return PatFragRec->getRecord()->getValueAsString("ImmediateCode").str(); | |
| } | |
| bool TreePredicateFn::immCodeUsesAPInt() const { | |
| return getOrigPatFragRecord()->getRecord()->getValueAsBit("IsAPInt"); | |
| } | |
| bool TreePredicateFn::immCodeUsesAPFloat() const { | |
| bool Unset; | |
| // The return value will be false when IsAPFloat is unset. | |
| return getOrigPatFragRecord()->getRecord()->getValueAsBitOrUnset("IsAPFloat", | |
| Unset); | |
| } | |
| bool TreePredicateFn::isPredefinedPredicateEqualTo(StringRef Field, | |
| bool Value) const { | |
| bool Unset; | |
| bool Result = | |
| getOrigPatFragRecord()->getRecord()->getValueAsBitOrUnset(Field, Unset); | |
| if (Unset) | |
| return false; | |
| return Result == Value; | |
| } | |
| bool TreePredicateFn::usesOperands() const { | |
| return isPredefinedPredicateEqualTo("PredicateCodeUsesOperands", true); | |
| } | |
| bool TreePredicateFn::hasNoUse() const { | |
| return isPredefinedPredicateEqualTo("HasNoUse", true); | |
| } | |
| bool TreePredicateFn::hasOneUse() const { | |
| return isPredefinedPredicateEqualTo("HasOneUse", true); | |
| } | |
| bool TreePredicateFn::isLoad() const { | |
| return isPredefinedPredicateEqualTo("IsLoad", true); | |
| } | |
| bool TreePredicateFn::isStore() const { | |
| return isPredefinedPredicateEqualTo("IsStore", true); | |
| } | |
| bool TreePredicateFn::isAtomic() const { | |
| return isPredefinedPredicateEqualTo("IsAtomic", true); | |
| } | |
| bool TreePredicateFn::isUnindexed() const { | |
| return isPredefinedPredicateEqualTo("IsUnindexed", true); | |
| } | |
| bool TreePredicateFn::isNonExtLoad() const { | |
| return isPredefinedPredicateEqualTo("IsNonExtLoad", true); | |
| } | |
| bool TreePredicateFn::isAnyExtLoad() const { | |
| return isPredefinedPredicateEqualTo("IsAnyExtLoad", true); | |
| } | |
| bool TreePredicateFn::isSignExtLoad() const { | |
| return isPredefinedPredicateEqualTo("IsSignExtLoad", true); | |
| } | |
| bool TreePredicateFn::isZeroExtLoad() const { | |
| return isPredefinedPredicateEqualTo("IsZeroExtLoad", true); | |
| } | |
| bool TreePredicateFn::isNonTruncStore() const { | |
| return isPredefinedPredicateEqualTo("IsTruncStore", false); | |
| } | |
| bool TreePredicateFn::isTruncStore() const { | |
| return isPredefinedPredicateEqualTo("IsTruncStore", true); | |
| } | |
| bool TreePredicateFn::isAtomicOrderingMonotonic() const { | |
| return isPredefinedPredicateEqualTo("IsAtomicOrderingMonotonic", true); | |
| } | |
| bool TreePredicateFn::isAtomicOrderingAcquire() const { | |
| return isPredefinedPredicateEqualTo("IsAtomicOrderingAcquire", true); | |
| } | |
| bool TreePredicateFn::isAtomicOrderingRelease() const { | |
| return isPredefinedPredicateEqualTo("IsAtomicOrderingRelease", true); | |
| } | |
| bool TreePredicateFn::isAtomicOrderingAcquireRelease() const { | |
| return isPredefinedPredicateEqualTo("IsAtomicOrderingAcquireRelease", true); | |
| } | |
| bool TreePredicateFn::isAtomicOrderingSequentiallyConsistent() const { | |
| return isPredefinedPredicateEqualTo("IsAtomicOrderingSequentiallyConsistent", | |
| true); | |
| } | |
| bool TreePredicateFn::isAtomicOrderingAcquireOrStronger() const { | |
| return isPredefinedPredicateEqualTo("IsAtomicOrderingAcquireOrStronger", | |
| true); | |
| } | |
| bool TreePredicateFn::isAtomicOrderingWeakerThanAcquire() const { | |
| return isPredefinedPredicateEqualTo("IsAtomicOrderingAcquireOrStronger", | |
| false); | |
| } | |
| bool TreePredicateFn::isAtomicOrderingReleaseOrStronger() const { | |
| return isPredefinedPredicateEqualTo("IsAtomicOrderingReleaseOrStronger", | |
| true); | |
| } | |
| bool TreePredicateFn::isAtomicOrderingWeakerThanRelease() const { | |
| return isPredefinedPredicateEqualTo("IsAtomicOrderingReleaseOrStronger", | |
| false); | |
| } | |
| const Record *TreePredicateFn::getMemoryVT() const { | |
| const Record *R = getOrigPatFragRecord()->getRecord(); | |
| if (R->isValueUnset("MemoryVT")) | |
| return nullptr; | |
| return R->getValueAsDef("MemoryVT"); | |
| } | |
| const ListInit *TreePredicateFn::getAddressSpaces() const { | |
| const Record *R = getOrigPatFragRecord()->getRecord(); | |
| if (R->isValueUnset("AddressSpaces")) | |
| return nullptr; | |
| return R->getValueAsListInit("AddressSpaces"); | |
| } | |
| int64_t TreePredicateFn::getMinAlignment() const { | |
| const Record *R = getOrigPatFragRecord()->getRecord(); | |
| if (R->isValueUnset("MinAlignment")) | |
| return 0; | |
| return R->getValueAsInt("MinAlignment"); | |
| } | |
| const Record *TreePredicateFn::getScalarMemoryVT() const { | |
| const Record *R = getOrigPatFragRecord()->getRecord(); | |
| if (R->isValueUnset("ScalarMemoryVT")) | |
| return nullptr; | |
| return R->getValueAsDef("ScalarMemoryVT"); | |
| } | |
| bool TreePredicateFn::hasGISelPredicateCode() const { | |
| return !PatFragRec->getRecord() | |
| ->getValueAsString("GISelPredicateCode") | |
| .empty(); | |
| } | |
| std::string TreePredicateFn::getGISelPredicateCode() const { | |
| return PatFragRec->getRecord()->getValueAsString("GISelPredicateCode").str(); | |
| } | |
| bool TreePredicateFn::hasGISelLeafPredicateCode() const { | |
| return PatFragRec->getRecord() | |
| ->getValueAsOptionalString("GISelLeafPredicateCode") | |
| .has_value(); | |
| } | |
| std::string TreePredicateFn::getGISelLeafPredicateCode() const { | |
| return PatFragRec->getRecord() | |
| ->getValueAsOptionalString("GISelLeafPredicateCode") | |
| .value_or(StringRef()) | |
| .str(); | |
| } | |
| StringRef TreePredicateFn::getImmType() const { | |
| if (immCodeUsesAPInt()) | |
| return "const APInt &"; | |
| if (immCodeUsesAPFloat()) | |
| return "const APFloat &"; | |
| return "int64_t"; | |
| } | |
| StringRef TreePredicateFn::getImmTypeIdentifier() const { | |
| if (immCodeUsesAPInt()) | |
| return "APInt"; | |
| if (immCodeUsesAPFloat()) | |
| return "APFloat"; | |
| return "I64"; | |
| } | |
| /// isAlwaysTrue - Return true if this is a noop predicate. | |
| bool TreePredicateFn::isAlwaysTrue() const { | |
| return !hasPredCode() && !hasImmCode(); | |
| } | |
| /// Return the name to use in the generated code to reference this, this is | |
| /// "Predicate_foo" if from a pattern fragment "foo". | |
| std::string TreePredicateFn::getFnName() const { | |
| return "Predicate_" + PatFragRec->getRecord()->getName().str(); | |
| } | |
| /// getCodeToRunOnSDNode - Return the code for the function body that | |
| /// evaluates this predicate. The argument is expected to be in "Node", | |
| /// not N. This handles casting and conversion to a concrete node type as | |
| /// appropriate. | |
| std::string TreePredicateFn::getCodeToRunOnSDNode() const { | |
| // Handle immediate predicates first. | |
| std::string ImmCode = getImmCode(); | |
| if (!ImmCode.empty()) { | |
| if (isLoad()) | |
| PrintFatalError(getOrigPatFragRecord()->getRecord()->getLoc(), | |
| "IsLoad cannot be used with ImmLeaf or its subclasses"); | |
| if (isStore()) | |
| PrintFatalError(getOrigPatFragRecord()->getRecord()->getLoc(), | |
| "IsStore cannot be used with ImmLeaf or its subclasses"); | |
| if (isUnindexed()) | |
| PrintFatalError( | |
| getOrigPatFragRecord()->getRecord()->getLoc(), | |
| "IsUnindexed cannot be used with ImmLeaf or its subclasses"); | |
| if (isNonExtLoad()) | |
| PrintFatalError( | |
| getOrigPatFragRecord()->getRecord()->getLoc(), | |
| "IsNonExtLoad cannot be used with ImmLeaf or its subclasses"); | |
| if (isAnyExtLoad()) | |
| PrintFatalError( | |
| getOrigPatFragRecord()->getRecord()->getLoc(), | |
| "IsAnyExtLoad cannot be used with ImmLeaf or its subclasses"); | |
| if (isSignExtLoad()) | |
| PrintFatalError( | |
| getOrigPatFragRecord()->getRecord()->getLoc(), | |
| "IsSignExtLoad cannot be used with ImmLeaf or its subclasses"); | |
| if (isZeroExtLoad()) | |
| PrintFatalError( | |
| getOrigPatFragRecord()->getRecord()->getLoc(), | |
| "IsZeroExtLoad cannot be used with ImmLeaf or its subclasses"); | |
| if (isNonTruncStore()) | |
| PrintFatalError( | |
| getOrigPatFragRecord()->getRecord()->getLoc(), | |
| "IsNonTruncStore cannot be used with ImmLeaf or its subclasses"); | |
| if (isTruncStore()) | |
| PrintFatalError( | |
| getOrigPatFragRecord()->getRecord()->getLoc(), | |
| "IsTruncStore cannot be used with ImmLeaf or its subclasses"); | |
| if (getMemoryVT()) | |
| PrintFatalError(getOrigPatFragRecord()->getRecord()->getLoc(), | |
| "MemoryVT cannot be used with ImmLeaf or its subclasses"); | |
| if (getScalarMemoryVT()) | |
| PrintFatalError( | |
| getOrigPatFragRecord()->getRecord()->getLoc(), | |
| "ScalarMemoryVT cannot be used with ImmLeaf or its subclasses"); | |
| std::string Result = (" " + getImmType() + " Imm = ").str(); | |
| if (immCodeUsesAPFloat()) | |
| Result += "cast<ConstantFPSDNode>(Op.getNode())->getValueAPF();\n"; | |
| else if (immCodeUsesAPInt()) | |
| Result += "Op->getAsAPIntVal();\n"; | |
| else | |
| Result += "cast<ConstantSDNode>(Op.getNode())->getSExtValue();\n"; | |
| return Result + ImmCode; | |
| } | |
| // Handle arbitrary node predicates. | |
| assert(hasPredCode() && "Don't have any predicate code!"); | |
| // If this is using PatFrags, there are multiple trees to search. They should | |
| // all have the same class. FIXME: Is there a way to find a common | |
| // superclass? | |
| StringRef ClassName; | |
| for (const auto &Tree : PatFragRec->getTrees()) { | |
| StringRef TreeClassName; | |
| if (Tree->isLeaf()) | |
| TreeClassName = "SDNode"; | |
| else { | |
| const Record *Op = Tree->getOperator(); | |
| const SDNodeInfo &Info = PatFragRec->getDAGPatterns().getSDNodeInfo(Op); | |
| TreeClassName = Info.getSDClassName(); | |
| } | |
| if (ClassName.empty()) | |
| ClassName = TreeClassName; | |
| else if (ClassName != TreeClassName) { | |
| PrintFatalError(getOrigPatFragRecord()->getRecord()->getLoc(), | |
| "PatFrags trees do not have consistent class"); | |
| } | |
| } | |
| std::string Result; | |
| if (ClassName == "SDNode") | |
| Result = " SDNode *N = Op.getNode();\n"; | |
| else | |
| Result = " auto *N = cast<" + ClassName.str() + ">(Op.getNode());\n"; | |
| return (Twine(Result) + " (void)N;\n" + getPredCode()).str(); | |
| } | |
| //===----------------------------------------------------------------------===// | |
| // PatternToMatch implementation | |
| // | |
| static bool isImmAllOnesAllZerosMatch(const TreePatternNode &P) { | |
| if (!P.isLeaf()) | |
| return false; | |
| const DefInit *DI = dyn_cast<DefInit>(P.getLeafValue()); | |
| if (!DI) | |
| return false; | |
| const Record *R = DI->getDef(); | |
| return R->getName() == "immAllOnesV" || R->getName() == "immAllZerosV"; | |
| } | |
| /// getPatternSize - Return the 'size' of this pattern. We want to match large | |
| /// patterns before small ones. This is used to determine the size of a | |
| /// pattern. | |
| static unsigned getPatternSize(const TreePatternNode &P, | |
| const CodeGenDAGPatterns &CGP) { | |
| unsigned Size = 3; // The node itself. | |
| // If the root node is a ConstantSDNode, increases its size. | |
| // e.g. (set R32:$dst, 0). | |
| if (P.isLeaf() && isa<IntInit>(P.getLeafValue())) | |
| Size += 2; | |
| if (const ComplexPattern *AM = P.getComplexPatternInfo(CGP)) { | |
| Size += AM->getComplexity(); | |
| // We don't want to count any children twice, so return early. | |
| return Size; | |
| } | |
| // If this node has some predicate function that must match, it adds to the | |
| // complexity of this node. | |
| if (!P.getPredicateCalls().empty()) | |
| ++Size; | |
| // Count children in the count if they are also nodes. | |
| for (const TreePatternNode &Child : P.children()) { | |
| if (!Child.isLeaf() && Child.getNumTypes()) { | |
| // FIXME: Can we assume non-simple VTs should be counted? | |
| auto VVT = Child.getType(0); | |
| if (llvm::any_of(VVT, [](auto &P) { return P.second != MVT::Other; })) { | |
| Size += getPatternSize(Child, CGP); | |
| continue; | |
| } | |
| } | |
| if (Child.isLeaf()) { | |
| if (isa<IntInit>(Child.getLeafValue())) | |
| Size += 5; // Matches a ConstantSDNode (+3) and a specific value (+2). | |
| else if (Child.getComplexPatternInfo(CGP)) | |
| Size += getPatternSize(Child, CGP); | |
| else if (isImmAllOnesAllZerosMatch(Child)) | |
| Size += 4; // Matches a build_vector(+3) and a predicate (+1). | |
| else if (!Child.getPredicateCalls().empty()) | |
| ++Size; | |
| } | |
| } | |
| return Size; | |
| } | |
| /// Compute the complexity metric for the input pattern. This roughly | |
| /// corresponds to the number of nodes that are covered. | |
| int PatternToMatch::getPatternComplexity(const CodeGenDAGPatterns &CGP) const { | |
| return getPatternSize(getSrcPattern(), CGP) + getAddedComplexity(); | |
| } | |
| void PatternToMatch::getPredicateRecords( | |
| SmallVectorImpl<const Record *> &PredicateRecs) const { | |
| for (const Init *I : Predicates->getElements()) { | |
| if (const DefInit *Pred = dyn_cast<DefInit>(I)) { | |
| const Record *Def = Pred->getDef(); | |
| if (!Def->isSubClassOf("Predicate")) { | |
| #ifndef NDEBUG | |
| Def->dump(); | |
| #endif | |
| llvm_unreachable("Unknown predicate type!"); | |
| } | |
| PredicateRecs.push_back(Def); | |
| } | |
| } | |
| // Sort so that different orders get canonicalized to the same string. | |
| llvm::sort(PredicateRecs, LessRecord()); | |
| // Remove duplicate predicates. | |
| PredicateRecs.erase(llvm::unique(PredicateRecs), PredicateRecs.end()); | |
| } | |
| /// getPredicateCheck - Return a single string containing all of this | |
| /// pattern's predicates concatenated with "&&" operators. | |
| /// | |
| std::string PatternToMatch::getPredicateCheck() const { | |
| SmallVector<const Record *, 4> PredicateRecs; | |
| getPredicateRecords(PredicateRecs); | |
| SmallString<128> PredicateCheck; | |
| raw_svector_ostream OS(PredicateCheck); | |
| ListSeparator LS(" && "); | |
| for (const Record *Pred : PredicateRecs) { | |
| StringRef CondString = Pred->getValueAsString("CondString"); | |
| if (CondString.empty()) | |
| continue; | |
| OS << LS << '(' << CondString << ')'; | |
| } | |
| if (!HwModeFeatures.empty()) | |
| OS << LS << HwModeFeatures; | |
| return std::string(PredicateCheck); | |
| } | |
| //===----------------------------------------------------------------------===// | |
| // SDTypeConstraint implementation | |
| // | |
| SDTypeConstraint::SDTypeConstraint(const Record *R, const CodeGenHwModes &CGH) { | |
| OperandNo = R->getValueAsInt("OperandNum"); | |
| if (R->isSubClassOf("SDTCisVT")) { | |
| ConstraintType = SDTCisVT; | |
| VVT = getValueTypeByHwMode(R->getValueAsDef("VT"), CGH); | |
| for (const auto &P : VVT) | |
| if (P.second == MVT::isVoid) | |
| PrintFatalError(R->getLoc(), "Cannot use 'Void' as type to SDTCisVT"); | |
| } else if (R->isSubClassOf("SDTCisPtrTy")) { | |
| ConstraintType = SDTCisPtrTy; | |
| } else if (R->isSubClassOf("SDTCisInt")) { | |
| ConstraintType = SDTCisInt; | |
| } else if (R->isSubClassOf("SDTCisFP")) { | |
| ConstraintType = SDTCisFP; | |
| } else if (R->isSubClassOf("SDTCisVec")) { | |
| ConstraintType = SDTCisVec; | |
| } else if (R->isSubClassOf("SDTCisSameAs")) { | |
| ConstraintType = SDTCisSameAs; | |
| OtherOperandNo = R->getValueAsInt("OtherOperandNum"); | |
| } else if (R->isSubClassOf("SDTCisVTSmallerThanOp")) { | |
| ConstraintType = SDTCisVTSmallerThanOp; | |
| OtherOperandNo = R->getValueAsInt("OtherOperandNum"); | |
| } else if (R->isSubClassOf("SDTCisOpSmallerThanOp")) { | |
| ConstraintType = SDTCisOpSmallerThanOp; | |
| OtherOperandNo = R->getValueAsInt("BigOperandNum"); | |
| } else if (R->isSubClassOf("SDTCisEltOfVec")) { | |
| ConstraintType = SDTCisEltOfVec; | |
| OtherOperandNo = R->getValueAsInt("OtherOpNum"); | |
| } else if (R->isSubClassOf("SDTCisSubVecOfVec")) { | |
| ConstraintType = SDTCisSubVecOfVec; | |
| OtherOperandNo = R->getValueAsInt("OtherOpNum"); | |
| } else if (R->isSubClassOf("SDTCVecEltisVT")) { | |
| ConstraintType = SDTCVecEltisVT; | |
| VVT = getValueTypeByHwMode(R->getValueAsDef("VT"), CGH); | |
| for (const auto &P : VVT) { | |
| MVT T = P.second; | |
| if (T.isVector()) | |
| PrintFatalError(R->getLoc(), | |
| "Cannot use vector type as SDTCVecEltisVT"); | |
| if (!T.isInteger() && !T.isFloatingPoint()) | |
| PrintFatalError(R->getLoc(), "Must use integer or floating point type " | |
| "as SDTCVecEltisVT"); | |
| } | |
| } else if (R->isSubClassOf("SDTCisSameNumEltsAs")) { | |
| ConstraintType = SDTCisSameNumEltsAs; | |
| OtherOperandNo = R->getValueAsInt("OtherOperandNum"); | |
| } else if (R->isSubClassOf("SDTCisSameSizeAs")) { | |
| ConstraintType = SDTCisSameSizeAs; | |
| OtherOperandNo = R->getValueAsInt("OtherOperandNum"); | |
| } else { | |
| PrintFatalError(R->getLoc(), | |
| "Unrecognized SDTypeConstraint '" + R->getName() + "'!\n"); | |
| } | |
| } | |
| /// getOperandNum - Return the node corresponding to operand #OpNo in tree | |
| /// N, and the result number in ResNo. | |
| static TreePatternNode &getOperandNum(unsigned OpNo, TreePatternNode &N, | |
| const SDNodeInfo &NodeInfo, | |
| unsigned &ResNo) { | |
| unsigned NumResults = NodeInfo.getNumResults(); | |
| if (OpNo < NumResults) { | |
| ResNo = OpNo; | |
| return N; | |
| } | |
| OpNo -= NumResults; | |
| if (OpNo >= N.getNumChildren()) { | |
| PrintFatalError([&N, OpNo, NumResults](raw_ostream &OS) { | |
| OS << "Invalid operand number in type constraint " << (OpNo + NumResults); | |
| N.print(OS); | |
| }); | |
| } | |
| return N.getChild(OpNo); | |
| } | |
| /// ApplyTypeConstraint - Given a node in a pattern, apply this type | |
| /// constraint to the nodes operands. This returns true if it makes a | |
| /// change, false otherwise. If a type contradiction is found, flag an error. | |
| bool SDTypeConstraint::ApplyTypeConstraint(TreePatternNode &N, | |
| const SDNodeInfo &NodeInfo, | |
| TreePattern &TP) const { | |
| if (TP.hasError()) | |
| return false; | |
| unsigned ResNo = 0; // The result number being referenced. | |
| TreePatternNode &NodeToApply = getOperandNum(OperandNo, N, NodeInfo, ResNo); | |
| TypeInfer &TI = TP.getInfer(); | |
| switch (ConstraintType) { | |
| case SDTCisVT: | |
| // Operand must be a particular type. | |
| return NodeToApply.UpdateNodeType(ResNo, VVT, TP); | |
| case SDTCisPtrTy: { | |
| // Operand must be a legal pointer (iPTR, or possibly cPTR) type. | |
| const TypeSetByHwMode &PtrTys = TP.getDAGPatterns().getLegalPtrTypes(); | |
| return NodeToApply.UpdateNodeType(ResNo, PtrTys, TP); | |
| } | |
| case SDTCisInt: | |
| // Require it to be one of the legal integer VTs. | |
| return TI.EnforceInteger(NodeToApply.getExtType(ResNo)); | |
| case SDTCisFP: | |
| // Require it to be one of the legal fp VTs. | |
| return TI.EnforceFloatingPoint(NodeToApply.getExtType(ResNo)); | |
| case SDTCisVec: | |
| // Require it to be one of the legal vector VTs. | |
| return TI.EnforceVector(NodeToApply.getExtType(ResNo)); | |
| case SDTCisSameAs: { | |
| unsigned OResNo = 0; | |
| TreePatternNode &OtherNode = | |
| getOperandNum(OtherOperandNo, N, NodeInfo, OResNo); | |
| return (int)NodeToApply.UpdateNodeType(ResNo, OtherNode.getExtType(OResNo), | |
| TP) | | |
| (int)OtherNode.UpdateNodeType(OResNo, NodeToApply.getExtType(ResNo), | |
| TP); | |
| } | |
| case SDTCisVTSmallerThanOp: { | |
| // The NodeToApply must be a leaf node that is a VT. OtherOperandNum must | |
| // have an integer type that is smaller than the VT. | |
| if (!NodeToApply.isLeaf() || !isa<DefInit>(NodeToApply.getLeafValue()) || | |
| !cast<DefInit>(NodeToApply.getLeafValue()) | |
| ->getDef() | |
| ->isSubClassOf("ValueType")) { | |
| TP.error(N.getOperator()->getName() + " expects a VT operand!"); | |
| return false; | |
| } | |
| const DefInit *DI = cast<DefInit>(NodeToApply.getLeafValue()); | |
| const CodeGenTarget &T = TP.getDAGPatterns().getTargetInfo(); | |
| auto VVT = getValueTypeByHwMode(DI->getDef(), T.getHwModes()); | |
| TypeSetByHwMode TypeListTmp(VVT); | |
| unsigned OResNo = 0; | |
| TreePatternNode &OtherNode = | |
| getOperandNum(OtherOperandNo, N, NodeInfo, OResNo); | |
| return TI.EnforceSmallerThan(TypeListTmp, OtherNode.getExtType(OResNo), | |
| /*SmallIsVT*/ true); | |
| } | |
| case SDTCisOpSmallerThanOp: { | |
| unsigned BResNo = 0; | |
| TreePatternNode &BigOperand = | |
| getOperandNum(OtherOperandNo, N, NodeInfo, BResNo); | |
| return TI.EnforceSmallerThan(NodeToApply.getExtType(ResNo), | |
| BigOperand.getExtType(BResNo)); | |
| } | |
| case SDTCisEltOfVec: { | |
| unsigned VResNo = 0; | |
| TreePatternNode &VecOperand = | |
| getOperandNum(OtherOperandNo, N, NodeInfo, VResNo); | |
| // Filter vector types out of VecOperand that don't have the right element | |
| // type. | |
| return TI.EnforceVectorEltTypeIs(VecOperand.getExtType(VResNo), | |
| NodeToApply.getExtType(ResNo)); | |
| } | |
| case SDTCisSubVecOfVec: { | |
| unsigned VResNo = 0; | |
| TreePatternNode &BigVecOperand = | |
| getOperandNum(OtherOperandNo, N, NodeInfo, VResNo); | |
| // Filter vector types out of BigVecOperand that don't have the | |
| // right subvector type. | |
| return TI.EnforceVectorSubVectorTypeIs(BigVecOperand.getExtType(VResNo), | |
| NodeToApply.getExtType(ResNo)); | |
| } | |
| case SDTCVecEltisVT: { | |
| return TI.EnforceVectorEltTypeIs(NodeToApply.getExtType(ResNo), VVT); | |
| } | |
| case SDTCisSameNumEltsAs: { | |
| unsigned OResNo = 0; | |
| TreePatternNode &OtherNode = | |
| getOperandNum(OtherOperandNo, N, NodeInfo, OResNo); | |
| return TI.EnforceSameNumElts(OtherNode.getExtType(OResNo), | |
| NodeToApply.getExtType(ResNo)); | |
| } | |
| case SDTCisSameSizeAs: { | |
| unsigned OResNo = 0; | |
| TreePatternNode &OtherNode = | |
| getOperandNum(OtherOperandNo, N, NodeInfo, OResNo); | |
| return TI.EnforceSameSize(OtherNode.getExtType(OResNo), | |
| NodeToApply.getExtType(ResNo)); | |
| } | |
| } | |
| llvm_unreachable("Invalid ConstraintType!"); | |
| } | |
| bool llvm::operator==(const SDTypeConstraint &LHS, | |
| const SDTypeConstraint &RHS) { | |
| if (std::tie(LHS.OperandNo, LHS.ConstraintType) != | |
| std::tie(RHS.OperandNo, RHS.ConstraintType)) | |
| return false; | |
| switch (LHS.ConstraintType) { | |
| case SDTypeConstraint::SDTCisVT: | |
| case SDTypeConstraint::SDTCVecEltisVT: | |
| return LHS.VVT == RHS.VVT; | |
| case SDTypeConstraint::SDTCisPtrTy: | |
| case SDTypeConstraint::SDTCisInt: | |
| case SDTypeConstraint::SDTCisFP: | |
| case SDTypeConstraint::SDTCisVec: | |
| break; | |
| case SDTypeConstraint::SDTCisSameAs: | |
| case SDTypeConstraint::SDTCisVTSmallerThanOp: | |
| case SDTypeConstraint::SDTCisOpSmallerThanOp: | |
| case SDTypeConstraint::SDTCisEltOfVec: | |
| case SDTypeConstraint::SDTCisSubVecOfVec: | |
| case SDTypeConstraint::SDTCisSameNumEltsAs: | |
| case SDTypeConstraint::SDTCisSameSizeAs: | |
| return LHS.OtherOperandNo == RHS.OtherOperandNo; | |
| } | |
| return true; | |
| } | |
| bool llvm::operator<(const SDTypeConstraint &LHS, const SDTypeConstraint &RHS) { | |
| if (std::tie(LHS.OperandNo, LHS.ConstraintType) != | |
| std::tie(RHS.OperandNo, RHS.ConstraintType)) | |
| return std::tie(LHS.OperandNo, LHS.ConstraintType) < | |
| std::tie(RHS.OperandNo, RHS.ConstraintType); | |
| switch (LHS.ConstraintType) { | |
| case SDTypeConstraint::SDTCisVT: | |
| case SDTypeConstraint::SDTCVecEltisVT: | |
| return LHS.VVT < RHS.VVT; | |
| case SDTypeConstraint::SDTCisPtrTy: | |
| case SDTypeConstraint::SDTCisInt: | |
| case SDTypeConstraint::SDTCisFP: | |
| case SDTypeConstraint::SDTCisVec: | |
| break; | |
| case SDTypeConstraint::SDTCisSameAs: | |
| case SDTypeConstraint::SDTCisVTSmallerThanOp: | |
| case SDTypeConstraint::SDTCisOpSmallerThanOp: | |
| case SDTypeConstraint::SDTCisEltOfVec: | |
| case SDTypeConstraint::SDTCisSubVecOfVec: | |
| case SDTypeConstraint::SDTCisSameNumEltsAs: | |
| case SDTypeConstraint::SDTCisSameSizeAs: | |
| return LHS.OtherOperandNo < RHS.OtherOperandNo; | |
| } | |
| return false; | |
| } | |
| /// RegClassByHwMode acts like ValueTypeByHwMode, taking the type of the | |
| /// register class from the active mode. | |
| static TypeSetByHwMode getTypeForRegClassByHwMode(const CodeGenTarget &T, | |
| const Record *R, | |
| ArrayRef<SMLoc> Loc) { | |
| TypeSetByHwMode TypeSet; | |
| RegClassByHwMode Helper(R, T.getRegBank()); | |
| for (auto [ModeID, RegClass] : Helper) { | |
| ArrayRef<ValueTypeByHwMode> RegClassVTs = RegClass->getValueTypes(); | |
| MachineValueTypeSet &ModeTypeSet = TypeSet.getOrCreate(ModeID); | |
| for (const ValueTypeByHwMode &VT : RegClassVTs) { | |
| if (!VT.hasMode(ModeID) && !VT.hasDefault()) { | |
| PrintError(R->getLoc(), "Could not resolve VT for Mode " + | |
| T.getHwModes().getModeName(ModeID, true)); | |
| if (VT.getRecord()) | |
| PrintNote(VT.getRecord()->getLoc(), "ValueTypeByHwMode " + | |
| VT.getRecord()->getName() + | |
| " defined here"); | |
| PrintFatalNote(Loc, "pattern instantiated here"); | |
| continue; | |
| } | |
| ModeTypeSet.insert(VT.getType(ModeID)); | |
| } | |
| } | |
| return TypeSet; | |
| } | |
| // Update the node type to match an instruction operand or result as specified | |
| // in the ins or outs lists on the instruction definition. Return true if the | |
| // type was actually changed. | |
| bool TreePatternNode::UpdateNodeTypeFromInst(unsigned ResNo, | |
| const Record *Operand, | |
| TreePattern &TP) { | |
| // The 'unknown' operand indicates that types should be inferred from the | |
| // context. | |
| if (Operand->isSubClassOf("unknown_class")) | |
| return false; | |
| // The Operand class specifies a type directly. | |
| if (Operand->isSubClassOf("Operand")) { | |
| const Record *R = Operand->getValueAsDef("Type"); | |
| const CodeGenTarget &T = TP.getDAGPatterns().getTargetInfo(); | |
| return UpdateNodeType(ResNo, getValueTypeByHwMode(R, T.getHwModes()), TP); | |
| } | |
| // Both RegisterClass and RegisterOperand operands derive their types from a | |
| // register class def. | |
| const Record *RC = nullptr; | |
| if (Operand->isSubClassOf("RegisterClassLike")) | |
| RC = Operand; | |
| else if (Operand->isSubClassOf("RegisterOperand")) | |
| RC = Operand->getValueAsDef("RegClass"); | |
| if (!RC) { | |
| TP.error("cannot update node type from unknown operand!"); | |
| return false; | |
| } | |
| CodeGenTarget &Tgt = TP.getDAGPatterns().getTargetInfo(); | |
| if (RC->isSubClassOf("RegClassByHwMode")) | |
| return UpdateNodeType( | |
| ResNo, getTypeForRegClassByHwMode(Tgt, RC, TP.getRecord()->getLoc()), | |
| TP); | |
| return UpdateNodeType(ResNo, Tgt.getRegisterClass(RC).getValueTypes(), TP); | |
| } | |
| bool TreePatternNode::ContainsUnresolvedType(TreePattern &TP) const { | |
| for (const TypeSetByHwMode &Type : Types) | |
| if (!Type.isValueTypeByHwMode(/*AllowEmpty=*/true)) | |
| return true; | |
| for (const TreePatternNode &Child : children()) | |
| if (Child.ContainsUnresolvedType(TP)) | |
| return true; | |
| return false; | |
| } | |
| bool TreePatternNode::hasProperTypeByHwMode() const { | |
| for (const TypeSetByHwMode &S : Types) | |
| if (!S.isSimple()) | |
| return true; | |
| for (const TreePatternNodePtr &C : Children) | |
| if (C->hasProperTypeByHwMode()) | |
| return true; | |
| return false; | |
| } | |
| bool TreePatternNode::hasPossibleType() const { | |
| for (const TypeSetByHwMode &S : Types) | |
| if (!S.isPossible()) | |
| return false; | |
| for (const TreePatternNodePtr &C : Children) | |
| if (!C->hasPossibleType()) | |
| return false; | |
| return true; | |
| } | |
| bool TreePatternNode::setDefaultMode(unsigned Mode) { | |
| for (TypeSetByHwMode &S : Types) { | |
| S.makeSimple(Mode); | |
| // Check if the selected mode had a type conflict. | |
| if (S.get(DefaultMode).empty()) | |
| return false; | |
| } | |
| for (const TreePatternNodePtr &C : Children) | |
| if (!C->setDefaultMode(Mode)) | |
| return false; | |
| return true; | |
| } | |
| //===----------------------------------------------------------------------===// | |
| // SDNodeInfo implementation | |
| // | |
| SDNodeInfo::SDNodeInfo(const Record *R, const CodeGenHwModes &CGH) : Def(R) { | |
| EnumName = R->getValueAsString("Opcode"); | |
| SDClassName = R->getValueAsString("SDClass"); | |
| const Record *TypeProfile = R->getValueAsDef("TypeProfile"); | |
| NumResults = TypeProfile->getValueAsInt("NumResults"); | |
| NumOperands = TypeProfile->getValueAsInt("NumOperands"); | |
| // Parse the properties. | |
| Properties = parseSDPatternOperatorProperties(R); | |
| IsStrictFP = R->getValueAsBit("IsStrictFP"); | |
| std::optional<int64_t> MaybeTSFlags = | |
| R->getValueAsBitsInit("TSFlags")->convertInitializerToInt(); | |
| if (!MaybeTSFlags) | |
| PrintFatalError(R->getLoc(), "Invalid TSFlags"); | |
| assert(isUInt<32>(*MaybeTSFlags) && "TSFlags bit width out of sync"); | |
| TSFlags = *MaybeTSFlags; | |
| // Parse the type constraints. | |
| for (const Record *R : TypeProfile->getValueAsListOfDefs("Constraints")) | |
| TypeConstraints.emplace_back(R, CGH); | |
| } | |
| /// getKnownType - If the type constraints on this node imply a fixed type | |
| /// (e.g. all stores return void, etc), then return it as an | |
| /// MVT. Otherwise, return EEVT::Other. | |
| MVT SDNodeInfo::getKnownType(unsigned ResNo) const { | |
| unsigned NumResults = getNumResults(); | |
| assert(NumResults <= 1 && | |
| "We only work with nodes with zero or one result so far!"); | |
| assert(ResNo == 0 && "Only handles single result nodes so far"); | |
| for (const SDTypeConstraint &Constraint : TypeConstraints) { | |
| // Make sure that this applies to the correct node result. | |
| if (Constraint.OperandNo >= NumResults) // FIXME: need value # | |
| continue; | |
| switch (Constraint.ConstraintType) { | |
| default: | |
| break; | |
| case SDTypeConstraint::SDTCisVT: | |
| if (Constraint.VVT.isSimple()) | |
| return Constraint.VVT.getSimple().SimpleTy; | |
| break; | |
| case SDTypeConstraint::SDTCisPtrTy: | |
| return MVT::iPTR; | |
| } | |
| } | |
| return MVT::Other; | |
| } | |
| //===----------------------------------------------------------------------===// | |
| // TreePatternNode implementation | |
| // | |
| static unsigned GetNumNodeResults(const Record *Operator, | |
| CodeGenDAGPatterns &CDP) { | |
| if (Operator->getName() == "set") | |
| return 0; // All return nothing. | |
| if (Operator->isSubClassOf("Intrinsic")) | |
| return CDP.getIntrinsic(Operator).IS.RetTys.size(); | |
| if (Operator->isSubClassOf("SDNode")) | |
| return CDP.getSDNodeInfo(Operator).getNumResults(); | |
| if (Operator->isSubClassOf("PatFrags")) { | |
| // If we've already parsed this pattern fragment, get it. Otherwise, handle | |
| // the forward reference case where one pattern fragment references another | |
| // before it is processed. | |
| if (TreePattern *PFRec = CDP.getPatternFragmentIfRead(Operator)) { | |
| // The number of results of a fragment with alternative records is the | |
| // maximum number of results across all alternatives. | |
| unsigned NumResults = 0; | |
| for (const auto &T : PFRec->getTrees()) | |
| NumResults = std::max(NumResults, T->getNumTypes()); | |
| return NumResults; | |
| } | |
| const ListInit *LI = Operator->getValueAsListInit("Fragments"); | |
| assert(LI && "Invalid Fragment"); | |
| unsigned NumResults = 0; | |
| for (const Init *I : LI->getElements()) { | |
| const Record *Op = nullptr; | |
| if (const DagInit *Dag = dyn_cast<DagInit>(I)) | |
| if (const DefInit *DI = dyn_cast<DefInit>(Dag->getOperator())) | |
| Op = DI->getDef(); | |
| assert(Op && "Invalid Fragment"); | |
| NumResults = std::max(NumResults, GetNumNodeResults(Op, CDP)); | |
| } | |
| return NumResults; | |
| } | |
| if (Operator->isSubClassOf("Instruction")) { | |
| const CodeGenInstruction &InstInfo = | |
| CDP.getTargetInfo().getInstruction(Operator); | |
| unsigned NumDefsToAdd = InstInfo.Operands.NumDefs; | |
| // Subtract any defaulted outputs. | |
| for (unsigned i = 0; i != InstInfo.Operands.NumDefs; ++i) { | |
| const Record *OperandNode = InstInfo.Operands[i].Rec; | |
| if (OperandNode->isSubClassOf("OperandWithDefaultOps") && | |
| !CDP.getDefaultOperand(OperandNode).DefaultOps.empty()) | |
| --NumDefsToAdd; | |
| } | |
| // Add on one implicit def if it has a resolvable type. | |
| if (InstInfo.HasOneImplicitDefWithKnownVT(CDP.getTargetInfo()) != | |
| MVT::Other) | |
| ++NumDefsToAdd; | |
| return NumDefsToAdd; | |
| } | |
| if (Operator->isSubClassOf("SDNodeXForm")) | |
| return 1; // FIXME: Generalize SDNodeXForm | |
| if (Operator->isSubClassOf("ValueType")) | |
| return 1; // A type-cast of one result. | |
| if (Operator->isSubClassOf("ComplexPattern")) | |
| return 1; | |
| errs() << *Operator; | |
| PrintFatalError("Unhandled node in GetNumNodeResults"); | |
| } | |
| void TreePatternNode::print(raw_ostream &OS) const { | |
| if (isLeaf()) | |
| OS << *getLeafValue(); | |
| else | |
| OS << '(' << getOperator()->getName(); | |
| for (unsigned i = 0, e = Types.size(); i != e; ++i) { | |
| OS << ':'; | |
| getExtType(i).writeToStream(OS); | |
| } | |
| if (!isLeaf()) { | |
| if (getNumChildren() != 0) { | |
| OS << " "; | |
| ListSeparator LS; | |
| for (const TreePatternNode &Child : children()) { | |
| OS << LS; | |
| Child.print(OS); | |
| } | |
| } | |
| OS << ")"; | |
| } | |
| for (const TreePredicateCall &Pred : PredicateCalls) { | |
| OS << "<<P:"; | |
| if (Pred.Scope) | |
| OS << Pred.Scope << ":"; | |
| OS << Pred.Fn.getFnName() << ">>"; | |
| } | |
| if (TransformFn) | |
| OS << "<<X:" << TransformFn->getName() << ">>"; | |
| if (!getName().empty()) | |
| OS << ":$" << getName(); | |
| for (const ScopedName &Name : NamesAsPredicateArg) | |
| OS << ":$pred:" << Name.getScope() << ":" << Name.getIdentifier(); | |
| } | |
| void TreePatternNode::dump() const { | |
| print(dbgs()); | |
| dbgs() << '\n'; | |
| } | |
| /// isIsomorphicTo - Return true if this node is recursively | |
| /// isomorphic to the specified node. For this comparison, the node's | |
| /// entire state is considered. The assigned name is ignored, since | |
| /// nodes with differing names are considered isomorphic. However, if | |
| /// the assigned name is present in the dependent variable set, then | |
| /// the assigned name is considered significant and the node is | |
| /// isomorphic if the names match. | |
| bool TreePatternNode::isIsomorphicTo(const TreePatternNode &N, | |
| const MultipleUseVarSet &DepVars) const { | |
| if (&N == this) | |
| return true; | |
| if (N.isLeaf() != isLeaf()) | |
| return false; | |
| // Check operator of non-leaves early since it can be cheaper than checking | |
| // types. | |
| if (!isLeaf()) | |
| if (N.getOperator() != getOperator() || | |
| N.getNumChildren() != getNumChildren()) | |
| return false; | |
| if (getExtTypes() != N.getExtTypes() || | |
| getPredicateCalls() != N.getPredicateCalls() || | |
| getTransformFn() != N.getTransformFn()) | |
| return false; | |
| if (isLeaf()) { | |
| if (const DefInit *DI = dyn_cast<DefInit>(getLeafValue())) { | |
| if (const DefInit *NDI = dyn_cast<DefInit>(N.getLeafValue())) { | |
| return ((DI->getDef() == NDI->getDef()) && | |
| (!DepVars.contains(getName()) || getName() == N.getName())); | |
| } | |
| } | |
| return getLeafValue() == N.getLeafValue(); | |
| } | |
| for (unsigned i = 0, e = getNumChildren(); i != e; ++i) | |
| if (!getChild(i).isIsomorphicTo(N.getChild(i), DepVars)) | |
| return false; | |
| return true; | |
| } | |
| /// clone - Make a copy of this tree and all of its children. | |
| /// | |
| TreePatternNodePtr TreePatternNode::clone() const { | |
| TreePatternNodePtr New; | |
| if (isLeaf()) { | |
| New = makeIntrusiveRefCnt<TreePatternNode>(getLeafValue(), getNumTypes()); | |
| } else { | |
| std::vector<TreePatternNodePtr> CChildren; | |
| CChildren.reserve(Children.size()); | |
| for (const TreePatternNode &Child : children()) | |
| CChildren.push_back(Child.clone()); | |
| New = makeIntrusiveRefCnt<TreePatternNode>( | |
| getOperator(), std::move(CChildren), getNumTypes()); | |
| } | |
| New->setName(getName()); | |
| New->setNamesAsPredicateArg(getNamesAsPredicateArg()); | |
| New->Types = Types; | |
| New->setPredicateCalls(getPredicateCalls()); | |
| New->setGISelFlagsRecord(getGISelFlagsRecord()); | |
| New->setTransformFn(getTransformFn()); | |
| return New; | |
| } | |
| /// RemoveAllTypes - Recursively strip all the types of this tree. | |
| void TreePatternNode::RemoveAllTypes() { | |
| // Reset to unknown type. | |
| llvm::fill(Types, TypeSetByHwMode()); | |
| if (isLeaf()) | |
| return; | |
| for (TreePatternNode &Child : children()) | |
| Child.RemoveAllTypes(); | |
| } | |
| /// SubstituteFormalArguments - Replace the formal arguments in this tree | |
| /// with actual values specified by ArgMap. | |
| void TreePatternNode::SubstituteFormalArguments( | |
| std::map<StringRef, TreePatternNodePtr> &ArgMap) { | |
| if (isLeaf()) | |
| return; | |
| for (unsigned i = 0, e = getNumChildren(); i != e; ++i) { | |
| TreePatternNode &Child = getChild(i); | |
| if (Child.isLeaf()) { | |
| const Init *Val = Child.getLeafValue(); | |
| // Note that, when substituting into an output pattern, Val might be an | |
| // UnsetInit. | |
| if (isa<UnsetInit>(Val) || | |
| (isa<DefInit>(Val) && | |
| cast<DefInit>(Val)->getDef()->getName() == "node")) { | |
| // We found a use of a formal argument, replace it with its value. | |
| TreePatternNodePtr NewChild = ArgMap[Child.getName()]; | |
| assert(NewChild && "Couldn't find formal argument!"); | |
| assert((Child.getPredicateCalls().empty() || | |
| NewChild->getPredicateCalls() == Child.getPredicateCalls()) && | |
| "Non-empty child predicate clobbered!"); | |
| setChild(i, std::move(NewChild)); | |
| } | |
| } else { | |
| getChild(i).SubstituteFormalArguments(ArgMap); | |
| } | |
| } | |
| } | |
| /// InlinePatternFragments - If this pattern refers to any pattern | |
| /// fragments, return the set of inlined versions (this can be more than | |
| /// one if a PatFrags record has multiple alternatives). | |
| void TreePatternNode::InlinePatternFragments( | |
| TreePattern &TP, std::vector<TreePatternNodePtr> &OutAlternatives) { | |
| if (TP.hasError()) | |
| return; | |
| if (isLeaf()) { | |
| OutAlternatives.push_back(this); // nothing to do. | |
| return; | |
| } | |
| const Record *Op = getOperator(); | |
| if (!Op->isSubClassOf("PatFrags")) { | |
| if (getNumChildren() == 0) { | |
| OutAlternatives.push_back(this); | |
| return; | |
| } | |
| // Recursively inline children nodes. | |
| std::vector<std::vector<TreePatternNodePtr>> ChildAlternatives( | |
| getNumChildren()); | |
| for (unsigned i = 0, e = getNumChildren(); i != e; ++i) { | |
| TreePatternNodePtr Child = getChildShared(i); | |
| Child->InlinePatternFragments(TP, ChildAlternatives[i]); | |
| // If there are no alternatives for any child, there are no | |
| // alternatives for this expression as whole. | |
| if (ChildAlternatives[i].empty()) | |
| return; | |
| assert((Child->getPredicateCalls().empty() || | |
| llvm::all_of(ChildAlternatives[i], | |
| [&](const TreePatternNodePtr &NewChild) { | |
| return NewChild->getPredicateCalls() == | |
| Child->getPredicateCalls(); | |
| })) && | |
| "Non-empty child predicate clobbered!"); | |
| } | |
| // The end result is an all-pairs construction of the resultant pattern. | |
| std::vector<unsigned> Idxs(ChildAlternatives.size()); | |
| bool NotDone; | |
| do { | |
| // Create the variant and add it to the output list. | |
| std::vector<TreePatternNodePtr> NewChildren; | |
| NewChildren.reserve(ChildAlternatives.size()); | |
| for (unsigned i = 0, e = ChildAlternatives.size(); i != e; ++i) | |
| NewChildren.push_back(ChildAlternatives[i][Idxs[i]]); | |
| TreePatternNodePtr R = makeIntrusiveRefCnt<TreePatternNode>( | |
| getOperator(), std::move(NewChildren), getNumTypes()); | |
| // Copy over properties. | |
| R->setName(getName()); | |
| R->setNamesAsPredicateArg(getNamesAsPredicateArg()); | |
| R->setPredicateCalls(getPredicateCalls()); | |
| R->setGISelFlagsRecord(getGISelFlagsRecord()); | |
| R->setTransformFn(getTransformFn()); | |
| for (unsigned i = 0, e = getNumTypes(); i != e; ++i) | |
| R->setType(i, getExtType(i)); | |
| for (unsigned i = 0, e = getNumResults(); i != e; ++i) | |
| R->setResultIndex(i, getResultIndex(i)); | |
| // Register alternative. | |
| OutAlternatives.push_back(R); | |
| // Increment indices to the next permutation by incrementing the | |
| // indices from last index backward, e.g., generate the sequence | |
| // [0, 0], [0, 1], [1, 0], [1, 1]. | |
| int IdxsIdx; | |
| for (IdxsIdx = Idxs.size() - 1; IdxsIdx >= 0; --IdxsIdx) { | |
| if (++Idxs[IdxsIdx] == ChildAlternatives[IdxsIdx].size()) | |
| Idxs[IdxsIdx] = 0; | |
| else | |
| break; | |
| } | |
| NotDone = (IdxsIdx >= 0); | |
| } while (NotDone); | |
| return; | |
| } | |
| // Otherwise, we found a reference to a fragment. First, look up its | |
| // TreePattern record. | |
| TreePattern *Frag = TP.getDAGPatterns().getPatternFragment(Op); | |
| // Verify that we are passing the right number of operands. | |
| if (Frag->getNumArgs() != getNumChildren()) { | |
| TP.error("'" + Op->getName() + "' fragment requires " + | |
| Twine(Frag->getNumArgs()) + " operands!"); | |
| return; | |
| } | |
| TreePredicateFn PredFn(Frag); | |
| unsigned Scope = 0; | |
| if (TreePredicateFn(Frag).usesOperands()) | |
| Scope = TP.getDAGPatterns().allocateScope(); | |
| // Compute the map of formal to actual arguments. | |
| std::map<StringRef, TreePatternNodePtr> ArgMap; | |
| for (unsigned i = 0, e = Frag->getNumArgs(); i != e; ++i) { | |
| TreePatternNodePtr Child = getChildShared(i); | |
| if (Scope != 0) { | |
| Child = Child->clone(); | |
| Child->addNameAsPredicateArg(ScopedName(Scope, Frag->getArgName(i))); | |
| } | |
| ArgMap[Frag->getArgName(i)] = Child; | |
| } | |
| // Loop over all fragment alternatives. | |
| for (const auto &Alternative : Frag->getTrees()) { | |
| TreePatternNodePtr FragTree = Alternative->clone(); | |
| if (!PredFn.isAlwaysTrue()) | |
| FragTree->addPredicateCall(PredFn, Scope); | |
| // Resolve formal arguments to their actual value. | |
| if (Frag->getNumArgs()) | |
| FragTree->SubstituteFormalArguments(ArgMap); | |
| // Transfer types. Note that the resolved alternative may have fewer | |
| // (but not more) results than the PatFrags node. | |
| FragTree->setName(getName()); | |
| for (unsigned i = 0, e = FragTree->getNumTypes(); i != e; ++i) | |
| FragTree->UpdateNodeType(i, getExtType(i), TP); | |
| if (Op->isSubClassOf("GISelFlags")) | |
| FragTree->setGISelFlagsRecord(Op); | |
| // Transfer in the old predicates. | |
| for (const TreePredicateCall &Pred : getPredicateCalls()) | |
| FragTree->addPredicateCall(Pred); | |
| // The fragment we inlined could have recursive inlining that is needed. See | |
| // if there are any pattern fragments in it and inline them as needed. | |
| FragTree->InlinePatternFragments(TP, OutAlternatives); | |
| } | |
| } | |
| /// getImplicitType - Check to see if the specified record has an implicit | |
| /// type which should be applied to it. This will infer the type of register | |
| /// references from the register file information, for example. | |
| /// | |
| /// When Unnamed is set, return the type of a DAG operand with no name, such as | |
| /// the F8RC register class argument in: | |
| /// | |
| /// (COPY_TO_REGCLASS GPR:$src, F8RC) | |
| /// | |
| /// When Unnamed is false, return the type of a named DAG operand such as the | |
| /// GPR:$src operand above. | |
| /// | |
| static TypeSetByHwMode getImplicitType(const Record *R, unsigned ResNo, | |
| bool NotRegisters, bool Unnamed, | |
| TreePattern &TP) { | |
| CodeGenDAGPatterns &CDP = TP.getDAGPatterns(); | |
| // Check to see if this is a register operand. | |
| if (R->isSubClassOf("RegisterOperand")) { | |
| assert(ResNo == 0 && "Regoperand ref only has one result!"); | |
| if (NotRegisters) | |
| return TypeSetByHwMode(); // Unknown. | |
| const Record *RegClass = R->getValueAsDef("RegClass"); | |
| const CodeGenTarget &T = TP.getDAGPatterns().getTargetInfo(); | |
| if (RegClass->isSubClassOf("RegClassByHwMode")) | |
| return getTypeForRegClassByHwMode(T, RegClass, TP.getRecord()->getLoc()); | |
| return TypeSetByHwMode(T.getRegisterClass(RegClass).getValueTypes()); | |
| } | |
| // Check to see if this is a register or a register class. | |
| if (R->isSubClassOf("RegisterClass")) { | |
| assert(ResNo == 0 && "Regclass ref only has one result!"); | |
| // An unnamed register class represents itself as an i32 immediate, for | |
| // example on a COPY_TO_REGCLASS instruction. | |
| if (Unnamed) | |
| return TypeSetByHwMode(MVT::i32); | |
| // In a named operand, the register class provides the possible set of | |
| // types. | |
| if (NotRegisters) | |
| return TypeSetByHwMode(); // Unknown. | |
| const CodeGenTarget &T = TP.getDAGPatterns().getTargetInfo(); | |
| return TypeSetByHwMode(T.getRegisterClass(R).getValueTypes()); | |
| } | |
| if (R->isSubClassOf("RegClassByHwMode")) { | |
| if (NotRegisters) | |
| return TypeSetByHwMode(); // Unknown. | |
| const CodeGenTarget &T = CDP.getTargetInfo(); | |
| return getTypeForRegClassByHwMode(T, R, TP.getRecord()->getLoc()); | |
| } | |
| if (R->isSubClassOf("PatFrags")) { | |
| assert(ResNo == 0 && "FIXME: PatFrag with multiple results?"); | |
| // Pattern fragment types will be resolved when they are inlined. | |
| return TypeSetByHwMode(); // Unknown. | |
| } | |
| if (R->isSubClassOf("Register")) { | |
| assert(ResNo == 0 && "Registers only produce one result!"); | |
| if (NotRegisters) | |
| return TypeSetByHwMode(); // Unknown. | |
| const CodeGenTarget &T = TP.getDAGPatterns().getTargetInfo(); | |
| return TypeSetByHwMode(T.getRegisterVTs(R)); | |
| } | |
| if (R->isSubClassOf("SubRegIndex")) { | |
| assert(ResNo == 0 && "SubRegisterIndices only produce one result!"); | |
| return TypeSetByHwMode(MVT::i32); | |
| } | |
| if (R->isSubClassOf("ValueType")) { | |
| assert(ResNo == 0 && "This node only has one result!"); | |
| // An unnamed VTSDNode represents itself as an MVT::Other immediate. | |
| // | |
| // (sext_inreg GPR:$src, i16) | |
| // ~~~ | |
| if (Unnamed) | |
| return TypeSetByHwMode(MVT::Other); | |
| // With a name, the ValueType simply provides the type of the named | |
| // variable. | |
| // | |
| // (sext_inreg i32:$src, i16) | |
| // ~~~~~~~~ | |
| if (NotRegisters) | |
| return TypeSetByHwMode(); // Unknown. | |
| const CodeGenHwModes &CGH = CDP.getTargetInfo().getHwModes(); | |
| return TypeSetByHwMode(getValueTypeByHwMode(R, CGH)); | |
| } | |
| if (R->isSubClassOf("CondCode")) { | |
| assert(ResNo == 0 && "This node only has one result!"); | |
| // Using a CondCodeSDNode. | |
| return TypeSetByHwMode(MVT::Other); | |
| } | |
| if (R->isSubClassOf("ComplexPattern")) { | |
| assert(ResNo == 0 && "FIXME: ComplexPattern with multiple results?"); | |
| if (NotRegisters) | |
| return TypeSetByHwMode(); // Unknown. | |
| const Record *T = CDP.getComplexPattern(R).getValueType(); | |
| const CodeGenHwModes &CGH = CDP.getTargetInfo().getHwModes(); | |
| return TypeSetByHwMode(getValueTypeByHwMode(T, CGH)); | |
| } | |
| if (R->getName() == "node" || R->getName() == "srcvalue" || | |
| R->getName() == "zero_reg" || R->getName() == "immAllOnesV" || | |
| R->getName() == "immAllZerosV" || R->getName() == "undef_tied_input") { | |
| // Placeholder. | |
| return TypeSetByHwMode(); // Unknown. | |
| } | |
| if (R->isSubClassOf("Operand")) { | |
| const CodeGenHwModes &CGH = CDP.getTargetInfo().getHwModes(); | |
| const Record *T = R->getValueAsDef("Type"); | |
| return TypeSetByHwMode(getValueTypeByHwMode(T, CGH)); | |
| } | |
| TP.error("Unknown node flavor used in pattern: " + R->getName()); | |
| return TypeSetByHwMode(MVT::Other); | |
| } | |
| /// getIntrinsicInfo - If this node corresponds to an intrinsic, return the | |
| /// CodeGenIntrinsic information for it, otherwise return a null pointer. | |
| const CodeGenIntrinsic * | |
| TreePatternNode::getIntrinsicInfo(const CodeGenDAGPatterns &CDP) const { | |
| if (getOperator() != CDP.get_intrinsic_void_sdnode() && | |
| getOperator() != CDP.get_intrinsic_w_chain_sdnode() && | |
| getOperator() != CDP.get_intrinsic_wo_chain_sdnode()) | |
| return nullptr; | |
| unsigned IID = cast<IntInit>(getChild(0).getLeafValue())->getValue(); | |
| return &CDP.getIntrinsicInfo(IID); | |
| } | |
| /// getComplexPatternInfo - If this node corresponds to a ComplexPattern, | |
| /// return the ComplexPattern information, otherwise return null. | |
| const ComplexPattern * | |
| TreePatternNode::getComplexPatternInfo(const CodeGenDAGPatterns &CGP) const { | |
| const Record *Rec; | |
| if (isLeaf()) { | |
| const DefInit *DI = dyn_cast<DefInit>(getLeafValue()); | |
| if (!DI) | |
| return nullptr; | |
| Rec = DI->getDef(); | |
| } else { | |
| Rec = getOperator(); | |
| } | |
| if (!Rec->isSubClassOf("ComplexPattern")) | |
| return nullptr; | |
| return &CGP.getComplexPattern(Rec); | |
| } | |
| unsigned TreePatternNode::getNumMIResults(const CodeGenDAGPatterns &CGP) const { | |
| // A ComplexPattern specifically declares how many results it fills in. | |
| if (const ComplexPattern *CP = getComplexPatternInfo(CGP)) | |
| return CP->getNumOperands(); | |
| // If MIOperandInfo is specified, that gives the count. | |
| if (isLeaf()) { | |
| const DefInit *DI = dyn_cast<DefInit>(getLeafValue()); | |
| if (DI && DI->getDef()->isSubClassOf("Operand")) { | |
| const DagInit *MIOps = DI->getDef()->getValueAsDag("MIOperandInfo"); | |
| if (MIOps->getNumArgs()) | |
| return MIOps->getNumArgs(); | |
| } | |
| } | |
| // Otherwise there is just one result. | |
| return 1; | |
| } | |
| /// NodeHasProperty - Return true if this node has the specified property. | |
| bool TreePatternNode::NodeHasProperty(SDNP Property, | |
| const CodeGenDAGPatterns &CGP) const { | |
| if (isLeaf()) { | |
| if (const ComplexPattern *CP = getComplexPatternInfo(CGP)) | |
| return CP->hasProperty(Property); | |
| return false; | |
| } | |
| if (Property != SDNPHasChain) { | |
| // The chain proprety is already present on the different intrinsic node | |
| // types (intrinsic_w_chain, intrinsic_void), and is not explicitly listed | |
| // on the intrinsic. Anything else is specific to the individual intrinsic. | |
| if (const CodeGenIntrinsic *Int = getIntrinsicInfo(CGP)) | |
| return Int->hasProperty(Property); | |
| } | |
| if (!getOperator()->isSubClassOf("SDPatternOperator")) | |
| return false; | |
| return CGP.getSDNodeInfo(getOperator()).hasProperty(Property); | |
| } | |
| /// TreeHasProperty - Return true if any node in this tree has the specified | |
| /// property. | |
| bool TreePatternNode::TreeHasProperty(SDNP Property, | |
| const CodeGenDAGPatterns &CGP) const { | |
| if (NodeHasProperty(Property, CGP)) | |
| return true; | |
| for (const TreePatternNode &Child : children()) | |
| if (Child.TreeHasProperty(Property, CGP)) | |
| return true; | |
| return false; | |
| } | |
| /// isCommutativeIntrinsic - Return true if the node corresponds to a | |
| /// commutative intrinsic. | |
| bool TreePatternNode::isCommutativeIntrinsic( | |
| const CodeGenDAGPatterns &CDP) const { | |
| if (const CodeGenIntrinsic *Int = getIntrinsicInfo(CDP)) | |
| return Int->isCommutative; | |
| return false; | |
| } | |
| static bool isOperandClass(const TreePatternNode &N, StringRef Class) { | |
| if (!N.isLeaf()) | |
| return N.getOperator()->isSubClassOf(Class); | |
| const DefInit *DI = dyn_cast<DefInit>(N.getLeafValue()); | |
| if (DI && DI->getDef()->isSubClassOf(Class)) | |
| return true; | |
| return false; | |
| } | |
| static void emitTooManyOperandsError(TreePattern &TP, StringRef InstName, | |
| unsigned Expected, unsigned Actual) { | |
| TP.error("Instruction '" + InstName + "' was provided " + Twine(Actual) + | |
| " operands but expected only " + Twine(Expected) + "!"); | |
| } | |
| static void emitTooFewOperandsError(TreePattern &TP, StringRef InstName, | |
| unsigned Actual) { | |
| TP.error("Instruction '" + InstName + "' expects more than the provided " + | |
| Twine(Actual) + " operands!"); | |
| } | |
| /// ApplyTypeConstraints - Apply all of the type constraints relevant to | |
| /// this node and its children in the tree. This returns true if it makes a | |
| /// change, false otherwise. If a type contradiction is found, flag an error. | |
| bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) { | |
| if (TP.hasError()) | |
| return false; | |
| CodeGenDAGPatterns &CDP = TP.getDAGPatterns(); | |
| if (isLeaf()) { | |
| if (const DefInit *DI = dyn_cast<DefInit>(getLeafValue())) { | |
| // If it's a regclass or something else known, include the type. | |
| bool MadeChange = false; | |
| for (unsigned i = 0, e = Types.size(); i != e; ++i) | |
| MadeChange |= UpdateNodeType( | |
| i, getImplicitType(DI->getDef(), i, NotRegisters, !hasName(), TP), | |
| TP); | |
| return MadeChange; | |
| } | |
| if (const IntInit *II = dyn_cast<IntInit>(getLeafValue())) { | |
| assert(Types.size() == 1 && "Invalid IntInit"); | |
| // Int inits are always integers. :) | |
| bool MadeChange = TP.getInfer().EnforceInteger(Types[0]); | |
| if (!Types[0].isValueTypeByHwMode(/*AllowEmpty=*/false)) | |
| return MadeChange; | |
| ValueTypeByHwMode VVT = Types[0].getValueTypeByHwMode(); | |
| for (auto &P : VVT) { | |
| MVT VT = P.second; | |
| // Can only check for types of a known size | |
| if (VT == MVT::iPTR) | |
| continue; | |
| // Check that the value doesn't use more bits than we have. It must | |
| // either be a sign- or zero-extended equivalent of the original. | |
| unsigned Width = VT.getFixedSizeInBits(); | |
| int64_t Val = II->getValue(); | |
| if (!isIntN(Width, Val) && !isUIntN(Width, Val)) { | |
| TP.error("Integer value '" + Twine(Val) + | |
| "' is out of range for type '" + getEnumName(VT) + "'!"); | |
| break; | |
| } | |
| } | |
| return MadeChange; | |
| } | |
| return false; | |
| } | |
| if (const CodeGenIntrinsic *Int = getIntrinsicInfo(CDP)) { | |
| bool MadeChange = false; | |
| // Apply the result type to the node. | |
| unsigned NumRetVTs = Int->IS.RetTys.size(); | |
| unsigned NumParamVTs = Int->IS.ParamTys.size(); | |
| for (unsigned i = 0, e = NumRetVTs; i != e; ++i) | |
| MadeChange |= UpdateNodeType( | |
| i, getValueType(Int->IS.RetTys[i]->getValueAsDef("VT")), TP); | |
| if (getNumChildren() != NumParamVTs + 1) { | |
| TP.error("Intrinsic '" + Int->Name + "' expects " + Twine(NumParamVTs) + | |
| " operands, not " + Twine(getNumChildren() - 1) + " operands!"); | |
| return false; | |
| } | |
| // Apply type info to the intrinsic ID. | |
| MadeChange |= getChild(0).UpdateNodeType(0, MVT::iPTR, TP); | |
| for (unsigned i = 0, e = getNumChildren() - 1; i != e; ++i) { | |
| MadeChange |= getChild(i + 1).ApplyTypeConstraints(TP, NotRegisters); | |
| MVT OpVT = getValueType(Int->IS.ParamTys[i]->getValueAsDef("VT")); | |
| assert(getChild(i + 1).getNumTypes() == 1 && "Unhandled case"); | |
| MadeChange |= getChild(i + 1).UpdateNodeType(0, OpVT, TP); | |
| } | |
| return MadeChange; | |
| } | |
| if (getOperator()->isSubClassOf("SDNode")) { | |
| const SDNodeInfo &NI = CDP.getSDNodeInfo(getOperator()); | |
| // Check that the number of operands is sane. Negative operands -> varargs. | |
| if (NI.getNumOperands() >= 0 && | |
| getNumChildren() != (unsigned)NI.getNumOperands()) { | |
| TP.error(getOperator()->getName() + " node requires exactly " + | |
| Twine(NI.getNumOperands()) + " operands!"); | |
| return false; | |
| } | |
| bool MadeChange = false; | |
| for (TreePatternNode &Child : children()) | |
| MadeChange |= Child.ApplyTypeConstraints(TP, NotRegisters); | |
| MadeChange |= NI.ApplyTypeConstraints(*this, TP); | |
| return MadeChange; | |
| } | |
| if (getOperator()->isSubClassOf("Instruction")) { | |
| const DAGInstruction &Inst = CDP.getInstruction(getOperator()); | |
| const CodeGenInstruction &InstInfo = | |
| CDP.getTargetInfo().getInstruction(getOperator()); | |
| bool MadeChange = false; | |
| // Apply the result types to the node, these come from the things in the | |
| // (outs) list of the instruction. | |
| unsigned NumResultsToAdd = | |
| std::min(InstInfo.Operands.NumDefs, Inst.getNumResults()); | |
| for (unsigned ResNo = 0; ResNo != NumResultsToAdd; ++ResNo) | |
| MadeChange |= UpdateNodeTypeFromInst(ResNo, Inst.getResult(ResNo), TP); | |
| // If the instruction has implicit defs, we apply the first one as a result. | |
| // FIXME: This sucks, it should apply all implicit defs. | |
| if (!InstInfo.ImplicitDefs.empty()) { | |
| unsigned ResNo = NumResultsToAdd; | |
| // FIXME: Generalize to multiple possible types and multiple possible | |
| // ImplicitDefs. | |
| MVT VT = InstInfo.HasOneImplicitDefWithKnownVT(CDP.getTargetInfo()); | |
| if (VT != MVT::Other) | |
| MadeChange |= UpdateNodeType(ResNo, VT, TP); | |
| } | |
| // If this is an INSERT_SUBREG, constrain the source and destination VTs to | |
| // be the same. | |
| if (getOperator()->getName() == "INSERT_SUBREG") { | |
| assert(getChild(0).getNumTypes() == 1 && "FIXME: Unhandled"); | |
| MadeChange |= UpdateNodeType(0, getChild(0).getExtType(0), TP); | |
| MadeChange |= getChild(0).UpdateNodeType(0, getExtType(0), TP); | |
| } else if (getOperator()->getName() == "REG_SEQUENCE") { | |
| // We need to do extra, custom typechecking for REG_SEQUENCE since it is | |
| // variadic. | |
| unsigned NChild = getNumChildren(); | |
| if (NChild < 3) { | |
| TP.error("REG_SEQUENCE requires at least 3 operands!"); | |
| return false; | |
| } | |
| if (NChild % 2 == 0) { | |
| TP.error("REG_SEQUENCE requires an odd number of operands!"); | |
| return false; | |
| } | |
| if (!isOperandClass(getChild(0), "RegisterClass")) { | |
| TP.error("REG_SEQUENCE requires a RegisterClass for first operand!"); | |
| return false; | |
| } | |
| for (unsigned I = 1; I < NChild; I += 2) { | |
| TreePatternNode &SubIdxChild = getChild(I + 1); | |
| if (!isOperandClass(SubIdxChild, "SubRegIndex")) { | |
| TP.error("REG_SEQUENCE requires a SubRegIndex for operand " + | |
| Twine(I + 1) + "!"); | |
| return false; | |
| } | |
| } | |
| } | |
| unsigned NumResults = Inst.getNumResults(); | |
| unsigned NumFixedOperands = InstInfo.Operands.size(); | |
| // If one or more operands with a default value appear at the end of the | |
| // formal operand list for an instruction, we allow them to be overridden | |
| // by optional operands provided in the pattern. | |
| // | |
| // But if an operand B without a default appears at any point after an | |
| // operand A with a default, then we don't allow A to be overridden, | |
| // because there would be no way to specify whether the next operand in | |
| // the pattern was intended to override A or skip it. | |
| unsigned NonOverridableOperands = NumFixedOperands; | |
| while (NonOverridableOperands > NumResults && | |
| CDP.operandHasDefault( | |
| InstInfo.Operands[NonOverridableOperands - 1].Rec)) | |
| --NonOverridableOperands; | |
| unsigned ChildNo = 0; | |
| assert(NumResults <= NumFixedOperands); | |
| for (unsigned i = NumResults, e = NumFixedOperands; i != e; ++i) { | |
| const Record *OperandNode = InstInfo.Operands[i].Rec; | |
| // If the operand has a default value, do we use it? We must use the | |
| // default if we've run out of children of the pattern DAG to consume, | |
| // or if the operand is followed by a non-defaulted one. | |
| if (CDP.operandHasDefault(OperandNode) && | |
| (i < NonOverridableOperands || ChildNo >= getNumChildren())) | |
| continue; | |
| // If we have run out of child nodes and there _isn't_ a default | |
| // value we can use for the next operand, give an error. | |
| if (ChildNo >= getNumChildren()) { | |
| emitTooFewOperandsError(TP, getOperator()->getName(), getNumChildren()); | |
| return false; | |
| } | |
| TreePatternNode *Child = &getChild(ChildNo++); | |
| unsigned ChildResNo = 0; // Instructions always use res #0 of their op. | |
| // If the operand has sub-operands, they may be provided by distinct | |
| // child patterns, so attempt to match each sub-operand separately. | |
| if (OperandNode->isSubClassOf("Operand")) { | |
| const DagInit *MIOpInfo = OperandNode->getValueAsDag("MIOperandInfo"); | |
| if (unsigned NumArgs = MIOpInfo->getNumArgs()) { | |
| // But don't do that if the whole operand is being provided by | |
| // a single ComplexPattern-related Operand. | |
| if (Child->getNumMIResults(CDP) < NumArgs) { | |
| // Match first sub-operand against the child we already have. | |
| const Record *SubRec = cast<DefInit>(MIOpInfo->getArg(0))->getDef(); | |
| MadeChange |= Child->UpdateNodeTypeFromInst(ChildResNo, SubRec, TP); | |
| // And the remaining sub-operands against subsequent children. | |
| for (unsigned Arg = 1; Arg < NumArgs; ++Arg) { | |
| if (ChildNo >= getNumChildren()) { | |
| emitTooFewOperandsError(TP, getOperator()->getName(), | |
| getNumChildren()); | |
| return false; | |
| } | |
| Child = &getChild(ChildNo++); | |
| SubRec = cast<DefInit>(MIOpInfo->getArg(Arg))->getDef(); | |
| MadeChange |= | |
| Child->UpdateNodeTypeFromInst(ChildResNo, SubRec, TP); | |
| } | |
| continue; | |
| } | |
| } | |
| } | |
| // If we didn't match by pieces above, attempt to match the whole | |
| // operand now. | |
| MadeChange |= Child->UpdateNodeTypeFromInst(ChildResNo, OperandNode, TP); | |
| } | |
| if (!InstInfo.Operands.isVariadic && ChildNo != getNumChildren()) { | |
| emitTooManyOperandsError(TP, getOperator()->getName(), ChildNo, | |
| getNumChildren()); | |
| return false; | |
| } | |
| for (TreePatternNode &Child : children()) | |
| MadeChange |= Child.ApplyTypeConstraints(TP, NotRegisters); | |
| return MadeChange; | |
| } | |
| if (getOperator()->isSubClassOf("ComplexPattern")) { | |
| bool MadeChange = false; | |
| if (!NotRegisters) { | |
| assert(Types.size() == 1 && "ComplexPatterns only produce one result!"); | |
| const Record *T = CDP.getComplexPattern(getOperator()).getValueType(); | |
| const CodeGenHwModes &CGH = CDP.getTargetInfo().getHwModes(); | |
| const ValueTypeByHwMode VVT = getValueTypeByHwMode(T, CGH); | |
| // TODO: AArch64 and AMDGPU use ComplexPattern<untyped, ...> and then | |
| // exclusively use those as non-leaf nodes with explicit type casts, so | |
| // for backwards compatibility we do no inference in that case. This is | |
| // not supported when the ComplexPattern is used as a leaf value, | |
| // however; this inconsistency should be resolved, either by adding this | |
| // case there or by altering the backends to not do this (e.g. using Any | |
| // instead may work). | |
| if (!VVT.isSimple() || VVT.getSimple() != MVT::Untyped) | |
| MadeChange |= UpdateNodeType(0, VVT, TP); | |
| } | |
| for (TreePatternNode &Child : children()) | |
| MadeChange |= Child.ApplyTypeConstraints(TP, NotRegisters); | |
| return MadeChange; | |
| } | |
| if (!getOperator()->isSubClassOf("SDNodeXForm")) { | |
| TP.error("unknown node type '" + getOperator()->getName() + | |
| "' in input pattern"); | |
| return false; | |
| } | |
| // Node transforms always take one operand. | |
| if (getNumChildren() != 1) { | |
| TP.error("Node transform '" + getOperator()->getName() + | |
| "' requires one operand!"); | |
| return false; | |
| } | |
| bool MadeChange = getChild(0).ApplyTypeConstraints(TP, NotRegisters); | |
| return MadeChange; | |
| } | |
| /// OnlyOnRHSOfCommutative - Return true if this value is only allowed on the | |
| /// RHS of a commutative operation, not the on LHS. | |
| static bool OnlyOnRHSOfCommutative(const TreePatternNode &N) { | |
| if (!N.isLeaf() && N.getOperator()->getName() == "imm") | |
| return true; | |
| if (N.isLeaf() && isa<IntInit>(N.getLeafValue())) | |
| return true; | |
| if (isImmAllOnesAllZerosMatch(N)) | |
| return true; | |
| return false; | |
| } | |
| /// canPatternMatch - If it is impossible for this pattern to match on this | |
| /// target, fill in Reason and return false. Otherwise, return true. This is | |
| /// used as a sanity check for .td files (to prevent people from writing stuff | |
| /// that can never possibly work), and to prevent the pattern permuter from | |
| /// generating stuff that is useless. | |
| bool TreePatternNode::canPatternMatch(std::string &Reason, | |
| const CodeGenDAGPatterns &CDP) const { | |
| if (isLeaf()) | |
| return true; | |
| for (const TreePatternNode &Child : children()) | |
| if (!Child.canPatternMatch(Reason, CDP)) | |
| return false; | |
| // If this is an intrinsic, handle cases that would make it not match. For | |
| // example, if an operand is required to be an immediate. | |
| if (getOperator()->isSubClassOf("Intrinsic")) { | |
| // TODO: | |
| return true; | |
| } | |
| if (getOperator()->isSubClassOf("ComplexPattern")) | |
| return true; | |
| // If this node is a commutative operator, check that the LHS isn't an | |
| // immediate. | |
| const SDNodeInfo &NodeInfo = CDP.getSDNodeInfo(getOperator()); | |
| bool isCommIntrinsic = isCommutativeIntrinsic(CDP); | |
| if (NodeInfo.hasProperty(SDNPCommutative) || isCommIntrinsic) { | |
| // Scan all of the operands of the node and make sure that only the last one | |
| // is a constant node, unless the RHS also is. | |
| if (!OnlyOnRHSOfCommutative(getChild(getNumChildren() - 1))) { | |
| unsigned Skip = isCommIntrinsic ? 1 : 0; // First operand is intrinsic id. | |
| for (unsigned i = Skip, e = getNumChildren() - 1; i != e; ++i) | |
| if (OnlyOnRHSOfCommutative(getChild(i))) { | |
| Reason = | |
| "Immediate value must be on the RHS of commutative operators!"; | |
| return false; | |
| } | |
| } | |
| } | |
| return true; | |
| } | |
| //===----------------------------------------------------------------------===// | |
| // TreePattern implementation | |
| // | |
| TreePattern::TreePattern(const Record *TheRec, const ListInit *RawPat, | |
| bool isInput, CodeGenDAGPatterns &cdp) | |
| : TheRecord(TheRec), CDP(cdp), isInputPattern(isInput), HasError(false), | |
| Infer(*this) { | |
| for (const Init *I : RawPat->getElements()) { | |
| TreePatternNodePtr Node = ParseTreePattern(I, ""); | |
| if (!Node) | |
| return; | |
| Trees.push_back(Node); | |
| } | |
| } | |
| TreePattern::TreePattern(const Record *TheRec, const DagInit *Pat, bool isInput, | |
| CodeGenDAGPatterns &cdp) | |
| : TheRecord(TheRec), CDP(cdp), isInputPattern(isInput), HasError(false), | |
| Infer(*this) { | |
| TreePatternNodePtr Node = ParseTreePattern(Pat, ""); | |
| if (!Node) | |
| return; | |
| Trees.push_back(Node); | |
| } | |
| TreePattern::TreePattern(const Record *TheRec, ArrayRef<const Init *> Args, | |
| ArrayRef<const StringInit *> ArgNames, bool isInput, | |
| CodeGenDAGPatterns &cdp) | |
| : TheRecord(TheRec), CDP(cdp), isInputPattern(isInput), HasError(false), | |
| Infer(*this) { | |
| Trees.push_back(ParseRootlessTreePattern(Args, ArgNames)); | |
| } | |
| TreePattern::TreePattern(const Record *TheRec, TreePatternNodePtr Pat, | |
| bool isInput, CodeGenDAGPatterns &cdp) | |
| : TheRecord(TheRec), CDP(cdp), isInputPattern(isInput), HasError(false), | |
| Infer(*this) { | |
| Trees.push_back(Pat); | |
| } | |
| void TreePattern::error(const Twine &Msg) { | |
| if (HasError) | |
| return; | |
| dump(); | |
| PrintError(TheRecord->getLoc(), "In " + TheRecord->getName() + ": " + Msg); | |
| HasError = true; | |
| } | |
| void TreePattern::ComputeNamedNodes() { | |
| for (TreePatternNodePtr &Tree : Trees) | |
| ComputeNamedNodes(*Tree); | |
| } | |
| void TreePattern::ComputeNamedNodes(TreePatternNode &N) { | |
| if (!N.getName().empty()) | |
| NamedNodes[N.getName()].push_back(&N); | |
| for (TreePatternNode &Child : N.children()) | |
| ComputeNamedNodes(Child); | |
| } | |
| TreePatternNodePtr | |
| TreePattern::ParseRootlessTreePattern(ArrayRef<const Init *> Args, | |
| ArrayRef<const StringInit *> ArgNames) { | |
| std::vector<TreePatternNodePtr> Children; | |
| for (auto [Arg, ArgName] : llvm::zip_equal(Args, ArgNames)) { | |
| StringRef NameStr = ArgName ? ArgName->getValue() : ""; | |
| Children.push_back(ParseTreePattern(Arg, NameStr)); | |
| } | |
| return makeIntrusiveRefCnt<TreePatternNode>(nullptr, std::move(Children), 1); | |
| } | |
| TreePatternNodePtr TreePattern::ParseTreePattern(const Init *TheInit, | |
| StringRef OpName) { | |
| RecordKeeper &RK = TheInit->getRecordKeeper(); | |
| // Here, we are creating new records (BitsInit->InitInit), so const_cast | |
| // TheInit back to non-const pointer. | |
| if (const DefInit *DI = dyn_cast<DefInit>(TheInit)) { | |
| const Record *R = DI->getDef(); | |
| // Direct reference to a leaf DagNode or PatFrag? Turn it into a | |
| // TreePatternNode of its own. For example: | |
| /// (foo GPR, imm) -> (foo GPR, (imm)) | |
| if (R->isSubClassOf("SDNode") || R->isSubClassOf("PatFrags")) | |
| return ParseTreePattern(DagInit::get(DI, {}), OpName); | |
| // Input argument? | |
| TreePatternNodePtr Res = makeIntrusiveRefCnt<TreePatternNode>(DI, 1); | |
| if (R->getName() == "node" && !OpName.empty()) { | |
| if (OpName.empty()) | |
| error("'node' argument requires a name to match with operand list"); | |
| Args.push_back(OpName.str()); | |
| } | |
| Res->setName(OpName); | |
| return Res; | |
| } | |
| // ?:$name or just $name. | |
| if (isa<UnsetInit>(TheInit)) { | |
| if (OpName.empty()) | |
| error("'?' argument requires a name to match with operand list"); | |
| TreePatternNodePtr Res = makeIntrusiveRefCnt<TreePatternNode>(TheInit, 1); | |
| Args.push_back(OpName.str()); | |
| Res->setName(OpName); | |
| return Res; | |
| } | |
| if (isa<IntInit>(TheInit) || isa<BitInit>(TheInit)) { | |
| if (!OpName.empty()) | |
| error("Constant int or bit argument should not have a name!"); | |
| if (isa<BitInit>(TheInit)) | |
| TheInit = TheInit->convertInitializerTo(IntRecTy::get(RK)); | |
| return makeIntrusiveRefCnt<TreePatternNode>(TheInit, 1); | |
| } | |
| if (const BitsInit *BI = dyn_cast<BitsInit>(TheInit)) { | |
| // Turn this into an IntInit. | |
| const Init *II = BI->convertInitializerTo(IntRecTy::get(RK)); | |
| if (!II || !isa<IntInit>(II)) | |
| error("Bits value must be constants!"); | |
| return II ? ParseTreePattern(II, OpName) : nullptr; | |
| } | |
| const DagInit *Dag = dyn_cast<DagInit>(TheInit); | |
| if (!Dag) { | |
| TheInit->print(errs()); | |
| error("Pattern has unexpected init kind!"); | |
| return nullptr; | |
| } | |
| auto ParseCastOperand = [this](const DagInit *Dag, | |
| StringRef OpName) -> TreePatternNodePtr { | |
| if (Dag->getNumArgs() != 1) { | |
| error("Type cast only takes one operand!"); | |
| return nullptr; | |
| } | |
| if (!OpName.empty()) { | |
| error("Type cast should not have a name!"); | |
| return nullptr; | |
| } | |
| return ParseTreePattern(Dag->getArg(0), Dag->getArgNameStr(0)); | |
| }; | |
| if (const ListInit *LI = dyn_cast<ListInit>(Dag->getOperator())) { | |
| // If the operator is a list (of value types), then this must be "type cast" | |
| // of a leaf node with multiple results. | |
| TreePatternNodePtr New = ParseCastOperand(Dag, OpName); | |
| if (!New) | |
| return nullptr; | |
| size_t NumTypes = New->getNumTypes(); | |
| if (LI->empty() || LI->size() != NumTypes) | |
| error("Invalid number of type casts!"); | |
| // Apply the type casts. | |
| const CodeGenHwModes &CGH = getDAGPatterns().getTargetInfo().getHwModes(); | |
| for (unsigned i = 0; i < std::min(NumTypes, LI->size()); ++i) | |
| New->UpdateNodeType( | |
| i, getValueTypeByHwMode(LI->getElementAsRecord(i), CGH), *this); | |
| return New; | |
| } | |
| const DefInit *OpDef = dyn_cast<DefInit>(Dag->getOperator()); | |
| if (!OpDef) { | |
| error("Pattern has unexpected operator type!"); | |
| return nullptr; | |
| } | |
| const Record *Operator = OpDef->getDef(); | |
| if (Operator->isSubClassOf("ValueType")) { | |
| // If the operator is a ValueType, then this must be "type cast" of a leaf | |
| // node. | |
| TreePatternNodePtr New = ParseCastOperand(Dag, OpName); | |
| if (!New) | |
| return nullptr; | |
| if (New->getNumTypes() != 1) | |
| error("ValueType cast can only have one type!"); | |
| // Apply the type cast. | |
| const CodeGenHwModes &CGH = getDAGPatterns().getTargetInfo().getHwModes(); | |
| New->UpdateNodeType(0, getValueTypeByHwMode(Operator, CGH), *this); | |
| return New; | |
| } | |
| // Verify that this is something that makes sense for an operator. | |
| if (!Operator->isSubClassOf("PatFrags") && | |
| !Operator->isSubClassOf("SDNode") && | |
| !Operator->isSubClassOf("Instruction") && | |
| !Operator->isSubClassOf("SDNodeXForm") && | |
| !Operator->isSubClassOf("Intrinsic") && | |
| !Operator->isSubClassOf("ComplexPattern") && Operator->getName() != "set") | |
| error("Unrecognized node '" + Operator->getName() + "'!"); | |
| // Check to see if this is something that is illegal in an input pattern. | |
| if (isInputPattern) { | |
| if (Operator->isSubClassOf("Instruction") || | |
| Operator->isSubClassOf("SDNodeXForm")) | |
| error("Cannot use '" + Operator->getName() + "' in an input pattern!"); | |
| } else { | |
| if (Operator->isSubClassOf("Intrinsic")) | |
| error("Cannot use '" + Operator->getName() + "' in an output pattern!"); | |
| if (Operator->isSubClassOf("SDNode") && Operator->getName() != "imm" && | |
| Operator->getName() != "timm" && Operator->getName() != "fpimm" && | |
| Operator->getName() != "tglobaltlsaddr" && | |
| Operator->getName() != "tconstpool" && | |
| Operator->getName() != "tjumptable" && | |
| Operator->getName() != "tframeindex" && | |
| Operator->getName() != "texternalsym" && | |
| Operator->getName() != "tblockaddress" && | |
| Operator->getName() != "tglobaladdr" && Operator->getName() != "bb" && | |
| Operator->getName() != "vt" && Operator->getName() != "mcsym") | |
| error("Cannot use '" + Operator->getName() + "' in an output pattern!"); | |
| } | |
| std::vector<TreePatternNodePtr> Children; | |
| // Parse all the operands. | |
| for (unsigned i = 0, e = Dag->getNumArgs(); i != e; ++i) { | |
| TreePatternNodePtr Child = | |
| ParseTreePattern(Dag->getArg(i), Dag->getArgNameStr(i)); | |
| if (!Child) | |
| return nullptr; | |
| Children.push_back(Child); | |
| } | |
| // Get the actual number of results before Operator is converted to an | |
| // intrinsic node (which is hard-coded to have either zero or one result). | |
| unsigned NumResults = GetNumNodeResults(Operator, CDP); | |
| // If the operator is an intrinsic, then this is just syntactic sugar for | |
| // (intrinsic_* <number>, ..children..). Pick the right intrinsic node, and | |
| // convert the intrinsic name to a number. | |
| if (Operator->isSubClassOf("Intrinsic")) { | |
| const CodeGenIntrinsic &Int = getDAGPatterns().getIntrinsic(Operator); | |
| unsigned IID = getDAGPatterns().getIntrinsicID(Operator) + 1; | |
| // If this intrinsic returns void, it must have side-effects and thus a | |
| // chain. | |
| if (Int.IS.RetTys.empty()) | |
| Operator = getDAGPatterns().get_intrinsic_void_sdnode(); | |
| else if (!Int.ME.doesNotAccessMemory() || Int.hasSideEffects) | |
| // Has side-effects, requires chain. | |
| Operator = getDAGPatterns().get_intrinsic_w_chain_sdnode(); | |
| else // Otherwise, no chain. | |
| Operator = getDAGPatterns().get_intrinsic_wo_chain_sdnode(); | |
| Children.insert(Children.begin(), makeIntrusiveRefCnt<TreePatternNode>( | |
| IntInit::get(RK, IID), 1)); | |
| } | |
| if (Operator->isSubClassOf("ComplexPattern")) { | |
| for (unsigned i = 0; i < Children.size(); ++i) { | |
| TreePatternNodePtr Child = Children[i]; | |
| if (Child->getName().empty()) | |
| error("All arguments to a ComplexPattern must be named"); | |
| // Check that the ComplexPattern uses are consistent: "(MY_PAT $a, $b)" | |
| // and "(MY_PAT $b, $a)" should not be allowed in the same pattern; | |
| // neither should "(MY_PAT_1 $a, $b)" and "(MY_PAT_2 $a, $b)". | |
| auto OperandId = std::pair(Operator, i); | |
| auto [PrevOp, Inserted] = | |
| ComplexPatternOperands.try_emplace(Child->getName(), OperandId); | |
| if (!Inserted && PrevOp->getValue() != OperandId) { | |
| error("All ComplexPattern operands must appear consistently: " | |
| "in the same order in just one ComplexPattern instance."); | |
| } | |
| } | |
| } | |
| TreePatternNodePtr Result = makeIntrusiveRefCnt<TreePatternNode>( | |
| Operator, std::move(Children), NumResults); | |
| Result->setName(OpName); | |
| if (Dag->getName()) { | |
| assert(Result->getName().empty()); | |
| Result->setName(Dag->getNameStr()); | |
| } | |
| return Result; | |
| } | |
| /// SimplifyTree - See if we can simplify this tree to eliminate something that | |
| /// will never match in favor of something obvious that will. This is here | |
| /// strictly as a convenience to target authors because it allows them to write | |
| /// more type generic things and have useless type casts fold away. | |
| /// | |
| /// This returns true if any change is made. | |
| static bool SimplifyTree(TreePatternNodePtr &N) { | |
| if (N->isLeaf()) | |
| return false; | |
| // If we have a bitconvert with a resolved type and if the source and | |
| // destination types are the same, then the bitconvert is useless, remove it. | |
| // | |
| // We make an exception if the types are completely empty. This can come up | |
| // when the pattern being simplified is in the Fragments list of a PatFrags, | |
| // so that the operand is just an untyped "node". In that situation we leave | |
| // bitconverts unsimplified, and simplify them later once the fragment is | |
| // expanded into its true context. | |
| if (N->getOperator()->getName() == "bitconvert" && | |
| N->getExtType(0).isValueTypeByHwMode(false) && | |
| !N->getExtType(0).empty() && | |
| N->getExtType(0) == N->getChild(0).getExtType(0) && | |
| N->getName().empty()) { | |
| if (!N->getPredicateCalls().empty()) { | |
| std::string Str; | |
| raw_string_ostream OS(Str); | |
| OS << *N | |
| << "\n trivial bitconvert node should not have predicate calls\n"; | |
| PrintFatalError(Str); | |
| return false; | |
| } | |
| N = N->getChildShared(0); | |
| SimplifyTree(N); | |
| return true; | |
| } | |
| // Walk all children. | |
| bool MadeChange = false; | |
| for (unsigned i = 0, e = N->getNumChildren(); i != e; ++i) | |
| MadeChange |= SimplifyTree(N->getChildSharedPtr(i)); | |
| return MadeChange; | |
| } | |
| /// InferAllTypes - Infer/propagate as many types throughout the expression | |
| /// patterns as possible. Return true if all types are inferred, false | |
| /// otherwise. Flags an error if a type contradiction is found. | |
| bool TreePattern::InferAllTypes( | |
| const StringMap<SmallVector<TreePatternNode *, 1>> *InNamedTypes) { | |
| if (NamedNodes.empty()) | |
| ComputeNamedNodes(); | |
| bool MadeChange = true; | |
| while (MadeChange) { | |
| MadeChange = false; | |
| for (TreePatternNodePtr &Tree : Trees) { | |
| MadeChange |= Tree->ApplyTypeConstraints(*this, false); | |
| MadeChange |= SimplifyTree(Tree); | |
| } | |
| // If there are constraints on our named nodes, apply them. | |
| for (auto &Entry : NamedNodes) { | |
| SmallVectorImpl<TreePatternNode *> &Nodes = Entry.second; | |
| // If we have input named node types, propagate their types to the named | |
| // values here. | |
| if (InNamedTypes) { | |
| auto InIter = InNamedTypes->find(Entry.getKey()); | |
| if (InIter == InNamedTypes->end()) { | |
| error("Node '" + Entry.getKey().str() + | |
| "' in output pattern but not input pattern"); | |
| return true; | |
| } | |
| ArrayRef<TreePatternNode *> InNodes = InIter->second; | |
| // The input types should be fully resolved by now. | |
| for (TreePatternNode *Node : Nodes) { | |
| // If this node is a register class, and it is the root of the pattern | |
| // then we're mapping something onto an input register. We allow | |
| // changing the type of the input register in this case. This allows | |
| // us to match things like: | |
| // def : Pat<(v1i64 (bitconvert(v2i32 DPR:$src))), (v1i64 DPR:$src)>; | |
| if (Node == Trees[0].get() && Node->isLeaf()) { | |
| const DefInit *DI = dyn_cast<DefInit>(Node->getLeafValue()); | |
| if (DI && (DI->getDef()->isSubClassOf("RegisterClass") || | |
| DI->getDef()->isSubClassOf("RegisterOperand"))) | |
| continue; | |
| } | |
| assert(Node->getNumTypes() == 1 && InNodes[0]->getNumTypes() == 1 && | |
| "FIXME: cannot name multiple result nodes yet"); | |
| MadeChange |= | |
| Node->UpdateNodeType(0, InNodes[0]->getExtType(0), *this); | |
| } | |
| } | |
| // If there are multiple nodes with the same name, they must all have the | |
| // same type. | |
| if (Entry.second.size() > 1) { | |
| for (unsigned i = 0, e = Nodes.size() - 1; i != e; ++i) { | |
| TreePatternNode *N1 = Nodes[i], *N2 = Nodes[i + 1]; | |
| assert(N1->getNumTypes() == 1 && N2->getNumTypes() == 1 && | |
| "FIXME: cannot name multiple result nodes yet"); | |
| MadeChange |= N1->UpdateNodeType(0, N2->getExtType(0), *this); | |
| MadeChange |= N2->UpdateNodeType(0, N1->getExtType(0), *this); | |
| } | |
| } | |
| } | |
| } | |
| bool HasUnresolvedTypes = false; | |
| for (const TreePatternNodePtr &Tree : Trees) | |
| HasUnresolvedTypes |= Tree->ContainsUnresolvedType(*this); | |
| return !HasUnresolvedTypes; | |
| } | |
| void TreePattern::print(raw_ostream &OS) const { | |
| OS << getRecord()->getName(); | |
| if (!Args.empty()) | |
| OS << '(' << llvm::interleaved(Args) << ')'; | |
| OS << ": "; | |
| if (Trees.size() > 1) | |
| OS << "[\n"; | |
| for (const TreePatternNodePtr &Tree : Trees) { | |
| OS << "\t"; | |
| Tree->print(OS); | |
| OS << "\n"; | |
| } | |
| if (Trees.size() > 1) | |
| OS << "]\n"; | |
| } | |
| void TreePattern::dump() const { print(dbgs()); } | |
| //===----------------------------------------------------------------------===// | |
| // CodeGenDAGPatterns implementation | |
| // | |
| CodeGenDAGPatterns::CodeGenDAGPatterns(const RecordKeeper &R, bool ExpandHwMode) | |
| : Records(R), Target(R), Intrinsics(R), | |
| LegalVTS(Target.getLegalValueTypes()), | |
| LegalPtrVTS(ComputeLegalPtrTypes()) { | |
| IntrinsicIDs.reserve(Intrinsics.size()); | |
| for (auto [ID, Intrinsic] : enumerate(Intrinsics)) | |
| IntrinsicIDs.try_emplace(Intrinsic.TheDef, ID); | |
| ParseNodeInfo(); | |
| ParseNodeTransforms(); | |
| ParseComplexPatterns(); | |
| ParsePatternFragments(); | |
| ParseDefaultOperands(); | |
| ParseInstructions(); | |
| ParsePatternFragments(/*OutFrags*/ true); | |
| ParsePatterns(); | |
| // Generate variants. For example, commutative patterns can match | |
| // multiple ways. Add them to PatternsToMatch as well. | |
| GenerateVariants(); | |
| // Break patterns with parameterized types into a series of patterns, | |
| // where each one has a fixed type and is predicated on the conditions | |
| // of the associated HW mode. | |
| if (ExpandHwMode) | |
| ExpandHwModeBasedTypes(); | |
| // Infer instruction flags. For example, we can detect loads, | |
| // stores, and side effects in many cases by examining an | |
| // instruction's pattern. | |
| InferInstructionFlags(); | |
| // Verify that instruction flags match the patterns. | |
| VerifyInstructionFlags(); | |
| } | |
| const Record *CodeGenDAGPatterns::getSDNodeNamed(StringRef Name) const { | |
| const Record *N = Records.getDef(Name); | |
| if (!N || !N->isSubClassOf("SDNode")) | |
| PrintFatalError("Error getting SDNode '" + Name + "'!"); | |
| return N; | |
| } | |
| // Compute the subset of iPTR and cPTR legal for each mode, coalescing into the | |
| // default mode where possible to avoid predicate explosion. | |
| TypeSetByHwMode CodeGenDAGPatterns::ComputeLegalPtrTypes() const { | |
| auto LegalPtrsForSet = [](const MachineValueTypeSet &In) { | |
| MachineValueTypeSet Out; | |
| Out.insert(MVT::iPTR); | |
| for (MVT T : MVT::cheri_capability_valuetypes()) { | |
| if (In.count(T)) { | |
| Out.insert(MVT::cPTR); | |
| break; | |
| } | |
| } | |
| return Out; | |
| }; | |
| const TypeSetByHwMode &LegalTypes = getLegalTypes(); | |
| MachineValueTypeSet LegalPtrsDefault = | |
| LegalPtrsForSet(LegalTypes.get(DefaultMode)); | |
| TypeSetByHwMode LegalPtrTypes; | |
| for (const auto &I : LegalTypes) { | |
| MachineValueTypeSet S = LegalPtrsForSet(I.second); | |
| if (I.first != DefaultMode && S == LegalPtrsDefault) | |
| continue; | |
| LegalPtrTypes.getOrCreate(I.first).insert(S); | |
| } | |
| return LegalPtrTypes; | |
| } | |
| // Parse all of the SDNode definitions for the target, populating SDNodes. | |
| void CodeGenDAGPatterns::ParseNodeInfo() { | |
| const CodeGenHwModes &CGH = getTargetInfo().getHwModes(); | |
| for (const Record *R : reverse(Records.getAllDerivedDefinitions("SDNode"))) | |
| SDNodes.try_emplace(R, SDNodeInfo(R, CGH)); | |
| // Get the builtin intrinsic nodes. | |
| intrinsic_void_sdnode = getSDNodeNamed("intrinsic_void"); | |
| intrinsic_w_chain_sdnode = getSDNodeNamed("intrinsic_w_chain"); | |
| intrinsic_wo_chain_sdnode = getSDNodeNamed("intrinsic_wo_chain"); | |
| } | |
| /// ParseNodeTransforms - Parse all SDNodeXForm instances into the SDNodeXForms | |
| /// map, and emit them to the file as functions. | |
| void CodeGenDAGPatterns::ParseNodeTransforms() { | |
| for (const Record *XFormNode : | |
| reverse(Records.getAllDerivedDefinitions("SDNodeXForm"))) { | |
| const Record *SDNode = XFormNode->getValueAsDef("Opcode"); | |
| StringRef Code = XFormNode->getValueAsString("XFormFunction"); | |
| SDNodeXForms.try_emplace(XFormNode, NodeXForm(SDNode, Code.str())); | |
| } | |
| } | |
| void CodeGenDAGPatterns::ParseComplexPatterns() { | |
| for (const Record *R : | |
| reverse(Records.getAllDerivedDefinitions("ComplexPattern"))) | |
| ComplexPatterns.try_emplace(R, R); | |
| } | |
| /// ParsePatternFragments - Parse all of the PatFrag definitions in the .td | |
| /// file, building up the PatternFragments map. After we've collected them all, | |
| /// inline fragments together as necessary, so that there are no references left | |
| /// inside a pattern fragment to a pattern fragment. | |
| /// | |
| void CodeGenDAGPatterns::ParsePatternFragments(bool OutFrags) { | |
| // First step, parse all of the fragments. | |
| ArrayRef<const Record *> Fragments = | |
| Records.getAllDerivedDefinitions("PatFrags"); | |
| for (const Record *Frag : Fragments) { | |
| if (OutFrags != Frag->isSubClassOf("OutPatFrag")) | |
| continue; | |
| const ListInit *LI = Frag->getValueAsListInit("Fragments"); | |
| TreePattern *P = (PatternFragments[Frag] = std::make_unique<TreePattern>( | |
| Frag, LI, !Frag->isSubClassOf("OutPatFrag"), *this)) | |
| .get(); | |
| // Validate the argument list, converting it to set, to discard duplicates. | |
| std::vector<std::string> &Args = P->getArgList(); | |
| // Copy the args so we can take StringRefs to them. | |
| auto ArgsCopy = Args; | |
| SmallDenseSet<StringRef, 4> OperandsSet(llvm::from_range, ArgsCopy); | |
| if (OperandsSet.contains("")) | |
| P->error("Cannot have unnamed 'node' values in pattern fragment!"); | |
| // Parse the operands list. | |
| const DagInit *OpsList = Frag->getValueAsDag("Operands"); | |
| const DefInit *OpsOp = dyn_cast<DefInit>(OpsList->getOperator()); | |
| // Special cases: ops == outs == ins. Different names are used to | |
| // improve readability. | |
| if (!OpsOp || (OpsOp->getDef()->getName() != "ops" && | |
| OpsOp->getDef()->getName() != "outs" && | |
| OpsOp->getDef()->getName() != "ins")) | |
| P->error("Operands list should start with '(ops ... '!"); | |
| // Copy over the arguments. | |
| Args.clear(); | |
| for (unsigned j = 0, e = OpsList->getNumArgs(); j != e; ++j) { | |
| if (!isa<DefInit>(OpsList->getArg(j)) || | |
| cast<DefInit>(OpsList->getArg(j))->getDef()->getName() != "node") | |
| P->error("Operands list should all be 'node' values."); | |
| if (!OpsList->getArgName(j)) | |
| P->error("Operands list should have names for each operand!"); | |
| StringRef ArgNameStr = OpsList->getArgNameStr(j); | |
| if (!OperandsSet.erase(ArgNameStr)) | |
| P->error("'" + ArgNameStr + | |
| "' does not occur in pattern or was multiply specified!"); | |
| Args.push_back(ArgNameStr.str()); | |
| } | |
| if (!OperandsSet.empty()) | |
| P->error("Operands list does not contain an entry for operand '" + | |
| *OperandsSet.begin() + "'!"); | |
| // If there is a node transformation corresponding to this, keep track of | |
| // it. | |
| const Record *Transform = Frag->getValueAsDef("OperandTransform"); | |
| if (!getSDNodeTransform(Transform).second.empty()) // not noop xform? | |
| for (const auto &T : P->getTrees()) | |
| T->setTransformFn(Transform); | |
| } | |
| // Now that we've parsed all of the tree fragments, do a closure on them so | |
| // that there are not references to PatFrags left inside of them. | |
| for (const Record *Frag : Fragments) { | |
| if (OutFrags != Frag->isSubClassOf("OutPatFrag")) | |
| continue; | |
| TreePattern &ThePat = *PatternFragments[Frag]; | |
| ThePat.InlinePatternFragments(); | |
| // Infer as many types as possible. Don't worry about it if we don't infer | |
| // all of them, some may depend on the inputs of the pattern. Also, don't | |
| // validate type sets; validation may cause spurious failures e.g. if a | |
| // fragment needs floating-point types but the current target does not have | |
| // any (this is only an error if that fragment is ever used!). | |
| { | |
| TypeInfer::SuppressValidation SV(ThePat.getInfer()); | |
| ThePat.InferAllTypes(); | |
| ThePat.resetError(); | |
| } | |
| // If debugging, print out the pattern fragment result. | |
| LLVM_DEBUG(ThePat.dump()); | |
| } | |
| } | |
| void CodeGenDAGPatterns::ParseDefaultOperands() { | |
| ArrayRef<const Record *> DefaultOps = | |
| Records.getAllDerivedDefinitions("OperandWithDefaultOps"); | |
| for (unsigned i = 0, e = DefaultOps.size(); i != e; ++i) { | |
| const DagInit *DefaultInfo = DefaultOps[i]->getValueAsDag("DefaultOps"); | |
| // Create a TreePattern to parse this. | |
| TreePattern P(DefaultOps[i], DefaultInfo->getArgs(), | |
| DefaultInfo->getArgNames(), false, *this); | |
| assert(P.getNumTrees() == 1 && "This ctor can only produce one tree!"); | |
| // Copy the operands over into a DAGDefaultOperand. | |
| DAGDefaultOperand DefaultOpInfo; | |
| const TreePatternNodePtr &T = P.getTree(0); | |
| for (unsigned op = 0, e = T->getNumChildren(); op != e; ++op) { | |
| TreePatternNodePtr TPN = T->getChildShared(op); | |
| while (TPN->ApplyTypeConstraints(P, false)) | |
| /* Resolve all types */; | |
| if (TPN->ContainsUnresolvedType(P)) { | |
| PrintFatalError("Value #" + Twine(i) + " of OperandWithDefaultOps '" + | |
| DefaultOps[i]->getName() + | |
| "' doesn't have a concrete type!"); | |
| } | |
| DefaultOpInfo.DefaultOps.push_back(std::move(TPN)); | |
| } | |
| // Insert it into the DefaultOperands map so we can find it later. | |
| DefaultOperands[DefaultOps[i]] = DefaultOpInfo; | |
| } | |
| } | |
| /// HandleUse - Given "Pat" a leaf in the pattern, check to see if it is an | |
| /// instruction input. Return true if this is a real use. | |
| static bool HandleUse(TreePattern &I, TreePatternNodePtr Pat, | |
| std::map<StringRef, TreePatternNodePtr> &InstInputs) { | |
| // No name -> not interesting. | |
| if (Pat->getName().empty()) { | |
| if (Pat->isLeaf()) { | |
| const DefInit *DI = dyn_cast<DefInit>(Pat->getLeafValue()); | |
| if (DI && (DI->getDef()->isSubClassOf("RegisterClass") || | |
| DI->getDef()->isSubClassOf("RegisterOperand"))) | |
| I.error("Input " + DI->getDef()->getName() + " must be named!"); | |
| } | |
| return false; | |
| } | |
| const Record *Rec; | |
| if (Pat->isLeaf()) { | |
| const DefInit *DI = dyn_cast<DefInit>(Pat->getLeafValue()); | |
| if (!DI) { | |
| I.error("Input $" + Pat->getName() + " must be an identifier!"); | |
| return false; | |
| } | |
| Rec = DI->getDef(); | |
| } else { | |
| Rec = Pat->getOperator(); | |
| } | |
| // SRCVALUE nodes are ignored. | |
| if (Rec->getName() == "srcvalue") | |
| return false; | |
| TreePatternNodePtr &Slot = InstInputs[Pat->getName()]; | |
| if (!Slot) { | |
| Slot = Pat; | |
| return true; | |
| } | |
| const Record *SlotRec; | |
| if (Slot->isLeaf()) { | |
| SlotRec = cast<DefInit>(Slot->getLeafValue())->getDef(); | |
| } else { | |
| assert(Slot->getNumChildren() == 0 && "can't be a use with children!"); | |
| SlotRec = Slot->getOperator(); | |
| } | |
| // Ensure that the inputs agree if we've already seen this input. | |
| if (Rec != SlotRec) | |
| I.error("All $" + Pat->getName() + " inputs must agree with each other"); | |
| // Ensure that the types can agree as well. | |
| Slot->UpdateNodeType(0, Pat->getExtType(0), I); | |
| Pat->UpdateNodeType(0, Slot->getExtType(0), I); | |
| if (Slot->getExtTypes() != Pat->getExtTypes()) | |
| I.error("All $" + Pat->getName() + " inputs must agree with each other"); | |
| return true; | |
| } | |
| /// FindPatternInputsAndOutputs - Scan the specified TreePatternNode (which is | |
| /// part of "I", the instruction), computing the set of inputs and outputs of | |
| /// the pattern. Report errors if we see anything naughty. | |
| void CodeGenDAGPatterns::FindPatternInputsAndOutputs( | |
| TreePattern &I, TreePatternNodePtr Pat, InstInputsTy &InstInputs, | |
| InstResultsTy &InstResults, std::vector<const Record *> &InstImpResults) { | |
| // The instruction pattern still has unresolved fragments. For *named* | |
| // nodes we must resolve those here. This may not result in multiple | |
| // alternatives. | |
| if (!Pat->getName().empty()) { | |
| TreePattern SrcPattern(I.getRecord(), Pat, true, *this); | |
| SrcPattern.InlinePatternFragments(); | |
| SrcPattern.InferAllTypes(); | |
| Pat = SrcPattern.getOnlyTree(); | |
| } | |
| if (Pat->isLeaf()) { | |
| bool isUse = HandleUse(I, Pat, InstInputs); | |
| if (!isUse && Pat->getTransformFn()) | |
| I.error("Cannot specify a transform function for a non-input value!"); | |
| return; | |
| } | |
| if (Pat->getOperator()->getName() != "set") { | |
| // If this is not a set, verify that the children nodes are not void typed, | |
| // and recurse. | |
| for (unsigned i = 0, e = Pat->getNumChildren(); i != e; ++i) { | |
| if (Pat->getChild(i).getNumTypes() == 0) | |
| I.error("Cannot have void nodes inside of patterns!"); | |
| FindPatternInputsAndOutputs(I, Pat->getChildShared(i), InstInputs, | |
| InstResults, InstImpResults); | |
| } | |
| // If this is a non-leaf node with no children, treat it basically as if | |
| // it were a leaf. This handles nodes like (imm). | |
| bool isUse = HandleUse(I, Pat, InstInputs); | |
| if (!isUse && Pat->getTransformFn()) | |
| I.error("Cannot specify a transform function for a non-input value!"); | |
| return; | |
| } | |
| // Otherwise, this is a set, validate and collect instruction results. | |
| if (Pat->getNumChildren() == 0) | |
| I.error("set requires operands!"); | |
| if (Pat->getTransformFn()) | |
| I.error("Cannot specify a transform function on a set node!"); | |
| // Check the set destinations. | |
| unsigned NumDests = Pat->getNumChildren() - 1; | |
| for (unsigned i = 0; i != NumDests; ++i) { | |
| TreePatternNodePtr Dest = Pat->getChildShared(i); | |
| // For set destinations we also must resolve fragments here. | |
| TreePattern DestPattern(I.getRecord(), Dest, false, *this); | |
| DestPattern.InlinePatternFragments(); | |
| DestPattern.InferAllTypes(); | |
| Dest = DestPattern.getOnlyTree(); | |
| if (!Dest->isLeaf()) | |
| I.error("set destination should be a register!"); | |
| const DefInit *Val = dyn_cast<DefInit>(Dest->getLeafValue()); | |
| if (!Val) { | |
| I.error("set destination should be a register!"); | |
| continue; | |
| } | |
| if (Val->getDef()->isSubClassOf("RegisterClassLike") || | |
| Val->getDef()->isSubClassOf("ValueType") || | |
| Val->getDef()->isSubClassOf("RegisterOperand")) { | |
| if (Dest->getName().empty()) | |
| I.error("set destination must have a name!"); | |
| if (!InstResults.insert_or_assign(Dest->getName(), Dest).second) | |
| I.error("cannot set '" + Dest->getName() + "' multiple times"); | |
| } else if (Val->getDef()->isSubClassOf("Register")) { | |
| InstImpResults.push_back(Val->getDef()); | |
| } else { | |
| I.error("set destination should be a register!"); | |
| } | |
| } | |
| // Verify and collect info from the computation. | |
| FindPatternInputsAndOutputs(I, Pat->getChildShared(NumDests), InstInputs, | |
| InstResults, InstImpResults); | |
| } | |
| //===----------------------------------------------------------------------===// | |
| // Instruction Analysis | |
| //===----------------------------------------------------------------------===// | |
| class InstAnalyzer { | |
| const CodeGenDAGPatterns &CDP; | |
| public: | |
| bool hasSideEffects = false; | |
| bool mayStore = false; | |
| bool mayLoad = false; | |
| bool isBitcast = false; | |
| bool isVariadic = false; | |
| bool hasChain = false; | |
| InstAnalyzer(const CodeGenDAGPatterns &cdp) : CDP(cdp) {} | |
| void Analyze(const PatternToMatch &Pat) { | |
| const TreePatternNode &N = Pat.getSrcPattern(); | |
| AnalyzeNode(N); | |
| // These properties are detected only on the root node. | |
| isBitcast = IsNodeBitcast(N); | |
| } | |
| private: | |
| bool IsNodeBitcast(const TreePatternNode &N) const { | |
| if (hasSideEffects || mayLoad || mayStore || isVariadic) | |
| return false; | |
| if (N.isLeaf()) | |
| return false; | |
| if (N.getNumChildren() != 1 || !N.getChild(0).isLeaf()) | |
| return false; | |
| if (N.getOperator()->isSubClassOf("ComplexPattern")) | |
| return false; | |
| const SDNodeInfo &OpInfo = CDP.getSDNodeInfo(N.getOperator()); | |
| if (OpInfo.getNumResults() != 1 || OpInfo.getNumOperands() != 1) | |
| return false; | |
| return OpInfo.getEnumName() == "ISD::BITCAST"; | |
| } | |
| public: | |
| void AnalyzeNode(const TreePatternNode &N) { | |
| if (N.isLeaf()) { | |
| if (const DefInit *DI = dyn_cast<DefInit>(N.getLeafValue())) { | |
| const Record *LeafRec = DI->getDef(); | |
| // Handle ComplexPattern leaves. | |
| if (LeafRec->isSubClassOf("ComplexPattern")) { | |
| const ComplexPattern &CP = CDP.getComplexPattern(LeafRec); | |
| if (CP.hasProperty(SDNPMayStore)) | |
| mayStore = true; | |
| if (CP.hasProperty(SDNPMayLoad)) | |
| mayLoad = true; | |
| if (CP.hasProperty(SDNPSideEffect)) | |
| hasSideEffects = true; | |
| } | |
| } | |
| return; | |
| } | |
| // Analyze children. | |
| for (const TreePatternNode &Child : N.children()) | |
| AnalyzeNode(Child); | |
| // Notice properties of the node. | |
| if (N.NodeHasProperty(SDNPMayStore, CDP)) | |
| mayStore = true; | |
| if (N.NodeHasProperty(SDNPMayLoad, CDP)) | |
| mayLoad = true; | |
| if (N.NodeHasProperty(SDNPSideEffect, CDP)) | |
| hasSideEffects = true; | |
| if (N.NodeHasProperty(SDNPVariadic, CDP)) | |
| isVariadic = true; | |
| if (N.NodeHasProperty(SDNPHasChain, CDP)) | |
| hasChain = true; | |
| if (const CodeGenIntrinsic *IntInfo = N.getIntrinsicInfo(CDP)) { | |
| ModRefInfo MR = IntInfo->ME.getModRef(); | |
| // If this is an intrinsic, analyze it. | |
| if (isRefSet(MR)) | |
| mayLoad = true; // These may load memory. | |
| if (isModSet(MR)) | |
| mayStore = true; // Intrinsics that can write to memory are 'mayStore'. | |
| // Consider intrinsics that don't specify any restrictions on memory | |
| // effects as having a side-effect. | |
| if (IntInfo->ME == MemoryEffects::unknown() || IntInfo->hasSideEffects) | |
| hasSideEffects = true; | |
| } | |
| } | |
| }; | |
| static bool InferFromPattern(CodeGenInstruction &InstInfo, | |
| const InstAnalyzer &PatInfo, | |
| const Record *PatDef) { | |
| bool Error = false; | |
| // Remember where InstInfo got its flags. | |
| if (InstInfo.hasUndefFlags()) | |
| InstInfo.InferredFrom = PatDef; | |
| // Check explicitly set flags for consistency. | |
| if (InstInfo.hasSideEffects != PatInfo.hasSideEffects && | |
| !InstInfo.hasSideEffects_Unset) { | |
| // Allow explicitly setting hasSideEffects = 1 on instructions, even when | |
| // the pattern has no side effects. That could be useful for div/rem | |
| // instructions that may trap. | |
| if (!InstInfo.hasSideEffects) { | |
| Error = true; | |
| PrintError(PatDef->getLoc(), "Pattern doesn't match hasSideEffects = " + | |
| Twine(InstInfo.hasSideEffects)); | |
| } | |
| } | |
| if (InstInfo.mayStore != PatInfo.mayStore && !InstInfo.mayStore_Unset) { | |
| Error = true; | |
| PrintError(PatDef->getLoc(), | |
| "Pattern doesn't match mayStore = " + Twine(InstInfo.mayStore)); | |
| } | |
| if (InstInfo.mayLoad != PatInfo.mayLoad && !InstInfo.mayLoad_Unset) { | |
| // Allow explicitly setting mayLoad = 1, even when the pattern has no loads. | |
| // Some targets translate immediates to loads. | |
| if (!InstInfo.mayLoad) { | |
| Error = true; | |
| PrintError(PatDef->getLoc(), | |
| "Pattern doesn't match mayLoad = " + Twine(InstInfo.mayLoad)); | |
| } | |
| } | |
| // Transfer inferred flags. | |
| InstInfo.hasSideEffects |= PatInfo.hasSideEffects; | |
| InstInfo.mayStore |= PatInfo.mayStore; | |
| InstInfo.mayLoad |= PatInfo.mayLoad; | |
| // These flags are silently added without any verification. | |
| // FIXME: To match historical behavior of TableGen, for now add those flags | |
| // only when we're inferring from the primary instruction pattern. | |
| if (PatDef->isSubClassOf("Instruction")) { | |
| InstInfo.isBitcast |= PatInfo.isBitcast; | |
| InstInfo.hasChain |= PatInfo.hasChain; | |
| InstInfo.hasChain_Inferred = true; | |
| } | |
| // Don't infer isVariadic. This flag means something different on SDNodes and | |
| // instructions. For example, a CALL SDNode is variadic because it has the | |
| // call arguments as operands, but a CALL instruction is not variadic - it | |
| // has argument registers as implicit, not explicit uses. | |
| return Error; | |
| } | |
| /// hasNullFragReference - Return true if the DAG has any reference to the | |
| /// null_frag operator. | |
| static bool hasNullFragReference(const DagInit *DI) { | |
| const DefInit *OpDef = dyn_cast<DefInit>(DI->getOperator()); | |
| if (!OpDef) | |
| return false; | |
| const Record *Operator = OpDef->getDef(); | |
| // If this is the null fragment, return true. | |
| if (Operator->getName() == "null_frag") | |
| return true; | |
| // If any of the arguments reference the null fragment, return true. | |
| for (unsigned i = 0, e = DI->getNumArgs(); i != e; ++i) { | |
| if (auto Arg = dyn_cast<DefInit>(DI->getArg(i))) | |
| if (Arg->getDef()->getName() == "null_frag") | |
| return true; | |
| const DagInit *Arg = dyn_cast<DagInit>(DI->getArg(i)); | |
| if (Arg && hasNullFragReference(Arg)) | |
| return true; | |
| } | |
| return false; | |
| } | |
| /// hasNullFragReference - Return true if any DAG in the list references | |
| /// the null_frag operator. | |
| static bool hasNullFragReference(const ListInit *LI) { | |
| for (const Init *I : LI->getElements()) { | |
| const DagInit *DI = dyn_cast<DagInit>(I); | |
| assert(DI && "non-dag in an instruction Pattern list?!"); | |
| if (hasNullFragReference(DI)) | |
| return true; | |
| } | |
| return false; | |
| } | |
| /// Get all the instructions in a tree. | |
| static void getInstructionsInTree(TreePatternNode &Tree, | |
| SmallVectorImpl<const Record *> &Instrs) { | |
| if (Tree.isLeaf()) | |
| return; | |
| if (Tree.getOperator()->isSubClassOf("Instruction")) | |
| Instrs.push_back(Tree.getOperator()); | |
| for (TreePatternNode &Child : Tree.children()) | |
| getInstructionsInTree(Child, Instrs); | |
| } | |
| /// Check the class of a pattern leaf node against the instruction operand it | |
| /// represents. | |
| static bool checkOperandClass(const CGIOperandList::OperandInfo &OI, | |
| const Record *Leaf) { | |
| if (OI.Rec == Leaf) | |
| return true; | |
| // Allow direct value types to be used in instruction set patterns. | |
| // The type will be checked later. | |
| if (Leaf->isSubClassOf("ValueType")) | |
| return true; | |
| // Patterns can also be ComplexPattern instances. | |
| if (Leaf->isSubClassOf("ComplexPattern")) | |
| return true; | |
| return false; | |
| } | |
| void CodeGenDAGPatterns::parseInstructionPattern(const CodeGenInstruction &CGI, | |
| const ListInit *Pat, | |
| DAGInstMap &DAGInsts) { | |
| assert(!DAGInsts.count(CGI.TheDef) && "Instruction already parsed!"); | |
| // Parse the instruction. | |
| TreePattern I(CGI.TheDef, Pat, true, *this); | |
| // InstInputs - Keep track of all of the inputs of the instruction, along | |
| // with the record they are declared as. | |
| std::map<StringRef, TreePatternNodePtr> InstInputs; | |
| // InstResults - Keep track of all the virtual registers that are 'set' | |
| // in the instruction, including what reg class they are. | |
| MapVector<StringRef, TreePatternNodePtr, std::map<StringRef, unsigned>> | |
| InstResults; | |
| std::vector<const Record *> InstImpResults; | |
| // Verify that the top-level forms in the instruction are of void type, and | |
| // fill in the InstResults map. | |
| SmallString<32> TypesString; | |
| for (unsigned j = 0, e = I.getNumTrees(); j != e; ++j) { | |
| TypesString.clear(); | |
| TreePatternNodePtr Pat = I.getTree(j); | |
| if (Pat->getNumTypes() != 0) { | |
| raw_svector_ostream OS(TypesString); | |
| ListSeparator LS; | |
| for (unsigned k = 0, ke = Pat->getNumTypes(); k != ke; ++k) { | |
| OS << LS; | |
| Pat->getExtType(k).writeToStream(OS); | |
| } | |
| I.error("Top-level forms in instruction pattern should have" | |
| " void types, has types " + | |
| OS.str()); | |
| } | |
| // Find inputs and outputs, and verify the structure of the uses/defs. | |
| FindPatternInputsAndOutputs(I, Pat, InstInputs, InstResults, | |
| InstImpResults); | |
| } | |
| // Now that we have inputs and outputs of the pattern, inspect the operands | |
| // list for the instruction. This determines the order that operands are | |
| // added to the machine instruction the node corresponds to. | |
| unsigned NumResults = InstResults.size(); | |
| // Parse the operands list from the (ops) list, validating it. | |
| assert(I.getArgList().empty() && "Args list should still be empty here!"); | |
| // Check that all of the results occur first in the list. | |
| std::vector<const Record *> Results; | |
| std::vector<unsigned> ResultIndices; | |
| SmallVector<TreePatternNodePtr, 2> ResNodes; | |
| for (unsigned i = 0; i != NumResults; ++i) { | |
| if (i == CGI.Operands.size()) { | |
| StringRef OpName = | |
| llvm::find_if(InstResults, | |
| [](const std::pair<StringRef, TreePatternNodePtr> &P) { | |
| return P.second; | |
| }) | |
| ->first; | |
| I.error("'" + OpName + "' set but does not appear in operand list!"); | |
| } | |
| StringRef OpName = CGI.Operands[i].Name; | |
| // Check that it exists in InstResults. | |
| auto InstResultIter = InstResults.find(OpName); | |
| if (InstResultIter == InstResults.end() || !InstResultIter->second) { | |
| I.dump(); | |
| PrintFatalError(CGI.TheDef, "In " + CGI.TheDef->getName() + | |
| ": Operand $" + OpName + | |
| " does not exist in operand list!"); | |
| } | |
| TreePatternNodePtr RNode = InstResultIter->second; | |
| const Record *R = cast<DefInit>(RNode->getLeafValue())->getDef(); | |
| ResNodes.push_back(std::move(RNode)); | |
| if (!R) | |
| I.error("Operand $" + OpName + | |
| " should be a set destination: all " | |
| "outputs must occur before inputs in operand list!"); | |
| if (!checkOperandClass(CGI.Operands[i], R)) | |
| I.error("Operand $" + OpName + " class mismatch!"); | |
| // Remember the return type. | |
| Results.push_back(CGI.Operands[i].Rec); | |
| // Remember the result index. | |
| ResultIndices.push_back(std::distance(InstResults.begin(), InstResultIter)); | |
| // Okay, this one checks out. | |
| InstResultIter->second = nullptr; | |
| } | |
| // Loop over the inputs next. | |
| std::vector<TreePatternNodePtr> ResultNodeOperands; | |
| std::vector<const Record *> Operands; | |
| for (unsigned i = NumResults, e = CGI.Operands.size(); i != e; ++i) { | |
| const CGIOperandList::OperandInfo &Op = CGI.Operands[i]; | |
| StringRef OpName = Op.Name; | |
| if (OpName.empty()) { | |
| I.error("Operand #" + Twine(i) + " in operands list has no name!"); | |
| continue; | |
| } | |
| auto InIter = InstInputs.find(OpName); | |
| if (InIter == InstInputs.end()) { | |
| // If this is an operand with a DefaultOps set filled in, we can ignore | |
| // this. When we codegen it, we will do so as always executed. | |
| if (Op.Rec->isSubClassOf("OperandWithDefaultOps")) { | |
| // Does it have a non-empty DefaultOps field? If so, ignore this | |
| // operand. | |
| if (!getDefaultOperand(Op.Rec).DefaultOps.empty()) | |
| continue; | |
| } | |
| I.error("Operand $" + OpName + | |
| " does not appear in the instruction pattern"); | |
| continue; | |
| } | |
| TreePatternNodePtr InVal = InIter->second; | |
| InstInputs.erase(InIter); // It occurred, remove from map. | |
| if (InVal->isLeaf() && isa<DefInit>(InVal->getLeafValue())) { | |
| const Record *InRec = cast<DefInit>(InVal->getLeafValue())->getDef(); | |
| if (!checkOperandClass(Op, InRec)) { | |
| I.error("Operand $" + OpName + | |
| "'s register class disagrees" | |
| " between the operand and pattern"); | |
| continue; | |
| } | |
| } | |
| Operands.push_back(Op.Rec); | |
| // Construct the result for the dest-pattern operand list. | |
| TreePatternNodePtr OpNode = InVal->clone(); | |
| // No predicate is useful on the result. | |
| OpNode->clearPredicateCalls(); | |
| // Promote the xform function to be an explicit node if set. | |
| if (const Record *Xform = OpNode->getTransformFn()) { | |
| OpNode->setTransformFn(nullptr); | |
| std::vector<TreePatternNodePtr> Children; | |
| Children.push_back(OpNode); | |
| OpNode = makeIntrusiveRefCnt<TreePatternNode>(Xform, std::move(Children), | |
| OpNode->getNumTypes()); | |
| } | |
| ResultNodeOperands.push_back(std::move(OpNode)); | |
| } | |
| if (!InstInputs.empty()) | |
| I.error("Input operand $" + InstInputs.begin()->first + | |
| " occurs in pattern but not in operands list!"); | |
| TreePatternNodePtr ResultPattern = makeIntrusiveRefCnt<TreePatternNode>( | |
| I.getRecord(), std::move(ResultNodeOperands), | |
| GetNumNodeResults(I.getRecord(), *this)); | |
| // Copy fully inferred output node types to instruction result pattern. | |
| for (unsigned i = 0; i != NumResults; ++i) { | |
| assert(ResNodes[i]->getNumTypes() == 1 && "FIXME: Unhandled"); | |
| ResultPattern->setType(i, ResNodes[i]->getExtType(0)); | |
| ResultPattern->setResultIndex(i, ResultIndices[i]); | |
| } | |
| // FIXME: Assume only the first tree is the pattern. The others are clobber | |
| // nodes. | |
| TreePatternNodePtr Pattern = I.getTree(0); | |
| TreePatternNodePtr SrcPattern; | |
| if (Pattern->getOperator()->getName() == "set") { | |
| SrcPattern = Pattern->getChild(Pattern->getNumChildren() - 1).clone(); | |
| } else { | |
| // Not a set (store or something?) | |
| SrcPattern = Pattern; | |
| } | |
| // Create and insert the instruction. | |
| // FIXME: InstImpResults should not be part of DAGInstruction. | |
| DAGInsts.try_emplace(I.getRecord(), std::move(Results), std::move(Operands), | |
| std::move(InstImpResults), SrcPattern, ResultPattern); | |
| LLVM_DEBUG(I.dump()); | |
| } | |
| /// ParseInstructions - Parse all of the instructions, inlining and resolving | |
| /// any fragments involved. This populates the Instructions list with fully | |
| /// resolved instructions. | |
| void CodeGenDAGPatterns::ParseInstructions() { | |
| for (const Record *Instr : Records.getAllDerivedDefinitions("Instruction")) { | |
| const ListInit *LI = nullptr; | |
| if (isa<ListInit>(Instr->getValueInit("Pattern"))) | |
| LI = Instr->getValueAsListInit("Pattern"); | |
| // If there is no pattern, only collect minimal information about the | |
| // instruction for its operand list. We have to assume that there is one | |
| // result, as we have no detailed info. A pattern which references the | |
| // null_frag operator is as-if no pattern were specified. Normally this | |
| // is from a multiclass expansion w/ a SDPatternOperator passed in as | |
| // null_frag. | |
| if (!LI || LI->empty() || hasNullFragReference(LI)) { | |
| std::vector<const Record *> Results; | |
| std::vector<const Record *> Operands; | |
| const CodeGenInstruction &InstInfo = Target.getInstruction(Instr); | |
| if (InstInfo.Operands.size() != 0) { | |
| for (unsigned j = 0, e = InstInfo.Operands.NumDefs; j < e; ++j) | |
| Results.push_back(InstInfo.Operands[j].Rec); | |
| // The rest are inputs. | |
| for (unsigned j = InstInfo.Operands.NumDefs, | |
| e = InstInfo.Operands.size(); | |
| j < e; ++j) | |
| Operands.push_back(InstInfo.Operands[j].Rec); | |
| } | |
| // Create and insert the instruction. | |
| Instructions.try_emplace(Instr, std::move(Results), std::move(Operands), | |
| std::vector<const Record *>()); | |
| continue; // no pattern. | |
| } | |
| const CodeGenInstruction &CGI = Target.getInstruction(Instr); | |
| parseInstructionPattern(CGI, LI, Instructions); | |
| } | |
| // If we can, convert the instructions to be patterns that are matched! | |
| for (const auto &[Instr, TheInst] : Instructions) { | |
| TreePatternNodePtr SrcPattern = TheInst.getSrcPattern(); | |
| TreePatternNodePtr ResultPattern = TheInst.getResultPattern(); | |
| if (SrcPattern && ResultPattern) { | |
| TreePattern Pattern(Instr, SrcPattern, true, *this); | |
| TreePattern Result(Instr, ResultPattern, false, *this); | |
| ParseOnePattern(Instr, Pattern, Result, TheInst.getImpResults()); | |
| } | |
| } | |
| } | |
| using NameRecord = std::pair<TreePatternNode *, unsigned>; | |
| static void FindNames(TreePatternNode &P, | |
| std::map<StringRef, NameRecord> &Names, | |
| TreePattern *PatternTop) { | |
| if (!P.getName().empty()) { | |
| NameRecord &Rec = Names[P.getName()]; | |
| // If this is the first instance of the name, remember the node. | |
| if (Rec.second++ == 0) | |
| Rec.first = &P; | |
| else if (Rec.first->getExtTypes() != P.getExtTypes()) | |
| PatternTop->error("repetition of value: $" + P.getName() + | |
| " where different uses have different types!"); | |
| } | |
| if (!P.isLeaf()) { | |
| for (TreePatternNode &Child : P.children()) | |
| FindNames(Child, Names, PatternTop); | |
| } | |
| } | |
| void CodeGenDAGPatterns::AddPatternToMatch(TreePattern *Pattern, | |
| PatternToMatch &&PTM) { | |
| // Do some sanity checking on the pattern we're about to match. | |
| std::string Reason; | |
| if (!PTM.getSrcPattern().canPatternMatch(Reason, *this)) { | |
| PrintWarning(Pattern->getRecord()->getLoc(), | |
| Twine("Pattern can never match: ") + Reason); | |
| return; | |
| } | |
| // If the source pattern's root is a complex pattern, that complex pattern | |
| // must specify the nodes it can potentially match. | |
| if (const ComplexPattern *CP = | |
| PTM.getSrcPattern().getComplexPatternInfo(*this)) | |
| if (CP->getRootNodes().empty()) | |
| Pattern->error("ComplexPattern at root must specify list of opcodes it" | |
| " could match"); | |
| // Find all of the named values in the input and output, ensure they have the | |
| // same type. | |
| std::map<StringRef, NameRecord> SrcNames, DstNames; | |
| FindNames(PTM.getSrcPattern(), SrcNames, Pattern); | |
| FindNames(PTM.getDstPattern(), DstNames, Pattern); | |
| // Scan all of the named values in the destination pattern, rejecting them if | |
| // they don't exist in the input pattern. | |
| for (const auto &Entry : DstNames) { | |
| if (SrcNames[Entry.first].first == nullptr) | |
| Pattern->error("Pattern has input without matching name in output: $" + | |
| Entry.first); | |
| } | |
| // Scan all of the named values in the source pattern, rejecting them if the | |
| // name isn't used in the dest, and isn't used to tie two values together. | |
| for (const auto &Entry : SrcNames) | |
| if (DstNames[Entry.first].first == nullptr && | |
| SrcNames[Entry.first].second == 1) | |
| Pattern->error("Pattern has dead named input: $" + Entry.first + | |
| " (use srcvalue for an intentionally unused input)"); | |
| PatternsToMatch.push_back(std::move(PTM)); | |
| } | |
| void CodeGenDAGPatterns::InferInstructionFlags() { | |
| ArrayRef<const CodeGenInstruction *> Instructions = Target.getInstructions(); | |
| unsigned Errors = 0; | |
| // Try to infer flags from all patterns in PatternToMatch. These include | |
| // both the primary instruction patterns (which always come first) and | |
| // patterns defined outside the instruction. | |
| for (const PatternToMatch &PTM : ptms()) { | |
| // We can only infer from single-instruction patterns, otherwise we won't | |
| // know which instruction should get the flags. | |
| SmallVector<const Record *, 8> PatInstrs; | |
| getInstructionsInTree(PTM.getDstPattern(), PatInstrs); | |
| if (PatInstrs.size() != 1) | |
| continue; | |
| // Get the single instruction. | |
| CodeGenInstruction &InstInfo = Target.getInstruction(PatInstrs.front()); | |
| // Only infer properties from the first pattern. We'll verify the others. | |
| if (InstInfo.InferredFrom) | |
| continue; | |
| InstAnalyzer PatInfo(*this); | |
| PatInfo.Analyze(PTM); | |
| Errors += InferFromPattern(InstInfo, PatInfo, PTM.getSrcRecord()); | |
| } | |
| if (Errors) | |
| PrintFatalError("pattern conflicts"); | |
| // If requested by the target, guess any undefined properties. | |
| if (Target.guessInstructionProperties()) { | |
| for (const CodeGenInstruction *InstInfo : Instructions) { | |
| if (InstInfo->InferredFrom) | |
| continue; | |
| // The mayLoad and mayStore flags default to false. | |
| // Conservatively assume hasSideEffects if it wasn't explicit. | |
| if (InstInfo->hasSideEffects_Unset) | |
| const_cast<CodeGenInstruction *>(InstInfo)->hasSideEffects = true; | |
| } | |
| return; | |
| } | |
| // Complain about any flags that are still undefined. | |
| for (const CodeGenInstruction *InstInfo : Instructions) { | |
| if (InstInfo->InferredFrom) | |
| continue; | |
| if (InstInfo->hasSideEffects_Unset) | |
| PrintError(InstInfo->TheDef->getLoc(), | |
| "Can't infer hasSideEffects from patterns"); | |
| if (InstInfo->mayStore_Unset) | |
| PrintError(InstInfo->TheDef->getLoc(), | |
| "Can't infer mayStore from patterns"); | |
| if (InstInfo->mayLoad_Unset) | |
| PrintError(InstInfo->TheDef->getLoc(), | |
| "Can't infer mayLoad from patterns"); | |
| } | |
| } | |
| /// Verify instruction flags against pattern node properties. | |
| void CodeGenDAGPatterns::VerifyInstructionFlags() { | |
| unsigned Errors = 0; | |
| for (const PatternToMatch &PTM : ptms()) { | |
| SmallVector<const Record *, 8> Instrs; | |
| getInstructionsInTree(PTM.getDstPattern(), Instrs); | |
| if (Instrs.empty()) | |
| continue; | |
| // Count the number of instructions with each flag set. | |
| unsigned NumSideEffects = 0; | |
| unsigned NumStores = 0; | |
| unsigned NumLoads = 0; | |
| for (const Record *Instr : Instrs) { | |
| const CodeGenInstruction &InstInfo = Target.getInstruction(Instr); | |
| NumSideEffects += InstInfo.hasSideEffects; | |
| NumStores += InstInfo.mayStore; | |
| NumLoads += InstInfo.mayLoad; | |
| } | |
| // Analyze the source pattern. | |
| InstAnalyzer PatInfo(*this); | |
| PatInfo.Analyze(PTM); | |
| // Collect error messages. | |
| SmallVector<std::string, 4> Msgs; | |
| // Check for missing flags in the output. | |
| // Permit extra flags for now at least. | |
| if (PatInfo.hasSideEffects && !NumSideEffects) | |
| Msgs.push_back("pattern has side effects, but hasSideEffects isn't set"); | |
| // Don't verify store flags on instructions with side effects. At least for | |
| // intrinsics, side effects implies mayStore. | |
| if (!PatInfo.hasSideEffects && PatInfo.mayStore && !NumStores) | |
| Msgs.push_back("pattern may store, but mayStore isn't set"); | |
| // Similarly, mayStore implies mayLoad on intrinsics. | |
| if (!PatInfo.mayStore && PatInfo.mayLoad && !NumLoads) | |
| Msgs.push_back("pattern may load, but mayLoad isn't set"); | |
| // Print error messages. | |
| if (Msgs.empty()) | |
| continue; | |
| ++Errors; | |
| for (const std::string &Msg : Msgs) | |
| PrintError( | |
| PTM.getSrcRecord()->getLoc(), | |
| Twine(Msg) + " on the " + | |
| (Instrs.size() == 1 ? "instruction" : "output instructions")); | |
| // Provide the location of the relevant instruction definitions. | |
| for (const Record *Instr : Instrs) { | |
| if (Instr != PTM.getSrcRecord()) | |
| PrintError(Instr->getLoc(), "defined here"); | |
| const CodeGenInstruction &InstInfo = Target.getInstruction(Instr); | |
| if (InstInfo.InferredFrom && InstInfo.InferredFrom != InstInfo.TheDef && | |
| InstInfo.InferredFrom != PTM.getSrcRecord()) | |
| PrintError(InstInfo.InferredFrom->getLoc(), "inferred from pattern"); | |
| } | |
| } | |
| if (Errors) | |
| PrintFatalError("Errors in DAG patterns"); | |
| } | |
| /// Given a pattern result with an unresolved type, see if we can find one | |
| /// instruction with an unresolved result type. Force this result type to an | |
| /// arbitrary element if it's possible types to converge results. | |
| static bool ForceArbitraryInstResultType(TreePatternNode &N, TreePattern &TP) { | |
| if (N.isLeaf()) | |
| return false; | |
| // Analyze children. | |
| for (TreePatternNode &Child : N.children()) | |
| if (ForceArbitraryInstResultType(Child, TP)) | |
| return true; | |
| if (!N.getOperator()->isSubClassOf("Instruction")) | |
| return false; | |
| // If this type is already concrete or completely unknown we can't do | |
| // anything. | |
| TypeInfer &TI = TP.getInfer(); | |
| for (unsigned i = 0, e = N.getNumTypes(); i != e; ++i) { | |
| if (N.getExtType(i).empty() || | |
| N.getExtType(i).isValueTypeByHwMode(/*AllowEmpty=*/false)) | |
| continue; | |
| // Otherwise, force its type to an arbitrary choice. | |
| if (TI.forceArbitrary(N.getExtType(i))) | |
| return true; | |
| } | |
| return false; | |
| } | |
| // Promote xform function to be an explicit node wherever set. | |
| static TreePatternNodePtr PromoteXForms(TreePatternNodePtr N) { | |
| if (const Record *Xform = N->getTransformFn()) { | |
| N->setTransformFn(nullptr); | |
| std::vector<TreePatternNodePtr> Children; | |
| Children.push_back(PromoteXForms(N)); | |
| return makeIntrusiveRefCnt<TreePatternNode>(Xform, std::move(Children), | |
| N->getNumTypes()); | |
| } | |
| if (!N->isLeaf()) | |
| for (unsigned i = 0, e = N->getNumChildren(); i != e; ++i) { | |
| TreePatternNodePtr Child = N->getChildShared(i); | |
| N->setChild(i, PromoteXForms(Child)); | |
| } | |
| return N; | |
| } | |
| void CodeGenDAGPatterns::ParseOnePattern( | |
| const Record *TheDef, TreePattern &Pattern, TreePattern &Result, | |
| ArrayRef<const Record *> InstImpResults, bool ShouldIgnore) { | |
| // Inline pattern fragments and expand multiple alternatives. | |
| Pattern.InlinePatternFragments(); | |
| Result.InlinePatternFragments(); | |
| if (Result.getNumTrees() != 1) { | |
| Result.error("Cannot use multi-alternative fragments in result pattern!"); | |
| return; | |
| } | |
| // Infer types. | |
| bool IterateInference; | |
| bool InferredAllPatternTypes, InferredAllResultTypes; | |
| do { | |
| // Infer as many types as possible. If we cannot infer all of them, we | |
| // can never do anything with this pattern: report it to the user. | |
| InferredAllPatternTypes = | |
| Pattern.InferAllTypes(&Pattern.getNamedNodesMap()); | |
| // Infer as many types as possible. If we cannot infer all of them, we | |
| // can never do anything with this pattern: report it to the user. | |
| InferredAllResultTypes = Result.InferAllTypes(&Pattern.getNamedNodesMap()); | |
| IterateInference = false; | |
| // Apply the type of the result to the source pattern. This helps us | |
| // resolve cases where the input type is known to be a pointer type (which | |
| // is considered resolved), but the result knows it needs to be 32- or | |
| // 64-bits. Infer the other way for good measure. | |
| for (const auto &T : Pattern.getTrees()) | |
| for (unsigned i = 0, e = std::min(Result.getOnlyTree()->getNumTypes(), | |
| T->getNumTypes()); | |
| i != e; ++i) { | |
| IterateInference |= | |
| T->UpdateNodeType(i, Result.getOnlyTree()->getExtType(i), Result); | |
| IterateInference |= | |
| Result.getOnlyTree()->UpdateNodeType(i, T->getExtType(i), Result); | |
| } | |
| // If our iteration has converged and the input pattern's types are fully | |
| // resolved but the result pattern is not fully resolved, we may have a | |
| // situation where we have two instructions in the result pattern and | |
| // the instructions require a common register class, but don't care about | |
| // what actual MVT is used. This is actually a bug in our modelling: | |
| // output patterns should have register classes, not MVTs. | |
| // | |
| // In any case, to handle this, we just go through and disambiguate some | |
| // arbitrary types to the result pattern's nodes. | |
| if (!IterateInference && InferredAllPatternTypes && !InferredAllResultTypes) | |
| IterateInference = | |
| ForceArbitraryInstResultType(*Result.getTree(0), Result); | |
| } while (IterateInference); | |
| // Verify that we inferred enough types that we can do something with the | |
| // pattern and result. If these fire the user has to add type casts. | |
| if (!InferredAllPatternTypes) | |
| Pattern.error("Could not infer all types in pattern!"); | |
| if (!InferredAllResultTypes) { | |
| Pattern.dump(); | |
| Result.error("Could not infer all types in pattern result!"); | |
| } | |
| // Promote xform function to be an explicit node wherever set. | |
| TreePatternNodePtr DstShared = PromoteXForms(Result.getOnlyTree()); | |
| TreePattern Temp(Result.getRecord(), DstShared, false, *this); | |
| Temp.InferAllTypes(); | |
| const ListInit *Preds = TheDef->getValueAsListInit("Predicates"); | |
| int Complexity = TheDef->getValueAsInt("AddedComplexity"); | |
| // A pattern may end up with an "impossible" type, i.e. a situation | |
| // where all types have been eliminated for some node in this pattern. | |
| // This could occur for intrinsics that only make sense for a specific | |
| // value type, and use a specific register class. If, for some mode, | |
| // that register class does not accept that type, the type inference | |
| // will lead to a contradiction, which is not an error however, but | |
| // a sign that this pattern will simply never match. | |
| if (Temp.getOnlyTree()->hasPossibleType()) { | |
| for (const auto &T : Pattern.getTrees()) { | |
| if (T->hasPossibleType()) | |
| AddPatternToMatch(&Pattern, | |
| PatternToMatch(TheDef, Preds, T, Temp.getOnlyTree(), | |
| InstImpResults, Complexity, | |
| TheDef->getID(), ShouldIgnore)); | |
| } | |
| } else { | |
| // Show a message about a dropped pattern with some info to make it | |
| // easier to identify it in the .td files. | |
| LLVM_DEBUG({ | |
| dbgs() << "Dropping: "; | |
| Pattern.dump(); | |
| Temp.getOnlyTree()->dump(); | |
| dbgs() << "\n"; | |
| }); | |
| } | |
| } | |
| void CodeGenDAGPatterns::ParsePatterns() { | |
| for (const Record *CurPattern : Records.getAllDerivedDefinitions("Pattern")) { | |
| const DagInit *Tree = CurPattern->getValueAsDag("PatternToMatch"); | |
| // If the pattern references the null_frag, there's nothing to do. | |
| if (hasNullFragReference(Tree)) | |
| continue; | |
| TreePattern Pattern(CurPattern, Tree, true, *this); | |
| const ListInit *LI = CurPattern->getValueAsListInit("ResultInstrs"); | |
| if (LI->empty()) | |
| continue; // no pattern. | |
| // Parse the instruction. | |
| TreePattern Result(CurPattern, LI, false, *this); | |
| if (Result.getNumTrees() != 1) | |
| Result.error("Cannot handle instructions producing instructions " | |
| "with temporaries yet!"); | |
| // Validate that the input pattern is correct. | |
| InstInputsTy InstInputs; | |
| InstResultsTy InstResults; | |
| std::vector<const Record *> InstImpResults; | |
| for (unsigned j = 0, ee = Pattern.getNumTrees(); j != ee; ++j) | |
| FindPatternInputsAndOutputs(Pattern, Pattern.getTree(j), InstInputs, | |
| InstResults, InstImpResults); | |
| ParseOnePattern(CurPattern, Pattern, Result, InstImpResults, | |
| CurPattern->getValueAsBit("GISelShouldIgnore")); | |
| } | |
| } | |
| static void collectModes(std::set<unsigned> &Modes, const TreePatternNode &N) { | |
| for (const TypeSetByHwMode &VTS : N.getExtTypes()) | |
| for (const auto &I : VTS) | |
| Modes.insert(I.first); | |
| for (const TreePatternNode &Child : N.children()) | |
| collectModes(Modes, Child); | |
| } | |
| void CodeGenDAGPatterns::ExpandHwModeBasedTypes() { | |
| const CodeGenHwModes &CGH = getTargetInfo().getHwModes(); | |
| if (CGH.getNumModeIds() == 1) | |
| return; | |
| std::vector<PatternToMatch> Copy; | |
| PatternsToMatch.swap(Copy); | |
| auto AppendPattern = [this](PatternToMatch &P, unsigned Mode, | |
| StringRef Check) { | |
| TreePatternNodePtr NewSrc = P.getSrcPattern().clone(); | |
| TreePatternNodePtr NewDst = P.getDstPattern().clone(); | |
| if (!NewSrc->setDefaultMode(Mode) || !NewDst->setDefaultMode(Mode)) { | |
| return; | |
| } | |
| PatternsToMatch.emplace_back(P.getSrcRecord(), P.getPredicates(), | |
| std::move(NewSrc), std::move(NewDst), | |
| P.getDstRegs(), P.getAddedComplexity(), | |
| getNewUID(), P.getGISelShouldIgnore(), Check); | |
| }; | |
| for (PatternToMatch &P : Copy) { | |
| const TreePatternNode *SrcP = nullptr, *DstP = nullptr; | |
| if (P.getSrcPattern().hasProperTypeByHwMode()) | |
| SrcP = &P.getSrcPattern(); | |
| if (P.getDstPattern().hasProperTypeByHwMode()) | |
| DstP = &P.getDstPattern(); | |
| if (!SrcP && !DstP) { | |
| PatternsToMatch.push_back(P); | |
| continue; | |
| } | |
| std::set<unsigned> Modes; | |
| if (SrcP) | |
| collectModes(Modes, *SrcP); | |
| if (DstP) | |
| collectModes(Modes, *DstP); | |
| // The predicate for the default mode needs to be constructed for each | |
| // pattern separately. | |
| // Since not all modes must be present in each pattern, if a mode m is | |
| // absent, then there is no point in constructing a check for m. If such | |
| // a check was created, it would be equivalent to checking the default | |
| // mode, except not all modes' predicates would be a part of the checking | |
| // code. The subsequently generated check for the default mode would then | |
| // have the exact same patterns, but a different predicate code. To avoid | |
| // duplicated patterns with different predicate checks, construct the | |
| // default check as a negation of all predicates that are actually present | |
| // in the source/destination patterns. | |
| SmallString<128> DefaultCheck; | |
| for (unsigned M : Modes) { | |
| if (M == DefaultMode) | |
| continue; | |
| // Fill the map entry for this mode. | |
| const HwMode &HM = CGH.getMode(M); | |
| SmallString<128> PredicateCheck; | |
| raw_svector_ostream PS(PredicateCheck); | |
| SubtargetFeatureInfo::emitPredicateCheck(PS, HM.Predicates); | |
| AppendPattern(P, M, PredicateCheck); | |
| // Add negations of the HM's predicates to the default predicate. | |
| if (!DefaultCheck.empty()) | |
| DefaultCheck += " && "; | |
| DefaultCheck += "!("; | |
| DefaultCheck.append(PredicateCheck); | |
| DefaultCheck += ")"; | |
| } | |
| bool HasDefault = Modes.count(DefaultMode); | |
| if (HasDefault) | |
| AppendPattern(P, DefaultMode, DefaultCheck); | |
| } | |
| } | |
| /// Dependent variable map for CodeGenDAGPattern variant generation | |
| using DepVarMap = StringMap<int>; | |
| static void FindDepVarsOf(TreePatternNode &N, DepVarMap &DepMap) { | |
| if (N.isLeaf()) { | |
| if (N.hasName() && isa<DefInit>(N.getLeafValue())) | |
| DepMap[N.getName()]++; | |
| } else { | |
| for (TreePatternNode &Child : N.children()) | |
| FindDepVarsOf(Child, DepMap); | |
| } | |
| } | |
| /// Find dependent variables within child patterns | |
| static void FindDepVars(TreePatternNode &N, MultipleUseVarSet &DepVars) { | |
| DepVarMap depcounts; | |
| FindDepVarsOf(N, depcounts); | |
| for (const auto &Pair : depcounts) { | |
| if (Pair.getValue() > 1) | |
| DepVars.insert(Pair.getKey()); | |
| } | |
| } | |
| #ifndef NDEBUG | |
| /// Dump the dependent variable set: | |
| static void DumpDepVars(MultipleUseVarSet &DepVars) { | |
| if (DepVars.empty()) { | |
| LLVM_DEBUG(dbgs() << "<empty set>"); | |
| } else { | |
| LLVM_DEBUG(dbgs() << "[ "); | |
| for (const auto &DepVar : DepVars) { | |
| LLVM_DEBUG(dbgs() << DepVar.getKey() << " "); | |
| } | |
| LLVM_DEBUG(dbgs() << "]"); | |
| } | |
| } | |
| #endif | |
| /// CombineChildVariants - Given a bunch of permutations of each child of the | |
| /// 'operator' node, put them together in all possible ways. | |
| static void CombineChildVariants( | |
| TreePatternNodePtr Orig, | |
| const std::vector<std::vector<TreePatternNodePtr>> &ChildVariants, | |
| std::vector<TreePatternNodePtr> &OutVariants, CodeGenDAGPatterns &CDP, | |
| const MultipleUseVarSet &DepVars) { | |
| // Make sure that each operand has at least one variant to choose from. | |
| for (const auto &Variants : ChildVariants) | |
| if (Variants.empty()) | |
| return; | |
| // The end result is an all-pairs construction of the resultant pattern. | |
| std::vector<unsigned> Idxs(ChildVariants.size()); | |
| bool NotDone; | |
| do { | |
| #ifndef NDEBUG | |
| LLVM_DEBUG(if (!Idxs.empty()) { | |
| dbgs() << Orig->getOperator()->getName() << ": Idxs = [ "; | |
| for (unsigned Idx : Idxs) { | |
| dbgs() << Idx << " "; | |
| } | |
| dbgs() << "]\n"; | |
| }); | |
| #endif | |
| // Create the variant and add it to the output list. | |
| std::vector<TreePatternNodePtr> NewChildren; | |
| NewChildren.reserve(ChildVariants.size()); | |
| for (unsigned i = 0, e = ChildVariants.size(); i != e; ++i) | |
| NewChildren.push_back(ChildVariants[i][Idxs[i]]); | |
| TreePatternNodePtr R = makeIntrusiveRefCnt<TreePatternNode>( | |
| Orig->getOperator(), std::move(NewChildren), Orig->getNumTypes()); | |
| // Copy over properties. | |
| R->setName(Orig->getName()); | |
| R->setNamesAsPredicateArg(Orig->getNamesAsPredicateArg()); | |
| R->setPredicateCalls(Orig->getPredicateCalls()); | |
| R->setGISelFlagsRecord(Orig->getGISelFlagsRecord()); | |
| R->setTransformFn(Orig->getTransformFn()); | |
| for (unsigned i = 0, e = Orig->getNumTypes(); i != e; ++i) | |
| R->setType(i, Orig->getExtType(i)); | |
| // If this pattern cannot match, do not include it as a variant. | |
| std::string ErrString; | |
| // Scan to see if this pattern has already been emitted. We can get | |
| // duplication due to things like commuting: | |
| // (and GPRC:$a, GPRC:$b) -> (and GPRC:$b, GPRC:$a) | |
| // which are the same pattern. Ignore the dups. | |
| if (R->canPatternMatch(ErrString, CDP) && | |
| none_of(OutVariants, [&](TreePatternNodePtr Variant) { | |
| return R->isIsomorphicTo(*Variant, DepVars); | |
| })) | |
| OutVariants.push_back(R); | |
| // Increment indices to the next permutation by incrementing the | |
| // indices from last index backward, e.g., generate the sequence | |
| // [0, 0], [0, 1], [1, 0], [1, 1]. | |
| int IdxsIdx; | |
| for (IdxsIdx = Idxs.size() - 1; IdxsIdx >= 0; --IdxsIdx) { | |
| if (++Idxs[IdxsIdx] == ChildVariants[IdxsIdx].size()) | |
| Idxs[IdxsIdx] = 0; | |
| else | |
| break; | |
| } | |
| NotDone = (IdxsIdx >= 0); | |
| } while (NotDone); | |
| } | |
| /// CombineChildVariants - A helper function for binary operators. | |
| /// | |
| static void CombineChildVariants(TreePatternNodePtr Orig, | |
| const std::vector<TreePatternNodePtr> &LHS, | |
| const std::vector<TreePatternNodePtr> &RHS, | |
| std::vector<TreePatternNodePtr> &OutVariants, | |
| CodeGenDAGPatterns &CDP, | |
| const MultipleUseVarSet &DepVars) { | |
| std::vector<std::vector<TreePatternNodePtr>> ChildVariants; | |
| ChildVariants.push_back(LHS); | |
| ChildVariants.push_back(RHS); | |
| CombineChildVariants(Orig, ChildVariants, OutVariants, CDP, DepVars); | |
| } | |
| static void | |
| GatherChildrenOfAssociativeOpcode(TreePatternNodePtr N, | |
| std::vector<TreePatternNodePtr> &Children) { | |
| assert(N->getNumChildren() == 2 && | |
| "Associative but doesn't have 2 children!"); | |
| const Record *Operator = N->getOperator(); | |
| // Only permit raw nodes. | |
| if (!N->getName().empty() || !N->getPredicateCalls().empty() || | |
| N->getTransformFn()) { | |
| Children.push_back(N); | |
| return; | |
| } | |
| if (N->getChild(0).isLeaf() || N->getChild(0).getOperator() != Operator) | |
| Children.push_back(N->getChildShared(0)); | |
| else | |
| GatherChildrenOfAssociativeOpcode(N->getChildShared(0), Children); | |
| if (N->getChild(1).isLeaf() || N->getChild(1).getOperator() != Operator) | |
| Children.push_back(N->getChildShared(1)); | |
| else | |
| GatherChildrenOfAssociativeOpcode(N->getChildShared(1), Children); | |
| } | |
| /// GenerateVariantsOf - Given a pattern N, generate all permutations we can of | |
| /// the (potentially recursive) pattern by using algebraic laws. | |
| /// | |
| static void GenerateVariantsOf(TreePatternNodePtr N, | |
| std::vector<TreePatternNodePtr> &OutVariants, | |
| CodeGenDAGPatterns &CDP, | |
| const MultipleUseVarSet &DepVars) { | |
| // We cannot permute leaves or ComplexPattern uses. | |
| if (N->isLeaf() || N->getOperator()->isSubClassOf("ComplexPattern")) { | |
| OutVariants.push_back(N); | |
| return; | |
| } | |
| // Look up interesting info about the node. | |
| const SDNodeInfo &NodeInfo = CDP.getSDNodeInfo(N->getOperator()); | |
| // If this node is associative, re-associate. | |
| if (NodeInfo.hasProperty(SDNPAssociative)) { | |
| // Re-associate by pulling together all of the linked operators | |
| std::vector<TreePatternNodePtr> MaximalChildren; | |
| GatherChildrenOfAssociativeOpcode(N, MaximalChildren); | |
| // Only handle child sizes of 3. Otherwise we'll end up trying too many | |
| // permutations. | |
| if (MaximalChildren.size() == 3) { | |
| // Find the variants of all of our maximal children. | |
| std::vector<TreePatternNodePtr> AVariants, BVariants, CVariants; | |
| GenerateVariantsOf(MaximalChildren[0], AVariants, CDP, DepVars); | |
| GenerateVariantsOf(MaximalChildren[1], BVariants, CDP, DepVars); | |
| GenerateVariantsOf(MaximalChildren[2], CVariants, CDP, DepVars); | |
| // There are only two ways we can permute the tree: | |
| // (A op B) op C and A op (B op C) | |
| // Within these forms, we can also permute A/B/C. | |
| // Generate legal pair permutations of A/B/C. | |
| std::vector<TreePatternNodePtr> ABVariants; | |
| std::vector<TreePatternNodePtr> BAVariants; | |
| std::vector<TreePatternNodePtr> ACVariants; | |
| std::vector<TreePatternNodePtr> CAVariants; | |
| std::vector<TreePatternNodePtr> BCVariants; | |
| std::vector<TreePatternNodePtr> CBVariants; | |
| CombineChildVariants(N, AVariants, BVariants, ABVariants, CDP, DepVars); | |
| CombineChildVariants(N, BVariants, AVariants, BAVariants, CDP, DepVars); | |
| CombineChildVariants(N, AVariants, CVariants, ACVariants, CDP, DepVars); | |
| CombineChildVariants(N, CVariants, AVariants, CAVariants, CDP, DepVars); | |
| CombineChildVariants(N, BVariants, CVariants, BCVariants, CDP, DepVars); | |
| CombineChildVariants(N, CVariants, BVariants, CBVariants, CDP, DepVars); | |
| // Combine those into the result: (x op x) op x | |
| CombineChildVariants(N, ABVariants, CVariants, OutVariants, CDP, DepVars); | |
| CombineChildVariants(N, BAVariants, CVariants, OutVariants, CDP, DepVars); | |
| CombineChildVariants(N, ACVariants, BVariants, OutVariants, CDP, DepVars); | |
| CombineChildVariants(N, CAVariants, BVariants, OutVariants, CDP, DepVars); | |
| CombineChildVariants(N, BCVariants, AVariants, OutVariants, CDP, DepVars); | |
| CombineChildVariants(N, CBVariants, AVariants, OutVariants, CDP, DepVars); | |
| // Combine those into the result: x op (x op x) | |
| CombineChildVariants(N, CVariants, ABVariants, OutVariants, CDP, DepVars); | |
| CombineChildVariants(N, CVariants, BAVariants, OutVariants, CDP, DepVars); | |
| CombineChildVariants(N, BVariants, ACVariants, OutVariants, CDP, DepVars); | |
| CombineChildVariants(N, BVariants, CAVariants, OutVariants, CDP, DepVars); | |
| CombineChildVariants(N, AVariants, BCVariants, OutVariants, CDP, DepVars); | |
| CombineChildVariants(N, AVariants, CBVariants, OutVariants, CDP, DepVars); | |
| return; | |
| } | |
| } | |
| // Compute permutations of all children. | |
| std::vector<std::vector<TreePatternNodePtr>> ChildVariants( | |
| N->getNumChildren()); | |
| for (unsigned i = 0, e = N->getNumChildren(); i != e; ++i) | |
| GenerateVariantsOf(N->getChildShared(i), ChildVariants[i], CDP, DepVars); | |
| // Build all permutations based on how the children were formed. | |
| CombineChildVariants(N, ChildVariants, OutVariants, CDP, DepVars); | |
| // If this node is commutative, consider the commuted order. | |
| bool isCommIntrinsic = N->isCommutativeIntrinsic(CDP); | |
| if (NodeInfo.hasProperty(SDNPCommutative) || isCommIntrinsic) { | |
| unsigned Skip = isCommIntrinsic ? 1 : 0; // First operand is intrinsic id. | |
| assert(N->getNumChildren() >= (2 + Skip) && | |
| "Commutative but doesn't have 2 children!"); | |
| // Don't allow commuting children which are actually register references. | |
| bool NoRegisters = true; | |
| unsigned i = 0 + Skip; | |
| unsigned e = 2 + Skip; | |
| for (; i != e; ++i) { | |
| TreePatternNode &Child = N->getChild(i); | |
| if (Child.isLeaf()) | |
| if (const DefInit *DI = dyn_cast<DefInit>(Child.getLeafValue())) { | |
| const Record *RR = DI->getDef(); | |
| if (RR->isSubClassOf("Register")) | |
| NoRegisters = false; | |
| } | |
| } | |
| // Consider the commuted order. | |
| if (NoRegisters) { | |
| // Swap the first two operands after the intrinsic id, if present. | |
| unsigned i = isCommIntrinsic ? 1 : 0; | |
| std::swap(ChildVariants[i], ChildVariants[i + 1]); | |
| CombineChildVariants(N, ChildVariants, OutVariants, CDP, DepVars); | |
| } | |
| } | |
| } | |
| // GenerateVariants - Generate variants. For example, commutative patterns can | |
| // match multiple ways. Add them to PatternsToMatch as well. | |
| void CodeGenDAGPatterns::GenerateVariants() { | |
| LLVM_DEBUG(dbgs() << "Generating instruction variants.\n"); | |
| // Loop over all of the patterns we've collected, checking to see if we can | |
| // generate variants of the instruction, through the exploitation of | |
| // identities. This permits the target to provide aggressive matching without | |
| // the .td file having to contain tons of variants of instructions. | |
| // | |
| // Note that this loop adds new patterns to the PatternsToMatch list, but we | |
| // intentionally do not reconsider these. Any variants of added patterns have | |
| // already been added. | |
| // | |
| for (unsigned i = 0, e = PatternsToMatch.size(); i != e; ++i) { | |
| MultipleUseVarSet DepVars; | |
| std::vector<TreePatternNodePtr> Variants; | |
| FindDepVars(PatternsToMatch[i].getSrcPattern(), DepVars); | |
| LLVM_DEBUG(dbgs() << "Dependent/multiply used variables: "); | |
| LLVM_DEBUG(DumpDepVars(DepVars)); | |
| LLVM_DEBUG(dbgs() << "\n"); | |
| GenerateVariantsOf(PatternsToMatch[i].getSrcPatternShared(), Variants, | |
| *this, DepVars); | |
| assert(PatternsToMatch[i].getHwModeFeatures().empty() && | |
| "HwModes should not have been expanded yet!"); | |
| assert(!Variants.empty() && "Must create at least original variant!"); | |
| if (Variants.size() == 1) // No additional variants for this pattern. | |
| continue; | |
| LLVM_DEBUG(dbgs() << "FOUND VARIANTS OF: "; | |
| PatternsToMatch[i].getSrcPattern().dump(); dbgs() << "\n"); | |
| for (unsigned v = 0, e = Variants.size(); v != e; ++v) { | |
| TreePatternNodePtr Variant = Variants[v]; | |
| LLVM_DEBUG(dbgs() << " VAR#" << v << ": "; Variant->dump(); | |
| dbgs() << "\n"); | |
| // Scan to see if an instruction or explicit pattern already matches this. | |
| bool AlreadyExists = false; | |
| for (unsigned p = 0, e = PatternsToMatch.size(); p != e; ++p) { | |
| // Skip if the top level predicates do not match. | |
| if ((i != p) && (PatternsToMatch[i].getPredicates() != | |
| PatternsToMatch[p].getPredicates())) | |
| continue; | |
| // Check to see if this variant already exists. | |
| if (Variant->isIsomorphicTo(PatternsToMatch[p].getSrcPattern(), | |
| DepVars)) { | |
| LLVM_DEBUG(dbgs() << " *** ALREADY EXISTS, ignoring variant.\n"); | |
| AlreadyExists = true; | |
| break; | |
| } | |
| } | |
| // If we already have it, ignore the variant. | |
| if (AlreadyExists) | |
| continue; | |
| // Otherwise, add it to the list of patterns we have. | |
| PatternsToMatch.emplace_back( | |
| PatternsToMatch[i].getSrcRecord(), PatternsToMatch[i].getPredicates(), | |
| Variant, PatternsToMatch[i].getDstPatternShared(), | |
| PatternsToMatch[i].getDstRegs(), | |
| PatternsToMatch[i].getAddedComplexity(), getNewUID(), | |
| PatternsToMatch[i].getGISelShouldIgnore(), | |
| PatternsToMatch[i].getHwModeFeatures()); | |
| } | |
| LLVM_DEBUG(dbgs() << "\n"); | |
| } | |
| } | |
| unsigned CodeGenDAGPatterns::getNewUID() { | |
| RecordKeeper &MutableRC = const_cast<RecordKeeper &>(Records); | |
| return Record::getNewUID(MutableRC); | |
| } |