mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-29 06:10:48 +00:00
Use bitset for assembler predicates
AMDGPU target run out of Subtarget feature flags hitting the limit of 64. AssemblerPredicates uses at most uint64_t for their representation. At the same time CodeGen has exhausted this a long time ago and switched to a FeatureBitset with the current limit of 192 bits. This patch completes transition to the bitset for feature bits extending it to asm matcher and MC code emitter. Differential Revision: https://reviews.llvm.org/D59002 llvm-svn: 355839
This commit is contained in:
parent
b9b16d334d
commit
9260748488
@ -16,6 +16,7 @@
|
||||
#include "llvm/MC/MCParser/MCParsedAsmOperand.h"
|
||||
#include "llvm/MC/MCParser/MCAsmParserExtension.h"
|
||||
#include "llvm/MC/MCTargetOptions.h"
|
||||
#include "llvm/MC/SubtargetFeature.h"
|
||||
#include "llvm/Support/SMLoc.h"
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
@ -202,7 +203,7 @@ public:
|
||||
// The instruction encoding is not valid because it requires some target
|
||||
// features that are not currently enabled. MissingFeatures has a bit set for
|
||||
// each feature that the encoding needs but which is not enabled.
|
||||
static NearMissInfo getMissedFeature(uint64_t MissingFeatures) {
|
||||
static NearMissInfo getMissedFeature(const FeatureBitset &MissingFeatures) {
|
||||
NearMissInfo Result;
|
||||
Result.Kind = NearMissFeature;
|
||||
Result.Features = MissingFeatures;
|
||||
@ -254,7 +255,7 @@ public:
|
||||
|
||||
// Feature flags required by the instruction, that the current target does
|
||||
// not have.
|
||||
uint64_t getFeatures() const {
|
||||
const FeatureBitset& getFeatures() const {
|
||||
assert(Kind == NearMissFeature);
|
||||
return Features;
|
||||
}
|
||||
@ -304,7 +305,7 @@ private:
|
||||
};
|
||||
|
||||
union {
|
||||
uint64_t Features;
|
||||
FeatureBitset Features;
|
||||
unsigned PredicateError;
|
||||
MissedOpInfo MissedOperand;
|
||||
TooFewOperandsInfo TooFewOperands;
|
||||
@ -334,7 +335,7 @@ protected: // Can only create subclasses.
|
||||
MCSubtargetInfo ©STI();
|
||||
|
||||
/// AvailableFeatures - The current set of available features.
|
||||
uint64_t AvailableFeatures = 0;
|
||||
FeatureBitset AvailableFeatures;
|
||||
|
||||
/// ParsingInlineAsm - Are we parsing ms-style inline assembly?
|
||||
bool ParsingInlineAsm = false;
|
||||
@ -359,8 +360,12 @@ public:
|
||||
|
||||
const MCSubtargetInfo &getSTI() const;
|
||||
|
||||
uint64_t getAvailableFeatures() const { return AvailableFeatures; }
|
||||
void setAvailableFeatures(uint64_t Value) { AvailableFeatures = Value; }
|
||||
const FeatureBitset& getAvailableFeatures() const {
|
||||
return AvailableFeatures;
|
||||
}
|
||||
void setAvailableFeatures(const FeatureBitset& Value) {
|
||||
AvailableFeatures = Value;
|
||||
}
|
||||
|
||||
bool isParsingInlineAsm () { return ParsingInlineAsm; }
|
||||
void setParsingInlineAsm (bool Value) { ParsingInlineAsm = Value; }
|
||||
|
@ -46,6 +46,15 @@ public:
|
||||
for (auto I : Init)
|
||||
set(I);
|
||||
}
|
||||
|
||||
bool operator < (const FeatureBitset &Other) const {
|
||||
for (unsigned I = 0, E = size(); I != E; ++I) {
|
||||
bool LHS = test(I), RHS = Other.test(I);
|
||||
if (LHS != RHS)
|
||||
return LHS < RHS;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/// Class used to store the subtarget bits in the tables created by tablegen.
|
||||
|
@ -4166,7 +4166,8 @@ bool AArch64AsmParser::validateInstruction(MCInst &Inst, SMLoc &IDLoc,
|
||||
}
|
||||
}
|
||||
|
||||
static std::string AArch64MnemonicSpellCheck(StringRef S, uint64_t FBS,
|
||||
static std::string AArch64MnemonicSpellCheck(StringRef S,
|
||||
const FeatureBitset &FBS,
|
||||
unsigned VariantID = 0);
|
||||
|
||||
bool AArch64AsmParser::showMatchError(SMLoc Loc, unsigned ErrCode,
|
||||
@ -4776,10 +4777,12 @@ bool AArch64AsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
|
||||
}
|
||||
|
||||
MCInst Inst;
|
||||
FeatureBitset MissingFeatures;
|
||||
// First try to match against the secondary set of tables containing the
|
||||
// short-form NEON instructions (e.g. "fadd.2s v0, v1, v2").
|
||||
unsigned MatchResult =
|
||||
MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm, 1);
|
||||
MatchInstructionImpl(Operands, Inst, ErrorInfo, MissingFeatures,
|
||||
MatchingInlineAsm, 1);
|
||||
|
||||
// If that fails, try against the alternate table containing long-form NEON:
|
||||
// "fadd v0.2s, v1.2s, v2.2s"
|
||||
@ -4788,9 +4791,11 @@ bool AArch64AsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
|
||||
// long-form match also fails.
|
||||
auto ShortFormNEONErrorInfo = ErrorInfo;
|
||||
auto ShortFormNEONMatchResult = MatchResult;
|
||||
auto ShortFormNEONMissingFeatures = MissingFeatures;
|
||||
|
||||
MatchResult =
|
||||
MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm, 0);
|
||||
MatchInstructionImpl(Operands, Inst, ErrorInfo, MissingFeatures,
|
||||
MatchingInlineAsm, 0);
|
||||
|
||||
// Now, both matches failed, and the long-form match failed on the mnemonic
|
||||
// suffix token operand. The short-form match failure is probably more
|
||||
@ -4800,6 +4805,7 @@ bool AArch64AsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
|
||||
((AArch64Operand &)*Operands[1]).isTokenSuffix()) {
|
||||
MatchResult = ShortFormNEONMatchResult;
|
||||
ErrorInfo = ShortFormNEONErrorInfo;
|
||||
MissingFeatures = ShortFormNEONMissingFeatures;
|
||||
}
|
||||
}
|
||||
|
||||
@ -4818,17 +4824,15 @@ bool AArch64AsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
|
||||
return false;
|
||||
}
|
||||
case Match_MissingFeature: {
|
||||
assert(ErrorInfo && "Unknown missing feature!");
|
||||
assert(MissingFeatures.any() && "Unknown missing feature!");
|
||||
// Special case the error message for the very common case where only
|
||||
// a single subtarget feature is missing (neon, e.g.).
|
||||
std::string Msg = "instruction requires:";
|
||||
uint64_t Mask = 1;
|
||||
for (unsigned i = 0; i < (sizeof(ErrorInfo)*8-1); ++i) {
|
||||
if (ErrorInfo & Mask) {
|
||||
for (unsigned i = 0, e = MissingFeatures.size(); i != e; ++i) {
|
||||
if (MissingFeatures[i]) {
|
||||
Msg += " ";
|
||||
Msg += getSubtargetFeatureName(ErrorInfo & Mask);
|
||||
Msg += getSubtargetFeatureName(i);
|
||||
}
|
||||
Mask <<= 1;
|
||||
}
|
||||
return Error(IDLoc, Msg);
|
||||
}
|
||||
@ -5147,7 +5151,7 @@ bool AArch64AsmParser::parseDirectiveArch(SMLoc L) {
|
||||
FeatureBitset ToggleFeatures = EnableFeature
|
||||
? (~Features & Extension.Features)
|
||||
: ( Features & Extension.Features);
|
||||
uint64_t Features =
|
||||
FeatureBitset Features =
|
||||
ComputeAvailableFeatures(STI.ToggleFeature(ToggleFeatures));
|
||||
setAvailableFeatures(Features);
|
||||
break;
|
||||
@ -5191,7 +5195,7 @@ bool AArch64AsmParser::parseDirectiveArchExtension(SMLoc L) {
|
||||
FeatureBitset ToggleFeatures = EnableFeature
|
||||
? (~Features & Extension.Features)
|
||||
: (Features & Extension.Features);
|
||||
uint64_t Features =
|
||||
FeatureBitset Features =
|
||||
ComputeAvailableFeatures(STI.ToggleFeature(ToggleFeatures));
|
||||
setAvailableFeatures(Features);
|
||||
return false;
|
||||
@ -5256,7 +5260,7 @@ bool AArch64AsmParser::parseDirectiveCPU(SMLoc L) {
|
||||
FeatureBitset ToggleFeatures = EnableFeature
|
||||
? (~Features & Extension.Features)
|
||||
: ( Features & Extension.Features);
|
||||
uint64_t Features =
|
||||
FeatureBitset Features =
|
||||
ComputeAvailableFeatures(STI.ToggleFeature(ToggleFeatures));
|
||||
setAvailableFeatures(Features);
|
||||
FoundExtension = true;
|
||||
|
@ -187,9 +187,10 @@ public:
|
||||
const MCSubtargetInfo &STI) const;
|
||||
|
||||
private:
|
||||
uint64_t computeAvailableFeatures(const FeatureBitset &FB) const;
|
||||
void verifyInstructionPredicates(const MCInst &MI,
|
||||
uint64_t AvailableFeatures) const;
|
||||
FeatureBitset computeAvailableFeatures(const FeatureBitset &FB) const;
|
||||
void
|
||||
verifyInstructionPredicates(const MCInst &MI,
|
||||
const FeatureBitset &AvailableFeatures) const;
|
||||
};
|
||||
|
||||
} // end anonymous namespace
|
||||
|
@ -2671,7 +2671,8 @@ bool AMDGPUAsmParser::validateInstruction(const MCInst &Inst,
|
||||
return true;
|
||||
}
|
||||
|
||||
static std::string AMDGPUMnemonicSpellCheck(StringRef S, uint64_t FBS,
|
||||
static std::string AMDGPUMnemonicSpellCheck(StringRef S,
|
||||
const FeatureBitset &FBS,
|
||||
unsigned VariantID = 0);
|
||||
|
||||
bool AMDGPUAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
|
||||
@ -2717,7 +2718,7 @@ bool AMDGPUAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
|
||||
return Error(IDLoc, "instruction not supported on this GPU");
|
||||
|
||||
case Match_MnemonicFail: {
|
||||
uint64_t FBS = ComputeAvailableFeatures(getSTI().getFeatureBits());
|
||||
FeatureBitset FBS = ComputeAvailableFeatures(getSTI().getFeatureBits());
|
||||
std::string Suggestion = AMDGPUMnemonicSpellCheck(
|
||||
((AMDGPUOperand &)*Operands[0]).getToken(), FBS);
|
||||
return Error(IDLoc, "invalid instruction" + Suggestion,
|
||||
|
@ -64,9 +64,10 @@ public:
|
||||
}
|
||||
|
||||
protected:
|
||||
uint64_t computeAvailableFeatures(const FeatureBitset &FB) const;
|
||||
void verifyInstructionPredicates(const MCInst &MI,
|
||||
uint64_t AvailableFeatures) const;
|
||||
FeatureBitset computeAvailableFeatures(const FeatureBitset &FB) const;
|
||||
void
|
||||
verifyInstructionPredicates(const MCInst &MI,
|
||||
const FeatureBitset &AvailableFeatures) const;
|
||||
};
|
||||
|
||||
} // End namespace llvm
|
||||
|
@ -64,9 +64,10 @@ private:
|
||||
uint64_t getBinaryCodeForInstr(const MCInst &MI,
|
||||
SmallVectorImpl<MCFixup> &Fixups,
|
||||
const MCSubtargetInfo &STI) const;
|
||||
uint64_t computeAvailableFeatures(const FeatureBitset &FB) const;
|
||||
void verifyInstructionPredicates(const MCInst &MI,
|
||||
uint64_t AvailableFeatures) const;
|
||||
FeatureBitset computeAvailableFeatures(const FeatureBitset &FB) const;
|
||||
void
|
||||
verifyInstructionPredicates(const MCInst &MI,
|
||||
const FeatureBitset &AvailableFeatures) const;
|
||||
|
||||
};
|
||||
|
||||
|
@ -504,7 +504,7 @@ class ARMAsmParser : public MCTargetAsmParser {
|
||||
|
||||
void SwitchMode() {
|
||||
MCSubtargetInfo &STI = copySTI();
|
||||
uint64_t FB = ComputeAvailableFeatures(STI.ToggleFeature(ARM::ModeThumb));
|
||||
auto FB = ComputeAvailableFeatures(STI.ToggleFeature(ARM::ModeThumb));
|
||||
setAvailableFeatures(FB);
|
||||
}
|
||||
|
||||
@ -6009,7 +6009,8 @@ static bool doesIgnoreDataTypeSuffix(StringRef Mnemonic, StringRef DT) {
|
||||
return Mnemonic.startswith("vldm") || Mnemonic.startswith("vstm");
|
||||
}
|
||||
|
||||
static void applyMnemonicAliases(StringRef &Mnemonic, uint64_t Features,
|
||||
static void applyMnemonicAliases(StringRef &Mnemonic,
|
||||
const FeatureBitset &Features,
|
||||
unsigned VariantID);
|
||||
|
||||
// The GNU assembler has aliases of ldrd and strd with the second register
|
||||
@ -6067,7 +6068,7 @@ bool ARMAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
|
||||
// The generic tblgen'erated code does this later, at the start of
|
||||
// MatchInstructionImpl(), but that's too late for aliases that include
|
||||
// any sort of suffix.
|
||||
uint64_t AvailableFeatures = getAvailableFeatures();
|
||||
const FeatureBitset &AvailableFeatures = getAvailableFeatures();
|
||||
unsigned AssemblerDialect = getParser().getAssemblerDialect();
|
||||
applyMnemonicAliases(Name, AvailableFeatures, AssemblerDialect);
|
||||
|
||||
@ -9279,7 +9280,7 @@ unsigned ARMAsmParser::MatchInstruction(OperandVector &Operands, MCInst &Inst,
|
||||
return PlainMatchResult;
|
||||
}
|
||||
|
||||
static std::string ARMMnemonicSpellCheck(StringRef S, uint64_t FBS,
|
||||
static std::string ARMMnemonicSpellCheck(StringRef S, const FeatureBitset &FBS,
|
||||
unsigned VariantID = 0);
|
||||
|
||||
static const char *getSubtargetFeatureName(uint64_t Val);
|
||||
@ -9352,7 +9353,7 @@ bool ARMAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
|
||||
ReportNearMisses(NearMisses, IDLoc, Operands);
|
||||
return true;
|
||||
case Match_MnemonicFail: {
|
||||
uint64_t FBS = ComputeAvailableFeatures(getSTI().getFeatureBits());
|
||||
FeatureBitset FBS = ComputeAvailableFeatures(getSTI().getFeatureBits());
|
||||
std::string Suggestion = ARMMnemonicSpellCheck(
|
||||
((ARMOperand &)*Operands[0]).getToken(), FBS);
|
||||
return Error(IDLoc, "invalid instruction" + Suggestion,
|
||||
@ -10427,7 +10428,7 @@ ARMAsmParser::FilterNearMisses(SmallVectorImpl<NearMissInfo> &NearMissesIn,
|
||||
// variants of an instruction that take 8- and 16-bit immediates, we want
|
||||
// to only report the widest one.
|
||||
std::multimap<unsigned, unsigned> OperandMissesSeen;
|
||||
SmallSet<uint64_t, 4> FeatureMissesSeen;
|
||||
SmallSet<FeatureBitset, 4> FeatureMissesSeen;
|
||||
bool ReportedTooFewOperands = false;
|
||||
|
||||
// Process the near-misses in reverse order, so that we see more general ones
|
||||
@ -10478,7 +10479,7 @@ ARMAsmParser::FilterNearMisses(SmallVectorImpl<NearMissInfo> &NearMissesIn,
|
||||
break;
|
||||
}
|
||||
case NearMissInfo::NearMissFeature: {
|
||||
uint64_t MissingFeatures = I.getFeatures();
|
||||
const FeatureBitset &MissingFeatures = I.getFeatures();
|
||||
// Don't report the same set of features twice.
|
||||
if (FeatureMissesSeen.count(MissingFeatures))
|
||||
break;
|
||||
@ -10486,20 +10487,21 @@ ARMAsmParser::FilterNearMisses(SmallVectorImpl<NearMissInfo> &NearMissesIn,
|
||||
|
||||
// Special case: don't report a feature set which includes arm-mode for
|
||||
// targets that don't have ARM mode.
|
||||
if ((MissingFeatures & Feature_IsARM) && !hasARM())
|
||||
if (MissingFeatures.test(Feature_IsARMBit) && !hasARM())
|
||||
break;
|
||||
// Don't report any near-misses that both require switching instruction
|
||||
// set, and adding other subtarget features.
|
||||
if (isThumb() && (MissingFeatures & Feature_IsARM) &&
|
||||
(MissingFeatures & ~Feature_IsARM))
|
||||
if (isThumb() && MissingFeatures.test(Feature_IsARMBit) &&
|
||||
MissingFeatures.count() > 1)
|
||||
break;
|
||||
if (!isThumb() && (MissingFeatures & Feature_IsThumb) &&
|
||||
(MissingFeatures & ~Feature_IsThumb))
|
||||
if (!isThumb() && MissingFeatures.test(Feature_IsThumbBit) &&
|
||||
MissingFeatures.count() > 1)
|
||||
break;
|
||||
if (!isThumb() && (MissingFeatures & Feature_IsThumb2) &&
|
||||
(MissingFeatures & ~(Feature_IsThumb2 | Feature_IsThumb)))
|
||||
if (!isThumb() && MissingFeatures.test(Feature_IsThumb2Bit) &&
|
||||
(MissingFeatures & ~FeatureBitset({Feature_IsThumb2Bit,
|
||||
Feature_IsThumbBit})).any())
|
||||
break;
|
||||
if (isMClass() && (MissingFeatures & Feature_HasNEON))
|
||||
if (isMClass() && MissingFeatures.test(Feature_HasNEONBit))
|
||||
break;
|
||||
|
||||
NearMissMessage Message;
|
||||
@ -10507,14 +10509,10 @@ ARMAsmParser::FilterNearMisses(SmallVectorImpl<NearMissInfo> &NearMissesIn,
|
||||
raw_svector_ostream OS(Message.Message);
|
||||
|
||||
OS << "instruction requires:";
|
||||
uint64_t Mask = 1;
|
||||
for (unsigned MaskPos = 0; MaskPos < (sizeof(MissingFeatures) * 8 - 1);
|
||||
++MaskPos) {
|
||||
if (MissingFeatures & Mask) {
|
||||
OS << " " << getSubtargetFeatureName(MissingFeatures & Mask);
|
||||
}
|
||||
Mask <<= 1;
|
||||
}
|
||||
for (unsigned i = 0, e = MissingFeatures.size(); i != e; ++i)
|
||||
if (MissingFeatures.test(i))
|
||||
OS << ' ' << getSubtargetFeatureName(i);
|
||||
|
||||
NearMissesOut.emplace_back(Message);
|
||||
|
||||
break;
|
||||
@ -10590,38 +10588,42 @@ void ARMAsmParser::ReportNearMisses(SmallVectorImpl<NearMissInfo> &NearMisses,
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: This structure should be moved inside ARMTargetParser
|
||||
// when we start to table-generate them, and we can use the ARM
|
||||
// flags below, that were generated by table-gen.
|
||||
static const struct {
|
||||
const unsigned Kind;
|
||||
const uint64_t ArchCheck;
|
||||
const FeatureBitset Features;
|
||||
} Extensions[] = {
|
||||
{ ARM::AEK_CRC, Feature_HasV8, {ARM::FeatureCRC} },
|
||||
{ ARM::AEK_CRYPTO, Feature_HasV8,
|
||||
{ARM::FeatureCrypto, ARM::FeatureNEON, ARM::FeatureFPARMv8} },
|
||||
{ ARM::AEK_FP, Feature_HasV8, {ARM::FeatureFPARMv8} },
|
||||
{ (ARM::AEK_HWDIVTHUMB | ARM::AEK_HWDIVARM), Feature_HasV7 | Feature_IsNotMClass,
|
||||
{ARM::FeatureHWDivThumb, ARM::FeatureHWDivARM} },
|
||||
{ ARM::AEK_MP, Feature_HasV7 | Feature_IsNotMClass, {ARM::FeatureMP} },
|
||||
{ ARM::AEK_SIMD, Feature_HasV8, {ARM::FeatureNEON, ARM::FeatureFPARMv8} },
|
||||
{ ARM::AEK_SEC, Feature_HasV6K, {ARM::FeatureTrustZone} },
|
||||
// FIXME: Only available in A-class, isel not predicated
|
||||
{ ARM::AEK_VIRT, Feature_HasV7, {ARM::FeatureVirtualization} },
|
||||
{ ARM::AEK_FP16, Feature_HasV8_2a, {ARM::FeatureFPARMv8, ARM::FeatureFullFP16} },
|
||||
{ ARM::AEK_RAS, Feature_HasV8, {ARM::FeatureRAS} },
|
||||
// FIXME: Unsupported extensions.
|
||||
{ ARM::AEK_OS, Feature_None, {} },
|
||||
{ ARM::AEK_IWMMXT, Feature_None, {} },
|
||||
{ ARM::AEK_IWMMXT2, Feature_None, {} },
|
||||
{ ARM::AEK_MAVERICK, Feature_None, {} },
|
||||
{ ARM::AEK_XSCALE, Feature_None, {} },
|
||||
};
|
||||
|
||||
/// parseDirectiveArchExtension
|
||||
/// ::= .arch_extension [no]feature
|
||||
bool ARMAsmParser::parseDirectiveArchExtension(SMLoc L) {
|
||||
// FIXME: This structure should be moved inside ARMTargetParser
|
||||
// when we start to table-generate them, and we can use the ARM
|
||||
// flags below, that were generated by table-gen.
|
||||
static const struct {
|
||||
const unsigned Kind;
|
||||
const FeatureBitset ArchCheck;
|
||||
const FeatureBitset Features;
|
||||
} Extensions[] = {
|
||||
{ ARM::AEK_CRC, {Feature_HasV8Bit}, {ARM::FeatureCRC} },
|
||||
{ ARM::AEK_CRYPTO, {Feature_HasV8Bit},
|
||||
{ARM::FeatureCrypto, ARM::FeatureNEON, ARM::FeatureFPARMv8} },
|
||||
{ ARM::AEK_FP, {Feature_HasV8Bit}, {ARM::FeatureFPARMv8} },
|
||||
{ (ARM::AEK_HWDIVTHUMB | ARM::AEK_HWDIVARM),
|
||||
{Feature_HasV7Bit, Feature_IsNotMClassBit},
|
||||
{ARM::FeatureHWDivThumb, ARM::FeatureHWDivARM} },
|
||||
{ ARM::AEK_MP, {Feature_HasV7Bit, Feature_IsNotMClassBit},
|
||||
{ARM::FeatureMP} },
|
||||
{ ARM::AEK_SIMD, {Feature_HasV8Bit},
|
||||
{ARM::FeatureNEON, ARM::FeatureFPARMv8} },
|
||||
{ ARM::AEK_SEC, {Feature_HasV6KBit}, {ARM::FeatureTrustZone} },
|
||||
// FIXME: Only available in A-class, isel not predicated
|
||||
{ ARM::AEK_VIRT, {Feature_HasV7Bit}, {ARM::FeatureVirtualization} },
|
||||
{ ARM::AEK_FP16, {Feature_HasV8_2aBit},
|
||||
{ARM::FeatureFPARMv8, ARM::FeatureFullFP16} },
|
||||
{ ARM::AEK_RAS, {Feature_HasV8Bit}, {ARM::FeatureRAS} },
|
||||
// FIXME: Unsupported extensions.
|
||||
{ ARM::AEK_OS, {}, {} },
|
||||
{ ARM::AEK_IWMMXT, {}, {} },
|
||||
{ ARM::AEK_IWMMXT2, {}, {} },
|
||||
{ ARM::AEK_MAVERICK, {}, {} },
|
||||
{ ARM::AEK_XSCALE, {}, {} },
|
||||
};
|
||||
|
||||
MCAsmParser &Parser = getParser();
|
||||
|
||||
if (getLexer().isNot(AsmToken::Identifier))
|
||||
@ -10661,7 +10663,7 @@ bool ARMAsmParser::parseDirectiveArchExtension(SMLoc L) {
|
||||
? (~STI.getFeatureBits() & Extension.Features)
|
||||
: ( STI.getFeatureBits() & Extension.Features);
|
||||
|
||||
uint64_t Features =
|
||||
FeatureBitset Features =
|
||||
ComputeAvailableFeatures(STI.ToggleFeature(ToggleFeatures));
|
||||
setAvailableFeatures(Features);
|
||||
return false;
|
||||
|
@ -63,9 +63,10 @@ public:
|
||||
const MCSubtargetInfo &STI) const override;
|
||||
|
||||
private:
|
||||
uint64_t computeAvailableFeatures(const FeatureBitset &FB) const;
|
||||
void verifyInstructionPredicates(const MCInst &MI,
|
||||
uint64_t AvailableFeatures) const;
|
||||
FeatureBitset computeAvailableFeatures(const FeatureBitset &FB) const;
|
||||
void
|
||||
verifyInstructionPredicates(const MCInst &MI,
|
||||
const FeatureBitset &AvailableFeatures) const;
|
||||
};
|
||||
|
||||
} // end anonymous namespace
|
||||
|
@ -377,7 +377,7 @@ void HexagonMCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS,
|
||||
State.Bundle = &MI;
|
||||
State.Index = 0;
|
||||
size_t Last = HexagonMCInstrInfo::bundleSize(HMB) - 1;
|
||||
uint64_t Features = computeAvailableFeatures(STI.getFeatureBits());
|
||||
FeatureBitset Features = computeAvailableFeatures(STI.getFeatureBits());
|
||||
|
||||
for (auto &I : HexagonMCInstrInfo::bundleInstructions(HMB)) {
|
||||
MCInst &HMI = const_cast<MCInst &>(*I.getInst());
|
||||
|
@ -82,9 +82,10 @@ private:
|
||||
// Return parse bits for instruction `MCI' inside bundle `MCB'
|
||||
uint32_t parseBits(size_t Last, MCInst const &MCB, MCInst const &MCI) const;
|
||||
|
||||
uint64_t computeAvailableFeatures(const FeatureBitset &FB) const;
|
||||
void verifyInstructionPredicates(const MCInst &MI,
|
||||
uint64_t AvailableFeatures) const;
|
||||
FeatureBitset computeAvailableFeatures(const FeatureBitset &FB) const;
|
||||
void
|
||||
verifyInstructionPredicates(const MCInst &MI,
|
||||
const FeatureBitset &AvailableFeatures) const;
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
@ -6321,7 +6321,7 @@ bool MipsAsmParser::parseBracketSuffix(StringRef Name,
|
||||
return false;
|
||||
}
|
||||
|
||||
static std::string MipsMnemonicSpellCheck(StringRef S, uint64_t FBS,
|
||||
static std::string MipsMnemonicSpellCheck(StringRef S, const FeatureBitset &FBS,
|
||||
unsigned VariantID = 0);
|
||||
|
||||
bool MipsAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
|
||||
@ -6334,7 +6334,7 @@ bool MipsAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
|
||||
|
||||
// Check if we have valid mnemonic
|
||||
if (!mnemonicIsValid(Name, 0)) {
|
||||
uint64_t FBS = ComputeAvailableFeatures(getSTI().getFeatureBits());
|
||||
FeatureBitset FBS = ComputeAvailableFeatures(getSTI().getFeatureBits());
|
||||
std::string Suggestion = MipsMnemonicSpellCheck(Name, FBS);
|
||||
return Error(NameLoc, "unknown instruction" + Suggestion);
|
||||
}
|
||||
|
@ -1128,7 +1128,7 @@ void PPCAsmParser::ProcessInstruction(MCInst &Inst,
|
||||
}
|
||||
}
|
||||
|
||||
static std::string PPCMnemonicSpellCheck(StringRef S, uint64_t FBS,
|
||||
static std::string PPCMnemonicSpellCheck(StringRef S, const FeatureBitset &FBS,
|
||||
unsigned VariantID = 0);
|
||||
|
||||
bool PPCAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
|
||||
@ -1147,7 +1147,7 @@ bool PPCAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
|
||||
case Match_MissingFeature:
|
||||
return Error(IDLoc, "instruction use requires an option to be enabled");
|
||||
case Match_MnemonicFail: {
|
||||
uint64_t FBS = ComputeAvailableFeatures(getSTI().getFeatureBits());
|
||||
FeatureBitset FBS = ComputeAvailableFeatures(getSTI().getFeatureBits());
|
||||
std::string Suggestion = PPCMnemonicSpellCheck(
|
||||
((PPCOperand &)*Operands[0]).getToken(), FBS);
|
||||
return Error(IDLoc, "invalid instruction" + Suggestion,
|
||||
|
@ -98,9 +98,10 @@ public:
|
||||
unsigned getInstSizeInBytes(const MCInst &MI) const;
|
||||
|
||||
private:
|
||||
uint64_t computeAvailableFeatures(const FeatureBitset &FB) const;
|
||||
void verifyInstructionPredicates(const MCInst &MI,
|
||||
uint64_t AvailableFeatures) const;
|
||||
FeatureBitset computeAvailableFeatures(const FeatureBitset &FB) const;
|
||||
void
|
||||
verifyInstructionPredicates(const MCInst &MI,
|
||||
const FeatureBitset &AvailableFeatures) const;
|
||||
};
|
||||
|
||||
} // namespace llvm
|
||||
|
@ -645,7 +645,8 @@ bool SparcAsmParser::ParseRegister(unsigned &RegNo, SMLoc &StartLoc,
|
||||
return Error(StartLoc, "invalid register name");
|
||||
}
|
||||
|
||||
static void applyMnemonicAliases(StringRef &Mnemonic, uint64_t Features,
|
||||
static void applyMnemonicAliases(StringRef &Mnemonic,
|
||||
const FeatureBitset &Features,
|
||||
unsigned VariantID);
|
||||
|
||||
bool SparcAsmParser::ParseInstruction(ParseInstructionInfo &Info,
|
||||
|
@ -83,9 +83,10 @@ public:
|
||||
const MCSubtargetInfo &STI) const;
|
||||
|
||||
private:
|
||||
uint64_t computeAvailableFeatures(const FeatureBitset &FB) const;
|
||||
void verifyInstructionPredicates(const MCInst &MI,
|
||||
uint64_t AvailableFeatures) const;
|
||||
FeatureBitset computeAvailableFeatures(const FeatureBitset &FB) const;
|
||||
void
|
||||
verifyInstructionPredicates(const MCInst &MI,
|
||||
const FeatureBitset &AvailableFeatures) const;
|
||||
};
|
||||
|
||||
} // end anonymous namespace
|
||||
|
@ -1180,8 +1180,10 @@ bool SystemZAsmParser::parseOperand(OperandVector &Operands,
|
||||
// features to be available during the operand check, or else we will fail to
|
||||
// find the custom parser, and then we will later get an InvalidOperand error
|
||||
// instead of a MissingFeature errror.
|
||||
uint64_t AvailableFeatures = getAvailableFeatures();
|
||||
setAvailableFeatures(~(uint64_t)0);
|
||||
FeatureBitset AvailableFeatures = getAvailableFeatures();
|
||||
FeatureBitset All;
|
||||
All.set();
|
||||
setAvailableFeatures(All);
|
||||
OperandMatchResultTy ResTy = MatchOperandParserImpl(Operands, Mnemonic);
|
||||
setAvailableFeatures(AvailableFeatures);
|
||||
if (ResTy == MatchOperand_Success)
|
||||
@ -1232,7 +1234,8 @@ bool SystemZAsmParser::parseOperand(OperandVector &Operands,
|
||||
return false;
|
||||
}
|
||||
|
||||
static std::string SystemZMnemonicSpellCheck(StringRef S, uint64_t FBS,
|
||||
static std::string SystemZMnemonicSpellCheck(StringRef S,
|
||||
const FeatureBitset &FBS,
|
||||
unsigned VariantID = 0);
|
||||
|
||||
bool SystemZAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
|
||||
@ -1243,8 +1246,9 @@ bool SystemZAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
|
||||
MCInst Inst;
|
||||
unsigned MatchResult;
|
||||
|
||||
FeatureBitset MissingFeatures;
|
||||
MatchResult = MatchInstructionImpl(Operands, Inst, ErrorInfo,
|
||||
MatchingInlineAsm);
|
||||
MissingFeatures, MatchingInlineAsm);
|
||||
switch (MatchResult) {
|
||||
case Match_Success:
|
||||
Inst.setLoc(IDLoc);
|
||||
@ -1252,17 +1256,15 @@ bool SystemZAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
|
||||
return false;
|
||||
|
||||
case Match_MissingFeature: {
|
||||
assert(ErrorInfo && "Unknown missing feature!");
|
||||
assert(MissingFeatures.any() && "Unknown missing feature!");
|
||||
// Special case the error message for the very common case where only
|
||||
// a single subtarget feature is missing
|
||||
std::string Msg = "instruction requires:";
|
||||
uint64_t Mask = 1;
|
||||
for (unsigned I = 0; I < sizeof(ErrorInfo) * 8 - 1; ++I) {
|
||||
if (ErrorInfo & Mask) {
|
||||
for (unsigned I = 0, E = MissingFeatures.size(); I != E; ++I) {
|
||||
if (MissingFeatures[I]) {
|
||||
Msg += " ";
|
||||
Msg += getSubtargetFeatureName(ErrorInfo & Mask);
|
||||
Msg += getSubtargetFeatureName(I);
|
||||
}
|
||||
Mask <<= 1;
|
||||
}
|
||||
return Error(IDLoc, Msg);
|
||||
}
|
||||
@ -1281,7 +1283,7 @@ bool SystemZAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
|
||||
}
|
||||
|
||||
case Match_MnemonicFail: {
|
||||
uint64_t FBS = ComputeAvailableFeatures(getSTI().getFeatureBits());
|
||||
FeatureBitset FBS = ComputeAvailableFeatures(getSTI().getFeatureBits());
|
||||
std::string Suggestion = SystemZMnemonicSpellCheck(
|
||||
((SystemZOperand &)*Operands[0]).getToken(), FBS);
|
||||
return Error(IDLoc, "invalid instruction" + Suggestion,
|
||||
|
@ -143,9 +143,10 @@ private:
|
||||
}
|
||||
|
||||
private:
|
||||
uint64_t computeAvailableFeatures(const FeatureBitset &FB) const;
|
||||
void verifyInstructionPredicates(const MCInst &MI,
|
||||
uint64_t AvailableFeatures) const;
|
||||
FeatureBitset computeAvailableFeatures(const FeatureBitset &FB) const;
|
||||
void
|
||||
verifyInstructionPredicates(const MCInst &MI,
|
||||
const FeatureBitset &AvailableFeatures) const;
|
||||
};
|
||||
|
||||
} // end anonymous namespace
|
||||
|
@ -89,13 +89,14 @@ private:
|
||||
}
|
||||
|
||||
unsigned MatchInstruction(const OperandVector &Operands, MCInst &Inst,
|
||||
uint64_t &ErrorInfo, bool matchingInlineAsm,
|
||||
unsigned VariantID = 0) {
|
||||
uint64_t &ErrorInfo, FeatureBitset &MissingFeatures,
|
||||
bool matchingInlineAsm, unsigned VariantID = 0) {
|
||||
// In Code16GCC mode, match as 32-bit.
|
||||
if (Code16GCC)
|
||||
SwitchMode(X86::Mode32Bit);
|
||||
unsigned rv = MatchInstructionImpl(Operands, Inst, ErrorInfo,
|
||||
matchingInlineAsm, VariantID);
|
||||
MissingFeatures, matchingInlineAsm,
|
||||
VariantID);
|
||||
if (Code16GCC)
|
||||
SwitchMode(X86::Mode16Bit);
|
||||
return rv;
|
||||
@ -874,7 +875,7 @@ private:
|
||||
void MatchFPUWaitAlias(SMLoc IDLoc, X86Operand &Op, OperandVector &Operands,
|
||||
MCStreamer &Out, bool MatchingInlineAsm);
|
||||
|
||||
bool ErrorMissingFeature(SMLoc IDLoc, uint64_t ErrorInfo,
|
||||
bool ErrorMissingFeature(SMLoc IDLoc, const FeatureBitset &MissingFeatures,
|
||||
bool MatchingInlineAsm);
|
||||
|
||||
bool MatchAndEmitATTInstruction(SMLoc IDLoc, unsigned &Opcode,
|
||||
@ -913,7 +914,7 @@ private:
|
||||
MCSubtargetInfo &STI = copySTI();
|
||||
FeatureBitset AllModes({X86::Mode64Bit, X86::Mode32Bit, X86::Mode16Bit});
|
||||
FeatureBitset OldMode = STI.getFeatureBits() & AllModes;
|
||||
uint64_t FB = ComputeAvailableFeatures(
|
||||
FeatureBitset FB = ComputeAvailableFeatures(
|
||||
STI.ToggleFeature(OldMode.flip(mode)));
|
||||
setAvailableFeatures(FB);
|
||||
|
||||
@ -2906,17 +2907,16 @@ void X86AsmParser::MatchFPUWaitAlias(SMLoc IDLoc, X86Operand &Op,
|
||||
}
|
||||
}
|
||||
|
||||
bool X86AsmParser::ErrorMissingFeature(SMLoc IDLoc, uint64_t ErrorInfo,
|
||||
bool X86AsmParser::ErrorMissingFeature(SMLoc IDLoc,
|
||||
const FeatureBitset &MissingFeatures,
|
||||
bool MatchingInlineAsm) {
|
||||
assert(ErrorInfo && "Unknown missing feature!");
|
||||
assert(MissingFeatures.any() && "Unknown missing feature!");
|
||||
SmallString<126> Msg;
|
||||
raw_svector_ostream OS(Msg);
|
||||
OS << "instruction requires:";
|
||||
uint64_t Mask = 1;
|
||||
for (unsigned i = 0; i < (sizeof(ErrorInfo)*8-1); ++i) {
|
||||
if (ErrorInfo & Mask)
|
||||
OS << ' ' << getSubtargetFeatureName(ErrorInfo & Mask);
|
||||
Mask <<= 1;
|
||||
for (unsigned i = 0, e = MissingFeatures.size(); i != e; ++i) {
|
||||
if (MissingFeatures[i])
|
||||
OS << ' ' << getSubtargetFeatureName(i);
|
||||
}
|
||||
return Error(IDLoc, OS.str(), SMRange(), MatchingInlineAsm);
|
||||
}
|
||||
@ -2953,8 +2953,9 @@ bool X86AsmParser::MatchAndEmitATTInstruction(SMLoc IDLoc, unsigned &Opcode,
|
||||
Inst.setFlags(Prefixes);
|
||||
|
||||
// First, try a direct match.
|
||||
switch (MatchInstruction(Operands, Inst, ErrorInfo, MatchingInlineAsm,
|
||||
isParsingIntelSyntax())) {
|
||||
FeatureBitset MissingFeatures;
|
||||
switch (MatchInstruction(Operands, Inst, ErrorInfo, MissingFeatures,
|
||||
MatchingInlineAsm, isParsingIntelSyntax())) {
|
||||
default: llvm_unreachable("Unexpected match result!");
|
||||
case Match_Success:
|
||||
if (!MatchingInlineAsm && validateInstruction(Inst, Operands))
|
||||
@ -2972,7 +2973,7 @@ bool X86AsmParser::MatchAndEmitATTInstruction(SMLoc IDLoc, unsigned &Opcode,
|
||||
Opcode = Inst.getOpcode();
|
||||
return false;
|
||||
case Match_MissingFeature:
|
||||
return ErrorMissingFeature(IDLoc, ErrorInfo, MatchingInlineAsm);
|
||||
return ErrorMissingFeature(IDLoc, MissingFeatures, MatchingInlineAsm);
|
||||
case Match_InvalidOperand:
|
||||
WasOriginallyInvalidOperand = true;
|
||||
break;
|
||||
@ -3002,16 +3003,17 @@ bool X86AsmParser::MatchAndEmitATTInstruction(SMLoc IDLoc, unsigned &Opcode,
|
||||
|
||||
// Check for the various suffix matches.
|
||||
uint64_t ErrorInfoIgnore;
|
||||
uint64_t ErrorInfoMissingFeature = 0; // Init suppresses compiler warnings.
|
||||
FeatureBitset ErrorInfoMissingFeatures; // Init suppresses compiler warnings.
|
||||
unsigned Match[4];
|
||||
|
||||
for (unsigned I = 0, E = array_lengthof(Match); I != E; ++I) {
|
||||
Tmp.back() = Suffixes[I];
|
||||
Match[I] = MatchInstruction(Operands, Inst, ErrorInfoIgnore,
|
||||
MatchingInlineAsm, isParsingIntelSyntax());
|
||||
MissingFeatures, MatchingInlineAsm,
|
||||
isParsingIntelSyntax());
|
||||
// If this returned as a missing feature failure, remember that.
|
||||
if (Match[I] == Match_MissingFeature)
|
||||
ErrorInfoMissingFeature = ErrorInfoIgnore;
|
||||
ErrorInfoMissingFeatures = MissingFeatures;
|
||||
}
|
||||
|
||||
// Restore the old token.
|
||||
@ -3088,8 +3090,8 @@ bool X86AsmParser::MatchAndEmitATTInstruction(SMLoc IDLoc, unsigned &Opcode,
|
||||
// missing feature.
|
||||
if (std::count(std::begin(Match), std::end(Match),
|
||||
Match_MissingFeature) == 1) {
|
||||
ErrorInfo = ErrorInfoMissingFeature;
|
||||
return ErrorMissingFeature(IDLoc, ErrorInfoMissingFeature,
|
||||
ErrorInfo = Match_MissingFeature;
|
||||
return ErrorMissingFeature(IDLoc, ErrorInfoMissingFeatures,
|
||||
MatchingInlineAsm);
|
||||
}
|
||||
|
||||
@ -3153,7 +3155,8 @@ bool X86AsmParser::MatchAndEmitIntelInstruction(SMLoc IDLoc, unsigned &Opcode,
|
||||
}
|
||||
|
||||
SmallVector<unsigned, 8> Match;
|
||||
uint64_t ErrorInfoMissingFeature = 0;
|
||||
FeatureBitset ErrorInfoMissingFeatures;
|
||||
FeatureBitset MissingFeatures;
|
||||
|
||||
// If unsized push has immediate operand we should default the default pointer
|
||||
// size for the size.
|
||||
@ -3173,7 +3176,7 @@ bool X86AsmParser::MatchAndEmitIntelInstruction(SMLoc IDLoc, unsigned &Opcode,
|
||||
Op.setTokenValue(Tmp);
|
||||
// Do match in ATT mode to allow explicit suffix usage.
|
||||
Match.push_back(MatchInstruction(Operands, Inst, ErrorInfo,
|
||||
MatchingInlineAsm,
|
||||
MissingFeatures, MatchingInlineAsm,
|
||||
false /*isParsingIntelSyntax()*/));
|
||||
Op.setTokenValue(Base);
|
||||
}
|
||||
@ -3190,13 +3193,14 @@ bool X86AsmParser::MatchAndEmitIntelInstruction(SMLoc IDLoc, unsigned &Opcode,
|
||||
uint64_t ErrorInfoIgnore;
|
||||
unsigned LastOpcode = Inst.getOpcode();
|
||||
unsigned M = MatchInstruction(Operands, Inst, ErrorInfoIgnore,
|
||||
MatchingInlineAsm, isParsingIntelSyntax());
|
||||
MissingFeatures, MatchingInlineAsm,
|
||||
isParsingIntelSyntax());
|
||||
if (Match.empty() || LastOpcode != Inst.getOpcode())
|
||||
Match.push_back(M);
|
||||
|
||||
// If this returned as a missing feature failure, remember that.
|
||||
if (Match.back() == Match_MissingFeature)
|
||||
ErrorInfoMissingFeature = ErrorInfoIgnore;
|
||||
ErrorInfoMissingFeatures = MissingFeatures;
|
||||
}
|
||||
|
||||
// Restore the size of the unsized memory operand if we modified it.
|
||||
@ -3208,10 +3212,11 @@ bool X86AsmParser::MatchAndEmitIntelInstruction(SMLoc IDLoc, unsigned &Opcode,
|
||||
// matching with the unsized operand.
|
||||
if (Match.empty()) {
|
||||
Match.push_back(MatchInstruction(
|
||||
Operands, Inst, ErrorInfo, MatchingInlineAsm, isParsingIntelSyntax()));
|
||||
Operands, Inst, ErrorInfo, MissingFeatures, MatchingInlineAsm,
|
||||
isParsingIntelSyntax()));
|
||||
// If this returned as a missing feature failure, remember that.
|
||||
if (Match.back() == Match_MissingFeature)
|
||||
ErrorInfoMissingFeature = ErrorInfo;
|
||||
ErrorInfoMissingFeatures = MissingFeatures;
|
||||
}
|
||||
|
||||
// Restore the size of the unsized memory operand if we modified it.
|
||||
@ -3233,7 +3238,8 @@ bool X86AsmParser::MatchAndEmitIntelInstruction(SMLoc IDLoc, unsigned &Opcode,
|
||||
UnsizedMemOp->getMemFrontendSize()) {
|
||||
UnsizedMemOp->Mem.Size = UnsizedMemOp->getMemFrontendSize();
|
||||
unsigned M = MatchInstruction(
|
||||
Operands, Inst, ErrorInfo, MatchingInlineAsm, isParsingIntelSyntax());
|
||||
Operands, Inst, ErrorInfo, MissingFeatures, MatchingInlineAsm,
|
||||
isParsingIntelSyntax());
|
||||
if (M == Match_Success)
|
||||
NumSuccessfulMatches = 1;
|
||||
|
||||
@ -3273,8 +3279,8 @@ bool X86AsmParser::MatchAndEmitIntelInstruction(SMLoc IDLoc, unsigned &Opcode,
|
||||
// missing feature.
|
||||
if (std::count(std::begin(Match), std::end(Match),
|
||||
Match_MissingFeature) == 1) {
|
||||
ErrorInfo = ErrorInfoMissingFeature;
|
||||
return ErrorMissingFeature(IDLoc, ErrorInfoMissingFeature,
|
||||
ErrorInfo = Match_MissingFeature;
|
||||
return ErrorMissingFeature(IDLoc, ErrorInfoMissingFeatures,
|
||||
MatchingInlineAsm);
|
||||
}
|
||||
|
||||
|
@ -1473,7 +1473,6 @@ void AsmMatcherInfo::buildInfo() {
|
||||
for (const auto &Pair : SubtargetFeatures)
|
||||
LLVM_DEBUG(Pair.second.dump());
|
||||
#endif // NDEBUG
|
||||
assert(SubtargetFeatures.size() <= 64 && "Too many subtarget features!");
|
||||
|
||||
bool HasMnemonicFirst = AsmParser->getValueAsBit("HasMnemonicFirst");
|
||||
bool ReportMultipleNearMisses =
|
||||
@ -2675,7 +2674,7 @@ static void emitGetSubtargetFeatureName(AsmMatcherInfo &Info, raw_ostream &OS) {
|
||||
for (const auto &SF : Info.SubtargetFeatures) {
|
||||
const SubtargetFeatureInfo &SFI = SF.second;
|
||||
// FIXME: Totally just a placeholder name to get the algorithm working.
|
||||
OS << " case " << SFI.getEnumName() << ": return \""
|
||||
OS << " case " << SFI.getEnumBitName() << ": return \""
|
||||
<< SFI.TheDef->getValueAsString("PredicateName") << "\";\n";
|
||||
}
|
||||
OS << " default: return \"(unknown)\";\n";
|
||||
@ -2691,7 +2690,10 @@ static std::string GetAliasRequiredFeatures(Record *R,
|
||||
const AsmMatcherInfo &Info) {
|
||||
std::vector<Record*> ReqFeatures = R->getValueAsListOfDefs("Predicates");
|
||||
std::string Result;
|
||||
unsigned NumFeatures = 0;
|
||||
|
||||
if (ReqFeatures.empty())
|
||||
return Result;
|
||||
|
||||
for (unsigned i = 0, e = ReqFeatures.size(); i != e; ++i) {
|
||||
const SubtargetFeatureInfo *F = Info.getSubtargetFeature(ReqFeatures[i]);
|
||||
|
||||
@ -2699,15 +2701,12 @@ static std::string GetAliasRequiredFeatures(Record *R,
|
||||
PrintFatalError(R->getLoc(), "Predicate '" + ReqFeatures[i]->getName() +
|
||||
"' is not marked as an AssemblerPredicate!");
|
||||
|
||||
if (NumFeatures)
|
||||
Result += '|';
|
||||
if (i)
|
||||
Result += " && ";
|
||||
|
||||
Result += F->getEnumName();
|
||||
++NumFeatures;
|
||||
Result += "Features.test(" + F->getEnumBitName() + ')';
|
||||
}
|
||||
|
||||
if (NumFeatures > 1)
|
||||
Result = '(' + Result + ')';
|
||||
return Result;
|
||||
}
|
||||
|
||||
@ -2763,7 +2762,7 @@ static void emitMnemonicAliasVariant(raw_ostream &OS,const AsmMatcherInfo &Info,
|
||||
|
||||
if (!MatchCode.empty())
|
||||
MatchCode += "else ";
|
||||
MatchCode += "if ((Features & " + FeatureMask + ") == "+FeatureMask+")\n";
|
||||
MatchCode += "if (" + FeatureMask + ")\n";
|
||||
MatchCode += " Mnemonic = \"";
|
||||
MatchCode += R->getValueAsString("ToMnemonic");
|
||||
MatchCode += "\";\n";
|
||||
@ -2798,7 +2797,7 @@ static bool emitMnemonicAliases(raw_ostream &OS, const AsmMatcherInfo &Info,
|
||||
if (Aliases.empty()) return false;
|
||||
|
||||
OS << "static void applyMnemonicAliases(StringRef &Mnemonic, "
|
||||
"uint64_t Features, unsigned VariantID) {\n";
|
||||
"const FeatureBitset &Features, unsigned VariantID) {\n";
|
||||
OS << " switch (VariantID) {\n";
|
||||
unsigned VariantCount = Target.getAsmParserVariantCount();
|
||||
for (unsigned VC = 0; VC != VariantCount; ++VC) {
|
||||
@ -2823,7 +2822,9 @@ static bool emitMnemonicAliases(raw_ostream &OS, const AsmMatcherInfo &Info,
|
||||
static void emitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target,
|
||||
const AsmMatcherInfo &Info, StringRef ClassName,
|
||||
StringToOffsetTable &StringTable,
|
||||
unsigned MaxMnemonicIndex, bool HasMnemonicFirst) {
|
||||
unsigned MaxMnemonicIndex,
|
||||
unsigned MaxFeaturesIndex,
|
||||
bool HasMnemonicFirst) {
|
||||
unsigned MaxMask = 0;
|
||||
for (const OperandMatchEntry &OMI : Info.OperandMatchInfo) {
|
||||
MaxMask |= OMI.OperandMask;
|
||||
@ -2832,14 +2833,14 @@ static void emitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target,
|
||||
// Emit the static custom operand parsing table;
|
||||
OS << "namespace {\n";
|
||||
OS << " struct OperandMatchEntry {\n";
|
||||
OS << " " << getMinimalTypeForEnumBitfield(Info.SubtargetFeatures.size())
|
||||
<< " RequiredFeatures;\n";
|
||||
OS << " " << getMinimalTypeForRange(MaxMnemonicIndex)
|
||||
<< " Mnemonic;\n";
|
||||
OS << " " << getMinimalTypeForRange(MaxMask)
|
||||
<< " OperandMask;\n";
|
||||
OS << " " << getMinimalTypeForRange(std::distance(
|
||||
Info.Classes.begin(), Info.Classes.end())) << " Class;\n";
|
||||
OS << " " << getMinimalTypeForRange(MaxMask)
|
||||
<< " OperandMask;\n\n";
|
||||
OS << " " << getMinimalTypeForRange(MaxFeaturesIndex)
|
||||
<< " RequiredFeaturesIdx;\n\n";
|
||||
OS << " StringRef getMnemonic() const {\n";
|
||||
OS << " return StringRef(MnemonicTable + Mnemonic + 1,\n";
|
||||
OS << " MnemonicTable[Mnemonic]);\n";
|
||||
@ -2865,29 +2866,18 @@ static void emitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target,
|
||||
OS << "static const OperandMatchEntry OperandMatchTable["
|
||||
<< Info.OperandMatchInfo.size() << "] = {\n";
|
||||
|
||||
OS << " /* Operand List Mask, Mnemonic, Operand Class, Features */\n";
|
||||
OS << " /* Operand List Mnemonic, Mask, Operand Class, Features */\n";
|
||||
for (const OperandMatchEntry &OMI : Info.OperandMatchInfo) {
|
||||
const MatchableInfo &II = *OMI.MI;
|
||||
|
||||
OS << " { ";
|
||||
|
||||
// Write the required features mask.
|
||||
if (!II.RequiredFeatures.empty()) {
|
||||
for (unsigned i = 0, e = II.RequiredFeatures.size(); i != e; ++i) {
|
||||
if (i) OS << "|";
|
||||
OS << II.RequiredFeatures[i]->getEnumName();
|
||||
}
|
||||
} else
|
||||
OS << "0";
|
||||
|
||||
// Store a pascal-style length byte in the mnemonic.
|
||||
std::string LenMnemonic = char(II.Mnemonic.size()) + II.Mnemonic.str();
|
||||
OS << ", " << StringTable.GetOrAddStringOffset(LenMnemonic, false)
|
||||
OS << StringTable.GetOrAddStringOffset(LenMnemonic, false)
|
||||
<< " /* " << II.Mnemonic << " */, ";
|
||||
|
||||
OS << OMI.CI->Name;
|
||||
|
||||
OS << ", " << OMI.OperandMask;
|
||||
OS << OMI.OperandMask;
|
||||
OS << " /* ";
|
||||
bool printComma = false;
|
||||
for (int i = 0, e = 31; i !=e; ++i)
|
||||
@ -2897,7 +2887,17 @@ static void emitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target,
|
||||
OS << i;
|
||||
printComma = true;
|
||||
}
|
||||
OS << " */";
|
||||
OS << " */, ";
|
||||
|
||||
OS << OMI.CI->Name;
|
||||
|
||||
// Write the required features mask.
|
||||
OS << ", AMFBS";
|
||||
if (II.RequiredFeatures.empty())
|
||||
OS << "_None";
|
||||
else
|
||||
for (unsigned i = 0, e = II.RequiredFeatures.size(); i != e; ++i)
|
||||
OS << '_' << II.RequiredFeatures[i]->TheDef->getName();
|
||||
|
||||
OS << " },\n";
|
||||
}
|
||||
@ -2933,7 +2933,7 @@ static void emitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target,
|
||||
|
||||
// Emit code to get the available features.
|
||||
OS << " // Get the current feature set.\n";
|
||||
OS << " uint64_t AvailableFeatures = getAvailableFeatures();\n\n";
|
||||
OS << " const FeatureBitset &AvailableFeatures = getAvailableFeatures();\n\n";
|
||||
|
||||
OS << " // Get the next operand index.\n";
|
||||
OS << " unsigned NextOpNum = Operands.size()"
|
||||
@ -2967,8 +2967,10 @@ static void emitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target,
|
||||
|
||||
// Emit check that the required features are available.
|
||||
OS << " // check if the available features match\n";
|
||||
OS << " const FeatureBitset &RequiredFeatures = "
|
||||
"FeatureBitsets[it->RequiredFeaturesIdx];\n";
|
||||
OS << " if (!ParseForAllFeatures && (AvailableFeatures & "
|
||||
"it->RequiredFeatures) != it->RequiredFeatures)\n";
|
||||
"RequiredFeatures) != RequiredFeatures)\n";
|
||||
OS << " continue;\n\n";
|
||||
|
||||
// Emit check to ensure the operand number matches.
|
||||
@ -3034,7 +3036,8 @@ static void emitAsmTiedOperandConstraints(CodeGenTarget &Target,
|
||||
static void emitMnemonicSpellChecker(raw_ostream &OS, CodeGenTarget &Target,
|
||||
unsigned VariantCount) {
|
||||
OS << "static std::string " << Target.getName()
|
||||
<< "MnemonicSpellCheck(StringRef S, uint64_t FBS, unsigned VariantID) {\n";
|
||||
<< "MnemonicSpellCheck(StringRef S, const FeatureBitset &FBS,"
|
||||
<< " unsigned VariantID) {\n";
|
||||
if (!VariantCount)
|
||||
OS << " return \"\";";
|
||||
else {
|
||||
@ -3055,7 +3058,9 @@ static void emitMnemonicSpellChecker(raw_ostream &OS, CodeGenTarget &Target,
|
||||
OS << " }\n\n";
|
||||
OS << " for (auto I = Start; I < End; I++) {\n";
|
||||
OS << " // Ignore unsupported instructions.\n";
|
||||
OS << " if ((FBS & I->RequiredFeatures) != I->RequiredFeatures)\n";
|
||||
OS << " const FeatureBitset &RequiredFeatures = "
|
||||
"FeatureBitsets[I->RequiredFeaturesIdx];\n";
|
||||
OS << " if ((FBS & RequiredFeatures) != RequiredFeatures)\n";
|
||||
OS << " continue;\n";
|
||||
OS << "\n";
|
||||
OS << " StringRef T = I->getMnemonic();\n";
|
||||
@ -3103,6 +3108,14 @@ static void emitMatchClassKindNames(std::forward_list<ClassInfo> &Infos,
|
||||
OS << "#endif // NDEBUG\n";
|
||||
}
|
||||
|
||||
static std::string
|
||||
getNameForFeatureBitset(const std::vector<Record *> &FeatureBitset) {
|
||||
std::string Name = "AMFBS";
|
||||
for (const auto &Feature : FeatureBitset)
|
||||
Name += ("_" + Feature->getName()).str();
|
||||
return Name;
|
||||
}
|
||||
|
||||
void AsmMatcherEmitter::run(raw_ostream &OS) {
|
||||
CodeGenTarget Target(Records);
|
||||
Record *AsmParser = Target.getAsmParser();
|
||||
@ -3174,7 +3187,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
|
||||
OS << "#undef GET_ASSEMBLER_HEADER\n";
|
||||
OS << " // This should be included into the middle of the declaration of\n";
|
||||
OS << " // your subclasses implementation of MCTargetAsmParser.\n";
|
||||
OS << " uint64_t ComputeAvailableFeatures(const FeatureBitset& FB) const;\n";
|
||||
OS << " FeatureBitset ComputeAvailableFeatures(const FeatureBitset& FB) const;\n";
|
||||
if (HasOptionalOperands) {
|
||||
OS << " void convertToMCInst(unsigned Kind, MCInst &Inst, "
|
||||
<< "unsigned Opcode,\n"
|
||||
@ -3192,9 +3205,21 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
|
||||
if (ReportMultipleNearMisses)
|
||||
OS << " SmallVectorImpl<NearMissInfo> *NearMisses,\n";
|
||||
else
|
||||
OS << " uint64_t &ErrorInfo,\n";
|
||||
OS << " uint64_t &ErrorInfo,\n"
|
||||
<< " FeatureBitset &MissingFeatures,\n";
|
||||
OS << " bool matchingInlineAsm,\n"
|
||||
<< " unsigned VariantID = 0);\n";
|
||||
if (!ReportMultipleNearMisses)
|
||||
OS << " unsigned MatchInstructionImpl(const OperandVector &Operands,\n"
|
||||
<< " MCInst &Inst,\n"
|
||||
<< " uint64_t &ErrorInfo,\n"
|
||||
<< " bool matchingInlineAsm,\n"
|
||||
<< " unsigned VariantID = 0) {\n"
|
||||
<< " FeatureBitset MissingFeatures;\n"
|
||||
<< " return MatchInstructionImpl(Operands, Inst, ErrorInfo, MissingFeatures,\n"
|
||||
<< " matchingInlineAsm, VariantID);\n"
|
||||
<< " }\n\n";
|
||||
|
||||
|
||||
if (!Info.OperandMatchInfo.empty()) {
|
||||
OS << " OperandMatchResultTy MatchOperandParserImpl(\n";
|
||||
@ -3219,7 +3244,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
|
||||
OS << "#undef GET_REGISTER_MATCHER\n\n";
|
||||
|
||||
// Emit the subtarget feature enumeration.
|
||||
SubtargetFeatureInfo::emitSubtargetFeatureFlagEnumeration(
|
||||
SubtargetFeatureInfo::emitSubtargetFeatureBitEnumeration(
|
||||
Info.SubtargetFeatures, OS);
|
||||
|
||||
// Emit the function to match a register name to number.
|
||||
@ -3300,6 +3325,56 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
|
||||
StringTable.EmitString(OS);
|
||||
OS << ";\n\n";
|
||||
|
||||
std::vector<std::vector<Record *>> FeatureBitsets;
|
||||
for (const auto &MI : Info.Matchables) {
|
||||
if (MI->RequiredFeatures.empty())
|
||||
continue;
|
||||
FeatureBitsets.emplace_back();
|
||||
for (unsigned I = 0, E = MI->RequiredFeatures.size(); I != E; ++I)
|
||||
FeatureBitsets.back().push_back(MI->RequiredFeatures[I]->TheDef);
|
||||
}
|
||||
|
||||
llvm::sort(FeatureBitsets, [&](const std::vector<Record *> &A,
|
||||
const std::vector<Record *> &B) {
|
||||
if (A.size() < B.size())
|
||||
return true;
|
||||
if (A.size() > B.size())
|
||||
return false;
|
||||
for (const auto &Pair : zip(A, B)) {
|
||||
if (std::get<0>(Pair)->getName() < std::get<1>(Pair)->getName())
|
||||
return true;
|
||||
if (std::get<0>(Pair)->getName() > std::get<1>(Pair)->getName())
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
FeatureBitsets.erase(
|
||||
std::unique(FeatureBitsets.begin(), FeatureBitsets.end()),
|
||||
FeatureBitsets.end());
|
||||
OS << "// Feature bitsets.\n"
|
||||
<< "enum : " << getMinimalTypeForRange(FeatureBitsets.size()) << " {\n"
|
||||
<< " AMFBS_None,\n";
|
||||
for (const auto &FeatureBitset : FeatureBitsets) {
|
||||
if (FeatureBitset.empty())
|
||||
continue;
|
||||
OS << " " << getNameForFeatureBitset(FeatureBitset) << ",\n";
|
||||
}
|
||||
OS << "};\n\n"
|
||||
<< "const static FeatureBitset FeatureBitsets[] {\n"
|
||||
<< " {}, // AMFBS_None\n";
|
||||
for (const auto &FeatureBitset : FeatureBitsets) {
|
||||
if (FeatureBitset.empty())
|
||||
continue;
|
||||
OS << " {";
|
||||
for (const auto &Feature : FeatureBitset) {
|
||||
const auto &I = Info.SubtargetFeatures.find(Feature);
|
||||
assert(I != Info.SubtargetFeatures.end() && "Didn't import predicate?");
|
||||
OS << I->second.getEnumBitName() << ", ";
|
||||
}
|
||||
OS << "},\n";
|
||||
}
|
||||
OS << "};\n\n";
|
||||
|
||||
// Emit the static match table; unused classes get initialized to 0 which is
|
||||
// guaranteed to be InvalidMatchClass.
|
||||
//
|
||||
@ -3317,8 +3392,8 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
|
||||
OS << " uint16_t Opcode;\n";
|
||||
OS << " " << getMinimalTypeForRange(Info.Matchables.size())
|
||||
<< " ConvertFn;\n";
|
||||
OS << " " << getMinimalTypeForEnumBitfield(Info.SubtargetFeatures.size())
|
||||
<< " RequiredFeatures;\n";
|
||||
OS << " " << getMinimalTypeForRange(FeatureBitsets.size())
|
||||
<< " RequiredFeaturesIdx;\n";
|
||||
OS << " " << getMinimalTypeForRange(
|
||||
std::distance(Info.Classes.begin(), Info.Classes.end()))
|
||||
<< " Classes[" << MaxNumOperands << "];\n";
|
||||
@ -3363,13 +3438,12 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
|
||||
<< MI->ConversionFnKind << ", ";
|
||||
|
||||
// Write the required features mask.
|
||||
if (!MI->RequiredFeatures.empty()) {
|
||||
for (unsigned i = 0, e = MI->RequiredFeatures.size(); i != e; ++i) {
|
||||
if (i) OS << "|";
|
||||
OS << MI->RequiredFeatures[i]->getEnumName();
|
||||
}
|
||||
} else
|
||||
OS << "0";
|
||||
OS << "AMFBS";
|
||||
if (MI->RequiredFeatures.empty())
|
||||
OS << "_None";
|
||||
else
|
||||
for (unsigned i = 0, e = MI->RequiredFeatures.size(); i != e; ++i)
|
||||
OS << '_' << MI->RequiredFeatures[i]->TheDef->getName();
|
||||
|
||||
OS << ", { ";
|
||||
for (unsigned i = 0, e = MI->AsmOperands.size(); i != e; ++i) {
|
||||
@ -3394,7 +3468,8 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
|
||||
if (ReportMultipleNearMisses)
|
||||
OS << " SmallVectorImpl<NearMissInfo> *NearMisses,\n";
|
||||
else
|
||||
OS << " uint64_t &ErrorInfo,\n";
|
||||
OS << " uint64_t &ErrorInfo,\n"
|
||||
<< " FeatureBitset &MissingFeatures,\n";
|
||||
OS << " bool matchingInlineAsm, unsigned VariantID) {\n";
|
||||
|
||||
if (!ReportMultipleNearMisses) {
|
||||
@ -3409,7 +3484,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
|
||||
|
||||
// Emit code to get the available features.
|
||||
OS << " // Get the current feature set.\n";
|
||||
OS << " uint64_t AvailableFeatures = getAvailableFeatures();\n\n";
|
||||
OS << " const FeatureBitset &AvailableFeatures = getAvailableFeatures();\n\n";
|
||||
|
||||
OS << " // Get the instruction mnemonic, which is the first token.\n";
|
||||
if (HasMnemonicFirst) {
|
||||
@ -3433,7 +3508,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
|
||||
OS << " bool HadMatchOtherThanFeatures = false;\n";
|
||||
OS << " bool HadMatchOtherThanPredicate = false;\n";
|
||||
OS << " unsigned RetCode = Match_InvalidOperand;\n";
|
||||
OS << " uint64_t MissingFeatures = ~0ULL;\n";
|
||||
OS << " MissingFeatures.set();\n";
|
||||
OS << " // Set ErrorInfo to the operand that mismatches if it is\n";
|
||||
OS << " // wrong for all instances of the instruction.\n";
|
||||
OS << " ErrorInfo = ~0ULL;\n";
|
||||
@ -3479,9 +3554,10 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
|
||||
OS << " for (const MatchEntry *it = MnemonicRange.first, "
|
||||
<< "*ie = MnemonicRange.second;\n";
|
||||
OS << " it != ie; ++it) {\n";
|
||||
OS << " const FeatureBitset &RequiredFeatures = "
|
||||
"FeatureBitsets[it->RequiredFeaturesIdx];\n";
|
||||
OS << " bool HasRequiredFeatures =\n";
|
||||
OS << " (AvailableFeatures & it->RequiredFeatures) == "
|
||||
"it->RequiredFeatures;\n";
|
||||
OS << " (AvailableFeatures & RequiredFeatures) == RequiredFeatures;\n";
|
||||
OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \"Trying to match opcode \"\n";
|
||||
OS << " << MII.getName(it->Opcode) << \"\\n\");\n";
|
||||
|
||||
@ -3640,16 +3716,18 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
|
||||
OS << " if (!HasRequiredFeatures) {\n";
|
||||
if (!ReportMultipleNearMisses)
|
||||
OS << " HadMatchOtherThanFeatures = true;\n";
|
||||
OS << " uint64_t NewMissingFeatures = it->RequiredFeatures & "
|
||||
OS << " FeatureBitset NewMissingFeatures = RequiredFeatures & "
|
||||
"~AvailableFeatures;\n";
|
||||
OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \"Missing target features: \"\n";
|
||||
OS << " << format_hex(NewMissingFeatures, 18)\n";
|
||||
OS << " << \"\\n\");\n";
|
||||
OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \"Missing target features:\";\n";
|
||||
OS << " for (unsigned I = 0, E = NewMissingFeatures.size(); I != E; ++I)\n";
|
||||
OS << " if (NewMissingFeatures[I])\n";
|
||||
OS << " dbgs() << ' ' << I;\n";
|
||||
OS << " dbgs() << \"\\n\");\n";
|
||||
if (ReportMultipleNearMisses) {
|
||||
OS << " FeaturesNearMiss = NearMissInfo::getMissedFeature(NewMissingFeatures);\n";
|
||||
} else {
|
||||
OS << " if (countPopulation(NewMissingFeatures) <=\n"
|
||||
" countPopulation(MissingFeatures))\n";
|
||||
OS << " if (NewMissingFeatures.count() <=\n"
|
||||
" MissingFeatures.count())\n";
|
||||
OS << " MissingFeatures = NewMissingFeatures;\n";
|
||||
OS << " continue;\n";
|
||||
}
|
||||
@ -3804,15 +3882,15 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
|
||||
OS << " // Okay, we had no match. Try to return a useful error code.\n";
|
||||
OS << " if (HadMatchOtherThanPredicate || !HadMatchOtherThanFeatures)\n";
|
||||
OS << " return RetCode;\n\n";
|
||||
OS << " // Missing feature matches return which features were missing\n";
|
||||
OS << " ErrorInfo = MissingFeatures;\n";
|
||||
OS << " ErrorInfo = 0;\n";
|
||||
OS << " return Match_MissingFeature;\n";
|
||||
}
|
||||
OS << "}\n\n";
|
||||
|
||||
if (!Info.OperandMatchInfo.empty())
|
||||
emitCustomOperandParsing(OS, Target, Info, ClassName, StringTable,
|
||||
MaxMnemonicIndex, HasMnemonicFirst);
|
||||
MaxMnemonicIndex, FeatureBitsets.size(),
|
||||
HasMnemonicFirst);
|
||||
|
||||
OS << "#endif // GET_MATCHER_IMPLEMENTATION\n\n";
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "CodeGenInstruction.h"
|
||||
#include "CodeGenTarget.h"
|
||||
#include "SubtargetFeatureInfo.h"
|
||||
#include "Types.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
@ -228,6 +229,14 @@ std::string CodeEmitterGen::getInstructionCase(Record *R,
|
||||
return Case;
|
||||
}
|
||||
|
||||
static std::string
|
||||
getNameForFeatureBitset(const std::vector<Record *> &FeatureBitset) {
|
||||
std::string Name = "CEFBS";
|
||||
for (const auto &Feature : FeatureBitset)
|
||||
Name += ("_" + Feature->getName()).str();
|
||||
return Name;
|
||||
}
|
||||
|
||||
void CodeEmitterGen::run(raw_ostream &o) {
|
||||
CodeGenTarget Target(Records);
|
||||
std::vector<Record*> Insts = Records.getAllDerivedDefinitions("Instruction");
|
||||
@ -326,8 +335,8 @@ void CodeEmitterGen::run(raw_ostream &o) {
|
||||
<< "#include <sstream>\n\n";
|
||||
|
||||
// Emit the subtarget feature enumeration.
|
||||
SubtargetFeatureInfo::emitSubtargetFeatureFlagEnumeration(SubtargetFeatures,
|
||||
o);
|
||||
SubtargetFeatureInfo::emitSubtargetFeatureBitEnumeration(SubtargetFeatures,
|
||||
o);
|
||||
|
||||
// Emit the name table for error messages.
|
||||
o << "#ifndef NDEBUG\n";
|
||||
@ -339,35 +348,97 @@ void CodeEmitterGen::run(raw_ostream &o) {
|
||||
Target.getName(), "MCCodeEmitter", "computeAvailableFeatures",
|
||||
SubtargetFeatures, o);
|
||||
|
||||
// Emit the predicate verifier.
|
||||
o << "void " << Target.getName()
|
||||
<< "MCCodeEmitter::verifyInstructionPredicates(\n"
|
||||
<< " const MCInst &Inst, uint64_t AvailableFeatures) const {\n"
|
||||
<< "#ifndef NDEBUG\n"
|
||||
<< " static uint64_t RequiredFeatures[] = {\n";
|
||||
unsigned InstIdx = 0;
|
||||
std::vector<std::vector<Record *>> FeatureBitsets;
|
||||
for (const CodeGenInstruction *Inst : Target.getInstructionsByEnumValue()) {
|
||||
o << " ";
|
||||
FeatureBitsets.emplace_back();
|
||||
for (Record *Predicate : Inst->TheDef->getValueAsListOfDefs("Predicates")) {
|
||||
const auto &I = SubtargetFeatures.find(Predicate);
|
||||
if (I != SubtargetFeatures.end())
|
||||
o << I->second.getEnumName() << " | ";
|
||||
FeatureBitsets.back().push_back(I->second.TheDef);
|
||||
}
|
||||
o << "0, // " << Inst->TheDef->getName() << " = " << InstIdx << "\n";
|
||||
}
|
||||
|
||||
llvm::sort(FeatureBitsets, [&](const std::vector<Record *> &A,
|
||||
const std::vector<Record *> &B) {
|
||||
if (A.size() < B.size())
|
||||
return true;
|
||||
if (A.size() > B.size())
|
||||
return false;
|
||||
for (const auto &Pair : zip(A, B)) {
|
||||
if (std::get<0>(Pair)->getName() < std::get<1>(Pair)->getName())
|
||||
return true;
|
||||
if (std::get<0>(Pair)->getName() > std::get<1>(Pair)->getName())
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
FeatureBitsets.erase(
|
||||
std::unique(FeatureBitsets.begin(), FeatureBitsets.end()),
|
||||
FeatureBitsets.end());
|
||||
o << "#ifndef NDEBUG\n"
|
||||
<< "// Feature bitsets.\n"
|
||||
<< "enum : " << getMinimalTypeForRange(FeatureBitsets.size()) << " {\n"
|
||||
<< " CEFBS_None,\n";
|
||||
for (const auto &FeatureBitset : FeatureBitsets) {
|
||||
if (FeatureBitset.empty())
|
||||
continue;
|
||||
o << " " << getNameForFeatureBitset(FeatureBitset) << ",\n";
|
||||
}
|
||||
o << "};\n\n"
|
||||
<< "const static FeatureBitset FeatureBitsets[] {\n"
|
||||
<< " {}, // CEFBS_None\n";
|
||||
for (const auto &FeatureBitset : FeatureBitsets) {
|
||||
if (FeatureBitset.empty())
|
||||
continue;
|
||||
o << " {";
|
||||
for (const auto &Feature : FeatureBitset) {
|
||||
const auto &I = SubtargetFeatures.find(Feature);
|
||||
assert(I != SubtargetFeatures.end() && "Didn't import predicate?");
|
||||
o << I->second.getEnumBitName() << ", ";
|
||||
}
|
||||
o << "},\n";
|
||||
}
|
||||
o << "};\n"
|
||||
<< "#endif // NDEBUG\n\n";
|
||||
|
||||
|
||||
// Emit the predicate verifier.
|
||||
o << "void " << Target.getName()
|
||||
<< "MCCodeEmitter::verifyInstructionPredicates(\n"
|
||||
<< " const MCInst &Inst, const FeatureBitset &AvailableFeatures) const {\n"
|
||||
<< "#ifndef NDEBUG\n"
|
||||
<< " static " << getMinimalTypeForRange(FeatureBitsets.size())
|
||||
<< " RequiredFeaturesRefs[] = {\n";
|
||||
unsigned InstIdx = 0;
|
||||
for (const CodeGenInstruction *Inst : Target.getInstructionsByEnumValue()) {
|
||||
o << " CEFBS";
|
||||
unsigned NumPredicates = 0;
|
||||
for (Record *Predicate : Inst->TheDef->getValueAsListOfDefs("Predicates")) {
|
||||
const auto &I = SubtargetFeatures.find(Predicate);
|
||||
if (I != SubtargetFeatures.end()) {
|
||||
o << '_' << I->second.TheDef->getName();
|
||||
NumPredicates++;
|
||||
}
|
||||
}
|
||||
if (!NumPredicates)
|
||||
o << "_None";
|
||||
o << ", // " << Inst->TheDef->getName() << " = " << InstIdx << "\n";
|
||||
InstIdx++;
|
||||
}
|
||||
o << " };\n\n";
|
||||
o << " assert(Inst.getOpcode() < " << InstIdx << ");\n";
|
||||
o << " uint64_t MissingFeatures =\n"
|
||||
<< " (AvailableFeatures & RequiredFeatures[Inst.getOpcode()]) ^\n"
|
||||
<< " RequiredFeatures[Inst.getOpcode()];\n"
|
||||
<< " if (MissingFeatures) {\n"
|
||||
o << " const FeatureBitset &RequiredFeatures = "
|
||||
"FeatureBitsets[RequiredFeaturesRefs[Inst.getOpcode()]];\n";
|
||||
o << " FeatureBitset MissingFeatures =\n"
|
||||
<< " (AvailableFeatures & RequiredFeatures) ^\n"
|
||||
<< " RequiredFeatures;\n"
|
||||
<< " if (MissingFeatures.any()) {\n"
|
||||
<< " std::ostringstream Msg;\n"
|
||||
<< " Msg << \"Attempting to emit \" << "
|
||||
"MCII.getName(Inst.getOpcode()).str()\n"
|
||||
<< " << \" instruction but the \";\n"
|
||||
<< " for (unsigned i = 0; i < 8 * sizeof(MissingFeatures); ++i)\n"
|
||||
<< " if (MissingFeatures & (1ULL << i))\n"
|
||||
<< " for (unsigned i = 0, e = MissingFeatures.size(); i != e; ++i)\n"
|
||||
<< " if (MissingFeatures.test(i))\n"
|
||||
<< " Msg << SubtargetFeatureNames[i] << \" \";\n"
|
||||
<< " Msg << \"predicate(s) are not met\";\n"
|
||||
<< " report_fatal_error(Msg.str());\n"
|
||||
|
@ -44,20 +44,6 @@ SubtargetFeatureInfo::getAll(const RecordKeeper &Records) {
|
||||
return SubtargetFeatures;
|
||||
}
|
||||
|
||||
void SubtargetFeatureInfo::emitSubtargetFeatureFlagEnumeration(
|
||||
SubtargetFeatureInfoMap &SubtargetFeatures, raw_ostream &OS) {
|
||||
OS << "// Flags for subtarget features that participate in "
|
||||
<< "instruction matching.\n";
|
||||
OS << "enum SubtargetFeatureFlag : "
|
||||
<< getMinimalTypeForEnumBitfield(SubtargetFeatures.size()) << " {\n";
|
||||
for (const auto &SF : SubtargetFeatures) {
|
||||
const SubtargetFeatureInfo &SFI = SF.second;
|
||||
OS << " " << SFI.getEnumName() << " = (1ULL << " << SFI.Index << "),\n";
|
||||
}
|
||||
OS << " Feature_None = 0\n";
|
||||
OS << "};\n\n";
|
||||
}
|
||||
|
||||
void SubtargetFeatureInfo::emitSubtargetFeatureBitEnumeration(
|
||||
SubtargetFeatureInfoMap &SubtargetFeatures, raw_ostream &OS) {
|
||||
OS << "// Bits for subtarget features that participate in "
|
||||
@ -120,9 +106,9 @@ void SubtargetFeatureInfo::emitComputeAvailableFeatures(
|
||||
void SubtargetFeatureInfo::emitComputeAssemblerAvailableFeatures(
|
||||
StringRef TargetName, StringRef ClassName, StringRef FuncName,
|
||||
SubtargetFeatureInfoMap &SubtargetFeatures, raw_ostream &OS) {
|
||||
OS << "uint64_t " << TargetName << ClassName << "::\n"
|
||||
OS << "FeatureBitset " << TargetName << ClassName << "::\n"
|
||||
<< FuncName << "(const FeatureBitset& FB) const {\n";
|
||||
OS << " uint64_t Features = 0;\n";
|
||||
OS << " FeatureBitset Features;\n";
|
||||
for (const auto &SF : SubtargetFeatures) {
|
||||
const SubtargetFeatureInfo &SFI = SF.second;
|
||||
|
||||
@ -156,7 +142,7 @@ void SubtargetFeatureInfo::emitComputeAssemblerAvailableFeatures(
|
||||
} while (true);
|
||||
|
||||
OS << ")\n";
|
||||
OS << " Features |= " << SFI.getEnumName() << ";\n";
|
||||
OS << " Features[" << SFI.getEnumBitName() << "] = 1;\n";
|
||||
}
|
||||
OS << " return Features;\n";
|
||||
OS << "}\n\n";
|
||||
|
@ -53,13 +53,6 @@ struct SubtargetFeatureInfo {
|
||||
static std::vector<std::pair<Record *, SubtargetFeatureInfo>>
|
||||
getAll(const RecordKeeper &Records);
|
||||
|
||||
/// Emit the subtarget feature flag definitions.
|
||||
///
|
||||
/// This version emits the bit value for the feature and is therefore limited
|
||||
/// to 64 feature bits.
|
||||
static void emitSubtargetFeatureFlagEnumeration(
|
||||
SubtargetFeatureInfoMap &SubtargetFeatures, raw_ostream &OS);
|
||||
|
||||
/// Emit the subtarget feature flag definitions.
|
||||
///
|
||||
/// This version emits the bit index for the feature and can therefore support
|
||||
|
Loading…
Reference in New Issue
Block a user