33 changes: 6 additions & 27 deletions llvm/utils/TableGen/AsmMatcherEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2364,29 +2364,6 @@ static void emitMatchRegisterAltName(CodeGenTarget &Target, Record *AsmParser,
OS << "}\n\n";
}

static const char *getMinimalRequiredFeaturesType(const AsmMatcherInfo &Info) {
uint64_t MaxIndex = Info.SubtargetFeatures.size();
if (MaxIndex > 0)
MaxIndex--;
return getMinimalTypeForRange(1ULL << MaxIndex);
}

/// emitSubtargetFeatureFlagEnumeration - Emit the subtarget feature flag
/// definitions.
static void emitSubtargetFeatureFlagEnumeration(AsmMatcherInfo &Info,
raw_ostream &OS) {
OS << "// Flags for subtarget features that participate in "
<< "instruction matching.\n";
OS << "enum SubtargetFeatureFlag : " << getMinimalRequiredFeaturesType(Info)
<< " {\n";
for (const auto &SF : Info.SubtargetFeatures) {
const SubtargetFeatureInfo &SFI = SF.second;
OS << " " << SFI.getEnumName() << " = (1ULL << " << SFI.Index << "),\n";
}
OS << " Feature_None = 0\n";
OS << "};\n\n";
}

/// emitOperandDiagnosticTypes - Emit the operand matching diagnostic types.
static void emitOperandDiagnosticTypes(AsmMatcherInfo &Info, raw_ostream &OS) {
// Get the set of diagnostic types from all of the operand classes.
Expand Down Expand Up @@ -2568,7 +2545,7 @@ static void emitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target,
// Emit the static custom operand parsing table;
OS << "namespace {\n";
OS << " struct OperandMatchEntry {\n";
OS << " " << getMinimalRequiredFeaturesType(Info)
OS << " " << getMinimalTypeForEnumBitfield(Info.SubtargetFeatures.size())
<< " RequiredFeatures;\n";
OS << " " << getMinimalTypeForRange(MaxMnemonicIndex)
<< " Mnemonic;\n";
Expand Down Expand Up @@ -2837,7 +2814,8 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
OS << "#undef GET_REGISTER_MATCHER\n\n";

// Emit the subtarget feature enumeration.
emitSubtargetFeatureFlagEnumeration(Info, OS);
SubtargetFeatureInfo::emitSubtargetFeatureFlagEnumeration(
Info.SubtargetFeatures, OS);

// Emit the function to match a register name to number.
// This should be omitted for Mips target
Expand Down Expand Up @@ -2883,7 +2861,8 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {

// Emit the available features compute function.
SubtargetFeatureInfo::emitComputeAvailableFeatures(
Info.Target.getName(), ClassName, Info.SubtargetFeatures, OS);
Info.Target.getName(), ClassName, "ComputeAvailableFeatures",
Info.SubtargetFeatures, OS);

StringToOffsetTable StringTable;

Expand Down Expand Up @@ -2921,7 +2900,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
OS << " uint16_t Opcode;\n";
OS << " " << getMinimalTypeForRange(Info.Matchables.size())
<< " ConvertFn;\n";
OS << " " << getMinimalRequiredFeaturesType(Info)
OS << " " << getMinimalTypeForEnumBitfield(Info.SubtargetFeatures.size())
<< " RequiredFeatures;\n";
OS << " " << getMinimalTypeForRange(
std::distance(Info.Classes.begin(), Info.Classes.end()))
Expand Down
60 changes: 60 additions & 0 deletions llvm/utils/TableGen/CodeEmitterGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
//===----------------------------------------------------------------------===//

#include "CodeGenTarget.h"
#include "SubtargetFeatureInfo.h"
#include "Types.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/Debug.h"
#include "llvm/TableGen/Record.h"
Expand Down Expand Up @@ -307,6 +309,64 @@ void CodeEmitterGen::run(raw_ostream &o) {
<< " }\n"
<< " return Value;\n"
<< "}\n\n";

const auto &All = SubtargetFeatureInfo::getAll(Records);
std::map<Record *, SubtargetFeatureInfo, LessRecordByID> SubtargetFeatures;
SubtargetFeatures.insert(All.begin(), All.end());

o << "#ifdef ENABLE_INSTR_PREDICATE_VERIFIER\n"
<< "#undef ENABLE_INSTR_PREDICATE_VERIFIER\n"
<< "#include <sstream>\n\n";

// Emit the subtarget feature enumeration.
SubtargetFeatureInfo::emitSubtargetFeatureFlagEnumeration(SubtargetFeatures,
o);

// Emit the name table for error messages.
o << "#ifndef NDEBUG\n";
SubtargetFeatureInfo::emitNameTable(SubtargetFeatures, o);
o << "#endif // NDEBUG\n";

// Emit the available features compute function.
SubtargetFeatureInfo::emitComputeAvailableFeatures(
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;
for (const CodeGenInstruction *Inst : Target.getInstructionsByEnumValue()) {
o << " ";
for (Record *Predicate : Inst->TheDef->getValueAsListOfDefs("Predicates")) {
const auto &I = SubtargetFeatures.find(Predicate);
if (I != SubtargetFeatures.end())
o << I->second.getEnumName() << " | ";
}
o << "0, // " << 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"
<< " 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"
<< " Msg << SubtargetFeatureNames[i] << \" \";\n"
<< " Msg << \"predicate(s) are not met\";\n"
<< " report_fatal_error(Msg.str());\n"
<< " }\n"
<< "#endif // NDEBUG\n";
o << "}\n";
o << "#endif\n";
}

} // End anonymous namespace
Expand Down
34 changes: 32 additions & 2 deletions llvm/utils/TableGen/SubtargetFeatureInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include "SubtargetFeatureInfo.h"

#include "Types.h"
#include "llvm/TableGen/Record.h"

#include <map>
Expand Down Expand Up @@ -42,12 +43,41 @@ SubtargetFeatureInfo::getAll(const RecordKeeper &Records) {
return SubtargetFeatures;
}

void SubtargetFeatureInfo::emitSubtargetFeatureFlagEnumeration(
std::map<Record *, SubtargetFeatureInfo, LessRecordByID> &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::emitNameTable(
std::map<Record *, SubtargetFeatureInfo, LessRecordByID> &SubtargetFeatures,
raw_ostream &OS) {
OS << "static const char *SubtargetFeatureNames[] = {\n";
for (const auto &SF : SubtargetFeatures) {
const SubtargetFeatureInfo &SFI = SF.second;
OS << " \"" << SFI.getEnumName() << "\",\n";
}
// A small number of targets have no predicates. Null terminate the array to
// avoid a zero-length array.
OS << " nullptr\n"
<< "};\n\n";
}

void SubtargetFeatureInfo::emitComputeAvailableFeatures(
StringRef TargetName, StringRef ClassName,
StringRef TargetName, StringRef ClassName, StringRef FuncName,
std::map<Record *, SubtargetFeatureInfo, LessRecordByID> &SubtargetFeatures,
raw_ostream &OS) {
OS << "uint64_t " << TargetName << ClassName << "::\n"
<< "ComputeAvailableFeatures(const FeatureBitset& FB) const {\n";
<< FuncName << "(const FeatureBitset& FB) const {\n";
OS << " uint64_t Features = 0;\n";
for (const auto &SF : SubtargetFeatures) {
const SubtargetFeatureInfo &SFI = SF.second;
Expand Down
15 changes: 14 additions & 1 deletion llvm/utils/TableGen/SubtargetFeatureInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
#include "llvm/TableGen/Record.h"

#include <map>
#include <string>
#include <vector>

namespace llvm {
class Record;
Expand All @@ -37,17 +39,28 @@ struct SubtargetFeatureInfo {
static std::vector<std::pair<Record *, SubtargetFeatureInfo>>
getAll(const RecordKeeper &Records);

/// Emit the subtarget feature flag definitions.
static void emitSubtargetFeatureFlagEnumeration(
std::map<Record *, SubtargetFeatureInfo, LessRecordByID>
&SubtargetFeatures,
raw_ostream &OS);

static void emitNameTable(std::map<Record *, SubtargetFeatureInfo,
LessRecordByID> &SubtargetFeatures,
raw_ostream &OS);

/// Emit the function to compute the list of available features given a
/// subtarget.
///
/// \param TargetName The name of the target as used in class prefixes (e.g.
/// <TargetName>Subtarget)
/// \param ClassName The name of the class (without the <Target> prefix)
/// that will contain the generated functions.
/// \param FuncName The name of the function to emit.
/// \param SubtargetFeatures A map of TableGen records to the
/// SubtargetFeatureInfo equivalent.
static void emitComputeAvailableFeatures(
StringRef TargetName, StringRef ClassName,
StringRef TargetName, StringRef ClassName, StringRef FuncName,
std::map<Record *, SubtargetFeatureInfo, LessRecordByID>
&SubtargetFeatures,
raw_ostream &OS);
Expand Down
7 changes: 7 additions & 0 deletions llvm/utils/TableGen/Types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,10 @@ const char *llvm::getMinimalTypeForRange(uint64_t Range, unsigned MaxSize LLVM_A
return "uint16_t";
return "uint8_t";
}

const char *llvm::getMinimalTypeForEnumBitfield(uint64_t Size) {
uint64_t MaxIndex = Size;
if (MaxIndex > 0)
MaxIndex--;
return getMinimalTypeForRange(1ULL << MaxIndex);
}
3 changes: 3 additions & 0 deletions llvm/utils/TableGen/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ namespace llvm {
/// MaxSize indicates the largest size of integer to consider (in bits) and only
/// supports values of at least 32.
const char *getMinimalTypeForRange(uint64_t Range, unsigned MaxSize = 64);

/// Returns the smallest unsigned integer type that can hold the given bitfield.
const char *getMinimalTypeForEnumBitfield(uint64_t Size);
}

#endif