aboutsummaryrefslogtreecommitdiff
path: root/llvm/utils/TableGen/CodeGenDAGPatterns.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2022-07-14 18:50:02 +0000
committerDimitry Andric <dim@FreeBSD.org>2022-07-14 18:50:02 +0000
commit1f917f69ff07f09b6dbb670971f57f8efe718b84 (patch)
tree99293cbc1411737cd995dac10a99b2c40ef0944c /llvm/utils/TableGen/CodeGenDAGPatterns.cpp
parent145449b1e420787bb99721a429341fa6be3adfb6 (diff)
Diffstat (limited to 'llvm/utils/TableGen/CodeGenDAGPatterns.cpp')
-rw-r--r--llvm/utils/TableGen/CodeGenDAGPatterns.cpp154
1 files changed, 99 insertions, 55 deletions
diff --git a/llvm/utils/TableGen/CodeGenDAGPatterns.cpp b/llvm/utils/TableGen/CodeGenDAGPatterns.cpp
index 9d6adb6d2c37..c15728ac7d23 100644
--- a/llvm/utils/TableGen/CodeGenDAGPatterns.cpp
+++ b/llvm/utils/TableGen/CodeGenDAGPatterns.cpp
@@ -46,6 +46,9 @@ static inline bool isVector(MVT VT) {
static inline bool isScalar(MVT VT) {
return !VT.isVector();
}
+static inline bool isScalarInteger(MVT VT) {
+ return VT.isScalarInteger();
+}
template <typename Predicate>
static bool berase_if(MachineValueTypeSet &S, Predicate P) {
@@ -61,6 +64,17 @@ static bool berase_if(MachineValueTypeSet &S, Predicate P) {
return Erased;
}
+void MachineValueTypeSet::writeToStream(raw_ostream &OS) const {
+ SmallVector<MVT, 4> Types(begin(), end());
+ array_pod_sort(Types.begin(), Types.end());
+
+ OS << '[';
+ ListSeparator LS(" ");
+ for (const MVT &T : Types)
+ OS << LS << ValueTypeByHwMode::getMVTName(T);
+ OS << ']';
+}
+
// --- TypeSetByHwMode
// This is a parameterized type-set class. For each mode there is a list
@@ -193,22 +207,11 @@ void TypeSetByHwMode::writeToStream(raw_ostream &OS) const {
OS << '{';
for (unsigned M : Modes) {
OS << ' ' << getModeName(M) << ':';
- writeToStream(get(M), OS);
+ get(M).writeToStream(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();
@@ -253,6 +256,10 @@ bool TypeSetByHwMode::operator==(const TypeSetByHwMode &VTS) const {
}
namespace llvm {
+ raw_ostream &operator<<(raw_ostream &OS, const MachineValueTypeSet &T) {
+ T.writeToStream(OS);
+ return OS;
+ }
raw_ostream &operator<<(raw_ostream &OS, const TypeSetByHwMode &T) {
T.writeToStream(OS);
return OS;
@@ -266,10 +273,11 @@ void TypeSetByHwMode::dump() const {
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); };
+ // Complement of In.
+ auto CompIn = [&In](MVT T) -> bool { return !In.count(T); };
if (OutP == InP)
- return berase_if(Out, Int);
+ return berase_if(Out, CompIn);
// Compute the intersection of scalars separately to account for only
// one set containing iPTR.
@@ -285,42 +293,64 @@ bool TypeSetByHwMode::intersect(SetType &Out, const SetType &In) {
// { 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;
+ // Let In' = elements only in In, Out' = elements only in Out, and
+ // IO = elements common to both. Normally IO would be returned as the result
+ // of the intersection, but we need to account for iPTR being a "wildcard" of
+ // sorts. Since elements in IO are those that match both sets exactly, they
+ // will all belong to the output. If any of the "leftovers" (i.e. In' or
+ // Out') contain iPTR, it means that the other set doesn't have it, but it
+ // could have (1) a more specific type, or (2) a set of types that is less
+ // specific. The "leftovers" from the other set is what we want to examine
+ // more closely.
+
+ auto subtract = [](const SetType &A, const SetType &B) {
+ SetType Diff = A;
+ berase_if(Diff, [&B](MVT T) { return B.count(T); });
+ return 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);
+ SetType OutOnly = subtract(Out, In);
+ if (OutOnly.empty()) {
+ // This means that Out \subset In, so no change to Out.
+ return false;
+ }
+ unsigned NumI = llvm::count_if(OutOnly, isScalarInteger);
+ if (NumI == 1 && OutOnly.size() == 1) {
+ // There is only one element in Out', and it happens to be a scalar
+ // integer that should be kept as a match for iPTR in In.
+ return false;
+ }
+ berase_if(Out, CompIn);
+ if (NumI == 1) {
+ // Replace the iPTR with the leftover scalar integer.
+ Out.insert(*llvm::find_if(OutOnly, isScalarInteger));
+ } else if (NumI > 1) {
+ Out.insert(MVT::iPTR);
+ }
+ return true;
}
- // 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;
+ // OutP == true
+ SetType InOnly = subtract(In, Out);
+ unsigned SizeOut = Out.size();
+ berase_if(Out, CompIn); // This will remove at least the iPTR.
+ unsigned NumI = llvm::count_if(InOnly, isScalarInteger);
+ if (NumI == 0) {
+ // iPTR deleted from Out.
+ return true;
}
- return Changed;
+ if (NumI == 1) {
+ // Replace the iPTR with the leftover scalar integer.
+ Out.insert(*llvm::find_if(InOnly, isScalarInteger));
+ return true;
+ }
+
+ // NumI > 1: Keep the iPTR in Out.
+ Out.insert(MVT::iPTR);
+ // If iPTR was the only element initially removed from Out, then Out
+ // has not changed.
+ return SizeOut != Out.size();
}
bool TypeSetByHwMode::validate() const {
@@ -902,7 +932,7 @@ TreePredicateFn::TreePredicateFn(TreePattern *N) : PatFragRec(N) {
}
bool TreePredicateFn::hasPredCode() const {
- return isLoad() || isStore() || isAtomic() ||
+ return isLoad() || isStore() || isAtomic() || hasNoUse() ||
!PatFragRec->getRecord()->getValueAsString("PredicateCode").empty();
}
@@ -947,12 +977,15 @@ std::string TreePredicateFn::getPredCode() const {
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 (!isAtomic()) {
+ if (isSignExtLoad())
+ PrintFatalError(getOrigPatFragRecord()->getRecord()->getLoc(),
+ "IsSignExtLoad requires IsLoad or IsAtomic");
+ if (isZeroExtLoad())
+ PrintFatalError(getOrigPatFragRecord()->getRecord()->getLoc(),
+ "IsZeroExtLoad requires IsLoad or IsAtomic");
+ }
}
if (isStore()) {
@@ -973,8 +1006,9 @@ std::string TreePredicateFn::getPredCode() const {
if (isAtomic()) {
if (getMemoryVT() == nullptr && !isAtomicOrderingMonotonic() &&
getAddressSpaces() == nullptr &&
- !isAtomicOrderingAcquire() && !isAtomicOrderingRelease() &&
- !isAtomicOrderingAcquireRelease() &&
+ // FIXME: Should atomic loads be IsLoad, IsAtomic, or both?
+ !isZeroExtLoad() && !isSignExtLoad() && !isAtomicOrderingAcquire() &&
+ !isAtomicOrderingRelease() && !isAtomicOrderingAcquireRelease() &&
!isAtomicOrderingSequentiallyConsistent() &&
!isAtomicOrderingAcquireOrStronger() &&
!isAtomicOrderingReleaseOrStronger() &&
@@ -1075,6 +1109,10 @@ std::string TreePredicateFn::getPredCode() const {
Code += "if (isReleaseOrStronger(cast<AtomicSDNode>(N)->getMergedOrdering())) "
"return false;\n";
+ // TODO: Handle atomic sextload/zextload normally when ATOMIC_LOAD is removed.
+ if (isAtomic() && (isZeroExtLoad() || isSignExtLoad()))
+ Code += "return false;\n";
+
if (isLoad() || isStore()) {
StringRef SDNodeName = isLoad() ? "LoadSDNode" : "StoreSDNode";
@@ -1124,6 +1162,9 @@ std::string TreePredicateFn::getPredCode() const {
.str();
}
+ if (hasNoUse())
+ Code += "if (!SDValue(N, 0).use_empty()) return false;\n";
+
std::string PredicateCode =
std::string(PatFragRec->getRecord()->getValueAsString("PredicateCode"));
@@ -1167,6 +1208,9 @@ bool TreePredicateFn::isPredefinedPredicateEqualTo(StringRef Field,
bool TreePredicateFn::usesOperands() const {
return isPredefinedPredicateEqualTo("PredicateCodeUsesOperands", true);
}
+bool TreePredicateFn::hasNoUse() const {
+ return isPredefinedPredicateEqualTo("HasNoUse", true);
+}
bool TreePredicateFn::isLoad() const {
return isPredefinedPredicateEqualTo("IsLoad", true);
}