--- /dev/null
+//===---------------- IncrementalSourceMgr.h --------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// This file contains IncrementalSourceMgr, an implementation of SourceMgr
+/// that allows users to add new instructions incrementally / dynamically.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_MCA_INCREMENTALSOURCEMGR_H
+#define LLVM_MCA_INCREMENTALSOURCEMGR_H
+
+#include "llvm/MCA/SourceMgr.h"
+#include <deque>
+
+namespace llvm {
+namespace mca {
+
+/// An implementation of \a SourceMgr that allows users to add new instructions
+/// incrementally / dynamically.
+/// Note that this SourceMgr takes ownership of all \a mca::Instruction.
+class IncrementalSourceMgr : public SourceMgr {
+ /// Owner of all mca::Instruction instances. Note that we use std::deque here
+ /// to have a better throughput, in comparison to std::vector or
+ /// llvm::SmallVector, as they usually pay a higher re-allocation cost when
+ /// there is a large number of instructions.
+ std::deque<UniqueInst> InstStorage;
+
+ /// Current instruction index.
+ unsigned TotalCounter;
+
+ /// End-of-stream flag.
+ bool EOS;
+
+public:
+ IncrementalSourceMgr() : TotalCounter(0U), EOS(false) {}
+
+ void clear() {
+ InstStorage.clear();
+ TotalCounter = 0U;
+ EOS = false;
+ }
+
+ ArrayRef<UniqueInst> getInstructions() const override {
+ llvm_unreachable("Not applicable");
+ }
+
+ bool hasNext() const override { return TotalCounter < InstStorage.size(); }
+ bool isEnd() const override { return EOS; }
+
+ SourceRef peekNext() const override {
+ assert(hasNext());
+ return SourceRef(TotalCounter, *InstStorage[TotalCounter]);
+ }
+
+ /// Add a new instruction.
+ void addInst(UniqueInst &&Inst) { InstStorage.emplace_back(std::move(Inst)); }
+
+ void updateNext() override { ++TotalCounter; }
+
+ /// Mark the end of instruction stream.
+ void endOfStream() { EOS = true; }
+};
+
+} // end namespace mca
+} // end namespace llvm
+
+#endif // LLVM_MCA_INCREMENTALSOURCEMGR_H
Pipeline(const Pipeline &P) = delete;
Pipeline &operator=(const Pipeline &P) = delete;
+ enum class State {
+ Created, // Pipeline was just created. The default state.
+ Started, // Pipeline has started running.
+ Paused // Pipeline is paused.
+ };
+ State CurrentState;
+
/// An ordered list of stages that define this instruction pipeline.
SmallVector<std::unique_ptr<Stage>, 8> Stages;
std::set<HWEventListener *> Listeners;
void notifyCycleEnd();
public:
- Pipeline() : Cycles(0) {}
+ Pipeline() : CurrentState(State::Created), Cycles(0) {}
void appendStage(std::unique_ptr<Stage> S);
/// Returns the total number of simulated cycles.
Expected<unsigned> run();
void addEventListener(HWEventListener *Listener);
+
+ /// Returns whether the pipeline is currently paused.
+ bool isPaused() const { return CurrentState == State::Paused; }
};
} // namespace mca
} // namespace llvm
//
//===----------------------------------------------------------------------===//
/// \file
-/// This file implements class SourceMgr. Class SourceMgr abstracts the input
-/// code sequence (a sequence of MCInst), and assings unique identifiers to
-/// every instruction in the sequence.
+/// This file contains abstract class SourceMgr and the default implementation,
+/// CircularSourceMgr.
///
//===----------------------------------------------------------------------===//
// prevent compiler error C2139 about intrinsic type trait '__is_assignable'.
typedef std::pair<unsigned, const Instruction &> SourceRef;
-class SourceMgr {
+/// Abstracting the input code sequence (a sequence of MCInst) and assigning
+/// unique identifiers to every instruction in the sequence.
+struct SourceMgr {
using UniqueInst = std::unique_ptr<Instruction>;
+
+ /// Provides a fixed range of \a UniqueInst to iterate.
+ virtual ArrayRef<UniqueInst> getInstructions() const = 0;
+
+ /// (Fixed) Number of \a UniqueInst. Returns the size of
+ /// \a getInstructions by default.
+ virtual size_t size() const { return getInstructions().size(); }
+
+ /// Whether there is any \a SourceRef to inspect / peek next.
+ /// Note that returning false from this doesn't mean the instruction
+ /// stream has ended.
+ virtual bool hasNext() const = 0;
+
+ /// Whether the instruction stream has eneded.
+ virtual bool isEnd() const = 0;
+
+ /// The next \a SourceRef.
+ virtual SourceRef peekNext() const = 0;
+
+ /// Advance to the next \a SourceRef.
+ virtual void updateNext() = 0;
+
+ virtual ~SourceMgr() {}
+};
+
+/// The default implementation of \a SourceMgr. It always takes a fixed number
+/// of instructions and provides an option to loop the given sequence for a
+/// certain iterations.
+class CircularSourceMgr : public SourceMgr {
ArrayRef<UniqueInst> Sequence;
unsigned Current;
const unsigned Iterations;
static const unsigned DefaultIterations = 100;
public:
- SourceMgr(ArrayRef<UniqueInst> S, unsigned Iter)
- : Sequence(S), Current(0), Iterations(Iter ? Iter : DefaultIterations) {}
+ CircularSourceMgr(ArrayRef<UniqueInst> S, unsigned Iter)
+ : Sequence(S), Current(0U), Iterations(Iter ? Iter : DefaultIterations) {}
+
+ ArrayRef<UniqueInst> getInstructions() const override { return Sequence; }
unsigned getNumIterations() const { return Iterations; }
- unsigned size() const { return Sequence.size(); }
- bool hasNext() const { return Current < (Iterations * Sequence.size()); }
- void updateNext() { ++Current; }
+ bool hasNext() const override {
+ return Current < (Iterations * Sequence.size());
+ }
+ bool isEnd() const override { return !hasNext(); }
- SourceRef peekNext() const {
+ SourceRef peekNext() const override {
assert(hasNext() && "Already at end of sequence!");
return SourceRef(Current, *Sequence[Current % Sequence.size()]);
}
- using const_iterator = ArrayRef<UniqueInst>::const_iterator;
- const_iterator begin() const { return Sequence.begin(); }
- const_iterator end() const { return Sequence.end(); }
+ void updateNext() override { ++Current; }
};
} // namespace mca
unsigned NumRetired;
// Updates the program counter, and sets 'CurrentInstruction'.
- void getNextInstruction();
+ Error getNextInstruction();
EntryStage(const EntryStage &Other) = delete;
EntryStage &operator=(const EntryStage &Other) = delete;
bool hasWorkToComplete() const override;
Error execute(InstRef &IR) override;
Error cycleStart() override;
+ Error cycleResume() override;
Error cycleEnd() override;
};
/// phase to prepare for the executions during the cycle.
virtual Error cycleStart() { return ErrorSuccess(); }
+ /// Called after the pipeline is resumed from pausing state.
+ virtual Error cycleResume() { return ErrorSuccess(); }
+
/// Called once at the end of each cycle.
virtual Error cycleEnd() { return ErrorSuccess(); }
}
};
+/// This is actually not an error but a marker to indicate that
+/// the instruction stream is paused.
+struct InstStreamPause : public ErrorInfo<InstStreamPause> {
+ static char ID;
+
+ std::error_code convertToErrorCode() const override {
+ return llvm::inconvertibleErrorCode();
+ }
+ void log(raw_ostream &OS) const override { OS << "Stream is paused"; }
+};
} // namespace mca
} // namespace llvm
#endif // LLVM_MCA_STAGES_STAGE_H
assert(!Stages.empty() && "Unexpected empty pipeline found!");
do {
- notifyCycleBegin();
+ if (!isPaused())
+ notifyCycleBegin();
if (Error Err = runCycle())
return std::move(Err);
notifyCycleEnd();
// Update stages before we start processing new instructions.
for (auto I = Stages.rbegin(), E = Stages.rend(); I != E && !Err; ++I) {
const std::unique_ptr<Stage> &S = *I;
- Err = S->cycleStart();
+ if (isPaused())
+ Err = S->cycleResume();
+ else
+ Err = S->cycleStart();
}
+ CurrentState = State::Started;
+
// Now fetch and execute new instructions.
InstRef IR;
Stage &FirstStage = *Stages[0];
while (!Err && FirstStage.isAvailable(IR))
Err = FirstStage.execute(IR);
+ if (Err.isA<InstStreamPause>()) {
+ CurrentState = State::Paused;
+ return Err;
+ }
+
// Update stages in preparation for a new cycle.
for (const std::unique_ptr<Stage> &S : Stages) {
Err = S->cycleEnd();
namespace mca {
bool EntryStage::hasWorkToComplete() const {
- return static_cast<bool>(CurrentInstruction);
+ return static_cast<bool>(CurrentInstruction) || !SM.isEnd();
}
bool EntryStage::isAvailable(const InstRef & /* unused */) const {
return false;
}
-void EntryStage::getNextInstruction() {
+Error EntryStage::getNextInstruction() {
assert(!CurrentInstruction && "There is already an instruction to process!");
- if (!SM.hasNext())
- return;
+ if (!SM.hasNext()) {
+ if (!SM.isEnd())
+ return llvm::make_error<InstStreamPause>();
+ else
+ return llvm::ErrorSuccess();
+ }
SourceRef SR = SM.peekNext();
std::unique_ptr<Instruction> Inst = std::make_unique<Instruction>(SR.second);
CurrentInstruction = InstRef(SR.first, Inst.get());
Instructions.emplace_back(std::move(Inst));
SM.updateNext();
+ return llvm::ErrorSuccess();
}
llvm::Error EntryStage::execute(InstRef & /*unused */) {
// Move the program counter.
CurrentInstruction.invalidate();
- getNextInstruction();
- return llvm::ErrorSuccess();
+ return getNextInstruction();
}
llvm::Error EntryStage::cycleStart() {
if (!CurrentInstruction)
- getNextInstruction();
+ return getNextInstruction();
return llvm::ErrorSuccess();
}
+llvm::Error EntryStage::cycleResume() {
+ assert(!CurrentInstruction);
+ return getNextInstruction();
+}
+
llvm::Error EntryStage::cycleEnd() {
// Find the first instruction which hasn't been retired.
auto Range = make_range(&Instructions[NumRetired], Instructions.end());
Listeners.insert(Listener);
}
+char InstStreamPause::ID = 0;
} // namespace mca
} // namespace llvm
AMDGPU::IsaVersion IV = AMDGPU::getIsaVersion(STI.getCPU());
InstrWaitCntInfo.resize(SrcMgr.size());
- int Index = 0;
- for (auto I = SrcMgr.begin(), E = SrcMgr.end(); I != E; ++I, ++Index) {
- const std::unique_ptr<Instruction> &Inst = *I;
+ for (const auto &EN : llvm::enumerate(SrcMgr.getInstructions())) {
+ const std::unique_ptr<Instruction> &Inst = EN.value();
+ unsigned Index = EN.index();
unsigned Opcode = Inst->getOpcode();
const MCInstrDesc &MCID = MCII.get(Opcode);
if ((MCID.TSFlags & SIInstrFlags::DS) &&
LoweredSequence.emplace_back(std::move(Inst.get()));
}
- mca::SourceMgr S(LoweredSequence, PrintInstructionTables ? 1 : Iterations);
+ mca::CircularSourceMgr S(LoweredSequence,
+ PrintInstructionTables ? 1 : Iterations);
if (PrintInstructionTables) {
// Create a pipeline, stages, and a printer.
llvm-exegesis
)
add_subdirectory(llvm-profgen)
+add_subdirectory(llvm-mca)
--- /dev/null
+set(LLVM_LINK_COMPONENTS
+ MC
+ MCA
+ Object
+ Support
+ )
+
+set(mca_root ${LLVM_MAIN_SRC_DIR}/tools/llvm-mca)
+
+set(mca_includes
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${mca_root}
+ )
+
+# Right now we only need SummaryView.
+set(mca_views_sources
+ SummaryView.cpp
+ )
+list(TRANSFORM mca_views_sources PREPEND "${mca_root}/Views/")
+
+set(mca_sources
+ MCATestBase.cpp
+ ${mca_views_sources}
+ )
+
+function(add_llvm_mca_unittest_includes)
+ set(mca_includes ${mca_includes} ${ARGV} PARENT_SCOPE)
+endfunction()
+
+function(add_llvm_mca_unittest_sources)
+ set(sources ${ARGV})
+ list(TRANSFORM sources PREPEND "${CMAKE_CURRENT_LIST_DIR}/")
+ set(mca_sources ${mca_sources} ${sources} PARENT_SCOPE)
+endfunction()
+
+function(add_llvm_mca_unittest_link_components comps)
+ set(LLVM_LINK_COMPONENTS ${LLVM_LINK_COMPONENTS} ${ARGV} PARENT_SCOPE)
+endfunction()
+
+if(LLVM_TARGETS_TO_BUILD MATCHES "X86")
+ include(X86/CMakeLists.txt)
+endif()
+
+list(REMOVE_DUPLICATES LLVM_LINK_COMPONENTS)
+
+include_directories(${mca_includes})
+
+add_llvm_target_unittest(LLVMMCATests
+ ${mca_sources}
+ )
+
+set_property(TARGET LLVMMCATests PROPERTY FOLDER "Tests/UnitTests/ToolTests")
--- /dev/null
+#include "MCATestBase.h"
+#include "Views/SummaryView.h"
+#include "llvm/MCA/CustomBehaviour.h"
+#include "llvm/MCA/InstrBuilder.h"
+#include "llvm/MCA/Pipeline.h"
+#include "llvm/MCA/SourceMgr.h"
+#include "llvm/MCA/View.h"
+#include "llvm/Support/JSON.h"
+#include "llvm/Support/WithColor.h"
+#include <string>
+
+using namespace llvm;
+using namespace mca;
+
+const Target *MCATestBase::getLLVMTarget() const {
+ std::string Error;
+ return TargetRegistry::lookupTarget(TheTriple.getTriple(), Error);
+}
+
+mca::PipelineOptions MCATestBase::getDefaultPipelineOptions() {
+ mca::PipelineOptions PO(/*MicroOpQueue=*/0, /*DecoderThroughput=*/0,
+ /*DispatchWidth=*/0,
+ /*RegisterFileSize=*/0,
+ /*LoadQueueSize=*/0, /*StoreQueueSize=*/0,
+ /*AssumeNoAlias=*/true,
+ /*EnableBottleneckAnalysis=*/false);
+ return PO;
+}
+
+void MCATestBase::SetUp() {
+ TheTarget = getLLVMTarget();
+ ASSERT_NE(TheTarget, nullptr);
+
+ StringRef TripleName = TheTriple.getTriple();
+
+ STI.reset(TheTarget->createMCSubtargetInfo(TripleName, CPUName, MAttr));
+ ASSERT_TRUE(STI);
+ ASSERT_TRUE(STI->isCPUStringValid(CPUName));
+
+ MRI.reset(TheTarget->createMCRegInfo(TripleName));
+ ASSERT_TRUE(MRI);
+
+ auto MCOptions = getMCTargetOptions();
+ MAI.reset(TheTarget->createMCAsmInfo(*MRI, TripleName, MCOptions));
+ ASSERT_TRUE(MAI);
+
+ Ctx = std::make_unique<MCContext>(TheTriple, MAI.get(), MRI.get(), STI.get());
+ MOFI.reset(TheTarget->createMCObjectFileInfo(*Ctx, /*PIC=*/false));
+ Ctx->setObjectFileInfo(MOFI.get());
+
+ MCII.reset(TheTarget->createMCInstrInfo());
+ ASSERT_TRUE(MCII);
+
+ MCIA.reset(TheTarget->createMCInstrAnalysis(MCII.get()));
+ ASSERT_TRUE(MCIA);
+
+ IP.reset(TheTarget->createMCInstPrinter(TheTriple, /*AssemblerDialect=*/0,
+ *MAI, *MCII, *MRI));
+ ASSERT_TRUE(IP);
+}
+
+Error MCATestBase::runBaselineMCA(json::Object &Result, ArrayRef<MCInst> Insts,
+ ArrayRef<mca::View *> Views,
+ const mca::PipelineOptions *PO) {
+ mca::Context MCA(*MRI, *STI);
+
+ mca::InstrBuilder IB(*STI, *MCII, *MRI, MCIA.get());
+
+ SmallVector<std::unique_ptr<mca::Instruction>> LoweredInsts;
+ for (const auto &MCI : Insts) {
+ Expected<std::unique_ptr<mca::Instruction>> Inst =
+ IB.createInstruction(MCI);
+ if (!Inst) {
+ if (auto NewE =
+ handleErrors(Inst.takeError(),
+ [this](const mca::InstructionError<MCInst> &IE) {
+ std::string InstructionStr;
+ raw_string_ostream SS(InstructionStr);
+ WithColor::error() << IE.Message << '\n';
+ IP->printInst(&IE.Inst, 0, "", *STI, SS);
+ WithColor::note()
+ << "instruction: " << InstructionStr << '\n';
+ })) {
+ // Default case.
+ return std::move(NewE);
+ }
+ } else {
+ LoweredInsts.emplace_back(std::move(Inst.get()));
+ }
+ }
+
+ mca::CircularSourceMgr SM(LoweredInsts, /*Iterations=*/1);
+
+ // Empty CustomBehaviour.
+ auto CB = std::make_unique<mca::CustomBehaviour>(*STI, SM, *MCII);
+
+ mca::PipelineOptions ThePO = PO ? *PO : getDefaultPipelineOptions();
+ auto P = MCA.createDefaultPipeline(ThePO, SM, *CB);
+
+ SmallVector<std::unique_ptr<mca::View>, 1> DefaultViews;
+ if (Views.empty()) {
+ // By default, we only add SummaryView.
+ auto SV = std::make_unique<SummaryView>(STI->getSchedModel(), Insts,
+ ThePO.DispatchWidth);
+ P->addEventListener(SV.get());
+ DefaultViews.emplace_back(std::move(SV));
+ } else {
+ for (auto *V : Views)
+ P->addEventListener(V);
+ }
+
+ // Run the pipeline.
+ Expected<unsigned> Cycles = P->run();
+ if (!Cycles)
+ return Cycles.takeError();
+
+ for (const auto *V : Views)
+ Result[V->getNameAsString()] = V->toJSON();
+ for (const auto &V : DefaultViews)
+ Result[V->getNameAsString()] = V->toJSON();
+
+ return Error::success();
+}
--- /dev/null
+//===---- MCATestBase.h -----------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// Test fixture common to all MCA tests.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_UNITTESTS_TOOLS_LLVMMCA_MCATESTBASE_H
+#define LLVM_UNITTESTS_TOOLS_LLVMMCA_MCATESTBASE_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCInstPrinter.h"
+#include "llvm/MC/MCInstrAnalysis.h"
+#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCObjectFileInfo.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/MC/MCTargetOptions.h"
+#include "llvm/MC/SubtargetFeature.h"
+#include "llvm/MC/TargetRegistry.h"
+#include "llvm/MCA/Context.h"
+
+#include "gtest/gtest.h"
+
+namespace llvm {
+namespace json {
+class Object;
+} // end namespace json
+
+namespace mca {
+class View;
+
+class MCATestBase : public ::testing::Test {
+protected:
+ // Note: Subclass ctors are expected to perform target-specific
+ // initializations.
+ MCATestBase(StringRef TripleStr, StringRef CPUName, StringRef MAttr = "")
+ : TheTriple(TripleStr), CPUName(CPUName), MAttr(MAttr) {}
+
+ /// Factory function to create a Target.
+ virtual const Target *getLLVMTarget() const;
+
+ /// Factory function to create a MCTargetOptions instance. Returns an
+ /// empty one by default.
+ virtual MCTargetOptions getMCTargetOptions() { return MCTargetOptions(); }
+
+ const Target *TheTarget;
+ const Triple TheTriple;
+ StringRef CPUName;
+ StringRef MAttr;
+
+ // MC components.
+ std::unique_ptr<MCSubtargetInfo> STI;
+ std::unique_ptr<MCRegisterInfo> MRI;
+ std::unique_ptr<MCAsmInfo> MAI;
+ std::unique_ptr<MCObjectFileInfo> MOFI;
+ std::unique_ptr<MCContext> Ctx;
+ std::unique_ptr<MCInstrInfo> MCII;
+ std::unique_ptr<MCInstrAnalysis> MCIA;
+ std::unique_ptr<MCInstPrinter> IP;
+
+ static mca::PipelineOptions getDefaultPipelineOptions();
+
+ void SetUp() override;
+
+ /// Utility function to run MCA with (nearly) the same configuration as the
+ /// `llvm-mca` tool to verify result correctness.
+ /// This function only displays on SummaryView by default.
+ virtual Error runBaselineMCA(json::Object &Result, ArrayRef<MCInst> Insts,
+ ArrayRef<mca::View *> Views = None,
+ const mca::PipelineOptions *PO = nullptr);
+};
+
+} // end namespace mca
+} // end namespace llvm
+#endif
--- /dev/null
+add_llvm_mca_unittest_includes(
+ ${LLVM_MAIN_SRC_DIR}/lib/Target/X86
+ ${LLVM_BINARY_DIR}/lib/Target/X86
+ )
+
+add_llvm_mca_unittest_sources(
+ TestIncrementalMCA.cpp
+ X86TestBase.cpp
+ )
+
+add_llvm_mca_unittest_link_components(
+ X86
+ )
--- /dev/null
+#include "Views/SummaryView.h"
+#include "X86TestBase.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/MCA/CustomBehaviour.h"
+#include "llvm/MCA/IncrementalSourceMgr.h"
+#include "llvm/MCA/InstrBuilder.h"
+#include "llvm/MCA/Pipeline.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/JSON.h"
+#include "llvm/Support/raw_ostream.h"
+#include <unordered_map>
+
+using namespace llvm;
+using namespace mca;
+
+TEST_F(X86TestBase, TestResumablePipeline) {
+ mca::Context MCA(*MRI, *STI);
+
+ mca::IncrementalSourceMgr ISM;
+ // Empty CustomBehaviour.
+ auto CB = std::make_unique<mca::CustomBehaviour>(*STI, ISM, *MCII);
+
+ auto PO = getDefaultPipelineOptions();
+ auto P = MCA.createDefaultPipeline(PO, ISM, *CB);
+ ASSERT_TRUE(P);
+
+ SmallVector<MCInst> MCIs;
+ getSimpleInsts(MCIs, /*Repeats=*/100);
+
+ // Add views.
+ auto SV = std::make_unique<SummaryView>(STI->getSchedModel(), MCIs,
+ PO.DispatchWidth);
+ P->addEventListener(SV.get());
+
+ mca::InstrBuilder IB(*STI, *MCII, *MRI, MCIA.get());
+
+ // Tile size = 7
+ for (unsigned i = 0U, E = MCIs.size(); i < E;) {
+ for (unsigned TE = i + 7; i < TE && i < E; ++i) {
+ Expected<std::unique_ptr<mca::Instruction>> InstOrErr =
+ IB.createInstruction(MCIs[i]);
+ ASSERT_TRUE(bool(InstOrErr));
+ ISM.addInst(std::move(InstOrErr.get()));
+ }
+
+ // Run the pipeline.
+ Expected<unsigned> Cycles = P->run();
+ if (!Cycles) {
+ // Should be a stream pause error.
+ ASSERT_TRUE(Cycles.errorIsA<mca::InstStreamPause>());
+ llvm::consumeError(Cycles.takeError());
+ }
+ }
+
+ ISM.endOfStream();
+ // Has to terminate properly.
+ Expected<unsigned> Cycles = P->run();
+ ASSERT_TRUE(bool(Cycles));
+
+ json::Value Result = SV->toJSON();
+ auto *ResultObj = Result.getAsObject();
+ ASSERT_TRUE(ResultObj);
+
+ // Run the baseline.
+ json::Object BaselineResult;
+ auto E = runBaselineMCA(BaselineResult, MCIs);
+ ASSERT_FALSE(bool(E)) << "Failed to run baseline";
+ auto *BaselineObj = BaselineResult.getObject(SV->getNameAsString());
+ ASSERT_TRUE(BaselineObj) << "Does not contain SummaryView result";
+
+ // Compare the results.
+ constexpr const char *Fields[] = {"Instructions", "TotalCycles", "TotaluOps",
+ "BlockRThroughput"};
+ for (const auto *F : Fields) {
+ auto V = ResultObj->getInteger(F);
+ auto BV = BaselineObj->getInteger(F);
+ ASSERT_TRUE(V && BV);
+ ASSERT_EQ(*BV, *V) << "Value of '" << F << "' does not match";
+ }
+}
--- /dev/null
+#include "X86TestBase.h"
+#include "MCTargetDesc/X86MCTargetDesc.h"
+#include "llvm/MC/MCInstBuilder.h"
+#include "llvm/Support/TargetSelect.h"
+
+using namespace llvm;
+using namespace mca;
+
+X86TestBase::X86TestBase() : MCATestBase("x86_64-unknown-linux", "skylake") {
+ LLVMInitializeX86TargetInfo();
+ LLVMInitializeX86TargetMC();
+ LLVMInitializeX86Target();
+ LLVMInitializeX86AsmPrinter();
+}
+
+void X86TestBase::getSimpleInsts(SmallVectorImpl<MCInst> &Insts,
+ unsigned Repeats) {
+ for (unsigned i = 0U; i < Repeats; ++i) {
+ // vmulps %xmm0, %xmm1, %xmm2
+ Insts.push_back(MCInstBuilder(X86::VMULPSrr)
+ .addReg(X86::XMM2)
+ .addReg(X86::XMM1)
+ .addReg(X86::XMM0));
+ // vhaddps %xmm2, %xmm2, %xmm3
+ Insts.push_back(MCInstBuilder(X86::VHADDPSrr)
+ .addReg(X86::XMM3)
+ .addReg(X86::XMM2)
+ .addReg(X86::XMM2));
+ // vhaddps %xmm3, %xmm3, %xmm4
+ Insts.push_back(MCInstBuilder(X86::VHADDPSrr)
+ .addReg(X86::XMM4)
+ .addReg(X86::XMM3)
+ .addReg(X86::XMM3));
+ }
+}
--- /dev/null
+//===---- X86TestBase.h -----------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// Test fixture common to all X86 MCA tests.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_UNITTESTS_TOOLS_LLVMMCA_X86_X86TESTBASE_H
+#define LLVM_UNITTESTS_TOOLS_LLVMMCA_X86_X86TESTBASE_H
+
+#include "MCATestBase.h"
+#include "llvm/ADT/SmallVector.h"
+
+namespace llvm {
+namespace mca {
+
+class X86TestBase : public MCATestBase {
+protected:
+ X86TestBase();
+
+ void getSimpleInsts(SmallVectorImpl<MCInst> &Insts, unsigned Repeats = 1);
+};
+
+} // end namespace mca
+} // end namespace llvm
+
+#endif