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