diff --git a/llvm/tools/llvm-exegesis/lib/AArch64/Target.cpp b/llvm/tools/llvm-exegesis/lib/AArch64/Target.cpp --- a/llvm/tools/llvm-exegesis/lib/AArch64/Target.cpp +++ b/llvm/tools/llvm-exegesis/lib/AArch64/Target.cpp @@ -9,6 +9,9 @@ #include "AArch64.h" #include "AArch64RegisterInfo.h" +#define GET_AVAILABLE_OPCODE_CHECKER +#include "AArch64GenInstrInfo.inc" + namespace llvm { namespace exegesis { @@ -38,7 +41,8 @@ class ExegesisAArch64Target : public ExegesisTarget { public: - ExegesisAArch64Target() : ExegesisTarget(AArch64CpuPfmCounters) {} + ExegesisAArch64Target() + : ExegesisTarget(AArch64CpuPfmCounters, AArch64_MC::isOpcodeAvailable) {} private: std::vector setRegTo(const MCSubtargetInfo &STI, unsigned Reg, diff --git a/llvm/tools/llvm-exegesis/lib/Mips/Target.cpp b/llvm/tools/llvm-exegesis/lib/Mips/Target.cpp --- a/llvm/tools/llvm-exegesis/lib/Mips/Target.cpp +++ b/llvm/tools/llvm-exegesis/lib/Mips/Target.cpp @@ -11,6 +11,9 @@ #include "Mips.h" #include "MipsRegisterInfo.h" +#define GET_AVAILABLE_OPCODE_CHECKER +#include "MipsGenInstrInfo.inc" + namespace llvm { namespace exegesis { @@ -51,7 +54,8 @@ namespace { class ExegesisMipsTarget : public ExegesisTarget { public: - ExegesisMipsTarget() : ExegesisTarget(MipsCpuPfmCounters) {} + ExegesisMipsTarget() + : ExegesisTarget(MipsCpuPfmCounters, Mips_MC::isOpcodeAvailable) {} private: unsigned getScratchMemoryRegister(const llvm::Triple &TT) const override; diff --git a/llvm/tools/llvm-exegesis/lib/PowerPC/Target.cpp b/llvm/tools/llvm-exegesis/lib/PowerPC/Target.cpp --- a/llvm/tools/llvm-exegesis/lib/PowerPC/Target.cpp +++ b/llvm/tools/llvm-exegesis/lib/PowerPC/Target.cpp @@ -10,6 +10,9 @@ #include "PPC.h" #include "PPCRegisterInfo.h" +#define GET_AVAILABLE_OPCODE_CHECKER +#include "PPCGenInstrInfo.inc" + namespace llvm { namespace exegesis { @@ -26,7 +29,8 @@ namespace { class ExegesisPowerPCTarget : public ExegesisTarget { public: - ExegesisPowerPCTarget() : ExegesisTarget(PPCCpuPfmCounters) {} + ExegesisPowerPCTarget() + : ExegesisTarget(PPCCpuPfmCounters, PPC_MC::isOpcodeAvailable) {} private: std::vector setRegTo(const MCSubtargetInfo &STI, unsigned Reg, diff --git a/llvm/tools/llvm-exegesis/lib/SerialSnippetGenerator.cpp b/llvm/tools/llvm-exegesis/lib/SerialSnippetGenerator.cpp --- a/llvm/tools/llvm-exegesis/lib/SerialSnippetGenerator.cpp +++ b/llvm/tools/llvm-exegesis/lib/SerialSnippetGenerator.cpp @@ -38,6 +38,8 @@ computeAliasingInstructions(const LLVMState &State, const Instruction *Instr, size_t MaxAliasingInstructions, const BitVector &ForbiddenRegisters) { + const auto &ET = State.getExegesisTarget(); + const auto AvailableFeatures = State.getSubtargetInfo().getFeatureBits(); // Randomly iterate the set of instructions. std::vector Opcodes; Opcodes.resize(State.getInstrInfo().getNumOpcodes()); @@ -46,6 +48,8 @@ std::vector AliasingInstructions; for (const unsigned OtherOpcode : Opcodes) { + if (!ET.isOpcodeAvailable(OtherOpcode, AvailableFeatures)) + continue; if (OtherOpcode == Instr->Description.getOpcode()) continue; const Instruction &OtherInstr = State.getIC().getInstr(OtherOpcode); @@ -58,7 +62,7 @@ } if (OtherInstr.hasMemoryOperands()) continue; - if (!State.getExegesisTarget().allowAsBackToBack(OtherInstr)) + if (!ET.allowAsBackToBack(OtherInstr)) continue; if (Instr->hasAliasingRegistersThrough(OtherInstr, ForbiddenRegisters)) AliasingInstructions.push_back(&OtherInstr); diff --git a/llvm/tools/llvm-exegesis/lib/Target.h b/llvm/tools/llvm-exegesis/lib/Target.h --- a/llvm/tools/llvm-exegesis/lib/Target.h +++ b/llvm/tools/llvm-exegesis/lib/Target.h @@ -29,6 +29,7 @@ #include "llvm/MC/MCRegisterInfo.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Error.h" +#include "llvm/TargetParser/SubtargetFeature.h" #include "llvm/TargetParser/Triple.h" namespace llvm { @@ -70,8 +71,10 @@ class ExegesisTarget { public: - explicit ExegesisTarget(ArrayRef CpuPfmCounters) - : CpuPfmCounters(CpuPfmCounters) {} + typedef bool (*OpcodeAvailabilityChecker)(unsigned, const FeatureBitset &); + ExegesisTarget(ArrayRef CpuPfmCounters, + OpcodeAvailabilityChecker IsOpcodeAvailable) + : CpuPfmCounters(CpuPfmCounters), IsOpcodeAvailable(IsOpcodeAvailable) {} // Targets can use this to create target-specific perf counters. virtual Expected> @@ -139,6 +142,12 @@ "current architecture\n"); } + // Returns true if all features are available that are required by Opcode. + virtual bool isOpcodeAvailable(unsigned Opcode, + const FeatureBitset &Features) const { + return IsOpcodeAvailable(Opcode, Features); + } + // Sets the stack register to the auxiliary memory so that operations // requiring the stack can be formed (e.g., setting large registers). The code // generated by this function may clobber registers. @@ -304,6 +313,7 @@ const ExegesisTarget *Next = nullptr; const ArrayRef CpuPfmCounters; + const OpcodeAvailabilityChecker IsOpcodeAvailable; }; } // namespace exegesis diff --git a/llvm/tools/llvm-exegesis/lib/Target.cpp b/llvm/tools/llvm-exegesis/lib/Target.cpp --- a/llvm/tools/llvm-exegesis/lib/Target.cpp +++ b/llvm/tools/llvm-exegesis/lib/Target.cpp @@ -14,6 +14,7 @@ #include "UopsBenchmarkRunner.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/Error.h" +#include "llvm/TargetParser/SubtargetFeature.h" namespace llvm { namespace exegesis { @@ -180,10 +181,12 @@ namespace { +bool opcodeIsNotAvailable(unsigned, const FeatureBitset &) { return false; } + // Default implementation. class ExegesisDefaultTarget : public ExegesisTarget { public: - ExegesisDefaultTarget() : ExegesisTarget({}) {} + ExegesisDefaultTarget() : ExegesisTarget({}, opcodeIsNotAvailable) {} private: std::vector setRegTo(const MCSubtargetInfo &STI, unsigned Reg, diff --git a/llvm/tools/llvm-exegesis/lib/X86/Target.cpp b/llvm/tools/llvm-exegesis/lib/X86/Target.cpp --- a/llvm/tools/llvm-exegesis/lib/X86/Target.cpp +++ b/llvm/tools/llvm-exegesis/lib/X86/Target.cpp @@ -43,6 +43,9 @@ #include #endif +#define GET_AVAILABLE_OPCODE_CHECKER +#include "X86GenInstrInfo.inc" + namespace llvm { namespace exegesis { @@ -669,7 +672,8 @@ class ExegesisX86Target : public ExegesisTarget { public: - ExegesisX86Target() : ExegesisTarget(X86CpuPfmCounters) {} + ExegesisX86Target() + : ExegesisTarget(X86CpuPfmCounters, X86_MC::isOpcodeAvailable) {} Expected> createCounter(StringRef CounterName, const LLVMState &State, diff --git a/llvm/tools/llvm-exegesis/llvm-exegesis.cpp b/llvm/tools/llvm-exegesis/llvm-exegesis.cpp --- a/llvm/tools/llvm-exegesis/llvm-exegesis.cpp +++ b/llvm/tools/llvm-exegesis/llvm-exegesis.cpp @@ -291,6 +291,9 @@ const size_t NumSetFlags = (OpcodeNames.empty() ? 0 : 1) + (OpcodeIndex == 0 ? 0 : 1) + (SnippetsFile.empty() ? 0 : 1); + const auto &ET = State.getExegesisTarget(); + const auto AvailableFeatures = State.getSubtargetInfo().getFeatureBits(); + if (NumSetFlags != 1) { ExitOnErr.setBanner("llvm-exegesis: "); ExitWithError("please provide one and only one of 'opcode-index', " @@ -304,8 +307,11 @@ std::vector Result; unsigned NumOpcodes = State.getInstrInfo().getNumOpcodes(); Result.reserve(NumOpcodes); - for (unsigned I = 0, E = NumOpcodes; I < E; ++I) + for (unsigned I = 0, E = NumOpcodes; I < E; ++I) { + if (!ET.isOpcodeAvailable(I, AvailableFeatures)) + continue; Result.push_back(I); + } return Result; } // Resolve opcode name -> opcode. diff --git a/llvm/utils/TableGen/InstrInfoEmitter.cpp b/llvm/utils/TableGen/InstrInfoEmitter.cpp --- a/llvm/utils/TableGen/InstrInfoEmitter.cpp +++ b/llvm/utils/TableGen/InstrInfoEmitter.cpp @@ -733,7 +733,8 @@ std::map SubtargetFeatures; SubtargetFeatures.insert(All.begin(), All.end()); - OS << "#if defined(ENABLE_INSTR_PREDICATE_VERIFIER) && !defined(NDEBUG)\n" + OS << "#if (defined(ENABLE_INSTR_PREDICATE_VERIFIER) && !defined(NDEBUG)) ||\\\n" + << " defined(GET_AVAILABLE_OPCODE_CHECKER)\n" << "#define GET_COMPUTE_FEATURES\n" << "#endif\n"; OS << "#ifdef GET_COMPUTE_FEATURES\n" @@ -826,6 +827,25 @@ << "} // end namespace llvm\n" << "#endif // GET_COMPUTE_FEATURES\n\n"; + OS << "#ifdef GET_AVAILABLE_OPCODE_CHECKER\n" + << "#undef GET_AVAILABLE_OPCODE_CHECKER\n" + << "namespace llvm {\n" + << "namespace " << Target.getName() << "_MC {\n"; + OS << "bool isOpcodeAvailable(" + << "unsigned Opcode, const FeatureBitset &Features) {\n" + << " FeatureBitset AvailableFeatures = " + "computeAvailableFeatures(Features);\n" + << " FeatureBitset RequiredFeatures = " + << "computeRequiredFeatures(Opcode);\n" + << " FeatureBitset MissingFeatures =\n" + << " (AvailableFeatures & RequiredFeatures) ^\n" + << " RequiredFeatures;\n" + << " return !MissingFeatures.any();\n" + << "}\n"; + OS << "} // end namespace " << Target.getName() << "_MC\n" + << "} // end namespace llvm\n" + << "#endif // GET_AVAILABLE_OPCODE_CHECKER\n\n"; + OS << "#ifdef ENABLE_INSTR_PREDICATE_VERIFIER\n" << "#undef ENABLE_INSTR_PREDICATE_VERIFIER\n" << "#include \n\n";