SubtargetFeature.cpp [plain text]
#include "llvm/MC/SubtargetFeature.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/ADT/StringExtras.h"
#include <algorithm>
#include <cassert>
#include <cctype>
#include <cstdlib>
using namespace llvm;
static inline bool hasFlag(const StringRef Feature) {
assert(!Feature.empty() && "Empty string");
char Ch = Feature[0];
return Ch == '+' || Ch =='-';
}
static inline std::string StripFlag(const StringRef Feature) {
return hasFlag(Feature) ? Feature.substr(1) : Feature;
}
static inline bool isEnabled(const StringRef Feature) {
assert(!Feature.empty() && "Empty string");
char Ch = Feature[0];
return Ch == '+';
}
static inline std::string PrependFlag(const StringRef Feature,
bool IsEnabled) {
assert(!Feature.empty() && "Empty string");
if (hasFlag(Feature))
return Feature;
std::string Prefix = IsEnabled ? "+" : "-";
Prefix += Feature;
return Prefix;
}
static void Split(std::vector<std::string> &V, const StringRef S) {
if (S.empty())
return;
size_t Pos = 0;
while (true) {
size_t Comma = S.find(',', Pos);
if (Comma == std::string::npos) {
V.push_back(S.substr(Pos));
break;
}
V.push_back(S.substr(Pos, Comma - Pos));
Pos = Comma + 1;
}
}
static std::string Join(const std::vector<std::string> &V) {
std::string Result;
if (!V.empty()) {
Result = V[0];
for (size_t i = 1; i < V.size(); i++) {
Result += ",";
Result += V[i];
}
}
return Result;
}
void SubtargetFeatures::AddFeature(const StringRef String,
bool IsEnabled) {
if (!String.empty()) {
Features.push_back(PrependFlag(LowercaseString(String), IsEnabled));
}
}
template<typename T> const T *Find(const StringRef S, const T *A, size_t L) {
T KV;
KV.Key = S.data();
const T *Hi = A + L;
const T *F = std::lower_bound(A, Hi, KV);
if (F == Hi || StringRef(F->Key) != S) return NULL;
return F;
}
static size_t getLongestEntryLength(const SubtargetFeatureKV *Table,
size_t Size) {
size_t MaxLen = 0;
for (size_t i = 0; i < Size; i++)
MaxLen = std::max(MaxLen, std::strlen(Table[i].Key));
return MaxLen;
}
static void Help(const SubtargetFeatureKV *CPUTable, size_t CPUTableSize,
const SubtargetFeatureKV *FeatTable, size_t FeatTableSize) {
unsigned MaxCPULen = getLongestEntryLength(CPUTable, CPUTableSize);
unsigned MaxFeatLen = getLongestEntryLength(FeatTable, FeatTableSize);
errs() << "Available CPUs for this target:\n\n";
for (size_t i = 0; i != CPUTableSize; i++)
errs() << " " << CPUTable[i].Key
<< std::string(MaxCPULen - std::strlen(CPUTable[i].Key), ' ')
<< " - " << CPUTable[i].Desc << ".\n";
errs() << "\n";
errs() << "Available features for this target:\n\n";
for (size_t i = 0; i != FeatTableSize; i++)
errs() << " " << FeatTable[i].Key
<< std::string(MaxFeatLen - std::strlen(FeatTable[i].Key), ' ')
<< " - " << FeatTable[i].Desc << ".\n";
errs() << "\n";
errs() << "Use +feature to enable a feature, or -feature to disable it.\n"
<< "For example, llc -mcpu=mycpu -mattr=+feature1,-feature2\n";
std::exit(1);
}
SubtargetFeatures::SubtargetFeatures(const StringRef Initial) {
Split(Features, Initial);
}
std::string SubtargetFeatures::getString() const {
return Join(Features);
}
static
void SetImpliedBits(uint64_t &Bits, const SubtargetFeatureKV *FeatureEntry,
const SubtargetFeatureKV *FeatureTable,
size_t FeatureTableSize) {
for (size_t i = 0; i < FeatureTableSize; ++i) {
const SubtargetFeatureKV &FE = FeatureTable[i];
if (FeatureEntry->Value == FE.Value) continue;
if (FeatureEntry->Implies & FE.Value) {
Bits |= FE.Value;
SetImpliedBits(Bits, &FE, FeatureTable, FeatureTableSize);
}
}
}
static
void ClearImpliedBits(uint64_t &Bits, const SubtargetFeatureKV *FeatureEntry,
const SubtargetFeatureKV *FeatureTable,
size_t FeatureTableSize) {
for (size_t i = 0; i < FeatureTableSize; ++i) {
const SubtargetFeatureKV &FE = FeatureTable[i];
if (FeatureEntry->Value == FE.Value) continue;
if (FE.Implies & FeatureEntry->Value) {
Bits &= ~FE.Value;
ClearImpliedBits(Bits, &FE, FeatureTable, FeatureTableSize);
}
}
}
uint64_t
SubtargetFeatures::ToggleFeature(uint64_t Bits, const StringRef Feature,
const SubtargetFeatureKV *FeatureTable,
size_t FeatureTableSize) {
const SubtargetFeatureKV *FeatureEntry =
Find(StripFlag(Feature), FeatureTable, FeatureTableSize);
if (FeatureEntry) {
if ((Bits & FeatureEntry->Value) == FeatureEntry->Value) {
Bits &= ~FeatureEntry->Value;
ClearImpliedBits(Bits, FeatureEntry, FeatureTable, FeatureTableSize);
} else {
Bits |= FeatureEntry->Value;
SetImpliedBits(Bits, FeatureEntry, FeatureTable, FeatureTableSize);
}
} else {
errs() << "'" << Feature
<< "' is not a recognized feature for this target"
<< " (ignoring feature)\n";
}
return Bits;
}
uint64_t SubtargetFeatures::getFeatureBits(const StringRef CPU,
const SubtargetFeatureKV *CPUTable,
size_t CPUTableSize,
const SubtargetFeatureKV *FeatureTable,
size_t FeatureTableSize) {
if (!FeatureTableSize || !CPUTableSize)
return 0;
#ifndef NDEBUG
for (size_t i = 1; i < CPUTableSize; i++) {
assert(strcmp(CPUTable[i - 1].Key, CPUTable[i].Key) < 0 &&
"CPU table is not sorted");
}
for (size_t i = 1; i < FeatureTableSize; i++) {
assert(strcmp(FeatureTable[i - 1].Key, FeatureTable[i].Key) < 0 &&
"CPU features table is not sorted");
}
#endif
uint64_t Bits = 0;
if (CPU == "help")
Help(CPUTable, CPUTableSize, FeatureTable, FeatureTableSize);
if (!CPU.empty()) {
const SubtargetFeatureKV *CPUEntry = Find(CPU, CPUTable, CPUTableSize);
if (CPUEntry) {
Bits = CPUEntry->Value;
for (size_t i = 0; i < FeatureTableSize; ++i) {
const SubtargetFeatureKV &FE = FeatureTable[i];
if (CPUEntry->Value & FE.Value)
SetImpliedBits(Bits, &FE, FeatureTable, FeatureTableSize);
}
} else {
errs() << "'" << CPU
<< "' is not a recognized processor for this target"
<< " (ignoring processor)\n";
}
}
for (size_t i = 0, E = Features.size(); i < E; i++) {
const StringRef Feature = Features[i];
if (Feature == "+help")
Help(CPUTable, CPUTableSize, FeatureTable, FeatureTableSize);
const SubtargetFeatureKV *FeatureEntry =
Find(StripFlag(Feature), FeatureTable, FeatureTableSize);
if (FeatureEntry) {
if (isEnabled(Feature)) {
Bits |= FeatureEntry->Value;
SetImpliedBits(Bits, FeatureEntry, FeatureTable, FeatureTableSize);
} else {
Bits &= ~FeatureEntry->Value;
ClearImpliedBits(Bits, FeatureEntry, FeatureTable, FeatureTableSize);
}
} else {
errs() << "'" << Feature
<< "' is not a recognized feature for this target"
<< " (ignoring feature)\n";
}
}
return Bits;
}
void *SubtargetFeatures::getItinerary(const StringRef CPU,
const SubtargetInfoKV *Table,
size_t TableSize) {
assert(Table && "missing table");
#ifndef NDEBUG
for (size_t i = 1; i < TableSize; i++) {
assert(strcmp(Table[i - 1].Key, Table[i].Key) < 0 && "Table is not sorted");
}
#endif
const SubtargetInfoKV *Entry = Find(CPU, Table, TableSize);
if (Entry) {
return Entry->Value;
} else {
errs() << "'" << CPU
<< "' is not a recognized processor for this target"
<< " (ignoring processor)\n";
return NULL;
}
}
void SubtargetFeatures::print(raw_ostream &OS) const {
for (size_t i = 0, e = Features.size(); i != e; ++i)
OS << Features[i] << " ";
OS << "\n";
}
void SubtargetFeatures::dump() const {
print(dbgs());
}
void SubtargetFeatures::getDefaultSubtargetFeatures(const Triple& Triple) {
if (Triple.getVendor() == Triple::Apple) {
if (Triple.getArch() == Triple::ppc) {
AddFeature("altivec");
} else if (Triple.getArch() == Triple::ppc64) {
AddFeature("64bit");
AddFeature("altivec");
}
}
}