[ARM] Add knowledge of FPU subtarget features to TargetParser

Add getFPUFeatures to TargetParser, which gets the list of subtarget features
that are enabled/disabled for each FPU, and use it when handling the .fpu
directive.

No functional change in this commit, though clang will start behaving
differently once it starts using this.

Differential Revision: http://reviews.llvm.org/D10237


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@239150 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
John Brawn 2015-06-05 13:29:24 +00:00
parent b4435accd5
commit c1c9bc1df7
7 changed files with 185 additions and 104 deletions

View File

@ -94,6 +94,10 @@ public:
/// feature bits. This version will also change all implied bits.
FeatureBitset ToggleFeature(StringRef FS);
/// Apply a feature flag and return the re-computed feature bits, including
/// all feature bits implied by the flag.
FeatureBitset ApplyFeatureFlag(StringRef FS);
/// getSchedModelForCPU - Get the machine model of a CPU.
///
MCSchedModel getSchedModelForCPU(StringRef CPU) const;

View File

@ -103,6 +103,10 @@ public:
FeatureBitset ToggleFeature(FeatureBitset Bits, StringRef String,
ArrayRef<SubtargetFeatureKV> FeatureTable);
/// Apply the feature flag and return the newly updated feature bits.
FeatureBitset ApplyFeatureFlag(FeatureBitset Bits, StringRef Feature,
ArrayRef<SubtargetFeatureKV> FeatureTable);
/// Get feature bits of a CPU.
FeatureBitset getFeatureBits(StringRef CPU,
ArrayRef<SubtargetFeatureKV> CPUTable,

View File

@ -15,6 +15,10 @@
#ifndef LLVM_SUPPORT_TARGETPARSER_H
#define LLVM_SUPPORT_TARGETPARSER_H
// FIXME: vector is used because that's what clang uses for subtarget feature
// lists, but SmallVector would probably be better
#include <vector>
namespace llvm {
class StringRef;
@ -44,6 +48,20 @@ namespace ARM {
FK_LAST
};
// An FPU name implies one of three levels of Neon support:
enum NeonSupportLevel {
NS_None = 0, //< No Neon
NS_Neon, //< Neon
NS_Crypto //< Neon with Crypto
};
// An FPU name restricts the FPU in one of three ways:
enum FPURestriction {
FR_None = 0, //< No restriction
FR_D16, //< Only 16 D registers
FR_SP_D16 //< Only single-precision instructions, with 16 D registers
};
// Arch names.
enum ArchKind {
AK_INVALID = 0,
@ -139,6 +157,12 @@ public:
// Information by ID
static const char * getFPUName(unsigned FPUKind);
static unsigned getFPUVersion(unsigned FPUKind);
static unsigned getFPUNeonSupportLevel(unsigned FPUKind);
static unsigned getFPURestriction(unsigned FPUKind);
// FIXME: This should be moved to TargetTuple once it exists
static bool getFPUFeatures(unsigned FPUKind,
std::vector<const char*> &Features);
static const char * getArchName(unsigned ArchKind);
static unsigned getArchAttr(unsigned ArchKind);
static const char * getCPUAttr(unsigned ArchKind);

View File

@ -81,6 +81,11 @@ FeatureBitset MCSubtargetInfo::ToggleFeature(StringRef FS) {
return FeatureBits;
}
FeatureBitset MCSubtargetInfo::ApplyFeatureFlag(StringRef FS) {
SubtargetFeatures Features;
FeatureBits = Features.ApplyFeatureFlag(FeatureBits, FS, ProcFeatures);
return FeatureBits;
}
MCSchedModel
MCSubtargetInfo::getSchedModelForCPU(StringRef CPU) const {

View File

@ -190,6 +190,38 @@ SubtargetFeatures::ToggleFeature(FeatureBitset Bits, StringRef Feature,
return Bits;
}
FeatureBitset
SubtargetFeatures::ApplyFeatureFlag(FeatureBitset Bits, StringRef Feature,
ArrayRef<SubtargetFeatureKV> FeatureTable) {
assert(hasFlag(Feature));
// Find feature in table.
const SubtargetFeatureKV *FeatureEntry =
Find(StripFlag(Feature), FeatureTable);
// If there is a match
if (FeatureEntry) {
// Enable/disable feature in bits
if (isEnabled(Feature)) {
Bits |= FeatureEntry->Value;
// For each feature that this implies, set it.
SetImpliedBits(Bits, FeatureEntry, FeatureTable);
} else {
Bits &= ~FeatureEntry->Value;
// For each feature that implies this, clear it.
ClearImpliedBits(Bits, FeatureEntry, FeatureTable);
}
} else {
errs() << "'" << Feature
<< "' is not a recognized feature for this target"
<< " (ignoring feature)\n";
}
return Bits;
}
/// getFeatureBits - Get feature bits a CPU.
///
@ -245,28 +277,7 @@ SubtargetFeatures::getFeatureBits(StringRef CPU,
if (Feature == "+help")
Help(CPUTable, FeatureTable);
// Find feature in table.
const SubtargetFeatureKV *FeatureEntry =
Find(StripFlag(Feature), FeatureTable);
// If there is a match
if (FeatureEntry) {
// Enable/disable feature in bits
if (isEnabled(Feature)) {
Bits |= FeatureEntry->Value;
// For each feature that this implies, set it.
SetImpliedBits(Bits, FeatureEntry, FeatureTable);
} else {
Bits &= ~FeatureEntry->Value;
// For each feature that implies this, clear it.
ClearImpliedBits(Bits, FeatureEntry, FeatureTable);
}
} else {
errs() << "'" << Feature
<< "' is not a recognized feature for this target"
<< " (ignoring feature)\n";
}
Bits = ApplyFeatureFlag(Bits, Feature, FeatureTable);
}
return Bits;

View File

@ -22,27 +22,33 @@ using namespace llvm;
namespace {
// List of canonical FPU names (use getFPUSynonym).
// List of canonical FPU names (use getFPUSynonym) and which architectural
// features they correspond to (use getFPUFeatures).
// FIXME: TableGen this.
struct {
const char * Name;
ARM::FPUKind ID;
unsigned FPUVersion; //< Corresponds directly to the FP arch version number.
ARM::NeonSupportLevel NeonSupport;
ARM::FPURestriction Restriction;
} FPUNames[] = {
{ "invalid", ARM::FK_INVALID },
{ "vfp", ARM::FK_VFP },
{ "vfpv2", ARM::FK_VFPV2 },
{ "vfpv3", ARM::FK_VFPV3 },
{ "vfpv3-d16", ARM::FK_VFPV3_D16 },
{ "vfpv4", ARM::FK_VFPV4 },
{ "vfpv4-d16", ARM::FK_VFPV4_D16 },
{ "fpv5-d16", ARM::FK_FPV5_D16 },
{ "fp-armv8", ARM::FK_FP_ARMV8 },
{ "neon", ARM::FK_NEON },
{ "neon-vfpv4", ARM::FK_NEON_VFPV4 },
{ "neon-fp-armv8", ARM::FK_NEON_FP_ARMV8 },
{ "crypto-neon-fp-armv8", ARM::FK_CRYPTO_NEON_FP_ARMV8 },
{ "softvfp", ARM::FK_SOFTVFP }
{ "invalid", ARM::FK_INVALID, 0, ARM::NS_None, ARM::FR_None},
{ "vfp", ARM::FK_VFP, 2, ARM::NS_None, ARM::FR_None},
{ "vfpv2", ARM::FK_VFPV2, 2, ARM::NS_None, ARM::FR_None},
{ "vfpv3", ARM::FK_VFPV3, 3, ARM::NS_None, ARM::FR_None},
{ "vfpv3-d16", ARM::FK_VFPV3_D16, 3, ARM::NS_None, ARM::FR_D16},
{ "vfpv4", ARM::FK_VFPV4, 4, ARM::NS_None, ARM::FR_None},
{ "vfpv4-d16", ARM::FK_VFPV4_D16, 4, ARM::NS_None, ARM::FR_D16},
{ "fpv5-d16", ARM::FK_FPV5_D16, 5, ARM::NS_None, ARM::FR_D16},
{ "fp-armv8", ARM::FK_FP_ARMV8, 5, ARM::NS_None, ARM::FR_None},
{ "neon", ARM::FK_NEON, 3, ARM::NS_Neon, ARM::FR_None},
{ "neon-vfpv4", ARM::FK_NEON_VFPV4, 4, ARM::NS_Neon, ARM::FR_None},
{ "neon-fp-armv8", ARM::FK_NEON_FP_ARMV8, 5, ARM::NS_Neon, ARM::FR_None},
{ "crypto-neon-fp-armv8",
ARM::FK_CRYPTO_NEON_FP_ARMV8, 5, ARM::NS_Crypto, ARM::FR_None},
{ "softvfp", ARM::FK_SOFTVFP, 0, ARM::NS_None, ARM::FR_None},
};
// List of canonical arch names (use getArchSynonym).
// This table also provides the build attribute fields for CPU arch
// and Arch ID, according to the Addenda to the ARM ABI, chapters
@ -226,6 +232,95 @@ const char *ARMTargetParser::getFPUName(unsigned FPUKind) {
return FPUNames[FPUKind].Name;
}
unsigned ARMTargetParser::getFPUVersion(unsigned FPUKind) {
if (FPUKind >= ARM::FK_LAST)
return 0;
return FPUNames[FPUKind].FPUVersion;
}
unsigned getFPUNeonSupportLevel(unsigned FPUKind) {
if (FPUKind >= ARM::FK_LAST)
return 0;
return FPUNames[FPUKind].NeonSupport;
}
unsigned getFPURestriction(unsigned FPUKind) {
if (FPUKind >= ARM::FK_LAST)
return 0;
return FPUNames[FPUKind].Restriction;
}
bool ARMTargetParser::getFPUFeatures(unsigned FPUKind,
std::vector<const char *> &Features) {
if (FPUKind >= ARM::FK_LAST || FPUKind == ARM::FK_INVALID)
return false;
// fp-only-sp and d16 subtarget features are independent of each other, so we
// must enable/disable both.
switch (FPUNames[FPUKind].Restriction) {
case ARM::FR_SP_D16:
Features.push_back("+fp-only-sp");
Features.push_back("+d16");
break;
case ARM::FR_D16:
Features.push_back("-fp-only-sp");
Features.push_back("+d16");
break;
case ARM::FR_None:
Features.push_back("-fp-only-sp");
Features.push_back("-d16");
break;
}
// FPU version subtarget features are inclusive of lower-numbered ones, so
// enable the one corresponding to this version and disable all that are
// higher.
switch (FPUNames[FPUKind].FPUVersion) {
case 5:
Features.push_back("+fp-armv8");
break;
case 4:
Features.push_back("+vfp4");
Features.push_back("-fp-armv8");
break;
case 3:
Features.push_back("+vfp3");
Features.push_back("-vfp4");
Features.push_back("-fp-armv8");
break;
case 2:
Features.push_back("+vfp2");
Features.push_back("-vfp3");
Features.push_back("-vfp4");
Features.push_back("-fp-armv8");
break;
case 0:
Features.push_back("-vfp2");
Features.push_back("-vfp3");
Features.push_back("-vfp4");
Features.push_back("-fp-armv8");
break;
}
// crypto includes neon, so we handle this similarly to FPU version.
switch (FPUNames[FPUKind].NeonSupport) {
case ARM::NS_Crypto:
Features.push_back("+crypto");
break;
case ARM::NS_Neon:
Features.push_back("+neon");
Features.push_back("-crypto");
break;
case ARM::NS_None:
Features.push_back("-neon");
Features.push_back("-crypto");
break;
}
return true;
}
const char *ARMTargetParser::getArchName(unsigned ArchKind) {
if (ArchKind >= ARM::AK_LAST)
return nullptr;

View File

@ -9181,60 +9181,6 @@ bool ARMAsmParser::parseDirectiveCPU(SMLoc L) {
return false;
}
// FIXME: This is duplicated in getARMFPUFeatures() in
// tools/clang/lib/Driver/Tools.cpp
static const struct {
const unsigned ID;
const FeatureBitset Enabled;
const FeatureBitset Disabled;
} FPUs[] = {
{/* ID */ ARM::FK_VFP,
/* Enabled */ {ARM::FeatureVFP2},
/* Disabled */ {ARM::FeatureNEON}},
{/* ID */ ARM::FK_VFPV2,
/* Enabled */ {ARM::FeatureVFP2},
/* Disabled */ {ARM::FeatureNEON}},
{/* ID */ ARM::FK_VFPV3,
/* Enabled */ {ARM::FeatureVFP2, ARM::FeatureVFP3},
/* Disabled */ {ARM::FeatureNEON, ARM::FeatureD16}},
{/* ID */ ARM::FK_VFPV3_D16,
/* Enabled */ {ARM::FeatureVFP2, ARM::FeatureVFP3, ARM::FeatureD16},
/* Disabled */ {ARM::FeatureNEON}},
{/* ID */ ARM::FK_VFPV4,
/* Enabled */ {ARM::FeatureVFP2, ARM::FeatureVFP3, ARM::FeatureVFP4},
/* Disabled */ {ARM::FeatureNEON, ARM::FeatureD16}},
{/* ID */ ARM::FK_VFPV4_D16,
/* Enabled */ {ARM::FeatureVFP2, ARM::FeatureVFP3, ARM::FeatureVFP4,
ARM::FeatureD16},
/* Disabled */ {ARM::FeatureNEON}},
{/* ID */ ARM::FK_FPV5_D16,
/* Enabled */ {ARM::FeatureVFP2, ARM::FeatureVFP3, ARM::FeatureVFP4,
ARM::FeatureFPARMv8, ARM::FeatureD16},
/* Disabled */ {ARM::FeatureNEON, ARM::FeatureCrypto}},
{/* ID */ ARM::FK_FP_ARMV8,
/* Enabled */ {ARM::FeatureVFP2, ARM::FeatureVFP3, ARM::FeatureVFP4,
ARM::FeatureFPARMv8},
/* Disabled */ {ARM::FeatureNEON, ARM::FeatureCrypto, ARM::FeatureD16}},
{/* ID */ ARM::FK_NEON,
/* Enabled */ {ARM::FeatureVFP2, ARM::FeatureVFP3, ARM::FeatureNEON},
/* Disabled */ {ARM::FeatureD16}},
{/* ID */ ARM::FK_NEON_VFPV4,
/* Enabled */ {ARM::FeatureVFP2, ARM::FeatureVFP3, ARM::FeatureVFP4,
ARM::FeatureNEON},
/* Disabled */ {ARM::FeatureD16}},
{/* ID */ ARM::FK_NEON_FP_ARMV8,
/* Enabled */ {ARM::FeatureVFP2, ARM::FeatureVFP3, ARM::FeatureVFP4,
ARM::FeatureFPARMv8, ARM::FeatureNEON},
/* Disabled */ {ARM::FeatureCrypto, ARM::FeatureD16}},
{/* ID */ ARM::FK_CRYPTO_NEON_FP_ARMV8,
/* Enabled */ {ARM::FeatureVFP2, ARM::FeatureVFP3, ARM::FeatureVFP4,
ARM::FeatureFPARMv8, ARM::FeatureNEON,
ARM::FeatureCrypto},
/* Disabled */ {ARM::FeatureD16}},
{ARM::FK_SOFTVFP, {}, {}},
};
/// parseDirectiveFPU
/// ::= .fpu str
bool ARMAsmParser::parseDirectiveFPU(SMLoc L) {
@ -9242,23 +9188,15 @@ bool ARMAsmParser::parseDirectiveFPU(SMLoc L) {
StringRef FPU = getParser().parseStringToEndOfStatement().trim();
unsigned ID = ARMTargetParser::parseFPU(FPU);
if (ID == ARM::FK_INVALID) {
std::vector<const char *> Features;
if (!ARMTargetParser::getFPUFeatures(ID, Features)) {
Error(FPUNameLoc, "Unknown FPU name");
return false;
}
for (const auto &Entry : FPUs) {
if (Entry.ID != ID)
continue;
// Need to toggle features that should be on but are off and that
// should off but are on.
FeatureBitset Toggle = (Entry.Enabled & ~STI.getFeatureBits()) |
(Entry.Disabled & STI.getFeatureBits());
setAvailableFeatures(ComputeAvailableFeatures(STI.ToggleFeature(Toggle)));
break;
}
for (auto Feature : Features)
STI.ApplyFeatureFlag(Feature);
setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits()));
getTargetStreamer().emitFPU(ID);
return false;