108 changes: 55 additions & 53 deletions llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -10478,43 +10479,40 @@ 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;
FeatureMissesSeen.insert(MissingFeatures);

// 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;
Message.Loc = IDLoc;
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;
Expand Down Expand Up @@ -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))
Expand Down Expand Up @@ -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;
Expand Down
7 changes: 4 additions & 3 deletions llvm/lib/Target/BPF/MCTargetDesc/BPFMCCodeEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,10 @@ class BPFMCCodeEmitter : public MCCodeEmitter {
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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down
7 changes: 4 additions & 3 deletions llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCCodeEmitter.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,10 @@ class HexagonMCCodeEmitter : public MCCodeEmitter {
// 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
Expand Down
4 changes: 2 additions & 2 deletions llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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);
}
Expand Down
4 changes: 2 additions & 2 deletions llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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,
Expand Down
7 changes: 4 additions & 3 deletions llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,10 @@ class PPCMCCodeEmitter : public MCCodeEmitter {
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
Expand Down
3 changes: 2 additions & 1 deletion llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
7 changes: 4 additions & 3 deletions llvm/lib/Target/Sparc/MCTargetDesc/SparcMCCodeEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,10 @@ class SparcMCCodeEmitter : public MCCodeEmitter {
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
Expand Down
24 changes: 13 additions & 11 deletions llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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,
Expand All @@ -1243,26 +1246,25 @@ 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);
Out.EmitInstruction(Inst, getSTI());
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);
}
Expand All @@ -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,
Expand Down
7 changes: 4 additions & 3 deletions llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCCodeEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -143,9 +143,10 @@ class SystemZMCCodeEmitter : public MCCodeEmitter {
}

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
Expand Down
64 changes: 35 additions & 29 deletions llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,13 +89,14 @@ class X86AsmParser : public MCTargetAsmParser {
}

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;
Expand Down Expand Up @@ -874,7 +875,7 @@ class X86AsmParser : public MCTargetAsmParser {
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,
Expand Down Expand Up @@ -913,7 +914,7 @@ class X86AsmParser : public MCTargetAsmParser {
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);

Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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))
Expand All @@ -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;
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -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.
Expand All @@ -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);
}
Expand All @@ -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.
Expand All @@ -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.
Expand All @@ -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;

Expand Down Expand Up @@ -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);
}

Expand Down
200 changes: 139 additions & 61 deletions llvm/utils/TableGen/AsmMatcherEmitter.cpp

Large diffs are not rendered by default.

99 changes: 85 additions & 14 deletions llvm/utils/TableGen/CodeEmitterGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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";
Expand All @@ -339,35 +348,97 @@ void CodeEmitterGen::run(raw_ostream &o) {
Target.getName(), "MCCodeEmitter", "computeAvailableFeatures",
SubtargetFeatures, o);

std::vector<std::vector<Record *>> FeatureBitsets;
for (const CodeGenInstruction *Inst : Target.getInstructionsByEnumValue()) {
FeatureBitsets.emplace_back();
for (Record *Predicate : Inst->TheDef->getValueAsListOfDefs("Predicates")) {
const auto &I = SubtargetFeatures.find(Predicate);
if (I != SubtargetFeatures.end())
FeatureBitsets.back().push_back(I->second.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());
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, uint64_t AvailableFeatures) const {\n"
<< " const MCInst &Inst, const FeatureBitset &AvailableFeatures) const {\n"
<< "#ifndef NDEBUG\n"
<< " static uint64_t RequiredFeatures[] = {\n";
<< " static " << getMinimalTypeForRange(FeatureBitsets.size())
<< " RequiredFeaturesRefs[] = {\n";
unsigned InstIdx = 0;
for (const CodeGenInstruction *Inst : Target.getInstructionsByEnumValue()) {
o << " ";
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.getEnumName() << " | ";
if (I != SubtargetFeatures.end()) {
o << '_' << I->second.TheDef->getName();
NumPredicates++;
}
}
o << "0, // " << Inst->TheDef->getName() << " = " << InstIdx << "\n";
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"
Expand Down
20 changes: 3 additions & 17 deletions llvm/utils/TableGen/SubtargetFeatureInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 "
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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";
Expand Down
7 changes: 0 additions & 7 deletions llvm/utils/TableGen/SubtargetFeatureInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down