[llvm] r335105 - [llvm-exegesis] Use a Prototype to defer picking a value for free vars.
Guillaume Chatelet via llvm-commits
llvm-commits at lists.llvm.org
Wed Jun 20 01:52:30 PDT 2018
Author: gchatelet
Date: Wed Jun 20 01:52:30 2018
New Revision: 335105
URL: http://llvm.org/viewvc/llvm-project?rev=335105&view=rev
Log:
[llvm-exegesis] Use a Prototype to defer picking a value for free vars.
Summary: Introducing a Prototype object to capture Variables that must be set but keeps degrees of freedom as Invalid. This allows exploring non constraint variables later on.
Reviewers: courbet
Subscribers: tschuett, llvm-commits
Differential Revision: https://reviews.llvm.org/D48316
Modified:
llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.h
llvm/trunk/tools/llvm-exegesis/lib/Latency.cpp
llvm/trunk/tools/llvm-exegesis/lib/Latency.h
llvm/trunk/tools/llvm-exegesis/lib/MCInstrDescView.cpp
llvm/trunk/tools/llvm-exegesis/lib/MCInstrDescView.h
llvm/trunk/tools/llvm-exegesis/lib/Uops.cpp
llvm/trunk/tools/llvm-exegesis/lib/Uops.h
llvm/trunk/unittests/tools/llvm-exegesis/X86/SnippetGeneratorTest.cpp
Modified: llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.cpp?rev=335105&r1=335104&r2=335105&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.cpp (original)
+++ llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.cpp Wed Jun 20 01:52:30 2018
@@ -47,7 +47,7 @@ BenchmarkRunner::run(unsigned Opcode, co
return std::move(E);
llvm::Expected<std::vector<BenchmarkConfiguration>> ConfigurationOrError =
- createConfigurations(Opcode);
+ generateConfigurations(Opcode);
if (llvm::Error E = ConfigurationOrError.takeError())
return std::move(E);
@@ -113,6 +113,20 @@ BenchmarkRunner::runOne(const BenchmarkC
return InstrBenchmark;
}
+llvm::Expected<std::vector<BenchmarkConfiguration>>
+BenchmarkRunner::generateConfigurations(unsigned Opcode) const {
+ if (auto E = generatePrototype(Opcode)) {
+ SnippetPrototype &Prototype = E.get();
+ // TODO: Generate as many configurations as needed here.
+ BenchmarkConfiguration Configuration;
+ Configuration.Info = Prototype.Explanation;
+ for (InstructionInstance &II : Prototype.Snippet)
+ Configuration.Snippet.push_back(II.randomizeUnsetVariablesAndBuild());
+ return std::vector<BenchmarkConfiguration>{Configuration};
+ } else
+ return E.takeError();
+}
+
llvm::Expected<std::string>
BenchmarkRunner::writeObjectFile(llvm::ArrayRef<llvm::MCInst> Code) const {
int ResultFD = 0;
Modified: llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.h?rev=335105&r1=335104&r2=335105&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.h (original)
+++ llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.h Wed Jun 20 01:52:30 2018
@@ -19,6 +19,7 @@
#include "Assembler.h"
#include "BenchmarkResult.h"
#include "LlvmState.h"
+#include "MCInstrDescView.h"
#include "RegisterAliasing.h"
#include "llvm/MC/MCInst.h"
#include "llvm/Support/Error.h"
@@ -80,10 +81,15 @@ private:
InstructionBenchmark runOne(const BenchmarkConfiguration &Configuration,
unsigned Opcode, unsigned NumRepetitions) const;
+ // Calls generatePrototype and expands the SnippetPrototype into one or more
+ // BenchmarkConfiguration.
+ llvm::Expected<std::vector<BenchmarkConfiguration>>
+ generateConfigurations(unsigned Opcode) const;
+
virtual InstructionBenchmark::ModeE getMode() const = 0;
- virtual llvm::Expected<std::vector<BenchmarkConfiguration>>
- createConfigurations(unsigned Opcode) const = 0;
+ virtual llvm::Expected<SnippetPrototype>
+ generatePrototype(unsigned Opcode) const = 0;
virtual std::vector<BenchmarkMeasure>
runMeasurements(const ExecutableFunction &EF,
Modified: llvm/trunk/tools/llvm-exegesis/lib/Latency.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/Latency.cpp?rev=335105&r1=335104&r2=335105&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/Latency.cpp (original)
+++ llvm/trunk/tools/llvm-exegesis/lib/Latency.cpp Wed Jun 20 01:52:30 2018
@@ -16,6 +16,7 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCInstBuilder.h"
+#include "llvm/Support/FormatVariadic.h"
namespace exegesis {
@@ -47,26 +48,27 @@ llvm::Error LatencyBenchmarkRunner::isIn
return llvm::Error::success();
}
-llvm::Expected<BenchmarkConfiguration>
-LatencyBenchmarkRunner::generateSelfAliasingConfiguration(
+llvm::Expected<SnippetPrototype>
+LatencyBenchmarkRunner::generateSelfAliasingPrototype(
const Instruction &Instr,
const AliasingConfigurations &SelfAliasing) const {
- BenchmarkConfiguration Conf;
+ SnippetPrototype Prototype;
InstructionInstance II(Instr);
if (SelfAliasing.hasImplicitAliasing()) {
- Conf.Info = "implicit Self cycles, picking random values.";
+ Prototype.Explanation = "implicit Self cycles, picking random values.";
} else {
- Conf.Info = "explicit self cycles, selecting one aliasing Conf.";
+ Prototype.Explanation =
+ "explicit self cycles, selecting one aliasing Conf.";
// This is a self aliasing instruction so defs and uses are from the same
// instance, hence twice II in the following call.
setRandomAliasing(SelfAliasing, II, II);
}
- Conf.Snippet = {II.randomizeUnsetVariablesAndBuild()};
- return Conf;
+ Prototype.Snippet.push_back(std::move(II));
+ return Prototype;
}
-llvm::Expected<BenchmarkConfiguration>
-LatencyBenchmarkRunner::generateTwoInstructionConfiguration(
+llvm::Expected<SnippetPrototype>
+LatencyBenchmarkRunner::generateTwoInstructionPrototype(
const Instruction &Instr,
const AliasingConfigurations &SelfAliasing) const {
std::vector<unsigned> Opcodes;
@@ -74,7 +76,7 @@ LatencyBenchmarkRunner::generateTwoInstr
std::iota(Opcodes.begin(), Opcodes.end(), 0U);
std::shuffle(Opcodes.begin(), Opcodes.end(), randomGenerator());
for (const unsigned OtherOpcode : Opcodes) {
- if (OtherOpcode == Instr.Description.Opcode)
+ if (OtherOpcode == Instr.Description->Opcode)
continue;
const auto &OtherInstrDesc = MCInstrInfo.get(OtherOpcode);
if (auto E = isInfeasible(OtherInstrDesc)) {
@@ -92,21 +94,19 @@ LatencyBenchmarkRunner::generateTwoInstr
setRandomAliasing(Forward, ThisII, OtherII);
if (!Back.hasImplicitAliasing())
setRandomAliasing(Back, OtherII, ThisII);
- BenchmarkConfiguration Conf;
- Conf.Info = llvm::Twine("creating cycle through ")
- .concat(MCInstrInfo.getName(OtherOpcode))
- .concat(".")
- .str();
- Conf.Snippet.push_back(ThisII.randomizeUnsetVariablesAndBuild());
- Conf.Snippet.push_back(OtherII.randomizeUnsetVariablesAndBuild());
- return Conf;
+ SnippetPrototype Prototype;
+ Prototype.Explanation = llvm::formatv("creating cycle through {0}.",
+ MCInstrInfo.getName(OtherOpcode));
+ Prototype.Snippet.push_back(std::move(ThisII));
+ Prototype.Snippet.push_back(std::move(OtherII));
+ return Prototype;
}
return llvm::make_error<BenchmarkFailure>(
"Infeasible : Didn't find any scheme to make the instruction serial");
}
-llvm::Expected<BenchmarkConfiguration>
-LatencyBenchmarkRunner::generateConfiguration(unsigned Opcode) const {
+llvm::Expected<SnippetPrototype>
+LatencyBenchmarkRunner::generatePrototype(unsigned Opcode) const {
const auto &InstrDesc = MCInstrInfo.get(Opcode);
if (auto E = isInfeasible(InstrDesc))
return std::move(E);
@@ -114,20 +114,12 @@ LatencyBenchmarkRunner::generateConfigur
const AliasingConfigurations SelfAliasing(Instr, Instr);
if (SelfAliasing.empty()) {
// No self aliasing, trying to create a dependency through another opcode.
- return generateTwoInstructionConfiguration(Instr, SelfAliasing);
+ return generateTwoInstructionPrototype(Instr, SelfAliasing);
} else {
- return generateSelfAliasingConfiguration(Instr, SelfAliasing);
+ return generateSelfAliasingPrototype(Instr, SelfAliasing);
}
}
-llvm::Expected<std::vector<BenchmarkConfiguration>>
-LatencyBenchmarkRunner::createConfigurations(unsigned Opcode) const {
- if (auto E = generateConfiguration(Opcode))
- return std::vector<BenchmarkConfiguration>{E.get()};
- else
- return E.takeError();
-}
-
std::vector<BenchmarkMeasure>
LatencyBenchmarkRunner::runMeasurements(const ExecutableFunction &Function,
const unsigned NumRepetitions) const {
Modified: llvm/trunk/tools/llvm-exegesis/lib/Latency.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/Latency.h?rev=335105&r1=335104&r2=335105&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/Latency.h (original)
+++ llvm/trunk/tools/llvm-exegesis/lib/Latency.h Wed Jun 20 01:52:30 2018
@@ -25,25 +25,22 @@ public:
using BenchmarkRunner::BenchmarkRunner;
~LatencyBenchmarkRunner() override;
- llvm::Expected<BenchmarkConfiguration>
- generateConfiguration(unsigned Opcode) const;
+ llvm::Expected<SnippetPrototype>
+ generatePrototype(unsigned Opcode) const override;
private:
llvm::Error isInfeasible(const llvm::MCInstrDesc &MCInstrDesc) const;
- llvm::Expected<BenchmarkConfiguration> generateSelfAliasingConfiguration(
+ llvm::Expected<SnippetPrototype> generateSelfAliasingPrototype(
const Instruction &Instr,
const AliasingConfigurations &SelfAliasing) const;
- llvm::Expected<BenchmarkConfiguration> generateTwoInstructionConfiguration(
+ llvm::Expected<SnippetPrototype> generateTwoInstructionPrototype(
const Instruction &Instr,
const AliasingConfigurations &SelfAliasing) const;
InstructionBenchmark::ModeE getMode() const override;
- llvm::Expected<std::vector<BenchmarkConfiguration>>
- createConfigurations(unsigned OpcodeIndex) const override;
-
std::vector<BenchmarkMeasure>
runMeasurements(const ExecutableFunction &EF,
const unsigned NumRepetitions) const override;
Modified: llvm/trunk/tools/llvm-exegesis/lib/MCInstrDescView.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/MCInstrDescView.cpp?rev=335105&r1=335104&r2=335105&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/MCInstrDescView.cpp (original)
+++ llvm/trunk/tools/llvm-exegesis/lib/MCInstrDescView.cpp Wed Jun 20 01:52:30 2018
@@ -19,7 +19,7 @@ namespace exegesis {
Instruction::Instruction(const llvm::MCInstrDesc &MCInstrDesc,
const RegisterAliasingTrackerCache &RATC)
- : Description(MCInstrDesc) {
+ : Description(&MCInstrDesc) {
unsigned OpIndex = 0;
for (; OpIndex < MCInstrDesc.getNumOperands(); ++OpIndex) {
const auto &OpInfo = MCInstrDesc.opInfo_begin()[OpIndex];
@@ -71,7 +71,7 @@ Instruction::Instruction(const llvm::MCI
// Assigning Operands to Variables.
for (auto &Op : Operands)
if (Op.VariableIndex >= 0)
- Variables[Op.VariableIndex].TiedOperands.push_back(&Op);
+ Variables[Op.VariableIndex].TiedOperands.push_back(Op.Index);
// Processing Aliasing.
DefRegisters = RATC.emptyRegisters();
UseRegisters = RATC.emptyRegisters();
@@ -86,6 +86,16 @@ Instruction::Instruction(const llvm::MCI
InstructionInstance::InstructionInstance(const Instruction &Instr)
: Instr(Instr), VariableValues(Instr.Variables.size()) {}
+InstructionInstance::InstructionInstance(InstructionInstance &&) noexcept =
+ default;
+
+InstructionInstance &InstructionInstance::
+operator=(InstructionInstance &&) noexcept = default;
+
+unsigned InstructionInstance::getOpcode() const {
+ return Instr.Description->getOpcode();
+}
+
llvm::MCOperand &InstructionInstance::getValueFor(const Variable &Var) {
return VariableValues[Var.Index];
}
@@ -96,22 +106,37 @@ llvm::MCOperand &InstructionInstance::ge
}
// forward declaration.
-static void randomize(const Variable &Var, llvm::MCOperand &AssignedValue);
+static void randomize(const Instruction &Instr, const Variable &Var,
+ llvm::MCOperand &AssignedValue);
+
+bool InstructionInstance::hasImmediateVariables() const {
+ return llvm::any_of(Instr.Variables, [this](const Variable &Var) {
+ assert(!Var.TiedOperands.empty());
+ const unsigned OpIndex = Var.TiedOperands[0];
+ const Operand &Op = Instr.Operands[OpIndex];
+ assert(Op.Info);
+ return Op.Info->OperandType == llvm::MCOI::OPERAND_IMMEDIATE;
+ });
+}
llvm::MCInst InstructionInstance::randomizeUnsetVariablesAndBuild() {
for (const Variable &Var : Instr.Variables) {
llvm::MCOperand &AssignedValue = getValueFor(Var);
if (!AssignedValue.isValid())
- randomize(Var, AssignedValue);
+ randomize(Instr, Var, AssignedValue);
}
llvm::MCInst Result;
- Result.setOpcode(Instr.Description.Opcode);
+ Result.setOpcode(Instr.Description->Opcode);
for (const auto &Op : Instr.Operands)
if (Op.IsExplicit)
Result.addOperand(getValueFor(Op));
return Result;
}
+SnippetPrototype::SnippetPrototype(SnippetPrototype &&) = default;
+
+SnippetPrototype &SnippetPrototype::operator=(SnippetPrototype &&) = default;
+
bool RegisterOperandAssignment::
operator==(const RegisterOperandAssignment &Other) const {
return std::tie(Op, Reg) == std::tie(Other.Op, Other.Reg);
@@ -183,10 +208,10 @@ static auto randomElement(const C &Conta
return Container[randomIndex(Container.size())];
}
-static void randomize(const Variable &Var, llvm::MCOperand &AssignedValue) {
+static void randomize(const Instruction &Instr, const Variable &Var,
+ llvm::MCOperand &AssignedValue) {
assert(!Var.TiedOperands.empty());
- assert(Var.TiedOperands.front() != nullptr);
- const Operand &Op = *Var.TiedOperands.front();
+ const Operand &Op = Instr.Operands[Var.TiedOperands.front()];
assert(Op.Info != nullptr);
const auto &OpInfo = *Op.Info;
switch (OpInfo.OperandType) {
Modified: llvm/trunk/tools/llvm-exegesis/lib/MCInstrDescView.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/MCInstrDescView.h?rev=335105&r1=335104&r2=335105&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/MCInstrDescView.h (original)
+++ llvm/trunk/tools/llvm-exegesis/lib/MCInstrDescView.h Wed Jun 20 01:52:30 2018
@@ -35,7 +35,8 @@ struct Operand; // forward declaration.
// A variable represents the value associated to an Operand or a set of Operands
// if they are tied together.
struct Variable {
- llvm::SmallVector<const Operand *, 2> TiedOperands;
+ // The indices of the operands tied to this Variable.
+ llvm::SmallVector<unsigned, 2> TiedOperands;
llvm::MCOperand AssignedValue;
// The index of this Variable in Instruction.Variables and its associated
// Value in InstructionInstance.VariableValues.
@@ -71,7 +72,7 @@ struct Instruction {
Instruction(const llvm::MCInstrDesc &MCInstrDesc,
const RegisterAliasingTrackerCache &ATC);
- const llvm::MCInstrDesc &Description;
+ const llvm::MCInstrDesc *Description; // Never nullptr.
llvm::SmallVector<Operand, 8> Operands;
llvm::SmallVector<Variable, 4> Variables;
llvm::BitVector DefRegisters; // The union of the aliased def registers.
@@ -82,17 +83,46 @@ struct Instruction {
struct InstructionInstance {
InstructionInstance(const Instruction &Instr);
+ // No copy.
+ InstructionInstance(const InstructionInstance &) = delete;
+ InstructionInstance &operator=(const InstructionInstance &) = delete;
+
+ // Moving is OK.
+ InstructionInstance(InstructionInstance &&) noexcept;
+ InstructionInstance &operator=(InstructionInstance &&) noexcept;
+
+ unsigned getOpcode() const;
llvm::MCOperand &getValueFor(const Variable &Var);
llvm::MCOperand &getValueFor(const Operand &Op);
+ bool hasImmediateVariables() const;
// Assigns a Random Value to all Variables that are still Invalid and returns
// the instance as an llvm::MCInst.
llvm::MCInst randomizeUnsetVariablesAndBuild();
- const Instruction &Instr;
+ Instruction Instr;
llvm::SmallVector<llvm::MCOperand, 4> VariableValues;
};
+// A prototype is a set of InstructionInstances with an explanation of how
+// it's been built. The prototype can then be randomized to exercice several
+// immediate values. It is also used to gather the used registers and define
+// their initial values.
+struct SnippetPrototype {
+ SnippetPrototype() = default;
+
+ // No copy.
+ SnippetPrototype(const SnippetPrototype &) = delete;
+ SnippetPrototype &operator=(const SnippetPrototype &) = delete;
+
+ // Moving is OK.
+ SnippetPrototype(SnippetPrototype &&) noexcept;
+ SnippetPrototype &operator=(SnippetPrototype &&) noexcept;
+
+ std::string Explanation;
+ std::vector<InstructionInstance> Snippet;
+};
+
// Represents the assignment of a Register to an Operand.
struct RegisterOperandAssignment {
RegisterOperandAssignment(const Operand *Operand, llvm::MCPhysReg Reg)
Modified: llvm/trunk/tools/llvm-exegesis/lib/Uops.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/Uops.cpp?rev=335105&r1=335104&r2=335105&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/Uops.cpp (original)
+++ llvm/trunk/tools/llvm-exegesis/lib/Uops.cpp Wed Jun 20 01:52:30 2018
@@ -102,11 +102,12 @@ UopsBenchmarkRunner::isInfeasible(const
}
// Returns whether this Variable ties Use and Def operands together.
-static bool hasTiedOperands(const Variable &Var) {
+static bool hasTiedOperands(const Instruction &Instr, const Variable &Var) {
bool HasUse = false;
bool HasDef = false;
- for (const Operand *Op : Var.TiedOperands) {
- if (Op->IsDef)
+ for (const unsigned OpIndex : Var.TiedOperands) {
+ const Operand &Op = Instr.Operands[OpIndex];
+ if (Op.IsDef)
HasDef = true;
else
HasUse = true;
@@ -118,7 +119,7 @@ static llvm::SmallVector<const Variable
getTiedVariables(const Instruction &Instr) {
llvm::SmallVector<const Variable *, 8> Result;
for (const auto &Var : Instr.Variables)
- if (hasTiedOperands(Var))
+ if (hasTiedOperands(Instr, Var))
Result.push_back(&Var);
return Result;
}
@@ -135,26 +136,24 @@ InstructionBenchmark::ModeE UopsBenchmar
return InstructionBenchmark::Uops;
}
-llvm::Expected<BenchmarkConfiguration>
-UopsBenchmarkRunner::generateConfiguration(unsigned Opcode) const {
+llvm::Expected<SnippetPrototype>
+UopsBenchmarkRunner::generatePrototype(unsigned Opcode) const {
const auto &InstrDesc = MCInstrInfo.get(Opcode);
if (auto E = isInfeasible(InstrDesc))
return std::move(E);
const Instruction Instr(InstrDesc, RATC);
const AliasingConfigurations SelfAliasing(Instr, Instr);
if (SelfAliasing.empty()) {
- InstructionInstance II(Instr);
- BenchmarkConfiguration Conf;
- Conf.Info = "instruction is parallel, repeating a random one.";
- Conf.Snippet = {II.randomizeUnsetVariablesAndBuild()};
- return Conf;
+ SnippetPrototype Prototype;
+ Prototype.Explanation = "instruction is parallel, repeating a random one.";
+ Prototype.Snippet.emplace_back(Instr);
+ return Prototype;
}
if (SelfAliasing.hasImplicitAliasing()) {
- InstructionInstance II(Instr);
- BenchmarkConfiguration Conf;
- Conf.Info = "instruction is serial, repeating a random one.";
- Conf.Snippet = {II.randomizeUnsetVariablesAndBuild()};
- return Conf;
+ SnippetPrototype Prototype;
+ Prototype.Explanation = "instruction is serial, repeating a random one.";
+ Prototype.Snippet.emplace_back(Instr);
+ return Prototype;
}
const auto TiedVariables = getTiedVariables(Instr);
if (!TiedVariables.empty()) {
@@ -162,19 +161,20 @@ UopsBenchmarkRunner::generateConfigurati
return llvm::make_error<llvm::StringError>(
"Infeasible : don't know how to handle several tied variables",
llvm::inconvertibleErrorCode());
- BenchmarkConfiguration Conf;
- Conf.Info = "instruction has tied variables using static renaming.";
const Variable *Var = TiedVariables.front();
assert(Var);
assert(!Var->TiedOperands.empty());
- const Operand &Operand = *Var->TiedOperands.front();
- assert(Operand.Tracker);
- for (const llvm::MCPhysReg Reg : Operand.Tracker->sourceBits().set_bits()) {
- InstructionInstance II(Instr);
- II.getValueFor(*Var) = llvm::MCOperand::createReg(Reg);
- Conf.Snippet.push_back(II.randomizeUnsetVariablesAndBuild());
+ const Operand &Op = Instr.Operands[Var->TiedOperands.front()];
+ assert(Op.Tracker);
+ SnippetPrototype Prototype;
+ Prototype.Explanation =
+ "instruction has tied variables using static renaming.";
+ for (const llvm::MCPhysReg Reg : Op.Tracker->sourceBits().set_bits()) {
+ Prototype.Snippet.emplace_back(Instr);
+ Prototype.Snippet.back().getValueFor(*Var) =
+ llvm::MCOperand::createReg(Reg);
}
- return Conf;
+ return Prototype;
}
InstructionInstance II(Instr);
// No tied variables, we pick random values for defs.
@@ -201,19 +201,11 @@ UopsBenchmarkRunner::generateConfigurati
II.getValueFor(Op) = llvm::MCOperand::createReg(RandomReg);
}
}
- BenchmarkConfiguration Conf;
- Conf.Info =
+ SnippetPrototype Prototype;
+ Prototype.Explanation =
"instruction has no tied variables picking Uses different from defs";
- Conf.Snippet = {II.randomizeUnsetVariablesAndBuild()};
- return Conf;
-}
-
-llvm::Expected<std::vector<BenchmarkConfiguration>>
-UopsBenchmarkRunner::createConfigurations(unsigned Opcode) const {
- if (auto E = generateConfiguration(Opcode))
- return std::vector<BenchmarkConfiguration>{E.get()};
- else
- return E.takeError();
+ Prototype.Snippet.push_back(std::move(II));
+ return Prototype;
}
std::vector<BenchmarkMeasure>
Modified: llvm/trunk/tools/llvm-exegesis/lib/Uops.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/Uops.h?rev=335105&r1=335104&r2=335105&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/Uops.h (original)
+++ llvm/trunk/tools/llvm-exegesis/lib/Uops.h Wed Jun 20 01:52:30 2018
@@ -24,17 +24,14 @@ public:
using BenchmarkRunner::BenchmarkRunner;
~UopsBenchmarkRunner() override;
- llvm::Expected<BenchmarkConfiguration>
- generateConfiguration(unsigned Opcode) const;
+ llvm::Expected<SnippetPrototype>
+ generatePrototype(unsigned Opcode) const override;
private:
llvm::Error isInfeasible(const llvm::MCInstrDesc &MCInstrDesc) const;
InstructionBenchmark::ModeE getMode() const override;
- llvm::Expected<std::vector<BenchmarkConfiguration>>
- createConfigurations(unsigned Opcode) const override;
-
std::vector<BenchmarkMeasure>
runMeasurements(const ExecutableFunction &EF,
const unsigned NumRepetitions) const override;
Modified: llvm/trunk/unittests/tools/llvm-exegesis/X86/SnippetGeneratorTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/tools/llvm-exegesis/X86/SnippetGeneratorTest.cpp?rev=335105&r1=335104&r2=335105&view=diff
==============================================================================
--- llvm/trunk/unittests/tools/llvm-exegesis/X86/SnippetGeneratorTest.cpp (original)
+++ llvm/trunk/unittests/tools/llvm-exegesis/X86/SnippetGeneratorTest.cpp Wed Jun 20 01:52:30 2018
@@ -20,6 +20,13 @@
namespace exegesis {
namespace {
+using testing::HasSubstr;
+using testing::Not;
+using testing::SizeIs;
+
+MATCHER(IsInvalid, "") { return !arg.isValid(); }
+MATCHER(IsReg, "") { return arg.isReg(); }
+
class X86SnippetGeneratorTest : public ::testing::Test {
protected:
X86SnippetGeneratorTest()
@@ -38,20 +45,26 @@ protected:
const llvm::MCRegisterInfo &MCRegisterInfo;
};
-class LatencySnippetGeneratorTest : public X86SnippetGeneratorTest {
+template <typename BenchmarkRunner>
+class SnippetGeneratorTest : public X86SnippetGeneratorTest {
protected:
- LatencySnippetGeneratorTest() : Runner(State) {}
+ SnippetGeneratorTest() : Runner(State) {}
- BenchmarkConfiguration checkAndGetConfiguration(unsigned Opcode) {
+ SnippetPrototype checkAndGetConfigurations(unsigned Opcode) {
randomGenerator().seed(0); // Initialize seed.
- auto ConfOrError = Runner.generateConfiguration(Opcode);
- EXPECT_FALSE(ConfOrError.takeError()); // Valid configuration.
- return ConfOrError.get();
+ auto ProtoOrError = Runner.generatePrototype(Opcode);
+ EXPECT_FALSE(ProtoOrError.takeError()); // Valid configuration.
+ return std::move(ProtoOrError.get());
}
- LatencyBenchmarkRunner Runner;
+ BenchmarkRunner Runner;
};
+using LatencySnippetGeneratorTest =
+ SnippetGeneratorTest<LatencyBenchmarkRunner>;
+
+using UopsSnippetGeneratorTest = SnippetGeneratorTest<UopsBenchmarkRunner>;
+
TEST_F(LatencySnippetGeneratorTest, ImplicitSelfDependency) {
// ADC16i16 self alias because of implicit use and def.
@@ -61,17 +74,17 @@ TEST_F(LatencySnippetGeneratorTest, Impl
// implicit use : AX
// implicit use : EFLAGS
const unsigned Opcode = llvm::X86::ADC16i16;
- auto Conf = checkAndGetConfiguration(Opcode);
- EXPECT_THAT(Conf.Info, testing::HasSubstr("implicit"));
- ASSERT_THAT(Conf.Snippet, testing::SizeIs(1));
- const llvm::MCInst Instr = Conf.Snippet[0];
- EXPECT_THAT(Instr.getOpcode(), Opcode);
- EXPECT_THAT(Instr.getNumOperands(), 1);
- EXPECT_TRUE(Instr.getOperand(0).isImm()); // Use
EXPECT_THAT(MCInstrInfo.get(Opcode).getImplicitDefs()[0], llvm::X86::AX);
EXPECT_THAT(MCInstrInfo.get(Opcode).getImplicitDefs()[1], llvm::X86::EFLAGS);
EXPECT_THAT(MCInstrInfo.get(Opcode).getImplicitUses()[0], llvm::X86::AX);
EXPECT_THAT(MCInstrInfo.get(Opcode).getImplicitUses()[1], llvm::X86::EFLAGS);
+ const SnippetPrototype Proto = checkAndGetConfigurations(Opcode);
+ EXPECT_THAT(Proto.Explanation, HasSubstr("implicit"));
+ ASSERT_THAT(Proto.Snippet, SizeIs(1));
+ const InstructionInstance &II = Proto.Snippet[0];
+ EXPECT_THAT(II.getOpcode(), Opcode);
+ ASSERT_THAT(II.VariableValues, SizeIs(1)); // Imm.
+ EXPECT_THAT(II.VariableValues[0], IsInvalid()) << "Immediate is not set";
}
TEST_F(LatencySnippetGeneratorTest, ExplicitSelfDependency) {
@@ -82,18 +95,15 @@ TEST_F(LatencySnippetGeneratorTest, Expl
// explicit use 2 : imm
// implicit def : EFLAGS
const unsigned Opcode = llvm::X86::ADD16ri;
- auto Conf = checkAndGetConfiguration(Opcode);
- EXPECT_THAT(Conf.Info, testing::HasSubstr("explicit"));
- ASSERT_THAT(Conf.Snippet, testing::SizeIs(1));
- const llvm::MCInst Instr = Conf.Snippet[0];
- EXPECT_THAT(Instr.getOpcode(), Opcode);
- EXPECT_THAT(Instr.getNumOperands(), 3);
- EXPECT_TRUE(Instr.getOperand(0).isReg());
- EXPECT_TRUE(Instr.getOperand(1).isReg());
- EXPECT_THAT(Instr.getOperand(0).getReg(), Instr.getOperand(1).getReg())
- << "Op0 and Op1 should have the same value";
- EXPECT_TRUE(Instr.getOperand(2).isImm());
EXPECT_THAT(MCInstrInfo.get(Opcode).getImplicitDefs()[0], llvm::X86::EFLAGS);
+ const SnippetPrototype Proto = checkAndGetConfigurations(Opcode);
+ EXPECT_THAT(Proto.Explanation, HasSubstr("explicit"));
+ ASSERT_THAT(Proto.Snippet, SizeIs(1));
+ const InstructionInstance &II = Proto.Snippet[0];
+ EXPECT_THAT(II.getOpcode(), Opcode);
+ ASSERT_THAT(II.VariableValues, SizeIs(2));
+ EXPECT_THAT(II.VariableValues[0], IsReg()) << "Operand 0 and 1";
+ EXPECT_THAT(II.VariableValues[1], IsInvalid()) << "Operand 2 is not set";
}
TEST_F(LatencySnippetGeneratorTest, DependencyThroughOtherOpcode) {
@@ -103,49 +113,43 @@ TEST_F(LatencySnippetGeneratorTest, Depe
// implicit def : EFLAGS
const unsigned Opcode = llvm::X86::CMP64rr;
- auto Conf = checkAndGetConfiguration(Opcode);
- EXPECT_THAT(Conf.Info, testing::HasSubstr("cycle through"));
- ASSERT_THAT(Conf.Snippet, testing::SizeIs(2));
- const llvm::MCInst Instr = Conf.Snippet[0];
- EXPECT_THAT(Instr.getOpcode(), Opcode);
+ const SnippetPrototype Proto = checkAndGetConfigurations(Opcode);
+ EXPECT_THAT(Proto.Explanation, HasSubstr("cycle through"));
+ ASSERT_THAT(Proto.Snippet, SizeIs(2));
+ const InstructionInstance &II = Proto.Snippet[0];
+ EXPECT_THAT(II.getOpcode(), Opcode);
+ ASSERT_THAT(II.VariableValues, SizeIs(2));
+ EXPECT_THAT(II.VariableValues[0], IsReg());
+ EXPECT_THAT(II.VariableValues[1], IsInvalid());
+ EXPECT_THAT(Proto.Snippet[1].getOpcode(), Not(Opcode));
// TODO: check that the two instructions alias each other.
}
TEST_F(LatencySnippetGeneratorTest, LAHF) {
const unsigned Opcode = llvm::X86::LAHF;
- auto Conf = checkAndGetConfiguration(Opcode);
- EXPECT_THAT(Conf.Info, testing::HasSubstr("cycle through"));
- ASSERT_THAT(Conf.Snippet, testing::SizeIs(2));
- const llvm::MCInst Instr = Conf.Snippet[0];
- EXPECT_THAT(Instr.getOpcode(), Opcode);
+ const SnippetPrototype Proto = checkAndGetConfigurations(Opcode);
+ EXPECT_THAT(Proto.Explanation, HasSubstr("cycle through"));
+ ASSERT_THAT(Proto.Snippet, SizeIs(2));
+ const InstructionInstance &II = Proto.Snippet[0];
+ EXPECT_THAT(II.getOpcode(), Opcode);
+ ASSERT_THAT(II.VariableValues, SizeIs(0));
}
-class UopsSnippetGeneratorTest : public X86SnippetGeneratorTest {
-protected:
- UopsSnippetGeneratorTest() : Runner(State) {}
-
- BenchmarkConfiguration checkAndGetConfiguration(unsigned Opcode) {
- randomGenerator().seed(0); // Initialize seed.
- auto ConfOrError = Runner.generateConfiguration(Opcode);
- EXPECT_FALSE(ConfOrError.takeError()); // Valid configuration.
- return ConfOrError.get();
- }
-
- UopsBenchmarkRunner Runner;
-};
-
TEST_F(UopsSnippetGeneratorTest, ParallelInstruction) {
- // BNDCL32rr is parallelno matter what.
+ // BNDCL32rr is parallel no matter what.
// explicit use 0 : reg RegClass=BNDR
// explicit use 1 : reg RegClass=GR32
const unsigned Opcode = llvm::X86::BNDCL32rr;
- auto Conf = checkAndGetConfiguration(Opcode);
- EXPECT_THAT(Conf.Info, testing::HasSubstr("parallel"));
- ASSERT_THAT(Conf.Snippet, testing::SizeIs(1));
- const llvm::MCInst Instr = Conf.Snippet[0];
- EXPECT_THAT(Instr.getOpcode(), Opcode);
+ const SnippetPrototype Proto = checkAndGetConfigurations(Opcode);
+ EXPECT_THAT(Proto.Explanation, HasSubstr("parallel"));
+ ASSERT_THAT(Proto.Snippet, SizeIs(1));
+ const InstructionInstance &II = Proto.Snippet[0];
+ EXPECT_THAT(II.getOpcode(), Opcode);
+ ASSERT_THAT(II.VariableValues, SizeIs(2));
+ EXPECT_THAT(II.VariableValues[0], IsInvalid());
+ EXPECT_THAT(II.VariableValues[1], IsInvalid());
}
TEST_F(UopsSnippetGeneratorTest, SerialInstruction) {
@@ -155,11 +159,12 @@ TEST_F(UopsSnippetGeneratorTest, SerialI
// implicit def : EDX
// implicit use : EAX
const unsigned Opcode = llvm::X86::CDQ;
- auto Conf = checkAndGetConfiguration(Opcode);
- EXPECT_THAT(Conf.Info, testing::HasSubstr("serial"));
- ASSERT_THAT(Conf.Snippet, testing::SizeIs(1));
- const llvm::MCInst Instr = Conf.Snippet[0];
- EXPECT_THAT(Instr.getOpcode(), Opcode);
+ const SnippetPrototype Proto = checkAndGetConfigurations(Opcode);
+ EXPECT_THAT(Proto.Explanation, HasSubstr("serial"));
+ ASSERT_THAT(Proto.Snippet, SizeIs(1));
+ const InstructionInstance &II = Proto.Snippet[0];
+ EXPECT_THAT(II.getOpcode(), Opcode);
+ ASSERT_THAT(II.VariableValues, SizeIs(0));
}
TEST_F(UopsSnippetGeneratorTest, StaticRenaming) {
@@ -171,14 +176,16 @@ TEST_F(UopsSnippetGeneratorTest, StaticR
// explicit use 2 : reg RegClass=GR32
// implicit use : EFLAGS
const unsigned Opcode = llvm::X86::CMOVA32rr;
- auto Conf = checkAndGetConfiguration(Opcode);
- EXPECT_THAT(Conf.Info, testing::HasSubstr("static renaming"));
+ const SnippetPrototype Proto = checkAndGetConfigurations(Opcode);
+ EXPECT_THAT(Proto.Explanation, HasSubstr("static renaming"));
constexpr const unsigned kInstructionCount = 15;
- ASSERT_THAT(Conf.Snippet, testing::SizeIs(kInstructionCount));
+ ASSERT_THAT(Proto.Snippet, SizeIs(kInstructionCount));
std::unordered_set<unsigned> AllDefRegisters;
- for (const auto &Inst : Conf.Snippet)
- AllDefRegisters.insert(Inst.getOperand(0).getReg());
- EXPECT_THAT(AllDefRegisters, testing::SizeIs(kInstructionCount))
+ for (const auto &II : Proto.Snippet) {
+ ASSERT_THAT(II.VariableValues, SizeIs(2));
+ AllDefRegisters.insert(II.VariableValues[0].getReg());
+ }
+ EXPECT_THAT(AllDefRegisters, SizeIs(kInstructionCount))
<< "Each instruction writes to a different register";
}
@@ -192,19 +199,17 @@ TEST_F(UopsSnippetGeneratorTest, NoTiedV
// explicit use 3 : imm
// implicit use : EFLAGS
const unsigned Opcode = llvm::X86::CMOV_GR32;
- auto Conf = checkAndGetConfiguration(Opcode);
- EXPECT_THAT(Conf.Info, testing::HasSubstr("no tied variables"));
- ASSERT_THAT(Conf.Snippet, testing::SizeIs(1));
- const llvm::MCInst Instr = Conf.Snippet[0];
- EXPECT_THAT(Instr.getOpcode(), Opcode);
- EXPECT_THAT(Instr.getNumOperands(), 4);
- EXPECT_THAT(Instr.getOperand(0).getReg(),
- testing::Not(Instr.getOperand(1).getReg()))
+ const SnippetPrototype Proto = checkAndGetConfigurations(Opcode);
+ EXPECT_THAT(Proto.Explanation, HasSubstr("no tied variables"));
+ ASSERT_THAT(Proto.Snippet, SizeIs(1));
+ const InstructionInstance &II = Proto.Snippet[0];
+ EXPECT_THAT(II.getOpcode(), Opcode);
+ ASSERT_THAT(II.VariableValues, SizeIs(4));
+ EXPECT_THAT(II.VariableValues[0].getReg(), Not(II.VariableValues[1].getReg()))
<< "Def is different from first Use";
- EXPECT_THAT(Instr.getOperand(0).getReg(),
- testing::Not(Instr.getOperand(2).getReg()))
+ EXPECT_THAT(II.VariableValues[0].getReg(), Not(II.VariableValues[2].getReg()))
<< "Def is different from second Use";
- EXPECT_THAT(Instr.getOperand(3).getImm(), 1);
+ EXPECT_THAT(II.VariableValues[3], IsInvalid());
}
} // namespace
More information about the llvm-commits
mailing list