| //===- 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 "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/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; |
| } |
| |
| // --- 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) { |
| for (const ValueTypeByHwMode &VVT : VTList) { |
| insert(VVT); |
| AddrSpaces.push_back(VVT.PtrAddrSpace); |
| } |
| } |
| |
| 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() const { |
| assert(isValueTypeByHwMode(true) && |
| "The type set has multiple types for at least one HW mode"); |
| ValueTypeByHwMode VVT; |
| auto ASI = AddrSpaces.begin(); |
| |
| for (const auto &I : *this) { |
| MVT T = I.second.empty() ? MVT::Other : *I.second.begin(); |
| VVT.getOrCreateTypeForMode(I.first, T); |
| if (ASI != AddrSpaces.end()) |
| VVT.PtrAddrSpace = *ASI++; |
| } |
| 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.insert({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 { |
| SmallVector<unsigned, 4> Modes; |
| Modes.reserve(Map.size()); |
| |
| for (const auto &I : *this) |
| Modes.push_back(I.first); |
| if (Modes.empty()) { |
| OS << "{}"; |
| return; |
| } |
| array_pod_sort(Modes.begin(), Modes.end()); |
| |
| OS << '{'; |
| for (unsigned M : Modes) { |
| OS << ' ' << getModeName(M) << ':'; |
| writeToStream(get(M), OS); |
| } |
| OS << " }"; |
| } |
| |
| void TypeSetByHwMode::writeToStream(const SetType &S, raw_ostream &OS) { |
| SmallVector<MVT, 4> Types(S.begin(), S.end()); |
| array_pod_sort(Types.begin(), Types.end()); |
| |
| OS << '['; |
| ListSeparator LS(" "); |
| for (const MVT &T : Types) |
| OS << LS << ValueTypeByHwMode::getMVTName(T); |
| 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 *begin() == *VTS.begin(); |
| |
| // 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; |
| for (auto &I : *this) |
| Modes.insert(I.first); |
| for (const auto &I : VTS) |
| Modes.insert(I.first); |
| |
| 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; |
| } |
| |
| namespace llvm { |
| raw_ostream &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) { |
| bool OutP = Out.count(MVT::iPTR), InP = In.count(MVT::iPTR); |
| auto Int = [&In](MVT T) -> bool { return !In.count(T); }; |
| |
| if (OutP == InP) |
| return berase_if(Out, Int); |
| |
| // Compute the intersection of scalars separately to account for only |
| // one set containing iPTR. |
| // The intersection of iPTR with a set of integer scalar types that does not |
| // include iPTR will result in the most specific scalar type: |
| // - iPTR is more specific than any set with two elements or more |
| // - iPTR is less specific than any single integer scalar type. |
| // For example |
| // { 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 } |
| |
| // Compute the difference between the two sets in such a way that the |
| // iPTR is in the set that is being subtracted. This is to see if there |
| // are any extra scalars in the set without iPTR that are not in the |
| // set containing iPTR. Then the iPTR could be considered a "wildcard" |
| // matching these scalars. If there is only one such scalar, it would |
| // replace the iPTR, if there are more, the iPTR would be retained. |
| SetType Diff; |
| if (InP) { |
| Diff = Out; |
| berase_if(Diff, [&In](MVT T) { return In.count(T); }); |
| // Pre-remove these elements and rely only on InP/OutP to determine |
| // whether a change has been made. |
| berase_if(Out, [&Diff](MVT T) { return Diff.count(T); }); |
| } else { |
| Diff = In; |
| berase_if(Diff, [&Out](MVT T) { return Out.count(T); }); |
| Out.erase(MVT::iPTR); |
| } |
| |
| // The actual intersection. |
| bool Changed = berase_if(Out, Int); |
| unsigned NumD = Diff.size(); |
| if (NumD == 0) |
| return Changed; |
| |
| if (NumD == 1) { |
| Out.insert(*Diff.begin()); |
| // This is a change only if Out was the one with iPTR (which is now |
| // being replaced). |
| Changed |= OutP; |
| } else { |
| // Multiple elements from Out are now replaced with iPTR. |
| Out.insert(MVT::iPTR); |
| Changed |= !OutP; |
| } |
| return Changed; |
| } |
| |
| bool TypeSetByHwMode::validate() const { |
| #ifndef NDEBUG |
| if (empty()) |
| return true; |
| bool AllEmpty = true; |
| for (const auto &I : *this) |
| AllEmpty &= I.second.empty(); |
| return !AllEmpty; |
| #endif |
| return true; |
| } |
| |
| // --- TypeInfer |
| |
| bool TypeInfer::MergeInTypeInfo(TypeSetByHwMode &Out, |
| const TypeSetByHwMode &In) { |
| 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::make_tuple(A.isScalableVector(), A.getScalarSizeInBits(), |
| A.getSizeInBits().getKnownMinSize()); |
| auto BSize = std::make_tuple(B.isScalableVector(), B.getScalarSizeInBits(), |
| B.getSizeInBits().getKnownMinSize()); |
| 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::make_tuple(A.isVector(), A.isScalableVector()) != |
| std::make_tuple(B.isVector(), B.isScalableVector())) |
| return false; |
| |
| return std::make_tuple(A.getScalarSizeInBits(), |
| A.getSizeInBits().getKnownMinSize()) <= |
| std::make_tuple(B.getScalarSizeInBits(), |
| B.getSizeInBits().getKnownMinSize()); |
| }; |
| |
| 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; |
| // Logically a <4 x i32> is a valid subvector of <n x 4 x i32> |
| // but until there are obvious use-cases for this, keep the |
| // types separate. |
| if (B.isScalableVector() != P.isScalableVector()) |
| return false; |
| if (B.getVectorElementType() != P.getVectorElementType()) |
| return false; |
| 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.count(T.isVector() ? T.getVectorElementCount() |
| : ElementCount::getNull()); |
| }; |
| |
| 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::getNull()); |
| for (MVT T : WS) |
| WN.insert(T.isVector() ? T.getVectorElementCount() |
| : ElementCount::getNull()); |
| |
| 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::make_tuple(LHS.isScalable(), LHS.getKnownMinValue()) < |
| std::make_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); |
| |
| typedef SmallSet<TypeSize, 2, TypeSizeComparator> TypeSizeSet; |
| |
| auto NoSize = [](const TypeSizeSet &Sizes, MVT T) -> bool { |
| return !Sizes.count(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) { |
| ValidateOnExit _1(VTS, *this); |
| const TypeSetByHwMode &Legal = getLegalTypes(); |
| assert(Legal.isDefaultOnly() && "Default-mode only expected"); |
| const TypeSetByHwMode::SetType &LegalTypes = Legal.get(DefaultMode); |
| |
| for (auto &I : VTS) |
| expandOverloads(I.second, LegalTypes); |
| } |
| |
| void TypeInfer::expandOverloads(TypeSetByHwMode::SetType &Out, |
| const TypeSetByHwMode::SetType &Legal) { |
| std::set<MVT> Ovs; |
| for (MVT T : Out) { |
| if (!T.isOverloaded()) |
| continue; |
| |
| Ovs.insert(T); |
| // MachineValueTypeSet allows iteration and erasing. |
| Out.erase(T); |
| } |
| |
| for (MVT Ov : Ovs) { |
| switch (Ov.SimpleTy) { |
| case MVT::iPTRAny: |
| Out.insert(MVT::iPTR); |
| return; |
| case 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); |
| return; |
| case 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); |
| return; |
| case MVT::vAny: |
| for (MVT T : MVT::vector_valuetypes()) |
| if (Legal.count(T)) |
| Out.insert(T); |
| return; |
| case MVT::Any: |
| for (MVT T : MVT::all_valuetypes()) |
| if (Legal.count(T)) |
| Out.insert(T); |
| return; |
| default: |
| break; |
| } |
| } |
| } |
| |
| const TypeSetByHwMode &TypeInfer::getLegalTypes() { |
| 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.isDefaultOnly() && "Default-mode only expected"); |
| return LegalCache; |
| } |
| |
| #ifndef NDEBUG |
| TypeInfer::ValidateOnExit::~ValidateOnExit() { |
| if (Infer.Validate && !VTS.validate()) { |
| dbgs() << "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(); |
| dbgs() << "Generated from record:\n"; |
| Infer.TP.getRecord()->dump(); |
| PrintFatalError(Infer.TP.getRecord()->getLoc(), |
| "Type set is empty for each HW mode in '" + |
| Infer.TP.getRecord()->getName() + "'"); |
| } |
| } |
| #endif |
| |
| |
| //===----------------------------------------------------------------------===// |
| // 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"); |
| } |
| |
| bool TreePredicateFn::hasPredCode() const { |
| return isLoad() || isStore() || isAtomic() || |
| !PatFragRec->getRecord()->getValueAsString("PredicateCode").empty(); |
| } |
| |
| std::string TreePredicateFn::getPredCode() const { |
| std::string Code; |
| |
| if (!isLoad() && !isStore() && !isAtomic()) { |
| Record *MemoryVT = getMemoryVT(); |
| |
| if (MemoryVT) |
| PrintFatalError(getOrigPatFragRecord()->getRecord()->getLoc(), |
| "MemoryVT requires IsLoad or IsStore"); |
| } |
| |
| if (!isLoad() && !isStore()) { |
| if (isUnindexed()) |
| PrintFatalError(getOrigPatFragRecord()->getRecord()->getLoc(), |
| "IsUnindexed requires IsLoad or IsStore"); |
| |
| Record *ScalarMemoryVT = getScalarMemoryVT(); |
| |
| if (ScalarMemoryVT) |
| 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 (isNonExtLoad()) |
| PrintFatalError(getOrigPatFragRecord()->getRecord()->getLoc(), |
| "IsNonExtLoad requires IsLoad"); |
| if (isAnyExtLoad()) |
| PrintFatalError(getOrigPatFragRecord()->getRecord()->getLoc(), |
| "IsAnyExtLoad requires IsLoad"); |
| if (isSignExtLoad()) |
| PrintFatalError(getOrigPatFragRecord()->getRecord()->getLoc(), |
| "IsSignExtLoad requires IsLoad"); |
| if (isZeroExtLoad()) |
| PrintFatalError(getOrigPatFragRecord()->getRecord()->getLoc(), |
| "IsZeroExtLoad requires IsLoad"); |
| } |
| |
| 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 (isNonTruncStore()) |
| PrintFatalError(getOrigPatFragRecord()->getRecord()->getLoc(), |
| "IsNonTruncStore requires IsStore"); |
| if (isTruncStore()) |
| PrintFatalError(getOrigPatFragRecord()->getRecord()->getLoc(), |
| "IsTruncStore requires IsStore"); |
| } |
| |
| if (isAtomic()) { |
| if (getMemoryVT() == nullptr && !isAtomicOrderingMonotonic() && |
| getAddressSpaces() == nullptr && |
| !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 (ListInit *AddressSpaces = getAddressSpaces()) { |
| Code += "unsigned AddrSpace = cast<MemSDNode>(N)->getAddressSpace();\n" |
| " if ("; |
| |
| ListSeparator LS(" && "); |
| for (Init *Val : AddressSpaces->getValues()) { |
| Code += LS; |
| |
| 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"; |
| } |
| |
| Record *MemoryVT = getMemoryVT(); |
| |
| if (MemoryVT) |
| 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 (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"; |
| } |
| |
| Record *ScalarMemoryVT = getScalarMemoryVT(); |
| |
| if (ScalarMemoryVT) |
| Code += ("if (cast<" + SDNodeName + |
| ">(N)->getMemoryVT().getScalarType() != MVT::" + |
| ScalarMemoryVT->getName() + ") return false;\n") |
| .str(); |
| } |
| |
| std::string PredicateCode = |
| std::string(PatFragRec->getRecord()->getValueAsString("PredicateCode")); |
| |
| 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 std::string( |
| PatFragRec->getRecord()->getValueAsString("ImmediateCode")); |
| } |
| |
| 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::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); |
| } |
| Record *TreePredicateFn::getMemoryVT() const { |
| Record *R = getOrigPatFragRecord()->getRecord(); |
| if (R->isValueUnset("MemoryVT")) |
| return nullptr; |
| return R->getValueAsDef("MemoryVT"); |
| } |
| |
| ListInit *TreePredicateFn::getAddressSpaces() const { |
| Record *R = getOrigPatFragRecord()->getRecord(); |
| if (R->isValueUnset("AddressSpaces")) |
| return nullptr; |
| return R->getValueAsListInit("AddressSpaces"); |
| } |
| |
| int64_t TreePredicateFn::getMinAlignment() const { |
| Record *R = getOrigPatFragRecord()->getRecord(); |
| if (R->isValueUnset("MinAlignment")) |
| return 0; |
| return R->getValueAsInt("MinAlignment"); |
| } |
| |
| Record *TreePredicateFn::getScalarMemoryVT() 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 std::string( |
| PatFragRec->getRecord()->getValueAsString("GISelPredicateCode")); |
| } |
| |
| 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>(Node)->getValueAPF();\n"; |
| else if (immCodeUsesAPInt()) |
| Result += "cast<ConstantSDNode>(Node)->getAPIntValue();\n"; |
| else |
| Result += "cast<ConstantSDNode>(Node)->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 { |
| 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 = Node;\n"; |
| else |
| Result = " auto *N = cast<" + ClassName.str() + ">(Node);\n"; |
| |
| return (Twine(Result) + " (void)N;\n" + getPredCode()).str(); |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // PatternToMatch implementation |
| // |
| |
| static bool isImmAllOnesAllZerosMatch(const TreePatternNode *P) { |
| if (!P->isLeaf()) |
| return false; |
| DefInit *DI = dyn_cast<DefInit>(P->getLeafValue()); |
| if (!DI) |
| return false; |
| |
| 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 (unsigned i = 0, e = P->getNumChildren(); i != e; ++i) { |
| const TreePatternNode *Child = P->getChild(i); |
| if (!Child->isLeaf() && Child->getNumTypes()) { |
| const TypeSetByHwMode &T0 = Child->getExtType(0); |
| // At this point, all variable type sets should be simple, i.e. only |
| // have a default mode. |
| if (T0.getMachineValueType() != 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<Record *> &PredicateRecs) const { |
| for (Init *I : Predicates->getValues()) { |
| if (DefInit *Pred = dyn_cast<DefInit>(I)) { |
| 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()); |
| } |
| |
| /// getPredicateCheck - Return a single string containing all of this |
| /// pattern's predicates concatenated with "&&" operators. |
| /// |
| std::string PatternToMatch::getPredicateCheck() const { |
| SmallVector<Record *, 4> PredicateRecs; |
| getPredicateRecords(PredicateRecs); |
| |
| SmallString<128> PredicateCheck; |
| for (Record *Pred : PredicateRecs) { |
| StringRef CondString = Pred->getValueAsString("CondString"); |
| if (CondString.empty()) |
| continue; |
| if (!PredicateCheck.empty()) |
| PredicateCheck += " && "; |
| PredicateCheck += "("; |
| PredicateCheck += CondString; |
| PredicateCheck += ")"; |
| } |
| |
| if (!HwModeFeatures.empty()) { |
| if (!PredicateCheck.empty()) |
| PredicateCheck += " && "; |
| PredicateCheck += HwModeFeatures; |
| } |
| |
| return std::string(PredicateCheck); |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // SDTypeConstraint implementation |
| // |
| |
| SDTypeConstraint::SDTypeConstraint(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; |
| x.SDTCisSameAs_Info.OtherOperandNum = R->getValueAsInt("OtherOperandNum"); |
| } else if (R->isSubClassOf("SDTCisVTSmallerThanOp")) { |
| ConstraintType = SDTCisVTSmallerThanOp; |
| x.SDTCisVTSmallerThanOp_Info.OtherOperandNum = |
| R->getValueAsInt("OtherOperandNum"); |
| } else if (R->isSubClassOf("SDTCisOpSmallerThanOp")) { |
| ConstraintType = SDTCisOpSmallerThanOp; |
| x.SDTCisOpSmallerThanOp_Info.BigOperandNum = |
| R->getValueAsInt("BigOperandNum"); |
| } else if (R->isSubClassOf("SDTCisEltOfVec")) { |
| ConstraintType = SDTCisEltOfVec; |
| x.SDTCisEltOfVec_Info.OtherOperandNum = R->getValueAsInt("OtherOpNum"); |
| } else if (R->isSubClassOf("SDTCisSubVecOfVec")) { |
| ConstraintType = SDTCisSubVecOfVec; |
| x.SDTCisSubVecOfVec_Info.OtherOperandNum = |
| 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; |
| x.SDTCisSameNumEltsAs_Info.OtherOperandNum = |
| R->getValueAsInt("OtherOperandNum"); |
| } else if (R->isSubClassOf("SDTCisSameSizeAs")) { |
| ConstraintType = SDTCisSameSizeAs; |
| x.SDTCisSameSizeAs_Info.OtherOperandNum = |
| 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()) { |
| std::string S; |
| raw_string_ostream OS(S); |
| OS << "Invalid operand number in type constraint " |
| << (OpNo+NumResults) << " "; |
| N->print(OS); |
| PrintFatalError(OS.str()); |
| } |
| |
| 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 same as target pointer type. |
| return NodeToApply->UpdateNodeType(ResNo, MVT::iPTR, 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(x.SDTCisSameAs_Info.OtherOperandNum, 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; |
| } |
| 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(x.SDTCisVTSmallerThanOp_Info.OtherOperandNum, N, NodeInfo, |
| OResNo); |
| |
| return TI.EnforceSmallerThan(TypeListTmp, OtherNode->getExtType(OResNo), |
| /*SmallIsVT*/ true); |
| } |
| case SDTCisOpSmallerThanOp: { |
| unsigned BResNo = 0; |
| TreePatternNode *BigOperand = |
| getOperandNum(x.SDTCisOpSmallerThanOp_Info.BigOperandNum, N, NodeInfo, |
| BResNo); |
| return TI.EnforceSmallerThan(NodeToApply->getExtType(ResNo), |
| BigOperand->getExtType(BResNo)); |
| } |
| case SDTCisEltOfVec: { |
| unsigned VResNo = 0; |
| TreePatternNode *VecOperand = |
| getOperandNum(x.SDTCisEltOfVec_Info.OtherOperandNum, 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(x.SDTCisSubVecOfVec_Info.OtherOperandNum, 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(x.SDTCisSameNumEltsAs_Info.OtherOperandNum, |
| N, NodeInfo, OResNo); |
| return TI.EnforceSameNumElts(OtherNode->getExtType(OResNo), |
| NodeToApply->getExtType(ResNo)); |
| } |
| case SDTCisSameSizeAs: { |
| unsigned OResNo = 0; |
| TreePatternNode *OtherNode = |
| getOperandNum(x.SDTCisSameSizeAs_Info.OtherOperandNum, |
| N, NodeInfo, OResNo); |
| return TI.EnforceSameSize(OtherNode->getExtType(OResNo), |
| NodeToApply->getExtType(ResNo)); |
| } |
| } |
| llvm_unreachable("Invalid ConstraintType!"); |
| } |
| |
| // 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, |
| 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")) { |
| Record *R = Operand->getValueAsDef("Type"); |
| const CodeGenTarget &T = TP.getDAGPatterns().getTargetInfo(); |
| return UpdateNodeType(ResNo, getValueTypeByHwMode(R, T.getHwModes()), TP); |
| } |
| |
| // PointerLikeRegClass has a type that is determined at runtime. |
| if (Operand->isSubClassOf("PointerLikeRegClass")) |
| return UpdateNodeType(ResNo, MVT::iPTR, TP); |
| |
| // Both RegisterClass and RegisterOperand operands derive their types from a |
| // register class def. |
| Record *RC = nullptr; |
| if (Operand->isSubClassOf("RegisterClass")) |
| RC = Operand; |
| else if (Operand->isSubClassOf("RegisterOperand")) |
| RC = Operand->getValueAsDef("RegClass"); |
| |
| assert(RC && "Unknown operand type"); |
| CodeGenTarget &Tgt = TP.getDAGPatterns().getTargetInfo(); |
| return UpdateNodeType(ResNo, Tgt.getRegisterClass(RC).getValueTypes(), TP); |
| } |
| |
| bool TreePatternNode::ContainsUnresolvedType(TreePattern &TP) const { |
| for (unsigned i = 0, e = Types.size(); i != e; ++i) |
| if (!TP.getInfer().isConcrete(Types[i], true)) |
| return true; |
| for (unsigned i = 0, e = getNumChildren(); i != e; ++i) |
| if (getChild(i)->ContainsUnresolvedType(TP)) |
| return true; |
| return false; |
| } |
| |
| bool TreePatternNode::hasProperTypeByHwMode() const { |
| for (const TypeSetByHwMode &S : Types) |
| if (!S.isDefaultOnly()) |
| 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(Record *R, const CodeGenHwModes &CGH) : Def(R) { |
| EnumName = R->getValueAsString("Opcode"); |
| SDClassName = R->getValueAsString("SDClass"); |
| Record *TypeProfile = R->getValueAsDef("TypeProfile"); |
| NumResults = TypeProfile->getValueAsInt("NumResults"); |
| NumOperands = TypeProfile->getValueAsInt("NumOperands"); |
| |
| // Parse the properties. |
| Properties = parseSDPatternOperatorProperties(R); |
| |
| // Parse the type constraints. |
| std::vector<Record*> ConstraintList = |
| TypeProfile->getValueAsListOfDefs("Constraints"); |
| for (Record *R : ConstraintList) |
| 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::SimpleValueType. Otherwise, return EEVT::Other. |
| MVT::SimpleValueType 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(Record *Operator, CodeGenDAGPatterns &CDP) { |
| if (Operator->getName() == "set" || |
| Operator->getName() == "implicit") |
| return 0; // All return nothing. |
| |
| if (Operator->isSubClassOf("Intrinsic")) |
| return CDP.getIntrinsic(Operator).IS.RetVTs.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; |
| } |
| |
| ListInit *LI = Operator->getValueAsListInit("Fragments"); |
| assert(LI && "Invalid Fragment"); |
| unsigned NumResults = 0; |
| for (Init *I : LI->getValues()) { |
| Record *Op = nullptr; |
| if (DagInit *Dag = dyn_cast<DagInit>(I)) |
| if (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")) { |
| CodeGenInstruction &InstInfo = CDP.getTargetInfo().getInstruction(Operator); |
| |
| unsigned NumDefsToAdd = InstInfo.Operands.NumDefs; |
| |
| // Subtract any defaulted outputs. |
| for (unsigned i = 0; i != InstInfo.Operands.NumDefs; ++i) { |
| 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 (unsigned i = 0, e = getNumChildren(); i != e; ++i) { |
| OS << LS; |
| getChild(i)->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(errs()); |
| } |
| |
| /// 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() || getExtTypes() != N->getExtTypes() || |
| getPredicateCalls() != N->getPredicateCalls() || |
| getTransformFn() != N->getTransformFn()) |
| return false; |
| |
| if (isLeaf()) { |
| if (DefInit *DI = dyn_cast<DefInit>(getLeafValue())) { |
| if (DefInit *NDI = dyn_cast<DefInit>(N->getLeafValue())) { |
| return ((DI->getDef() == NDI->getDef()) |
| && (DepVars.find(getName()) == DepVars.end() |
| || getName() == N->getName())); |
| } |
| } |
| return getLeafValue() == N->getLeafValue(); |
| } |
| |
| if (N->getOperator() != getOperator() || |
| N->getNumChildren() != getNumChildren()) return false; |
| 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 = std::make_shared<TreePatternNode>(getLeafValue(), getNumTypes()); |
| } else { |
| std::vector<TreePatternNodePtr> CChildren; |
| CChildren.reserve(Children.size()); |
| for (unsigned i = 0, e = getNumChildren(); i != e; ++i) |
| CChildren.push_back(getChild(i)->clone()); |
| New = std::make_shared<TreePatternNode>(getOperator(), std::move(CChildren), |
| getNumTypes()); |
| } |
| New->setName(getName()); |
| New->setNamesAsPredicateArg(getNamesAsPredicateArg()); |
| New->Types = Types; |
| New->setPredicateCalls(getPredicateCalls()); |
| New->setTransformFn(getTransformFn()); |
| return New; |
| } |
| |
| /// RemoveAllTypes - Recursively strip all the types of this tree. |
| void TreePatternNode::RemoveAllTypes() { |
| // Reset to unknown type. |
| std::fill(Types.begin(), Types.end(), TypeSetByHwMode()); |
| if (isLeaf()) return; |
| for (unsigned i = 0, e = getNumChildren(); i != e; ++i) |
| getChild(i)->RemoveAllTypes(); |
| } |
| |
| |
| /// SubstituteFormalArguments - Replace the formal arguments in this tree |
| /// with actual values specified by ArgMap. |
| void TreePatternNode::SubstituteFormalArguments( |
| std::map<std::string, TreePatternNodePtr> &ArgMap) { |
| if (isLeaf()) return; |
| |
| for (unsigned i = 0, e = getNumChildren(); i != e; ++i) { |
| TreePatternNode *Child = getChild(i); |
| if (Child->isLeaf()) { |
| 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( |
| TreePatternNodePtr T, TreePattern &TP, |
| std::vector<TreePatternNodePtr> &OutAlternatives) { |
| |
| if (TP.hasError()) |
| return; |
| |
| if (isLeaf()) { |
| OutAlternatives.push_back(T); // nothing to do. |
| return; |
| } |
| |
| Record *Op = getOperator(); |
| |
| if (!Op->isSubClassOf("PatFrags")) { |
| if (getNumChildren() == 0) { |
| OutAlternatives.push_back(T); |
| return; |
| } |
| |
| // Recursively inline children nodes. |
| std::vector<std::vector<TreePatternNodePtr> > ChildAlternatives; |
| ChildAlternatives.resize(getNumChildren()); |
| for (unsigned i = 0, e = getNumChildren(); i != e; ++i) { |
| TreePatternNodePtr Child = getChildShared(i); |
| Child->InlinePatternFragments(Child, 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; |
| Idxs.resize(ChildAlternatives.size()); |
| bool NotDone; |
| do { |
| // Create the variant and add it to the output list. |
| std::vector<TreePatternNodePtr> NewChildren; |
| for (unsigned i = 0, e = ChildAlternatives.size(); i != e; ++i) |
| NewChildren.push_back(ChildAlternatives[i][Idxs[i]]); |
| TreePatternNodePtr R = std::make_shared<TreePatternNode>( |
| getOperator(), std::move(NewChildren), getNumTypes()); |
| |
| // Copy over properties. |
| R->setName(getName()); |
| R->setNamesAsPredicateArg(getNamesAsPredicateArg()); |
| R->setPredicateCalls(getPredicateCalls()); |
| 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() != Children.size()) { |
| 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<std::string, 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); |
| |
| // 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(FragTree, 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(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. |
| Record *RegClass = R->getValueAsDef("RegClass"); |
| const CodeGenTarget &T = TP.getDAGPatterns().getTargetInfo(); |
| 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("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. |
| return TypeSetByHwMode(CDP.getComplexPattern(R).getValueType()); |
| } |
| if (R->isSubClassOf("PointerLikeRegClass")) { |
| assert(ResNo == 0 && "Regclass can only have one result!"); |
| TypeSetByHwMode VTS(MVT::iPTR); |
| TP.getInfer().expandOverloads(VTS); |
| return VTS; |
| } |
| |
| 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(); |
| 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 { |
| Record *Rec; |
| if (isLeaf()) { |
| 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()) { |
| DefInit *DI = dyn_cast<DefInit>(getLeafValue()); |
| if (DI && DI->getDef()->isSubClassOf("Operand")) { |
| 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 (!Operator->isSubClassOf("SDPatternOperator")) |
| return false; |
| |
| return CGP.getSDNodeInfo(Operator).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 (unsigned i = 0, e = getNumChildren(); i != e; ++i) |
| if (getChild(i)->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); |
| |
| 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 (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 (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 (!TP.getInfer().isConcrete(Types[0], false)) |
| return MadeChange; |
| |
| ValueTypeByHwMode VVT = TP.getInfer().getConcrete(Types[0], false); |
| for (auto &P : VVT) { |
| MVT::SimpleValueType VT = P.second.SimpleTy; |
| if (VT == MVT::iPTR || VT == MVT::iPTRAny) |
| continue; |
| unsigned Size = MVT(VT).getFixedSizeInBits(); |
| // Make sure that the value is representable for this type. |
| if (Size >= 32) |
| 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. |
| int64_t SignBitAndAbove = II->getValue() >> (Size - 1); |
| if (SignBitAndAbove == -1 || SignBitAndAbove == 0 || |
| SignBitAndAbove == 1) |
| continue; |
| |
| TP.error("Integer value '" + Twine(II->getValue()) + |
| "' 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.RetVTs.size(); |
| unsigned NumParamVTs = Int->IS.ParamVTs.size(); |
| |
| for (unsigned i = 0, e = NumRetVTs; i != e; ++i) |
| MadeChange |= UpdateNodeType(i, Int->IS.RetVTs[i], 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::SimpleValueType OpVT = Int->IS.ParamVTs[i]; |
| 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 (unsigned i = 0, e = getNumChildren(); i != e; ++i) |
| MadeChange |= getChild(i)->ApplyTypeConstraints(TP, NotRegisters); |
| MadeChange |= NI.ApplyTypeConstraints(this, TP); |
| return MadeChange; |
| } |
| |
| if (getOperator()->isSubClassOf("Instruction")) { |
| const DAGInstruction &Inst = CDP.getInstruction(getOperator()); |
| 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::SimpleValueType 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) { |
| 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")) { |
| 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. |
| 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; |
| } |
| |
|
|