Index: lib/Target/AArch64/MCTargetDesc/AArch64MCCodeEmitter.cpp =================================================================== --- lib/Target/AArch64/MCTargetDesc/AArch64MCCodeEmitter.cpp +++ lib/Target/AArch64/MCTargetDesc/AArch64MCCodeEmitter.cpp @@ -170,6 +170,11 @@ unsigned fixOneOperandFPComparison(const MCInst &MI, unsigned EncodedValue, const MCSubtargetInfo &STI) const; + +private: + uint64_t ComputeAvailableFeatures(const FeatureBitset &FB) const; + void verifyInstructionPredicates(const MCInst &MI, + uint64_t AvailableFeatures) const; }; } // end anonymous namespace @@ -547,6 +552,9 @@ void AArch64MCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const { + verifyInstructionPredicates(MI, + ComputeAvailableFeatures(STI.getFeatureBits())); + if (MI.getOpcode() == AArch64::TLSDESCCALL) { // This is a directive which applies an R_AARCH64_TLSDESC_CALL to the // following (BLR) instruction. It doesn't emit any code itself so it @@ -589,4 +597,5 @@ return EncodedValue; } +#define ENABLE_INSTR_PREDICATE_VERIFIER #include "AArch64GenMCCodeEmitter.inc" Index: lib/Target/AMDGPU/MCTargetDesc/AMDGPUMCCodeEmitter.h =================================================================== --- lib/Target/AMDGPU/MCTargetDesc/AMDGPUMCCodeEmitter.h +++ lib/Target/AMDGPU/MCTargetDesc/AMDGPUMCCodeEmitter.h @@ -23,6 +23,7 @@ class MCInst; class MCOperand; class MCSubtargetInfo; +class FeatureBitset; class AMDGPUMCCodeEmitter : public MCCodeEmitter { virtual void anchor(); @@ -43,6 +44,11 @@ const MCSubtargetInfo &STI) const { return 0; } + +protected: + uint64_t ComputeAvailableFeatures(const FeatureBitset &FB) const; + void verifyInstructionPredicates(const MCInst &MI, + uint64_t AvailableFeatures) const; }; } // End namespace llvm Index: lib/Target/AMDGPU/MCTargetDesc/R600MCCodeEmitter.cpp =================================================================== --- lib/Target/AMDGPU/MCTargetDesc/R600MCCodeEmitter.cpp +++ lib/Target/AMDGPU/MCTargetDesc/R600MCCodeEmitter.cpp @@ -86,6 +86,9 @@ void R600MCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const { + verifyInstructionPredicates(MI, + ComputeAvailableFeatures(STI.getFeatureBits())); + const MCInstrDesc &Desc = MCII.get(MI.getOpcode()); if (MI.getOpcode() == AMDGPU::RETURN || MI.getOpcode() == AMDGPU::FETCH_CLAUSE || @@ -178,4 +181,5 @@ return MO.getImm(); } +#define ENABLE_INSTR_PREDICATE_VERIFIER #include "AMDGPUGenMCCodeEmitter.inc" Index: lib/Target/AMDGPU/MCTargetDesc/SIMCCodeEmitter.cpp =================================================================== --- lib/Target/AMDGPU/MCTargetDesc/SIMCCodeEmitter.cpp +++ lib/Target/AMDGPU/MCTargetDesc/SIMCCodeEmitter.cpp @@ -190,6 +190,8 @@ void SIMCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const { + verifyInstructionPredicates(MI, + ComputeAvailableFeatures(STI.getFeatureBits())); uint64_t Encoding = getBinaryCodeForInstr(MI, Fixups, STI); const MCInstrDesc &Desc = MCII.get(MI.getOpcode()); Index: lib/Target/AMDGPU/VOP1Instructions.td =================================================================== --- lib/Target/AMDGPU/VOP1Instructions.td +++ lib/Target/AMDGPU/VOP1Instructions.td @@ -536,6 +536,7 @@ PseudoInstExpansion<(V_MOV_B32_e32_vi getVALUDstForVT.ret:$vdst, getVOPSrc0ForVT.ret:$src0)> { let VOP1 = 1; + let SubtargetPredicate = isGCN; } let Predicates = [isVI] in { Index: lib/Target/BPF/MCTargetDesc/BPFMCCodeEmitter.cpp =================================================================== --- lib/Target/BPF/MCTargetDesc/BPFMCCodeEmitter.cpp +++ lib/Target/BPF/MCTargetDesc/BPFMCCodeEmitter.cpp @@ -58,6 +58,11 @@ void encodeInstruction(const MCInst &MI, raw_ostream &OS, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const override; + +private: + uint64_t ComputeAvailableFeatures(const FeatureBitset &FB) const; + void verifyInstructionPredicates(const MCInst &MI, + uint64_t AvailableFeatures) const; }; } @@ -108,6 +113,9 @@ void BPFMCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const { + verifyInstructionPredicates(MI, + ComputeAvailableFeatures(STI.getFeatureBits())); + unsigned Opcode = MI.getOpcode(); support::endian::Writer LE(OS); support::endian::Writer BE(OS); @@ -165,4 +173,5 @@ return Encoding; } +#define ENABLE_INSTR_PREDICATE_VERIFIER #include "BPFGenMCCodeEmitter.inc" Index: lib/Target/Hexagon/MCTargetDesc/HexagonMCCodeEmitter.h =================================================================== --- lib/Target/Hexagon/MCTargetDesc/HexagonMCCodeEmitter.h +++ lib/Target/Hexagon/MCTargetDesc/HexagonMCCodeEmitter.h @@ -63,6 +63,11 @@ unsigned getMachineOpValue(MCInst const &MI, MCOperand const &MO, SmallVectorImpl &Fixups, MCSubtargetInfo const &STI) const; + +private: + uint64_t ComputeAvailableFeatures(const FeatureBitset &FB) const; + void verifyInstructionPredicates(const MCInst &MI, + uint64_t AvailableFeatures) const; }; // class HexagonMCCodeEmitter } // namespace llvm Index: lib/Target/Hexagon/MCTargetDesc/HexagonMCCodeEmitter.cpp =================================================================== --- lib/Target/Hexagon/MCTargetDesc/HexagonMCCodeEmitter.cpp +++ lib/Target/Hexagon/MCTargetDesc/HexagonMCCodeEmitter.cpp @@ -78,6 +78,9 @@ size_t Last = HexagonMCInstrInfo::bundleSize(HMB) - 1; for (auto &I : HexagonMCInstrInfo::bundleInstructions(HMB)) { MCInst &HMI = const_cast(*I.getInst()); + verifyInstructionPredicates(HMI, + ComputeAvailableFeatures(STI.getFeatureBits())); + EncodeSingleInstruction(HMI, OS, Fixups, STI, parseBits(Instruction, Last, HMB, HMI), Instruction); @@ -817,4 +820,5 @@ return new HexagonMCCodeEmitter(MII, MCT); } +#define ENABLE_INSTR_PREDICATE_VERIFIER #include "HexagonGenMCCodeEmitter.inc" Index: lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp =================================================================== --- lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp +++ lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp @@ -106,6 +106,9 @@ void encodeInstruction(const MCInst &MI, raw_ostream &OS, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const override { + verifyInstructionPredicates(MI, + ComputeAvailableFeatures(STI.getFeatureBits())); + unsigned Opcode = MI.getOpcode(); const MCInstrDesc &Desc = MCII.get(Opcode); @@ -139,7 +142,11 @@ ++MCNumEmitted; // Keep track of the # of mi's emitted. } - + +private: + uint64_t ComputeAvailableFeatures(const FeatureBitset &FB) const; + void verifyInstructionPredicates(const MCInst &MI, + uint64_t AvailableFeatures) const; }; } // end anonymous namespace @@ -377,4 +384,6 @@ } + +#define ENABLE_INSTR_PREDICATE_VERIFIER #include "PPCGenMCCodeEmitter.inc" Index: lib/Target/Sparc/MCTargetDesc/SparcMCCodeEmitter.cpp =================================================================== --- lib/Target/Sparc/MCTargetDesc/SparcMCCodeEmitter.cpp +++ lib/Target/Sparc/MCTargetDesc/SparcMCCodeEmitter.cpp @@ -71,6 +71,10 @@ SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; +private: + uint64_t ComputeAvailableFeatures(const FeatureBitset &FB) const; + void verifyInstructionPredicates(const MCInst &MI, + uint64_t AvailableFeatures) const; }; } // end anonymous namespace @@ -83,6 +87,9 @@ void SparcMCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const { + verifyInstructionPredicates(MI, + ComputeAvailableFeatures(STI.getFeatureBits())); + unsigned Bits = getBinaryCodeForInstr(MI, Fixups, STI); if (Ctx.getAsmInfo()->isLittleEndian()) { @@ -215,6 +222,5 @@ return 0; } - - +#define ENABLE_INSTR_PREDICATE_VERIFIER #include "SparcGenMCCodeEmitter.inc" Index: lib/Target/SystemZ/MCTargetDesc/SystemZMCCodeEmitter.cpp =================================================================== --- lib/Target/SystemZ/MCTargetDesc/SystemZMCCodeEmitter.cpp +++ lib/Target/SystemZ/MCTargetDesc/SystemZMCCodeEmitter.cpp @@ -110,6 +110,11 @@ return getPCRelEncoding(MI, OpNum, Fixups, SystemZ::FK_390_PC32DBL, 2, true); } + +private: + uint64_t ComputeAvailableFeatures(const FeatureBitset &FB) const; + void verifyInstructionPredicates(const MCInst &MI, + uint64_t AvailableFeatures) const; }; } // end anonymous namespace @@ -123,6 +128,9 @@ encodeInstruction(const MCInst &MI, raw_ostream &OS, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const { + verifyInstructionPredicates(MI, + ComputeAvailableFeatures(STI.getFeatureBits())); + uint64_t Bits = getBinaryCodeForInstr(MI, Fixups, STI); unsigned Size = MCII.get(MI.getOpcode()).getSize(); // Big-endian insertion of Size bytes. @@ -240,4 +248,5 @@ return 0; } +#define ENABLE_INSTR_PREDICATE_VERIFIER #include "SystemZGenMCCodeEmitter.inc" Index: utils/TableGen/AsmMatcherEmitter.cpp =================================================================== --- utils/TableGen/AsmMatcherEmitter.cpp +++ utils/TableGen/AsmMatcherEmitter.cpp @@ -1414,6 +1414,7 @@ void AsmMatcherInfo::buildInfo() { // Build information about all of the AssemblerPredicates. + const auto &SubtargetFeaturePairs = SubtargetFeatureInfo::getAll(Records); SubtargetFeatures.insert(SubtargetFeaturePairs.begin(), SubtargetFeaturePairs.end()); @@ -2359,29 +2360,6 @@ 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. @@ -2563,7 +2541,7 @@ // 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"; @@ -2839,7 +2817,8 @@ 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 @@ -2923,7 +2902,7 @@ 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())) Index: utils/TableGen/CodeEmitterGen.cpp =================================================================== --- utils/TableGen/CodeEmitterGen.cpp +++ utils/TableGen/CodeEmitterGen.cpp @@ -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" @@ -307,6 +309,46 @@ << " }\n" << " return Value;\n" << "}\n\n"; + + const auto &All = SubtargetFeatureInfo::getAll(Records); + std::map SubtargetFeatures; + SubtargetFeatures.insert(All.begin(), All.end()); + + o << "#ifdef ENABLE_INSTR_PREDICATE_VERIFIER\n" + "#undef ENABLE_INSTR_PREDICATE_VERIFIER\n"; + + // Emit the subtarget feature enumeration. + SubtargetFeatureInfo::emitSubtargetFeatureFlagEnumeration(SubtargetFeatures, + o); + + // Emit the available features compute function. + SubtargetFeatureInfo::emitComputeAvailableFeatures( + Target.getName(), "MCCodeEmitter", SubtargetFeatures, o); + + // Emit the predicate verifier. + o << "void " << Target.getName() + << "MCCodeEmitter::verifyInstructionPredicates(\n" + << " const MCInst &Inst, uint64_t AvailableFeatures) const {\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"; + o << " assert(Inst.getOpcode() < " << InstIdx << ");\n"; + o << " assert((AvailableFeatures & RequiredFeatures[Inst.getOpcode()])\n" + << " == RequiredFeatures[Inst.getOpcode()] &&\n" + << " \"Attempting to emit an instruction that doesn't satisfy the required\"\n" + << " \"features\");\n"; + o << "}\n"; + o << "#endif\n"; } } // End anonymous namespace Index: utils/TableGen/SubtargetFeatureInfo.h =================================================================== --- utils/TableGen/SubtargetFeatureInfo.h +++ utils/TableGen/SubtargetFeatureInfo.h @@ -14,6 +14,8 @@ #include "llvm/TableGen/Record.h" #include +#include +#include namespace llvm { class Record; @@ -37,6 +39,12 @@ static std::vector> getAll(const RecordKeeper &Records); + /// Emit the subtarget feature flag definitions. + static void emitSubtargetFeatureFlagEnumeration( + std::map + &SubtargetFeatures, + raw_ostream &OS); + /// Emit the function to compute the list of available features given a /// subtarget. static void emitComputeAvailableFeatures( Index: utils/TableGen/SubtargetFeatureInfo.cpp =================================================================== --- utils/TableGen/SubtargetFeatureInfo.cpp +++ utils/TableGen/SubtargetFeatureInfo.cpp @@ -9,6 +9,7 @@ #include "SubtargetFeatureInfo.h" +#include "Types.h" #include "llvm/TableGen/Record.h" #include @@ -39,6 +40,21 @@ return SubtargetFeatures; } +void SubtargetFeatureInfo::emitSubtargetFeatureFlagEnumeration( + std::map &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::emitComputeAvailableFeatures( std::string TargetName, std::string ClassName, std::map &SubtargetFeatures, Index: utils/TableGen/Types.h =================================================================== --- utils/TableGen/Types.h +++ utils/TableGen/Types.h @@ -17,6 +17,9 @@ /// 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 Index: utils/TableGen/Types.cpp =================================================================== --- utils/TableGen/Types.cpp +++ utils/TableGen/Types.cpp @@ -26,3 +26,10 @@ 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); +}