aboutsummaryrefslogtreecommitdiff
path: root/llvm/utils/TableGen
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/utils/TableGen')
-rw-r--r--llvm/utils/TableGen/CodeEmitterGen.cpp133
-rw-r--r--llvm/utils/TableGen/CodeGenDAGPatterns.cpp154
-rw-r--r--llvm/utils/TableGen/CodeGenDAGPatterns.h8
-rw-r--r--llvm/utils/TableGen/CodeGenRegisters.cpp20
-rw-r--r--llvm/utils/TableGen/CodeGenRegisters.h5
-rw-r--r--llvm/utils/TableGen/GlobalISelEmitter.cpp77
-rw-r--r--llvm/utils/TableGen/InstrInfoEmitter.cpp154
-rw-r--r--llvm/utils/TableGen/SubtargetFeatureInfo.cpp9
8 files changed, 350 insertions, 210 deletions
diff --git a/llvm/utils/TableGen/CodeEmitterGen.cpp b/llvm/utils/TableGen/CodeEmitterGen.cpp
index 2b9931b23c11..1d00c3cfd069 100644
--- a/llvm/utils/TableGen/CodeEmitterGen.cpp
+++ b/llvm/utils/TableGen/CodeEmitterGen.cpp
@@ -332,14 +332,6 @@ std::string CodeEmitterGen::getInstructionCaseForEncoding(Record *R, Record *Enc
return Case;
}
-static std::string
-getNameForFeatureBitset(const std::vector<Record *> &FeatureBitset) {
- std::string Name = "CEFBS";
- for (const auto &Feature : FeatureBitset)
- Name += ("_" + Feature->getName()).str();
- return Name;
-}
-
static void emitInstBits(raw_ostream &OS, const APInt &Bits) {
for (unsigned I = 0; I < Bits.getNumWords(); ++I)
OS << ((I > 0) ? ", " : "") << "UINT64_C(" << utostr(Bits.getRawData()[I])
@@ -530,131 +522,6 @@ void CodeEmitterGen::run(raw_ostream &o) {
o << " return Value;\n";
o << "}\n\n";
}
-
- const auto &All = SubtargetFeatureInfo::getAll(Records);
- std::map<Record *, SubtargetFeatureInfo, LessRecordByID> SubtargetFeatures;
- SubtargetFeatures.insert(All.begin(), All.end());
-
- o << "#ifdef ENABLE_INSTR_PREDICATE_VERIFIER\n"
- << "#undef ENABLE_INSTR_PREDICATE_VERIFIER\n"
- << "#include <sstream>\n\n";
-
- // Emit the subtarget feature enumeration.
- SubtargetFeatureInfo::emitSubtargetFeatureBitEnumeration(SubtargetFeatures,
- o);
-
- // Emit the name table for error messages.
- o << "#ifndef NDEBUG\n";
- SubtargetFeatureInfo::emitNameTable(SubtargetFeatures, o);
- o << "#endif // NDEBUG\n";
-
- // Emit the available features compute function.
- SubtargetFeatureInfo::emitComputeAssemblerAvailableFeatures(
- Target.getName(), "MCCodeEmitter", "computeAvailableFeatures",
- SubtargetFeatures, o);
-
- std::vector<std::vector<Record *>> FeatureBitsets;
- for (const CodeGenInstruction *Inst : Target.getInstructionsByEnumValue()) {
- FeatureBitsets.emplace_back();
- for (Record *Predicate : Inst->TheDef->getValueAsListOfDefs("Predicates")) {
- const auto &I = SubtargetFeatures.find(Predicate);
- if (I != SubtargetFeatures.end())
- FeatureBitsets.back().push_back(I->second.TheDef);
- }
- }
-
- llvm::sort(FeatureBitsets, [&](const std::vector<Record *> &A,
- const std::vector<Record *> &B) {
- if (A.size() < B.size())
- return true;
- if (A.size() > B.size())
- return false;
- for (auto Pair : zip(A, B)) {
- if (std::get<0>(Pair)->getName() < std::get<1>(Pair)->getName())
- return true;
- if (std::get<0>(Pair)->getName() > std::get<1>(Pair)->getName())
- return false;
- }
- return false;
- });
- FeatureBitsets.erase(
- std::unique(FeatureBitsets.begin(), FeatureBitsets.end()),
- FeatureBitsets.end());
- o << "#ifndef NDEBUG\n"
- << "// Feature bitsets.\n"
- << "enum : " << getMinimalTypeForRange(FeatureBitsets.size()) << " {\n"
- << " CEFBS_None,\n";
- for (const auto &FeatureBitset : FeatureBitsets) {
- if (FeatureBitset.empty())
- continue;
- o << " " << getNameForFeatureBitset(FeatureBitset) << ",\n";
- }
- o << "};\n\n"
- << "static constexpr FeatureBitset FeatureBitsets[] = {\n"
- << " {}, // CEFBS_None\n";
- for (const auto &FeatureBitset : FeatureBitsets) {
- if (FeatureBitset.empty())
- continue;
- o << " {";
- for (const auto &Feature : FeatureBitset) {
- const auto &I = SubtargetFeatures.find(Feature);
- assert(I != SubtargetFeatures.end() && "Didn't import predicate?");
- o << I->second.getEnumBitName() << ", ";
- }
- o << "},\n";
- }
- o << "};\n"
- << "#endif // NDEBUG\n\n";
-
-
- // Emit the predicate verifier.
- o << "void " << Target.getName()
- << "MCCodeEmitter::verifyInstructionPredicates(\n"
- << " const MCInst &Inst, const FeatureBitset &AvailableFeatures) const {\n"
- << "#ifndef NDEBUG\n"
- << " static " << getMinimalTypeForRange(FeatureBitsets.size())
- << " RequiredFeaturesRefs[] = {\n";
- unsigned InstIdx = 0;
- for (const CodeGenInstruction *Inst : Target.getInstructionsByEnumValue()) {
- o << " CEFBS";
- unsigned NumPredicates = 0;
- for (Record *Predicate : Inst->TheDef->getValueAsListOfDefs("Predicates")) {
- const auto &I = SubtargetFeatures.find(Predicate);
- if (I != SubtargetFeatures.end()) {
- o << '_' << I->second.TheDef->getName();
- NumPredicates++;
- }
- }
- if (!NumPredicates)
- o << "_None";
- o << ", // " << Inst->TheDef->getName() << " = " << InstIdx << "\n";
- InstIdx++;
- }
- o << " };\n\n";
- o << " assert(Inst.getOpcode() < " << InstIdx << ");\n";
- o << " const FeatureBitset &RequiredFeatures = "
- "FeatureBitsets[RequiredFeaturesRefs[Inst.getOpcode()]];\n";
- o << " FeatureBitset MissingFeatures =\n"
- << " (AvailableFeatures & RequiredFeatures) ^\n"
- << " RequiredFeatures;\n"
- << " if (MissingFeatures.any()) {\n"
- << " std::ostringstream Msg;\n"
- << " Msg << \"Attempting to emit \" << "
- "MCII.getName(Inst.getOpcode()).str()\n"
- << " << \" instruction but the \";\n"
- << " for (unsigned i = 0, e = MissingFeatures.size(); i != e; ++i)\n"
- << " if (MissingFeatures.test(i))\n"
- << " Msg << SubtargetFeatureNames[i] << \" \";\n"
- << " Msg << \"predicate(s) are not met\";\n"
- << " report_fatal_error(Msg.str().c_str());\n"
- << " }\n"
- << "#else\n"
- << " // Silence unused variable warning on targets that don't use MCII for "
- "other purposes (e.g. BPF).\n"
- << " (void)MCII;\n"
- << "#endif // NDEBUG\n";
- o << "}\n";
- o << "#endif\n";
}
} // end anonymous namespace
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);
}
diff --git a/llvm/utils/TableGen/CodeGenDAGPatterns.h b/llvm/utils/TableGen/CodeGenDAGPatterns.h
index 94694a96eb90..dbdc72f0873a 100644
--- a/llvm/utils/TableGen/CodeGenDAGPatterns.h
+++ b/llvm/utils/TableGen/CodeGenDAGPatterns.h
@@ -102,6 +102,8 @@ struct MachineValueTypeSet {
Words[T.SimpleTy / WordWidth] &= ~(WordType(1) << (T.SimpleTy % WordWidth));
}
+ void writeToStream(raw_ostream &OS) const;
+
struct const_iterator {
// Some implementations of the C++ library require these traits to be
// defined.
@@ -185,6 +187,8 @@ private:
std::array<WordType,NumWords> Words;
};
+raw_ostream &operator<<(raw_ostream &OS, const MachineValueTypeSet &T);
+
struct TypeSetByHwMode : public InfoByHwMode<MachineValueTypeSet> {
using SetType = MachineValueTypeSet;
SmallVector<unsigned, 16> AddrSpaces;
@@ -239,7 +243,6 @@ struct TypeSetByHwMode : public InfoByHwMode<MachineValueTypeSet> {
bool assign_if(const TypeSetByHwMode &VTS, Predicate P);
void writeToStream(raw_ostream &OS) const;
- static void writeToStream(const SetType &S, raw_ostream &OS);
bool operator==(const TypeSetByHwMode &VTS) const;
bool operator!=(const TypeSetByHwMode &VTS) const { return !(*this == VTS); }
@@ -538,6 +541,9 @@ public:
// Predicate code uses the PatFrag's captured operands.
bool usesOperands() const;
+ // Check if the HasNoUse predicate is set.
+ bool hasNoUse() const;
+
// Is the desired predefined predicate for a load?
bool isLoad() const;
// Is the desired predefined predicate for a store?
diff --git a/llvm/utils/TableGen/CodeGenRegisters.cpp b/llvm/utils/TableGen/CodeGenRegisters.cpp
index 2c61be713afc..93ed86cfb7e5 100644
--- a/llvm/utils/TableGen/CodeGenRegisters.cpp
+++ b/llvm/utils/TableGen/CodeGenRegisters.cpp
@@ -861,6 +861,26 @@ void CodeGenRegisterClass::inheritProperties(CodeGenRegBank &RegBank) {
Orders[i].push_back(Super.Orders[i][j]);
}
+bool CodeGenRegisterClass::hasType(const ValueTypeByHwMode &VT) const {
+ if (llvm::is_contained(VTs, VT))
+ return true;
+
+ // If VT is not identical to any of this class's types, but is a simple
+ // type, check if any of the types for this class contain it under some
+ // mode.
+ // The motivating example came from RISCV, where (likely because of being
+ // guarded by "64-bit" predicate), the type of X5 was {*:[i64]}, but the
+ // type in GRC was {*:[i32], m1:[i64]}.
+ if (VT.isSimple()) {
+ MVT T = VT.getSimple();
+ for (const ValueTypeByHwMode &OurVT : VTs) {
+ if (llvm::count_if(OurVT, [T](auto &&P) { return P.second == T; }))
+ return true;
+ }
+ }
+ return false;
+}
+
bool CodeGenRegisterClass::contains(const CodeGenRegister *Reg) const {
return std::binary_search(Members.begin(), Members.end(), Reg,
deref<std::less<>>());
diff --git a/llvm/utils/TableGen/CodeGenRegisters.h b/llvm/utils/TableGen/CodeGenRegisters.h
index 0fc8b3ef80dd..e5e92fc81f50 100644
--- a/llvm/utils/TableGen/CodeGenRegisters.h
+++ b/llvm/utils/TableGen/CodeGenRegisters.h
@@ -351,10 +351,7 @@ namespace llvm {
std::string getQualifiedName() const;
ArrayRef<ValueTypeByHwMode> getValueTypes() const { return VTs; }
unsigned getNumValueTypes() const { return VTs.size(); }
-
- bool hasType(const ValueTypeByHwMode &VT) const {
- return llvm::is_contained(VTs, VT);
- }
+ bool hasType(const ValueTypeByHwMode &VT) const;
const ValueTypeByHwMode &getValueTypeNum(unsigned VTNum) const {
if (VTNum < VTs.size())
diff --git a/llvm/utils/TableGen/GlobalISelEmitter.cpp b/llvm/utils/TableGen/GlobalISelEmitter.cpp
index c8eac56d03e6..4b47cda41567 100644
--- a/llvm/utils/TableGen/GlobalISelEmitter.cpp
+++ b/llvm/utils/TableGen/GlobalISelEmitter.cpp
@@ -331,6 +331,9 @@ static Error isTrivialOperatorNode(const TreePatternNode *N) {
if (Predicate.isImmediatePattern())
continue;
+ if (Predicate.hasNoUse())
+ continue;
+
if (Predicate.isNonExtLoad() || Predicate.isAnyExtLoad() ||
Predicate.isSignExtLoad() || Predicate.isZeroExtLoad())
continue;
@@ -1119,6 +1122,7 @@ public:
IPM_MemoryAddressSpace,
IPM_MemoryAlignment,
IPM_VectorSplatImm,
+ IPM_NoUse,
IPM_GenericPredicate,
OPM_SameOperand,
OPM_ComplexPattern,
@@ -2238,6 +2242,29 @@ public:
}
};
+/// Generates code to check for the absence of use of the result.
+// TODO? Generalize this to support checking for one use.
+class NoUsePredicateMatcher : public InstructionPredicateMatcher {
+public:
+ NoUsePredicateMatcher(unsigned InsnVarID)
+ : InstructionPredicateMatcher(IPM_NoUse, InsnVarID) {}
+
+ static bool classof(const PredicateMatcher *P) {
+ return P->getKind() == IPM_NoUse;
+ }
+
+ bool isIdentical(const PredicateMatcher &B) const override {
+ return InstructionPredicateMatcher::isIdentical(B);
+ }
+
+ void emitPredicateOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const override {
+ Table << MatchTable::Opcode("GIM_CheckHasNoUse")
+ << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
+ << MatchTable::LineBreak;
+ }
+};
+
/// Generates code to check that a set of predicates and operands match for a
/// particular instruction.
///
@@ -2943,7 +2970,7 @@ public:
<< MatchTable::IntValue(RendererID);
if (SubOperand)
Table << MatchTable::Comment("SubOperand")
- << MatchTable::IntValue(SubOperand.getValue());
+ << MatchTable::IntValue(SubOperand.value());
Table << MatchTable::Comment(SymbolicName) << MatchTable::LineBreak;
}
};
@@ -3758,10 +3785,12 @@ GlobalISelEmitter::getEquivNode(Record &Equiv, const TreePatternNode *N) const {
for (const TreePredicateCall &Call : N->getPredicateCalls()) {
const TreePredicateFn &Predicate = Call.Fn;
- if (!Equiv.isValueUnset("IfSignExtend") && Predicate.isLoad() &&
+ if (!Equiv.isValueUnset("IfSignExtend") &&
+ (Predicate.isLoad() || Predicate.isAtomic()) &&
Predicate.isSignExtLoad())
return &Target.getInstruction(Equiv.getValueAsDef("IfSignExtend"));
- if (!Equiv.isValueUnset("IfZeroExtend") && Predicate.isLoad() &&
+ if (!Equiv.isValueUnset("IfZeroExtend") &&
+ (Predicate.isLoad() || Predicate.isAtomic()) &&
Predicate.isZeroExtLoad())
return &Target.getInstruction(Equiv.getValueAsDef("IfZeroExtend"));
}
@@ -4000,6 +4029,17 @@ Expected<InstructionMatcher &> GlobalISelEmitter::createAndImportSelDAGMatcher(
if (auto Error = InsnMatcherOrError.takeError())
return std::move(Error);
+ // FIXME: This should be part of addBuiltinPredicates(). If we add this at
+ // the start of addBuiltinPredicates() without returning, then there might
+ // be cases where we hit the last return before which the
+ // HasAddedBuiltinMatcher will be set to false. The predicate could be
+ // missed if we add it in the middle or at the end due to return statements
+ // after the addPredicate<>() calls.
+ if (Predicate.hasNoUse()) {
+ InsnMatcher.addPredicate<NoUsePredicateMatcher>();
+ HasAddedBuiltinMatcher = true;
+ }
+
if (Predicate.hasGISelPredicateCode()) {
if (Predicate.usesOperands()) {
assert(WaitingForNamedOperands == 0 &&
@@ -4946,8 +4986,8 @@ Error GlobalISelEmitter::importDefaultOperandRenderers(
auto Def = DefaultDefOp->getDef();
if (Def->getName() == "undef_tied_input") {
unsigned TempRegID = M.allocateTempRegID();
- M.insertAction<MakeTempRegisterAction>(
- InsertPt, OpTyOrNone.getValue(), TempRegID);
+ M.insertAction<MakeTempRegisterAction>(InsertPt, OpTyOrNone.value(),
+ TempRegID);
InsertPt = M.insertAction<BuildMIAction>(
InsertPt, M.allocateOutputInsnID(),
&Target.getInstruction(RK.getDef("IMPLICIT_DEF")));
@@ -5206,16 +5246,31 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) {
auto &DstI = Target.getInstruction(DstOp);
StringRef DstIName = DstI.TheDef->getName();
- if (DstI.Operands.NumDefs < Src->getExtTypes().size())
- return failedImport("Src pattern result has more defs than dst MI (" +
- to_string(Src->getExtTypes().size()) + " def(s) vs " +
- to_string(DstI.Operands.NumDefs) + " def(s))");
+ unsigned DstNumDefs = DstI.Operands.NumDefs,
+ SrcNumDefs = Src->getExtTypes().size();
+ if (DstNumDefs < SrcNumDefs) {
+ if (DstNumDefs != 0)
+ return failedImport("Src pattern result has more defs than dst MI (" +
+ to_string(SrcNumDefs) + " def(s) vs " +
+ to_string(DstNumDefs) + " def(s))");
+
+ bool FoundNoUsePred = false;
+ for (const auto &Pred : InsnMatcher.predicates()) {
+ if ((FoundNoUsePred = isa<NoUsePredicateMatcher>(Pred.get())))
+ break;
+ }
+ if (!FoundNoUsePred)
+ return failedImport("Src pattern result has " + to_string(SrcNumDefs) +
+ " def(s) without the HasNoUse predicate set to true "
+ "but Dst MI has no def");
+ }
// The root of the match also has constraints on the register bank so that it
// matches the result instruction.
unsigned OpIdx = 0;
- for (const TypeSetByHwMode &VTy : Src->getExtTypes()) {
- (void)VTy;
+ unsigned N = std::min(DstNumDefs, SrcNumDefs);
+ for (unsigned I = 0; I < N; ++I) {
+ const TypeSetByHwMode &VTy = Src->getExtType(I);
const auto &DstIOperand = DstI.Operands[OpIdx];
Record *DstIOpRec = DstIOperand.Rec;
diff --git a/llvm/utils/TableGen/InstrInfoEmitter.cpp b/llvm/utils/TableGen/InstrInfoEmitter.cpp
index a7a4f4f5f1a7..da8d0a0096fd 100644
--- a/llvm/utils/TableGen/InstrInfoEmitter.cpp
+++ b/llvm/utils/TableGen/InstrInfoEmitter.cpp
@@ -17,7 +17,9 @@
#include "CodeGenTarget.h"
#include "PredicateExpander.h"
#include "SequenceToOffsetTable.h"
+#include "SubtargetFeatureInfo.h"
#include "TableGenBackends.h"
+#include "Types.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
@@ -79,6 +81,9 @@ private:
/// Expand TIIPredicate definitions to functions that accept a const MCInst
/// reference.
void emitMCIIHelperMethods(raw_ostream &OS, StringRef TargetName);
+
+ /// Write verifyInstructionPredicates methods.
+ void emitFeatureVerifier(raw_ostream &OS, const CodeGenTarget &Target);
void emitRecord(const CodeGenInstruction &Inst, unsigned Num,
Record *InstrInfo,
std::map<std::vector<Record*>, unsigned> &EL,
@@ -666,14 +671,13 @@ void InstrInfoEmitter::emitLogicalOperandTypeMappings(
void InstrInfoEmitter::emitMCIIHelperMethods(raw_ostream &OS,
StringRef TargetName) {
RecVec TIIPredicates = Records.getAllDerivedDefinitions("TIIPredicate");
- if (TIIPredicates.empty())
- return;
OS << "#ifdef GET_INSTRINFO_MC_HELPER_DECLS\n";
OS << "#undef GET_INSTRINFO_MC_HELPER_DECLS\n\n";
OS << "namespace llvm {\n";
- OS << "class MCInst;\n\n";
+ OS << "class MCInst;\n";
+ OS << "class FeatureBitset;\n\n";
OS << "namespace " << TargetName << "_MC {\n\n";
@@ -682,6 +686,9 @@ void InstrInfoEmitter::emitMCIIHelperMethods(raw_ostream &OS,
<< "(const MCInst &MI);\n";
}
+ OS << "void verifyInstructionPredicates(unsigned Opcode, const FeatureBitset "
+ "&Features);\n";
+
OS << "\n} // end namespace " << TargetName << "_MC\n";
OS << "} // end namespace llvm\n\n";
@@ -708,7 +715,143 @@ void InstrInfoEmitter::emitMCIIHelperMethods(raw_ostream &OS,
OS << "} // end namespace " << TargetName << "_MC\n";
OS << "} // end namespace llvm\n\n";
- OS << "#endif // GET_GENISTRINFO_MC_HELPERS\n";
+ OS << "#endif // GET_GENISTRINFO_MC_HELPERS\n\n";
+}
+
+static std::string
+getNameForFeatureBitset(const std::vector<Record *> &FeatureBitset) {
+ std::string Name = "CEFBS";
+ for (const auto &Feature : FeatureBitset)
+ Name += ("_" + Feature->getName()).str();
+ return Name;
+}
+
+void InstrInfoEmitter::emitFeatureVerifier(raw_ostream &OS,
+ const CodeGenTarget &Target) {
+ const auto &All = SubtargetFeatureInfo::getAll(Records);
+ std::map<Record *, SubtargetFeatureInfo, LessRecordByID> SubtargetFeatures;
+ SubtargetFeatures.insert(All.begin(), All.end());
+
+ OS << "#ifdef ENABLE_INSTR_PREDICATE_VERIFIER\n"
+ << "#undef ENABLE_INSTR_PREDICATE_VERIFIER\n"
+ << "#include <sstream>\n\n";
+
+ OS << "namespace llvm {\n";
+ OS << "namespace " << Target.getName() << "_MC {\n\n";
+
+ // Emit the subtarget feature enumeration.
+ SubtargetFeatureInfo::emitSubtargetFeatureBitEnumeration(SubtargetFeatures,
+ OS);
+
+ // Emit the name table for error messages.
+ OS << "#ifndef NDEBUG\n";
+ SubtargetFeatureInfo::emitNameTable(SubtargetFeatures, OS);
+ OS << "#endif // NDEBUG\n\n";
+
+ // Emit the available features compute function.
+ SubtargetFeatureInfo::emitComputeAssemblerAvailableFeatures(
+ Target.getName(), "", "computeAvailableFeatures", SubtargetFeatures, OS);
+
+ std::vector<std::vector<Record *>> FeatureBitsets;
+ for (const CodeGenInstruction *Inst : Target.getInstructionsByEnumValue()) {
+ FeatureBitsets.emplace_back();
+ for (Record *Predicate : Inst->TheDef->getValueAsListOfDefs("Predicates")) {
+ const auto &I = SubtargetFeatures.find(Predicate);
+ if (I != SubtargetFeatures.end())
+ FeatureBitsets.back().push_back(I->second.TheDef);
+ }
+ }
+
+ llvm::sort(FeatureBitsets, [&](const std::vector<Record *> &A,
+ const std::vector<Record *> &B) {
+ if (A.size() < B.size())
+ return true;
+ if (A.size() > B.size())
+ return false;
+ for (auto Pair : zip(A, B)) {
+ if (std::get<0>(Pair)->getName() < std::get<1>(Pair)->getName())
+ return true;
+ if (std::get<0>(Pair)->getName() > std::get<1>(Pair)->getName())
+ return false;
+ }
+ return false;
+ });
+ FeatureBitsets.erase(
+ std::unique(FeatureBitsets.begin(), FeatureBitsets.end()),
+ FeatureBitsets.end());
+ OS << "#ifndef NDEBUG\n"
+ << "// Feature bitsets.\n"
+ << "enum : " << getMinimalTypeForRange(FeatureBitsets.size()) << " {\n"
+ << " CEFBS_None,\n";
+ for (const auto &FeatureBitset : FeatureBitsets) {
+ if (FeatureBitset.empty())
+ continue;
+ OS << " " << getNameForFeatureBitset(FeatureBitset) << ",\n";
+ }
+ OS << "};\n\n"
+ << "static constexpr FeatureBitset FeatureBitsets[] = {\n"
+ << " {}, // CEFBS_None\n";
+ for (const auto &FeatureBitset : FeatureBitsets) {
+ if (FeatureBitset.empty())
+ continue;
+ OS << " {";
+ for (const auto &Feature : FeatureBitset) {
+ const auto &I = SubtargetFeatures.find(Feature);
+ assert(I != SubtargetFeatures.end() && "Didn't import predicate?");
+ OS << I->second.getEnumBitName() << ", ";
+ }
+ OS << "},\n";
+ }
+ OS << "};\n"
+ << "#endif // NDEBUG\n\n";
+
+ // Emit the predicate verifier.
+ OS << "void verifyInstructionPredicates(\n"
+ << " unsigned Opcode, const FeatureBitset &Features) {\n"
+ << "#ifndef NDEBUG\n"
+ << " static " << getMinimalTypeForRange(FeatureBitsets.size())
+ << " RequiredFeaturesRefs[] = {\n";
+ unsigned InstIdx = 0;
+ for (const CodeGenInstruction *Inst : Target.getInstructionsByEnumValue()) {
+ OS << " CEFBS";
+ unsigned NumPredicates = 0;
+ for (Record *Predicate : Inst->TheDef->getValueAsListOfDefs("Predicates")) {
+ const auto &I = SubtargetFeatures.find(Predicate);
+ if (I != SubtargetFeatures.end()) {
+ OS << '_' << I->second.TheDef->getName();
+ NumPredicates++;
+ }
+ }
+ if (!NumPredicates)
+ OS << "_None";
+ OS << ", // " << Inst->TheDef->getName() << " = " << InstIdx << "\n";
+ InstIdx++;
+ }
+ OS << " };\n\n";
+ OS << " assert(Opcode < " << InstIdx << ");\n";
+ OS << " FeatureBitset AvailableFeatures = "
+ "computeAvailableFeatures(Features);\n";
+ OS << " const FeatureBitset &RequiredFeatures = "
+ "FeatureBitsets[RequiredFeaturesRefs[Opcode]];\n";
+ OS << " FeatureBitset MissingFeatures =\n"
+ << " (AvailableFeatures & RequiredFeatures) ^\n"
+ << " RequiredFeatures;\n"
+ << " if (MissingFeatures.any()) {\n"
+ << " std::ostringstream Msg;\n"
+ << " Msg << \"Attempting to emit \" << &" << Target.getName()
+ << "InstrNameData[" << Target.getName() << "InstrNameIndices[Opcode]]\n"
+ << " << \" instruction but the \";\n"
+ << " for (unsigned i = 0, e = MissingFeatures.size(); i != e; ++i)\n"
+ << " if (MissingFeatures.test(i))\n"
+ << " Msg << SubtargetFeatureNames[i] << \" \";\n"
+ << " Msg << \"predicate(s) are not met\";\n"
+ << " report_fatal_error(Msg.str().c_str());\n"
+ << " }\n"
+ << "#endif // NDEBUG\n";
+ OS << "}\n";
+ OS << "} // end namespace " << Target.getName() << "_MC\n";
+ OS << "} // end namespace llvm\n";
+ OS << "#endif // ENABLE_INSTR_PREDICATE_VERIFIER\n\n";
}
void InstrInfoEmitter::emitTIIHelperMethods(raw_ostream &OS,
@@ -955,6 +1098,9 @@ void InstrInfoEmitter::run(raw_ostream &OS) {
Records.startTimer("Emit helper methods");
emitMCIIHelperMethods(OS, TargetName);
+
+ Records.startTimer("Emit verifier methods");
+ emitFeatureVerifier(OS, Target);
}
void InstrInfoEmitter::emitRecord(const CodeGenInstruction &Inst, unsigned Num,
diff --git a/llvm/utils/TableGen/SubtargetFeatureInfo.cpp b/llvm/utils/TableGen/SubtargetFeatureInfo.cpp
index f4f360fb5be2..2a63fc490380 100644
--- a/llvm/utils/TableGen/SubtargetFeatureInfo.cpp
+++ b/llvm/utils/TableGen/SubtargetFeatureInfo.cpp
@@ -144,8 +144,13 @@ static bool emitFeaturesAux(StringRef TargetName, const Init &Val,
void SubtargetFeatureInfo::emitComputeAssemblerAvailableFeatures(
StringRef TargetName, StringRef ClassName, StringRef FuncName,
SubtargetFeatureInfoMap &SubtargetFeatures, raw_ostream &OS) {
- OS << "FeatureBitset " << TargetName << ClassName << "::\n"
- << FuncName << "(const FeatureBitset &FB) const {\n";
+ OS << "FeatureBitset ";
+ if (!ClassName.empty())
+ OS << TargetName << ClassName << "::\n";
+ OS << FuncName << "(const FeatureBitset &FB) ";
+ if (!ClassName.empty())
+ OS << "const ";
+ OS << "{\n";
OS << " FeatureBitset Features;\n";
for (const auto &SF : SubtargetFeatures) {
const SubtargetFeatureInfo &SFI = SF.second;