1d88c1a5aSDimitry Andric //===- SubtargetFeatureInfo.cpp - Helpers for subtarget features ----------===//
2d88c1a5aSDimitry Andric //
3d88c1a5aSDimitry Andric // The LLVM Compiler Infrastructure
4d88c1a5aSDimitry Andric //
5d88c1a5aSDimitry Andric // This file is distributed under the University of Illinois Open Source
6d88c1a5aSDimitry Andric // License. See LICENSE.TXT for details.
7d88c1a5aSDimitry Andric //
8d88c1a5aSDimitry Andric //===----------------------------------------------------------------------===//
9d88c1a5aSDimitry Andric
10d88c1a5aSDimitry Andric #include "SubtargetFeatureInfo.h"
11d88c1a5aSDimitry Andric
12d88c1a5aSDimitry Andric #include "Types.h"
13*4ba319b5SDimitry Andric #include "llvm/Config/llvm-config.h"
14d88c1a5aSDimitry Andric #include "llvm/TableGen/Record.h"
15d88c1a5aSDimitry Andric
16d88c1a5aSDimitry Andric #include <map>
17d88c1a5aSDimitry Andric
18d88c1a5aSDimitry Andric using namespace llvm;
19d88c1a5aSDimitry Andric
207a7e6055SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
dump() const217a7e6055SDimitry Andric LLVM_DUMP_METHOD void SubtargetFeatureInfo::dump() const {
227a7e6055SDimitry Andric errs() << getEnumName() << " " << Index << "\n" << *TheDef;
23d88c1a5aSDimitry Andric }
247a7e6055SDimitry Andric #endif
25d88c1a5aSDimitry Andric
26d88c1a5aSDimitry Andric std::vector<std::pair<Record *, SubtargetFeatureInfo>>
getAll(const RecordKeeper & Records)27d88c1a5aSDimitry Andric SubtargetFeatureInfo::getAll(const RecordKeeper &Records) {
28d88c1a5aSDimitry Andric std::vector<std::pair<Record *, SubtargetFeatureInfo>> SubtargetFeatures;
29d88c1a5aSDimitry Andric std::vector<Record *> AllPredicates =
30d88c1a5aSDimitry Andric Records.getAllDerivedDefinitions("Predicate");
31d88c1a5aSDimitry Andric for (Record *Pred : AllPredicates) {
32d88c1a5aSDimitry Andric // Ignore predicates that are not intended for the assembler.
33d88c1a5aSDimitry Andric //
34d88c1a5aSDimitry Andric // The "AssemblerMatcherPredicate" string should be promoted to an argument
35d88c1a5aSDimitry Andric // if we re-use the machinery for non-assembler purposes in future.
36d88c1a5aSDimitry Andric if (!Pred->getValueAsBit("AssemblerMatcherPredicate"))
37d88c1a5aSDimitry Andric continue;
38d88c1a5aSDimitry Andric
39d88c1a5aSDimitry Andric if (Pred->getName().empty())
40d88c1a5aSDimitry Andric PrintFatalError(Pred->getLoc(), "Predicate has no name!");
41d88c1a5aSDimitry Andric
42d88c1a5aSDimitry Andric SubtargetFeatures.emplace_back(
43d88c1a5aSDimitry Andric Pred, SubtargetFeatureInfo(Pred, SubtargetFeatures.size()));
44d88c1a5aSDimitry Andric }
45d88c1a5aSDimitry Andric return SubtargetFeatures;
46d88c1a5aSDimitry Andric }
47d88c1a5aSDimitry Andric
emitSubtargetFeatureFlagEnumeration(SubtargetFeatureInfoMap & SubtargetFeatures,raw_ostream & OS)48d88c1a5aSDimitry Andric void SubtargetFeatureInfo::emitSubtargetFeatureFlagEnumeration(
49f37b6182SDimitry Andric SubtargetFeatureInfoMap &SubtargetFeatures, raw_ostream &OS) {
50d88c1a5aSDimitry Andric OS << "// Flags for subtarget features that participate in "
51d88c1a5aSDimitry Andric << "instruction matching.\n";
52d88c1a5aSDimitry Andric OS << "enum SubtargetFeatureFlag : "
53d88c1a5aSDimitry Andric << getMinimalTypeForEnumBitfield(SubtargetFeatures.size()) << " {\n";
54d88c1a5aSDimitry Andric for (const auto &SF : SubtargetFeatures) {
55d88c1a5aSDimitry Andric const SubtargetFeatureInfo &SFI = SF.second;
56d88c1a5aSDimitry Andric OS << " " << SFI.getEnumName() << " = (1ULL << " << SFI.Index << "),\n";
57d88c1a5aSDimitry Andric }
58d88c1a5aSDimitry Andric OS << " Feature_None = 0\n";
59d88c1a5aSDimitry Andric OS << "};\n\n";
60d88c1a5aSDimitry Andric }
61d88c1a5aSDimitry Andric
emitSubtargetFeatureBitEnumeration(SubtargetFeatureInfoMap & SubtargetFeatures,raw_ostream & OS)6251690af2SDimitry Andric void SubtargetFeatureInfo::emitSubtargetFeatureBitEnumeration(
63f37b6182SDimitry Andric SubtargetFeatureInfoMap &SubtargetFeatures, raw_ostream &OS) {
6451690af2SDimitry Andric OS << "// Bits for subtarget features that participate in "
6551690af2SDimitry Andric << "instruction matching.\n";
6651690af2SDimitry Andric OS << "enum SubtargetFeatureBits : "
6751690af2SDimitry Andric << getMinimalTypeForRange(SubtargetFeatures.size()) << " {\n";
6851690af2SDimitry Andric for (const auto &SF : SubtargetFeatures) {
6951690af2SDimitry Andric const SubtargetFeatureInfo &SFI = SF.second;
7051690af2SDimitry Andric OS << " " << SFI.getEnumBitName() << " = " << SFI.Index << ",\n";
7151690af2SDimitry Andric }
7251690af2SDimitry Andric OS << "};\n\n";
7351690af2SDimitry Andric }
7451690af2SDimitry Andric
emitNameTable(SubtargetFeatureInfoMap & SubtargetFeatures,raw_ostream & OS)75d88c1a5aSDimitry Andric void SubtargetFeatureInfo::emitNameTable(
76f37b6182SDimitry Andric SubtargetFeatureInfoMap &SubtargetFeatures, raw_ostream &OS) {
777a7e6055SDimitry Andric // Need to sort the name table so that lookup by the log of the enum value
787a7e6055SDimitry Andric // gives the proper name. More specifically, for a feature of value 1<<n,
797a7e6055SDimitry Andric // SubtargetFeatureNames[n] should be the name of the feature.
807a7e6055SDimitry Andric uint64_t IndexUB = 0;
817a7e6055SDimitry Andric for (const auto &SF : SubtargetFeatures)
827a7e6055SDimitry Andric if (IndexUB <= SF.second.Index)
837a7e6055SDimitry Andric IndexUB = SF.second.Index+1;
847a7e6055SDimitry Andric
857a7e6055SDimitry Andric std::vector<std::string> Names;
867a7e6055SDimitry Andric if (IndexUB > 0)
877a7e6055SDimitry Andric Names.resize(IndexUB);
887a7e6055SDimitry Andric for (const auto &SF : SubtargetFeatures)
897a7e6055SDimitry Andric Names[SF.second.Index] = SF.second.getEnumName();
907a7e6055SDimitry Andric
91d88c1a5aSDimitry Andric OS << "static const char *SubtargetFeatureNames[] = {\n";
927a7e6055SDimitry Andric for (uint64_t I = 0; I < IndexUB; ++I)
937a7e6055SDimitry Andric OS << " \"" << Names[I] << "\",\n";
947a7e6055SDimitry Andric
95d88c1a5aSDimitry Andric // A small number of targets have no predicates. Null terminate the array to
96d88c1a5aSDimitry Andric // avoid a zero-length array.
97d88c1a5aSDimitry Andric OS << " nullptr\n"
98d88c1a5aSDimitry Andric << "};\n\n";
99d88c1a5aSDimitry Andric }
100d88c1a5aSDimitry Andric
emitComputeAvailableFeatures(StringRef TargetName,StringRef ClassName,StringRef FuncName,SubtargetFeatureInfoMap & SubtargetFeatures,raw_ostream & OS,StringRef ExtraParams)101d88c1a5aSDimitry Andric void SubtargetFeatureInfo::emitComputeAvailableFeatures(
102d88c1a5aSDimitry Andric StringRef TargetName, StringRef ClassName, StringRef FuncName,
103f37b6182SDimitry Andric SubtargetFeatureInfoMap &SubtargetFeatures, raw_ostream &OS,
104f37b6182SDimitry Andric StringRef ExtraParams) {
10551690af2SDimitry Andric OS << "PredicateBitset " << TargetName << ClassName << "::\n"
106f37b6182SDimitry Andric << FuncName << "(const " << TargetName << "Subtarget *Subtarget";
107f37b6182SDimitry Andric if (!ExtraParams.empty())
108f37b6182SDimitry Andric OS << ", " << ExtraParams;
109f37b6182SDimitry Andric OS << ") const {\n";
11051690af2SDimitry Andric OS << " PredicateBitset Features;\n";
11151690af2SDimitry Andric for (const auto &SF : SubtargetFeatures) {
11251690af2SDimitry Andric const SubtargetFeatureInfo &SFI = SF.second;
11351690af2SDimitry Andric
11451690af2SDimitry Andric OS << " if (" << SFI.TheDef->getValueAsString("CondString") << ")\n";
11551690af2SDimitry Andric OS << " Features[" << SFI.getEnumBitName() << "] = 1;\n";
11651690af2SDimitry Andric }
11751690af2SDimitry Andric OS << " return Features;\n";
11851690af2SDimitry Andric OS << "}\n\n";
11951690af2SDimitry Andric }
12051690af2SDimitry Andric
emitComputeAssemblerAvailableFeatures(StringRef TargetName,StringRef ClassName,StringRef FuncName,SubtargetFeatureInfoMap & SubtargetFeatures,raw_ostream & OS)12151690af2SDimitry Andric void SubtargetFeatureInfo::emitComputeAssemblerAvailableFeatures(
12251690af2SDimitry Andric StringRef TargetName, StringRef ClassName, StringRef FuncName,
123f37b6182SDimitry Andric SubtargetFeatureInfoMap &SubtargetFeatures, raw_ostream &OS) {
124d88c1a5aSDimitry Andric OS << "uint64_t " << TargetName << ClassName << "::\n"
125d88c1a5aSDimitry Andric << FuncName << "(const FeatureBitset& FB) const {\n";
126d88c1a5aSDimitry Andric OS << " uint64_t Features = 0;\n";
127d88c1a5aSDimitry Andric for (const auto &SF : SubtargetFeatures) {
128d88c1a5aSDimitry Andric const SubtargetFeatureInfo &SFI = SF.second;
129d88c1a5aSDimitry Andric
130d88c1a5aSDimitry Andric OS << " if (";
131d88c1a5aSDimitry Andric std::string CondStorage =
132d88c1a5aSDimitry Andric SFI.TheDef->getValueAsString("AssemblerCondString");
133d88c1a5aSDimitry Andric StringRef Conds = CondStorage;
134d88c1a5aSDimitry Andric std::pair<StringRef, StringRef> Comma = Conds.split(',');
135d88c1a5aSDimitry Andric bool First = true;
136d88c1a5aSDimitry Andric do {
137d88c1a5aSDimitry Andric if (!First)
138d88c1a5aSDimitry Andric OS << " && ";
139d88c1a5aSDimitry Andric
140d88c1a5aSDimitry Andric bool Neg = false;
141d88c1a5aSDimitry Andric StringRef Cond = Comma.first;
142d88c1a5aSDimitry Andric if (Cond[0] == '!') {
143d88c1a5aSDimitry Andric Neg = true;
144d88c1a5aSDimitry Andric Cond = Cond.substr(1);
145d88c1a5aSDimitry Andric }
146d88c1a5aSDimitry Andric
147d88c1a5aSDimitry Andric OS << "(";
148d88c1a5aSDimitry Andric if (Neg)
149d88c1a5aSDimitry Andric OS << "!";
150d88c1a5aSDimitry Andric OS << "FB[" << TargetName << "::" << Cond << "])";
151d88c1a5aSDimitry Andric
152d88c1a5aSDimitry Andric if (Comma.second.empty())
153d88c1a5aSDimitry Andric break;
154d88c1a5aSDimitry Andric
155d88c1a5aSDimitry Andric First = false;
156d88c1a5aSDimitry Andric Comma = Comma.second.split(',');
157d88c1a5aSDimitry Andric } while (true);
158d88c1a5aSDimitry Andric
159d88c1a5aSDimitry Andric OS << ")\n";
160d88c1a5aSDimitry Andric OS << " Features |= " << SFI.getEnumName() << ";\n";
161d88c1a5aSDimitry Andric }
162d88c1a5aSDimitry Andric OS << " return Features;\n";
163d88c1a5aSDimitry Andric OS << "}\n\n";
164d88c1a5aSDimitry Andric }
165