1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
|
//===- SubtargetFeatureInfo.cpp - Helpers for subtarget features ----------===//
//
// 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
//
//===----------------------------------------------------------------------===//
#include "SubtargetFeatureInfo.h"
#include "Types.h"
#include "llvm/Config/llvm-config.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
#include <map>
using namespace llvm;
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
LLVM_DUMP_METHOD void SubtargetFeatureInfo::dump() const {
errs() << getEnumName() << " " << Index << "\n" << *TheDef;
}
#endif
std::vector<std::pair<Record *, SubtargetFeatureInfo>>
SubtargetFeatureInfo::getAll(const RecordKeeper &Records) {
std::vector<std::pair<Record *, SubtargetFeatureInfo>> SubtargetFeatures;
std::vector<Record *> AllPredicates =
Records.getAllDerivedDefinitions("Predicate");
for (Record *Pred : AllPredicates) {
// Ignore predicates that are not intended for the assembler.
//
// The "AssemblerMatcherPredicate" string should be promoted to an argument
// if we re-use the machinery for non-assembler purposes in future.
if (!Pred->getValueAsBit("AssemblerMatcherPredicate"))
continue;
if (Pred->getName().empty())
PrintFatalError(Pred->getLoc(), "Predicate has no name!");
// Ignore always true predicates.
if (Pred->getValueAsString("CondString").empty())
continue;
SubtargetFeatures.emplace_back(
Pred, SubtargetFeatureInfo(Pred, SubtargetFeatures.size()));
}
return SubtargetFeatures;
}
void SubtargetFeatureInfo::emitSubtargetFeatureBitEnumeration(
SubtargetFeatureInfoMap &SubtargetFeatures, raw_ostream &OS) {
OS << "// Bits for subtarget features that participate in "
<< "instruction matching.\n";
OS << "enum SubtargetFeatureBits : "
<< getMinimalTypeForRange(SubtargetFeatures.size()) << " {\n";
for (const auto &SF : SubtargetFeatures) {
const SubtargetFeatureInfo &SFI = SF.second;
OS << " " << SFI.getEnumBitName() << " = " << SFI.Index << ",\n";
}
OS << "};\n\n";
}
void SubtargetFeatureInfo::emitNameTable(
SubtargetFeatureInfoMap &SubtargetFeatures, raw_ostream &OS) {
// Need to sort the name table so that lookup by the log of the enum value
// gives the proper name. More specifically, for a feature of value 1<<n,
// SubtargetFeatureNames[n] should be the name of the feature.
uint64_t IndexUB = 0;
for (const auto &SF : SubtargetFeatures)
if (IndexUB <= SF.second.Index)
IndexUB = SF.second.Index+1;
std::vector<std::string> Names;
if (IndexUB > 0)
Names.resize(IndexUB);
for (const auto &SF : SubtargetFeatures)
Names[SF.second.Index] = SF.second.getEnumName();
OS << "static const char *SubtargetFeatureNames[] = {\n";
for (uint64_t I = 0; I < IndexUB; ++I)
OS << " \"" << Names[I] << "\",\n";
// A small number of targets have no predicates. Null terminate the array to
// avoid a zero-length array.
OS << " nullptr\n"
<< "};\n\n";
}
void SubtargetFeatureInfo::emitComputeAvailableFeatures(
StringRef TargetName, StringRef ClassName, StringRef FuncName,
SubtargetFeatureInfoMap &SubtargetFeatures, raw_ostream &OS,
StringRef ExtraParams) {
OS << "PredicateBitset " << TargetName << ClassName << "::\n"
<< FuncName << "(const " << TargetName << "Subtarget *Subtarget";
if (!ExtraParams.empty())
OS << ", " << ExtraParams;
OS << ") const {\n";
OS << " PredicateBitset Features;\n";
for (const auto &SF : SubtargetFeatures) {
const SubtargetFeatureInfo &SFI = SF.second;
StringRef CondStr = SFI.TheDef->getValueAsString("CondString");
assert(!CondStr.empty() && "true predicate should have been filtered");
OS << " if (" << CondStr << ")\n";
OS << " Features.set(" << SFI.getEnumBitName() << ");\n";
}
OS << " return Features;\n";
OS << "}\n\n";
}
// If ParenIfBinOp is true, print a surrounding () if Val uses && or ||.
static bool emitFeaturesAux(StringRef TargetName, const Init &Val,
bool ParenIfBinOp, raw_ostream &OS) {
if (auto *D = dyn_cast<DefInit>(&Val)) {
if (!D->getDef()->isSubClassOf("SubtargetFeature"))
return true;
OS << "FB[" << TargetName << "::" << D->getAsString() << "]";
return false;
}
if (auto *D = dyn_cast<DagInit>(&Val)) {
std::string Op = D->getOperator()->getAsString();
if (Op == "not" && D->getNumArgs() == 1) {
OS << '!';
return emitFeaturesAux(TargetName, *D->getArg(0), true, OS);
}
if ((Op == "any_of" || Op == "all_of") && D->getNumArgs() > 0) {
bool Paren = D->getNumArgs() > 1 && std::exchange(ParenIfBinOp, true);
if (Paren)
OS << '(';
ListSeparator LS(Op == "any_of" ? " || " : " && ");
for (auto *Arg : D->getArgs()) {
OS << LS;
if (emitFeaturesAux(TargetName, *Arg, ParenIfBinOp, OS))
return true;
}
if (Paren)
OS << ')';
return false;
}
}
return true;
}
void SubtargetFeatureInfo::emitComputeAssemblerAvailableFeatures(
StringRef TargetName, StringRef ClassName, StringRef FuncName,
SubtargetFeatureInfoMap &SubtargetFeatures, raw_ostream &OS) {
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;
OS << " if (";
emitFeaturesAux(TargetName, *SFI.TheDef->getValueAsDag("AssemblerCondDag"),
/*ParenIfBinOp=*/false, OS);
OS << ")\n";
OS << " Features.set(" << SFI.getEnumBitName() << ");\n";
}
OS << " return Features;\n";
OS << "}\n\n";
}
|