diff --git a/llvm/docs/CommandGuide/llvm-exegesis.rst b/llvm/docs/CommandGuide/llvm-exegesis.rst --- a/llvm/docs/CommandGuide/llvm-exegesis.rst +++ b/llvm/docs/CommandGuide/llvm-exegesis.rst @@ -363,6 +363,13 @@ are to be written, they will have names /path/to/file-OPCODE-REPETITOR.o with `-OPCODE` and `-REPETITOR` parts omitted if always the same. +.. option:: --dump-snippet-file= + + If set, llvm-exegesis will dump the generated snippet (without any repetition + and prologue/epilog code) to an assembler file with the appropriate + `LLVM-EXEGESIS-LIVEIN` and `LLVM-EXEGESIS-DEFREG` directives. If multiple + files are to be written, they will have names /path/to/file-OPCODE.s. + .. option:: --use-dummy-perf-counters If set, llvm-exegesis will not read any real performance counters and diff --git a/llvm/test/tools/llvm-exegesis/X86/latency/dump-snippet-file.s b/llvm/test/tools/llvm-exegesis/X86/latency/dump-snippet-file.s new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-exegesis/X86/latency/dump-snippet-file.s @@ -0,0 +1,87 @@ +# This test requires -debug-only=... command line option. +REQUIRES: asserts + +# Check that nothing is dumped if not requested. + +RUN: llvm-exegesis -mtriple=x86_64-unknown-unknown -mcpu=x86-64 -mode=latency -debug-only=exegesis-name-generator \ +RUN: -opcode-name=ADDPSrr -benchmark-phase=assemble-measured-code 2>&1 \ +RUN: | FileCheck %s --check-prefix=CHECK-OFF + +# An assembler snippet is dumped at any phase if explicitly requested. +# In the below examples, both snippets and yaml data are printed to stdout. + +RUN: llvm-exegesis -mtriple=x86_64-unknown-unknown -mcpu=x86-64 -mode=latency -debug-only=exegesis-name-generator \ +RUN: -dump-snippet-file=- -benchmark-phase=prepare-snippet -opcode-name=ADDPSrr 2>&1 \ +RUN: | FileCheck %s --implicit-check-not="Output file name is" --check-prefix=CHECK-STDOUT-ADDPSrr + +RUN: llvm-exegesis -mtriple=x86_64-unknown-unknown -mcpu=x86-64 -mode=latency -debug-only=exegesis-name-generator \ +RUN: -dump-snippet-file=- -benchmark-phase=prepare-and-assemble-snippet -opcode-name=ADDPSrr 2>&1 \ +RUN: | FileCheck %s --implicit-check-not="Output file name is" --check-prefix=CHECK-STDOUT-ADDPSrr + +RUN: llvm-exegesis -mtriple=x86_64-unknown-unknown -mcpu=x86-64 -mode=latency -debug-only=exegesis-name-generator \ +RUN: -dump-snippet-file=- -benchmark-phase=assemble-measured-code -opcode-name=ADDPSrr 2>&1 \ +RUN: | FileCheck %s --implicit-check-not="Output file name is" --check-prefix=CHECK-STDOUT-ADDPSrr + +# Output file names should be properly computed: they are affected by using multiple opcodes or +# multiple configs per opcode but *not* multiple repetitors. + +RUN: llvm-exegesis -mtriple=x86_64-unknown-unknown -mcpu=x86-64 -mode=latency -debug-only=exegesis-name-generator \ +RUN: -dump-snippet-file=%t-snippet.s -benchmark-phase=prepare-snippet \ +RUN: -opcode-name=ADDPSrr,ADDPDrr -repetition-mode=min 2>&1 \ +RUN: | FileCheck %s --implicit-check-not="Output file name is" --check-prefix=CHECK-FILE-ADDPSrr-ADDPDrr + +RUN: llvm-exegesis -mtriple=x86_64-unknown-unknown -mcpu=x86-64 -mode=latency -debug-only=exegesis-name-generator \ +RUN: -dump-snippet-file=%t-snippet.s -benchmark-phase=prepare-snippet \ +RUN: -opcode-name=SETCCr -max-configs-per-opcode=3 -repetition-mode=min 2>&1 \ +RUN: | FileCheck %s --implicit-check-not="Output file name is" --check-prefix=CHECK-FILE-MANY-CONFIGS + +# "-" is a special case if writing multiple snippets. + +RUN: llvm-exegesis -mtriple=x86_64-unknown-unknown -mcpu=x86-64 -mode=latency -debug-only=exegesis-name-generator \ +RUN: -dump-snippet-file=- -benchmark-phase=prepare-snippet \ +RUN: -opcode-name=ADDPSrr,ADDPDrr -repetition-mode=min 2>&1 \ +RUN: | FileCheck %s --implicit-check-not="Output file name is" --check-prefix=CHECK-STDOUT-ADDPSrr-ADDPDrr + +# Test that the dumped snippet can be loaded back by llvm-exegesis +RUN: llvm-exegesis -mtriple=x86_64-unknown-unknown -mcpu=x86-64 -mode=latency \ +RUN: -dump-snippet-file=%t-snippet.s -benchmark-phase=prepare-snippet \ +RUN: -opcode-name=ADDPSrr +RUN: llvm-exegesis -mtriple=x86_64-unknown-unknown -mcpu=x86-64 -mode=latency \ +RUN: -snippets-file=%t-snippet.s -benchmark-phase=assemble-measured-code \ +RUN: | FileCheck %s --check-prefix=CHECK-RELOAD + + +CHECK-OFF-NOT: Output file name is + +# Note: testing for *at least* one DEFREG XMM[0-9]+ + +CHECK-STDOUT-ADDPSrr: Output file name is - +CHECK-STDOUT-ADDPSrr: # LLVM-EXEGESIS-DEFREG XMM{{[0-9]+}} 0 +CHECK-STDOUT-ADDPSrr: # LLVM-EXEGESIS-DEFREG MXCSR 0 +CHECK-STDOUT-ADDPSrr: addps %xmm{{[0-9]+}}, %xmm{{[0-9]+}} + +CHECK-FILE-ADDPSrr-ADDPDrr: Output file name is {{.*}}-snippet-ADDPSrr.s +CHECK-FILE-ADDPSrr-ADDPDrr: Output file name is {{.*}}-snippet-ADDPDrr.s + +CHECK-FILE-MANY-CONFIGS: Output file name is {{.*}}-snippet-SETCCr.s +CHECK-FILE-MANY-CONFIGS: Output file name is {{.*}}-snippet-SETCCr-1.s +CHECK-FILE-MANY-CONFIGS: Output file name is {{.*}}-snippet-SETCCr-2.s + +CHECK-STDOUT-ADDPSrr-ADDPDrr: Output file name is - +CHECK-STDOUT-ADDPSrr-ADDPDrr: # LLVM-EXEGESIS-DEFREG XMM{{[0-9]+}} 0 +CHECK-STDOUT-ADDPSrr-ADDPDrr: # LLVM-EXEGESIS-DEFREG MXCSR 0 +CHECK-STDOUT-ADDPSrr-ADDPDrr: addps %xmm{{[0-9]+}}, %xmm{{[0-9]+}} +CHECK-STDOUT-ADDPSrr-ADDPDrr: Output file name is - +CHECK-STDOUT-ADDPSrr-ADDPDrr: # LLVM-EXEGESIS-DEFREG XMM{{[0-9]+}} 0 +CHECK-STDOUT-ADDPSrr-ADDPDrr: # LLVM-EXEGESIS-DEFREG MXCSR 0 +CHECK-STDOUT-ADDPSrr-ADDPDrr: addpd %xmm{{[0-9]+}}, %xmm{{[0-9]+}} + +CHECK-RELOAD: mode: latency +CHECK-RELOAD-NEXT: key: +CHECK-RELOAD-NEXT: instructions: +CHECK-RELOAD-NEXT: - 'ADDPSrr {{.*}}' +CHECK-RELOAD-NEXT: config: '' +CHECK-RELOAD-NEXT: register_initial_values: +CHECK-RELOAD-NEXT: - 'XMM{{[0-9]+}}=0x0' +CHECK-RELOAD: - 'MXCSR=0x0' +CHECK-RELOAD: assembled_snippet: {{[0-9A-F]+}} diff --git a/llvm/tools/llvm-exegesis/lib/Analysis.h b/llvm/tools/llvm-exegesis/lib/Analysis.h --- a/llvm/tools/llvm-exegesis/lib/Analysis.h +++ b/llvm/tools/llvm-exegesis/lib/Analysis.h @@ -109,7 +109,7 @@ const BenchmarkClustering &Clustering_; const LLVMState &State_; - std::unique_ptr DisasmHelper_; + const DisassemblerHelper &DisasmHelper_; const double AnalysisInconsistencyEpsilonSquared_; const bool AnalysisDisplayUnstableOpcodes_; }; diff --git a/llvm/tools/llvm-exegesis/lib/Analysis.cpp b/llvm/tools/llvm-exegesis/lib/Analysis.cpp --- a/llvm/tools/llvm-exegesis/lib/Analysis.cpp +++ b/llvm/tools/llvm-exegesis/lib/Analysis.cpp @@ -106,7 +106,7 @@ while (!Bytes.empty()) { MCInst MI; uint64_t MISize = 0; - if (!DisasmHelper_->decodeInst(MI, MISize, Bytes)) { + if (!DisasmHelper_.decodeInst(MI, MISize, Bytes)) { writeEscaped(OS, join(Lines, Separator)); writeEscaped(OS, Separator); writeEscaped(OS, "[error decoding asm snippet]"); @@ -114,7 +114,7 @@ } SmallString<128> InstPrinterStr; // FIXME: magic number. raw_svector_ostream OSS(InstPrinterStr); - DisasmHelper_->printInst(&MI, OSS); + DisasmHelper_.printInst(&MI, OSS); Bytes = Bytes.drop_front(MISize); Lines.emplace_back(InstPrinterStr.str().trim()); } @@ -156,14 +156,10 @@ double AnalysisInconsistencyEpsilon, bool AnalysisDisplayUnstableOpcodes) : Clustering_(Clustering), State_(State), + DisasmHelper_(State.getDisassemblerHelper()), AnalysisInconsistencyEpsilonSquared_(AnalysisInconsistencyEpsilon * AnalysisInconsistencyEpsilon), - AnalysisDisplayUnstableOpcodes_(AnalysisDisplayUnstableOpcodes) { - if (Clustering.getPoints().empty()) - return; - - DisasmHelper_ = std::make_unique(State); -} + AnalysisDisplayUnstableOpcodes_(AnalysisDisplayUnstableOpcodes) {} template <> Error Analysis::run(raw_ostream &OS) const { diff --git a/llvm/tools/llvm-exegesis/lib/DisassemblerHelper.h b/llvm/tools/llvm-exegesis/lib/DisassemblerHelper.h --- a/llvm/tools/llvm-exegesis/lib/DisassemblerHelper.h +++ b/llvm/tools/llvm-exegesis/lib/DisassemblerHelper.h @@ -15,7 +15,6 @@ #ifndef LLVM_TOOLS_LLVM_EXEGESIS_DISASSEMBLER_HELPER_H #define LLVM_TOOLS_LLVM_EXEGESIS_DISASSEMBLER_HELPER_H -#include "LlvmState.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCDisassembler/MCDisassembler.h" @@ -23,17 +22,20 @@ #include +namespace llvm { +class TargetMachine; +} // namespace llvm + namespace llvm { namespace exegesis { // A helper class for decoding and printing machine instructions. class DisassemblerHelper { public: - DisassemblerHelper(const LLVMState &State); + DisassemblerHelper(const TargetMachine &TM); void printInst(const MCInst *MI, raw_ostream &OS) const { - const auto &STI = State_.getSubtargetInfo(); - InstPrinter_->printInst(MI, 0, "", STI, OS); + InstPrinter_->printInst(MI, 0, "", STI_, OS); } bool decodeInst(MCInst &MI, uint64_t &MISize, ArrayRef Bytes) const { @@ -41,7 +43,7 @@ } private: - const LLVMState &State_; + const MCSubtargetInfo &STI_; std::unique_ptr Context_; std::unique_ptr AsmInfo_; std::unique_ptr InstPrinter_; diff --git a/llvm/tools/llvm-exegesis/lib/DisassemblerHelper.cpp b/llvm/tools/llvm-exegesis/lib/DisassemblerHelper.cpp --- a/llvm/tools/llvm-exegesis/lib/DisassemblerHelper.cpp +++ b/llvm/tools/llvm-exegesis/lib/DisassemblerHelper.cpp @@ -9,24 +9,25 @@ #include "DisassemblerHelper.h" #include "llvm/MC/TargetRegistry.h" +#include "llvm/Target/TargetMachine.h" namespace llvm { namespace exegesis { -DisassemblerHelper::DisassemblerHelper(const LLVMState &State) : State_(State) { +DisassemblerHelper::DisassemblerHelper(const TargetMachine &TM) + : STI_(*TM.getMCSubtargetInfo()) { MCTargetOptions MCOptions; - const auto &TM = State.getTargetMachine(); + const auto &RegInfo = *TM.getMCRegisterInfo(); + const auto &InstrInfo = *TM.getMCInstrInfo(); const auto &Triple = TM.getTargetTriple(); - AsmInfo_.reset(TM.getTarget().createMCAsmInfo(State_.getRegInfo(), - Triple.str(), MCOptions)); + AsmInfo_.reset( + TM.getTarget().createMCAsmInfo(RegInfo, Triple.str(), MCOptions)); InstPrinter_.reset(TM.getTarget().createMCInstPrinter( - Triple, 0 /*default variant*/, *AsmInfo_, State_.getInstrInfo(), - State_.getRegInfo())); + Triple, 0 /*default variant*/, *AsmInfo_, InstrInfo, RegInfo)); - Context_ = std::make_unique( - Triple, AsmInfo_.get(), &State_.getRegInfo(), &State_.getSubtargetInfo()); - Disasm_.reset(TM.getTarget().createMCDisassembler(State_.getSubtargetInfo(), - *Context_)); + Context_ = + std::make_unique(Triple, AsmInfo_.get(), &RegInfo, &STI_); + Disasm_.reset(TM.getTarget().createMCDisassembler(STI_, *Context_)); assert(Disasm_ && "cannot create MCDisassembler. missing call to " "InitializeXXXTargetDisassembler ?"); } diff --git a/llvm/tools/llvm-exegesis/lib/FileNameGenerator.h b/llvm/tools/llvm-exegesis/lib/FileNameGenerator.h --- a/llvm/tools/llvm-exegesis/lib/FileNameGenerator.h +++ b/llvm/tools/llvm-exegesis/lib/FileNameGenerator.h @@ -59,6 +59,7 @@ std::string getFileName(ArrayRef Infixes) const; bool IsEnabled; + bool IsSingleDash; std::string FileNamePrefix; std::string FileNameSuffix; SmallVector IsVariableInfix; diff --git a/llvm/tools/llvm-exegesis/lib/FileNameGenerator.cpp b/llvm/tools/llvm-exegesis/lib/FileNameGenerator.cpp --- a/llvm/tools/llvm-exegesis/lib/FileNameGenerator.cpp +++ b/llvm/tools/llvm-exegesis/lib/FileNameGenerator.cpp @@ -21,7 +21,8 @@ ArrayRef IsVariableInfix) : IsVariableInfix(IsVariableInfix) { IsEnabled = !FileName.empty(); - if (!IsEnabled) + IsSingleDash = FileName == "-"; + if (!IsEnabled || IsSingleDash) return; size_t DotPosition = FileName.rfind('.'); @@ -44,6 +45,11 @@ std::string FileNameGenerator::getFileName(ArrayRef Infixes) const { SmallVector Parts; + if (IsSingleDash) { + LLVM_DEBUG(errs() << "Output file name is -\n"); + return "-"; + } + Parts.push_back(FileNamePrefix); for (unsigned I = 0, N = IsVariableInfix.size(); I < N; ++I) if (IsVariableInfix[I]) diff --git a/llvm/tools/llvm-exegesis/lib/LlvmState.h b/llvm/tools/llvm-exegesis/lib/LlvmState.h --- a/llvm/tools/llvm-exegesis/lib/LlvmState.h +++ b/llvm/tools/llvm-exegesis/lib/LlvmState.h @@ -14,6 +14,7 @@ #ifndef LLVM_TOOLS_LLVM_EXEGESIS_LLVMSTATE_H #define LLVM_TOOLS_LLVM_EXEGESIS_LLVMSTATE_H +#include "DisassemblerHelper.h" #include "MCInstrDescView.h" #include "RegisterAliasing.h" #include "llvm/ADT/StringMap.h" @@ -81,6 +82,10 @@ return *RegNameToRegNoMapping; } + const DisassemblerHelper &getDisassemblerHelper() const { + return *DisasmHelper; + } + private: std::unique_ptr> createOpcodeNameToOpcodeIdxMapping() const; @@ -99,6 +104,7 @@ std::unique_ptr> OpcodeNameToOpcodeIdxMapping; std::unique_ptr> RegNameToRegNoMapping; + std::unique_ptr DisasmHelper; }; } // namespace exegesis diff --git a/llvm/tools/llvm-exegesis/lib/LlvmState.cpp b/llvm/tools/llvm-exegesis/lib/LlvmState.cpp --- a/llvm/tools/llvm-exegesis/lib/LlvmState.cpp +++ b/llvm/tools/llvm-exegesis/lib/LlvmState.cpp @@ -90,6 +90,8 @@ RATC.reset( new RegisterAliasingTrackerCache(getRegInfo(), std::move(ReservedRegs))); IC.reset(new InstructionsCache(getInstrInfo(), getRATC())); + + DisasmHelper.reset(new DisassemblerHelper(*TheTargetMachine)); } std::unique_ptr LLVMState::createTargetMachine() const { 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 @@ -244,6 +244,12 @@ cl::desc("Target a specific cpu type (-mcpu=help for details)"), cl::value_desc("cpu-name"), cl::cat(Options), cl::init("native")); +static cl::opt DumpSnippetFile( + "dump-snippet-file", + cl::desc("Dump generated snippet to assembler file (opcode name is " + "inserted if writing multiple files). \"-\" uses stdout."), + cl::cat(BenchmarkOptions), cl::init("")); + static cl::opt DumpObjectToDisk( "dump-object-to-disk", cl::desc("Dump generated benchmark object to file (opcode and repetitor " @@ -369,6 +375,31 @@ return formatv("{0}-{1}", OpcodeName, Key.Index); } +static void dumpAsmSnippet(const LLVMState &State, const BenchmarkCode &BC, + const StringRef DumpFileName) { + std::error_code EC; + raw_fd_ostream OFS(DumpFileName, EC); + ExitOnFileError(DumpFileName, errorCodeToError(EC)); + + const auto &RegInfo = State.getRegInfo(); + for (const RegisterValue &RV : BC.Key.RegisterInitialValues) { + OFS << "# LLVM-EXEGESIS-DEFREG " << RegInfo.getName(RV.Register) << " " + << formatv("{0:X}", RV.Value) << "\n"; + } + for (unsigned LI : BC.LiveIns) { + OFS << "# LLVM-EXEGESIS-LIVEIN " << RegInfo.getName(LI) << "\n"; + } + + const auto &DisasmHelper = State.getDisassemblerHelper(); + for (auto &MI : BC.Key.Instructions) { + DisasmHelper.printInst(&MI, OFS); + OFS << "\n"; + } + + OFS.flush(); + ExitOnFileError(DumpFileName, errorCodeToError(OFS.error())); +} + static void dumpObjectFile(const StringRef Buffer, const StringRef DumpFileName) { std::error_code EC; @@ -398,6 +429,7 @@ bool ManyConfigurations = Configurations.size() > 1; bool ManyRepetitors = Repetitors.size() > 1; + FileNameGenerator SnippetFileName(DumpSnippetFile, ManyConfigurations, false); FileNameGenerator DumpedObjectName(DumpObjectToDisk, ManyConfigurations, ManyRepetitors); @@ -409,6 +441,8 @@ SmallVector AllResults; const auto OpcodeLabel = formatOpcodeLabel(MCII, Conf.Key); + if (SnippetFileName.isEnabled()) + dumpAsmSnippet(State, Conf, SnippetFileName.getFileName(OpcodeLabel, "")); for (const std::unique_ptr &Repetitor : Repetitors) { @@ -484,7 +518,6 @@ #endif } - InitializeAllAsmPrinters(); InitializeAllAsmParsers(); InitializeAllExegesisTargets(); @@ -615,8 +648,6 @@ "and --analysis-inconsistencies-output-file must be specified"); } - InitializeAllAsmPrinters(); - InitializeAllDisassemblers(); InitializeAllExegesisTargets(); auto MemoryBuffer = ExitOnFileError( @@ -687,6 +718,8 @@ InitializeAllTargetInfos(); InitializeAllTargets(); InitializeAllTargetMCs(); + InitializeAllAsmPrinters(); + InitializeAllDisassemblers(); // Register the Target and CPU printer for --version. cl::AddExtraVersionPrinter(sys::printDefaultTargetAndDetectedCPU); diff --git a/llvm/unittests/tools/llvm-exegesis/AArch64/TargetTest.cpp b/llvm/unittests/tools/llvm-exegesis/AArch64/TargetTest.cpp --- a/llvm/unittests/tools/llvm-exegesis/AArch64/TargetTest.cpp +++ b/llvm/unittests/tools/llvm-exegesis/AArch64/TargetTest.cpp @@ -47,6 +47,8 @@ LLVMInitializeAArch64TargetInfo(); LLVMInitializeAArch64Target(); LLVMInitializeAArch64TargetMC(); + LLVMInitializeAArch64AsmPrinter(); + LLVMInitializeAArch64Disassembler(); InitializeAArch64ExegesisTarget(); } diff --git a/llvm/unittests/tools/llvm-exegesis/ARM/AssemblerTest.cpp b/llvm/unittests/tools/llvm-exegesis/ARM/AssemblerTest.cpp --- a/llvm/unittests/tools/llvm-exegesis/ARM/AssemblerTest.cpp +++ b/llvm/unittests/tools/llvm-exegesis/ARM/AssemblerTest.cpp @@ -24,6 +24,7 @@ LLVMInitializeARMTargetMC(); LLVMInitializeARMTarget(); LLVMInitializeARMAsmPrinter(); + LLVMInitializeARMDisassembler(); } }; diff --git a/llvm/unittests/tools/llvm-exegesis/Mips/TestBase.h b/llvm/unittests/tools/llvm-exegesis/Mips/TestBase.h --- a/llvm/unittests/tools/llvm-exegesis/Mips/TestBase.h +++ b/llvm/unittests/tools/llvm-exegesis/Mips/TestBase.h @@ -31,6 +31,8 @@ LLVMInitializeMipsTargetInfo(); LLVMInitializeMipsTargetMC(); LLVMInitializeMipsTarget(); + LLVMInitializeMipsAsmPrinter(); + LLVMInitializeMipsDisassembler(); InitializeMipsExegesisTarget(); } diff --git a/llvm/unittests/tools/llvm-exegesis/PowerPC/TestBase.h b/llvm/unittests/tools/llvm-exegesis/PowerPC/TestBase.h --- a/llvm/unittests/tools/llvm-exegesis/PowerPC/TestBase.h +++ b/llvm/unittests/tools/llvm-exegesis/PowerPC/TestBase.h @@ -32,6 +32,8 @@ LLVMInitializePowerPCTargetInfo(); LLVMInitializePowerPCTargetMC(); LLVMInitializePowerPCTarget(); + LLVMInitializePowerPCAsmPrinter(); + LLVMInitializePowerPCDisassembler(); InitializePowerPCExegesisTarget(); } diff --git a/llvm/unittests/tools/llvm-exegesis/X86/BenchmarkResultTest.cpp b/llvm/unittests/tools/llvm-exegesis/X86/BenchmarkResultTest.cpp --- a/llvm/unittests/tools/llvm-exegesis/X86/BenchmarkResultTest.cpp +++ b/llvm/unittests/tools/llvm-exegesis/X86/BenchmarkResultTest.cpp @@ -55,6 +55,8 @@ LLVMInitializeX86TargetInfo(); LLVMInitializeX86Target(); LLVMInitializeX86TargetMC(); + LLVMInitializeX86AsmPrinter(); + LLVMInitializeX86Disassembler(); InitializeX86ExegesisTarget(); // Read benchmarks. diff --git a/llvm/unittests/tools/llvm-exegesis/X86/TestBase.h b/llvm/unittests/tools/llvm-exegesis/X86/TestBase.h --- a/llvm/unittests/tools/llvm-exegesis/X86/TestBase.h +++ b/llvm/unittests/tools/llvm-exegesis/X86/TestBase.h @@ -33,6 +33,7 @@ LLVMInitializeX86Target(); LLVMInitializeX86AsmPrinter(); LLVMInitializeX86AsmParser(); + LLVMInitializeX86Disassembler(); InitializeX86ExegesisTarget(); }