mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-01-31 20:51:52 +01:00
[llvm-exegesis][NFC] moving code around.
Summary: Renaming InstructionBuilder into InstructionTemplate and moving code generation tools from MCInstrDescView to CodeTemplate. Reviewers: courbet Subscribers: tschuett, llvm-commits Differential Revision: https://reviews.llvm.org/D52592 llvm-svn: 343188
This commit is contained in:
parent
1790db7411
commit
b129eee8b8
@ -10,19 +10,13 @@
|
||||
#ifndef LLVM_TOOLS_LLVM_EXEGESIS_BENCHMARKCODE_H
|
||||
#define LLVM_TOOLS_LLVM_EXEGESIS_BENCHMARKCODE_H
|
||||
|
||||
#include "llvm/ADT/APInt.h"
|
||||
#include "RegisterValue.h"
|
||||
#include "llvm/MC/MCInst.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace exegesis {
|
||||
|
||||
// A simple object storing the value for a particular register.
|
||||
struct RegisterValue {
|
||||
unsigned Register;
|
||||
llvm::APInt Value;
|
||||
};
|
||||
|
||||
// A collection of instructions that are to be assembled, executed and measured.
|
||||
struct BenchmarkCode {
|
||||
// The sequence of instructions that are to be repeated.
|
||||
|
@ -15,4 +15,150 @@ CodeTemplate::CodeTemplate(CodeTemplate &&) = default;
|
||||
|
||||
CodeTemplate &CodeTemplate::operator=(CodeTemplate &&) = default;
|
||||
|
||||
InstructionTemplate::InstructionTemplate(const Instruction &Instr)
|
||||
: Instr(Instr), VariableValues(Instr.Variables.size()) {}
|
||||
|
||||
InstructionTemplate::InstructionTemplate(InstructionTemplate &&) = default;
|
||||
|
||||
InstructionTemplate &InstructionTemplate::
|
||||
operator=(InstructionTemplate &&) = default;
|
||||
|
||||
InstructionTemplate::InstructionTemplate(const InstructionTemplate &) = default;
|
||||
|
||||
InstructionTemplate &InstructionTemplate::
|
||||
operator=(const InstructionTemplate &) = default;
|
||||
|
||||
unsigned InstructionTemplate::getOpcode() const {
|
||||
return Instr.Description->getOpcode();
|
||||
}
|
||||
|
||||
llvm::MCOperand &InstructionTemplate::getValueFor(const Variable &Var) {
|
||||
return VariableValues[Var.Index];
|
||||
}
|
||||
|
||||
const llvm::MCOperand &
|
||||
InstructionTemplate::getValueFor(const Variable &Var) const {
|
||||
return VariableValues[Var.Index];
|
||||
}
|
||||
|
||||
llvm::MCOperand &InstructionTemplate::getValueFor(const Operand &Op) {
|
||||
assert(Op.VariableIndex >= 0);
|
||||
return getValueFor(Instr.Variables[Op.VariableIndex]);
|
||||
}
|
||||
|
||||
const llvm::MCOperand &
|
||||
InstructionTemplate::getValueFor(const Operand &Op) const {
|
||||
assert(Op.VariableIndex >= 0);
|
||||
return getValueFor(Instr.Variables[Op.VariableIndex]);
|
||||
}
|
||||
|
||||
// forward declaration.
|
||||
static void randomize(const Instruction &Instr, const Variable &Var,
|
||||
llvm::MCOperand &AssignedValue,
|
||||
const llvm::BitVector &ForbiddenRegs);
|
||||
|
||||
bool InstructionTemplate::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;
|
||||
});
|
||||
}
|
||||
|
||||
void InstructionTemplate::randomizeUnsetVariables(
|
||||
const llvm::BitVector &ForbiddenRegs) {
|
||||
for (const Variable &Var : Instr.Variables) {
|
||||
llvm::MCOperand &AssignedValue = getValueFor(Var);
|
||||
if (!AssignedValue.isValid())
|
||||
randomize(Instr, Var, AssignedValue, ForbiddenRegs);
|
||||
}
|
||||
}
|
||||
|
||||
llvm::MCInst InstructionTemplate::build() const {
|
||||
llvm::MCInst Result;
|
||||
Result.setOpcode(Instr.Description->Opcode);
|
||||
for (const auto &Op : Instr.Operands)
|
||||
if (Op.IsExplicit)
|
||||
Result.addOperand(getValueFor(Op));
|
||||
return Result;
|
||||
}
|
||||
|
||||
std::mt19937 &randomGenerator() {
|
||||
static std::random_device RandomDevice;
|
||||
static std::mt19937 RandomGenerator(RandomDevice());
|
||||
return RandomGenerator;
|
||||
}
|
||||
|
||||
static size_t randomIndex(size_t Size) {
|
||||
assert(Size > 0);
|
||||
std::uniform_int_distribution<> Distribution(0, Size - 1);
|
||||
return Distribution(randomGenerator());
|
||||
}
|
||||
|
||||
template <typename C>
|
||||
static auto randomElement(const C &Container) -> decltype(Container[0]) {
|
||||
return Container[randomIndex(Container.size())];
|
||||
}
|
||||
|
||||
static void randomize(const Instruction &Instr, const Variable &Var,
|
||||
llvm::MCOperand &AssignedValue,
|
||||
const llvm::BitVector &ForbiddenRegs) {
|
||||
assert(!Var.TiedOperands.empty());
|
||||
const Operand &Op = Instr.Operands[Var.TiedOperands.front()];
|
||||
assert(Op.Info != nullptr);
|
||||
const auto &OpInfo = *Op.Info;
|
||||
switch (OpInfo.OperandType) {
|
||||
case llvm::MCOI::OperandType::OPERAND_IMMEDIATE:
|
||||
// FIXME: explore immediate values too.
|
||||
AssignedValue = llvm::MCOperand::createImm(1);
|
||||
break;
|
||||
case llvm::MCOI::OperandType::OPERAND_REGISTER: {
|
||||
assert(Op.Tracker);
|
||||
auto AllowedRegs = Op.Tracker->sourceBits();
|
||||
assert(AllowedRegs.size() == ForbiddenRegs.size());
|
||||
for (auto I : ForbiddenRegs.set_bits())
|
||||
AllowedRegs.reset(I);
|
||||
AssignedValue = llvm::MCOperand::createReg(randomBit(AllowedRegs));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void setRegisterOperandValue(const RegisterOperandAssignment &ROV,
|
||||
InstructionTemplate &IB) {
|
||||
assert(ROV.Op);
|
||||
if (ROV.Op->IsExplicit) {
|
||||
auto &AssignedValue = IB.getValueFor(*ROV.Op);
|
||||
if (AssignedValue.isValid()) {
|
||||
assert(AssignedValue.isReg() && AssignedValue.getReg() == ROV.Reg);
|
||||
return;
|
||||
}
|
||||
AssignedValue = llvm::MCOperand::createReg(ROV.Reg);
|
||||
} else {
|
||||
assert(ROV.Op->ImplicitReg != nullptr);
|
||||
assert(ROV.Reg == *ROV.Op->ImplicitReg);
|
||||
}
|
||||
}
|
||||
|
||||
size_t randomBit(const llvm::BitVector &Vector) {
|
||||
assert(Vector.any());
|
||||
auto Itr = Vector.set_bits_begin();
|
||||
for (size_t I = randomIndex(Vector.count()); I != 0; --I)
|
||||
++Itr;
|
||||
return *Itr;
|
||||
}
|
||||
|
||||
void setRandomAliasing(const AliasingConfigurations &AliasingConfigurations,
|
||||
InstructionTemplate &DefIB, InstructionTemplate &UseIB) {
|
||||
assert(!AliasingConfigurations.empty());
|
||||
assert(!AliasingConfigurations.hasImplicitAliasing());
|
||||
const auto &RandomConf = randomElement(AliasingConfigurations.Configurations);
|
||||
setRegisterOperandValue(randomElement(RandomConf.Defs), DefIB);
|
||||
setRegisterOperandValue(randomElement(RandomConf.Uses), UseIB);
|
||||
}
|
||||
|
||||
} // namespace exegesis
|
||||
|
@ -8,10 +8,8 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// A CodeTemplate is a set of InstructionBuilders that may not be fully
|
||||
/// specified (i.e. some variables are not yet set). This allows the
|
||||
/// BenchmarkRunner to instantiate it many times with specific values to study
|
||||
/// their impact on instruction's performance.
|
||||
/// A set of structures and functions to craft instructions for the
|
||||
/// SnippetGenerator.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
@ -22,6 +20,39 @@
|
||||
|
||||
namespace exegesis {
|
||||
|
||||
// A template for an Instruction holding values for each of its Variables.
|
||||
struct InstructionTemplate {
|
||||
InstructionTemplate(const Instruction &Instr);
|
||||
|
||||
InstructionTemplate(const InstructionTemplate &); // default
|
||||
InstructionTemplate &operator=(const InstructionTemplate &); // default
|
||||
InstructionTemplate(InstructionTemplate &&); // default
|
||||
InstructionTemplate &operator=(InstructionTemplate &&); // default
|
||||
|
||||
unsigned getOpcode() const;
|
||||
llvm::MCOperand &getValueFor(const Variable &Var);
|
||||
const llvm::MCOperand &getValueFor(const Variable &Var) const;
|
||||
llvm::MCOperand &getValueFor(const Operand &Op);
|
||||
const llvm::MCOperand &getValueFor(const Operand &Op) const;
|
||||
bool hasImmediateVariables() const;
|
||||
|
||||
// Assigns a Random Value to all Variables that are still Invalid.
|
||||
// Do not use any of the registers in `ForbiddenRegs`.
|
||||
void randomizeUnsetVariables(const llvm::BitVector &ForbiddenRegs);
|
||||
|
||||
// Builds an llvm::MCInst from this InstructionTemplate setting its operands
|
||||
// to the corresponding variable values. Precondition: All VariableValues must
|
||||
// be set.
|
||||
llvm::MCInst build() const;
|
||||
|
||||
Instruction Instr;
|
||||
llvm::SmallVector<llvm::MCOperand, 4> VariableValues;
|
||||
};
|
||||
|
||||
// A CodeTemplate is a set of InstructionTemplates that may not be fully
|
||||
// specified (i.e. some variables are not yet set). This allows the
|
||||
// BenchmarkRunner to instantiate it many times with specific values to study
|
||||
// their impact on instruction's performance.
|
||||
struct CodeTemplate {
|
||||
CodeTemplate() = default;
|
||||
|
||||
@ -33,12 +64,26 @@ struct CodeTemplate {
|
||||
// Some information about how this template has been created.
|
||||
std::string Info;
|
||||
// The list of the instructions for this template.
|
||||
std::vector<InstructionBuilder> Instructions;
|
||||
std::vector<InstructionTemplate> Instructions;
|
||||
// If the template uses the provided scratch memory, the register in which
|
||||
// the pointer to this memory is passed in to the function.
|
||||
unsigned ScratchSpacePointerInReg = 0;
|
||||
};
|
||||
|
||||
// A global Random Number Generator to randomize configurations.
|
||||
// FIXME: Move random number generation into an object and make it seedable for
|
||||
// unit tests.
|
||||
std::mt19937 &randomGenerator();
|
||||
|
||||
// Picks a random bit among the bits set in Vector and returns its index.
|
||||
// Precondition: Vector must have at least one bit set.
|
||||
size_t randomBit(const llvm::BitVector &Vector);
|
||||
|
||||
// Picks a random configuration, then selects a random def and a random use from
|
||||
// it and finally set the selected values in the provided InstructionInstances.
|
||||
void setRandomAliasing(const AliasingConfigurations &AliasingConfigurations,
|
||||
InstructionTemplate &DefIB, InstructionTemplate &UseIB);
|
||||
|
||||
} // namespace exegesis
|
||||
|
||||
#endif // LLVM_TOOLS_LLVM_EXEGESIS_CODETEMPLATE_H
|
||||
|
@ -62,17 +62,17 @@ LatencySnippetGenerator::generateTwoInstructionPrototype(
|
||||
const AliasingConfigurations Back(OtherInstr, Instr);
|
||||
if (Forward.empty() || Back.empty())
|
||||
continue;
|
||||
InstructionBuilder ThisIB(Instr);
|
||||
InstructionBuilder OtherIB(OtherInstr);
|
||||
InstructionTemplate ThisIT(Instr);
|
||||
InstructionTemplate OtherIT(OtherInstr);
|
||||
if (!Forward.hasImplicitAliasing())
|
||||
setRandomAliasing(Forward, ThisIB, OtherIB);
|
||||
setRandomAliasing(Forward, ThisIT, OtherIT);
|
||||
if (!Back.hasImplicitAliasing())
|
||||
setRandomAliasing(Back, OtherIB, ThisIB);
|
||||
setRandomAliasing(Back, OtherIT, ThisIT);
|
||||
CodeTemplate CT;
|
||||
CT.Info = llvm::formatv("creating cycle through {0}.",
|
||||
State.getInstrInfo().getName(OtherOpcode));
|
||||
CT.Instructions.push_back(std::move(ThisIB));
|
||||
CT.Instructions.push_back(std::move(OtherIB));
|
||||
CT.Instructions.push_back(std::move(ThisIT));
|
||||
CT.Instructions.push_back(std::move(OtherIT));
|
||||
return std::move(CT);
|
||||
}
|
||||
return llvm::make_error<BenchmarkFailure>(
|
||||
|
@ -89,76 +89,6 @@ bool Instruction::hasMemoryOperands() const {
|
||||
[](const Operand &Op) { return Op.IsMem; });
|
||||
}
|
||||
|
||||
InstructionBuilder::InstructionBuilder(const Instruction &Instr)
|
||||
: Instr(Instr), VariableValues(Instr.Variables.size()) {}
|
||||
|
||||
InstructionBuilder::InstructionBuilder(InstructionBuilder &&) = default;
|
||||
|
||||
InstructionBuilder &InstructionBuilder::
|
||||
operator=(InstructionBuilder &&) = default;
|
||||
|
||||
InstructionBuilder::InstructionBuilder(const InstructionBuilder &) = default;
|
||||
|
||||
InstructionBuilder &InstructionBuilder::
|
||||
operator=(const InstructionBuilder &) = default;
|
||||
|
||||
unsigned InstructionBuilder::getOpcode() const {
|
||||
return Instr.Description->getOpcode();
|
||||
}
|
||||
|
||||
llvm::MCOperand &InstructionBuilder::getValueFor(const Variable &Var) {
|
||||
return VariableValues[Var.Index];
|
||||
}
|
||||
|
||||
const llvm::MCOperand &
|
||||
InstructionBuilder::getValueFor(const Variable &Var) const {
|
||||
return VariableValues[Var.Index];
|
||||
}
|
||||
|
||||
llvm::MCOperand &InstructionBuilder::getValueFor(const Operand &Op) {
|
||||
assert(Op.VariableIndex >= 0);
|
||||
return getValueFor(Instr.Variables[Op.VariableIndex]);
|
||||
}
|
||||
|
||||
const llvm::MCOperand &
|
||||
InstructionBuilder::getValueFor(const Operand &Op) const {
|
||||
assert(Op.VariableIndex >= 0);
|
||||
return getValueFor(Instr.Variables[Op.VariableIndex]);
|
||||
}
|
||||
|
||||
// forward declaration.
|
||||
static void randomize(const Instruction &Instr, const Variable &Var,
|
||||
llvm::MCOperand &AssignedValue,
|
||||
const llvm::BitVector &ForbiddenRegs);
|
||||
|
||||
bool InstructionBuilder::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;
|
||||
});
|
||||
}
|
||||
|
||||
void InstructionBuilder::randomizeUnsetVariables(
|
||||
const llvm::BitVector &ForbiddenRegs) {
|
||||
for (const Variable &Var : Instr.Variables) {
|
||||
llvm::MCOperand &AssignedValue = getValueFor(Var);
|
||||
if (!AssignedValue.isValid())
|
||||
randomize(Instr, Var, AssignedValue, ForbiddenRegs);
|
||||
}
|
||||
}
|
||||
|
||||
llvm::MCInst InstructionBuilder::build() const {
|
||||
llvm::MCInst Result;
|
||||
Result.setOpcode(Instr.Description->Opcode);
|
||||
for (const auto &Op : Instr.Operands)
|
||||
if (Op.IsExplicit)
|
||||
Result.addOperand(getValueFor(Op));
|
||||
return Result;
|
||||
}
|
||||
|
||||
bool RegisterOperandAssignment::
|
||||
operator==(const RegisterOperandAssignment &Other) const {
|
||||
return std::tie(Op, Reg) == std::tie(Other.Op, Other.Reg);
|
||||
@ -213,82 +143,6 @@ AliasingConfigurations::AliasingConfigurations(
|
||||
}
|
||||
}
|
||||
|
||||
std::mt19937 &randomGenerator() {
|
||||
static std::random_device RandomDevice;
|
||||
static std::mt19937 RandomGenerator(RandomDevice());
|
||||
return RandomGenerator;
|
||||
}
|
||||
|
||||
static size_t randomIndex(size_t Size) {
|
||||
assert(Size > 0);
|
||||
std::uniform_int_distribution<> Distribution(0, Size - 1);
|
||||
return Distribution(randomGenerator());
|
||||
}
|
||||
|
||||
template <typename C>
|
||||
static auto randomElement(const C &Container) -> decltype(Container[0]) {
|
||||
return Container[randomIndex(Container.size())];
|
||||
}
|
||||
|
||||
static void randomize(const Instruction &Instr, const Variable &Var,
|
||||
llvm::MCOperand &AssignedValue,
|
||||
const llvm::BitVector &ForbiddenRegs) {
|
||||
assert(!Var.TiedOperands.empty());
|
||||
const Operand &Op = Instr.Operands[Var.TiedOperands.front()];
|
||||
assert(Op.Info != nullptr);
|
||||
const auto &OpInfo = *Op.Info;
|
||||
switch (OpInfo.OperandType) {
|
||||
case llvm::MCOI::OperandType::OPERAND_IMMEDIATE:
|
||||
// FIXME: explore immediate values too.
|
||||
AssignedValue = llvm::MCOperand::createImm(1);
|
||||
break;
|
||||
case llvm::MCOI::OperandType::OPERAND_REGISTER: {
|
||||
assert(Op.Tracker);
|
||||
auto AllowedRegs = Op.Tracker->sourceBits();
|
||||
assert(AllowedRegs.size() == ForbiddenRegs.size());
|
||||
for (auto I : ForbiddenRegs.set_bits())
|
||||
AllowedRegs.reset(I);
|
||||
AssignedValue = llvm::MCOperand::createReg(randomBit(AllowedRegs));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void setRegisterOperandValue(const RegisterOperandAssignment &ROV,
|
||||
InstructionBuilder &IB) {
|
||||
assert(ROV.Op);
|
||||
if (ROV.Op->IsExplicit) {
|
||||
auto &AssignedValue = IB.getValueFor(*ROV.Op);
|
||||
if (AssignedValue.isValid()) {
|
||||
assert(AssignedValue.isReg() && AssignedValue.getReg() == ROV.Reg);
|
||||
return;
|
||||
}
|
||||
AssignedValue = llvm::MCOperand::createReg(ROV.Reg);
|
||||
} else {
|
||||
assert(ROV.Op->ImplicitReg != nullptr);
|
||||
assert(ROV.Reg == *ROV.Op->ImplicitReg);
|
||||
}
|
||||
}
|
||||
|
||||
size_t randomBit(const llvm::BitVector &Vector) {
|
||||
assert(Vector.any());
|
||||
auto Itr = Vector.set_bits_begin();
|
||||
for (size_t I = randomIndex(Vector.count()); I != 0; --I)
|
||||
++Itr;
|
||||
return *Itr;
|
||||
}
|
||||
|
||||
void setRandomAliasing(const AliasingConfigurations &AliasingConfigurations,
|
||||
InstructionBuilder &DefIB, InstructionBuilder &UseIB) {
|
||||
assert(!AliasingConfigurations.empty());
|
||||
assert(!AliasingConfigurations.hasImplicitAliasing());
|
||||
const auto &RandomConf = randomElement(AliasingConfigurations.Configurations);
|
||||
setRegisterOperandValue(randomElement(RandomConf.Defs), DefIB);
|
||||
setRegisterOperandValue(randomElement(RandomConf.Uses), UseIB);
|
||||
}
|
||||
|
||||
void DumpMCOperand(const llvm::MCRegisterInfo &MCRegisterInfo,
|
||||
const llvm::MCOperand &Op, llvm::raw_ostream &OS) {
|
||||
if (!Op.isValid())
|
||||
|
@ -82,35 +82,6 @@ struct Instruction {
|
||||
llvm::BitVector UseRegisters; // The union of the aliased use registers.
|
||||
};
|
||||
|
||||
// A builder for an Instruction holding values for each of its Variables.
|
||||
struct InstructionBuilder {
|
||||
InstructionBuilder(const Instruction &Instr);
|
||||
|
||||
InstructionBuilder(const InstructionBuilder &); // default
|
||||
InstructionBuilder &operator=(const InstructionBuilder &); // default
|
||||
InstructionBuilder(InstructionBuilder &&); // default
|
||||
InstructionBuilder &operator=(InstructionBuilder &&); // default
|
||||
|
||||
unsigned getOpcode() const;
|
||||
llvm::MCOperand &getValueFor(const Variable &Var);
|
||||
const llvm::MCOperand &getValueFor(const Variable &Var) const;
|
||||
llvm::MCOperand &getValueFor(const Operand &Op);
|
||||
const llvm::MCOperand &getValueFor(const Operand &Op) const;
|
||||
bool hasImmediateVariables() const;
|
||||
|
||||
// Assigns a Random Value to all Variables that are still Invalid.
|
||||
// Do not use any of the registers in `ForbiddenRegs`.
|
||||
void randomizeUnsetVariables(const llvm::BitVector &ForbiddenRegs);
|
||||
|
||||
// Builds an llvm::MCInst from this InstructionBuilder setting its operands to
|
||||
// the corresponding variable values.
|
||||
// Precondition: All VariableValues must be set.
|
||||
llvm::MCInst build() const;
|
||||
|
||||
Instruction Instr;
|
||||
llvm::SmallVector<llvm::MCOperand, 4> VariableValues;
|
||||
};
|
||||
|
||||
// Represents the assignment of a Register to an Operand.
|
||||
struct RegisterOperandAssignment {
|
||||
RegisterOperandAssignment(const Operand *Operand, llvm::MCPhysReg Reg)
|
||||
@ -153,20 +124,6 @@ struct AliasingConfigurations {
|
||||
llvm::SmallVector<AliasingRegisterOperands, 32> Configurations;
|
||||
};
|
||||
|
||||
// A global Random Number Generator to randomize configurations.
|
||||
// FIXME: Move random number generation into an object and make it seedable for
|
||||
// unit tests.
|
||||
std::mt19937 &randomGenerator();
|
||||
|
||||
// Picks a random bit among the bits set in Vector and returns its index.
|
||||
// Precondition: Vector must have at least one bit set.
|
||||
size_t randomBit(const llvm::BitVector &Vector);
|
||||
|
||||
// Picks a random configuration, then selects a random def and a random use from
|
||||
// it and finally set the selected values in the provided InstructionInstances.
|
||||
void setRandomAliasing(const AliasingConfigurations &AliasingConfigurations,
|
||||
InstructionBuilder &DefIB, InstructionBuilder &UseIB);
|
||||
|
||||
// Writes MCInst to OS.
|
||||
// This is not assembly but the internal LLVM's name for instructions and
|
||||
// registers.
|
||||
|
@ -15,9 +15,16 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <llvm/ADT/APFloat.h>
|
||||
#include <llvm/ADT/APInt.h>
|
||||
|
||||
namespace exegesis {
|
||||
|
||||
// A simple object storing the value for a particular register.
|
||||
struct RegisterValue {
|
||||
unsigned Register;
|
||||
llvm::APInt Value;
|
||||
};
|
||||
|
||||
enum class PredefinedValues {
|
||||
POS_ZERO, // Positive zero
|
||||
NEG_ZERO, // Negative zero
|
||||
|
@ -40,12 +40,12 @@ SnippetGenerator::generateConfigurations(unsigned Opcode) const {
|
||||
{
|
||||
BenchmarkCode BC;
|
||||
BC.Info = CT.Info;
|
||||
for (InstructionBuilder &IB : CT.Instructions) {
|
||||
IB.randomizeUnsetVariables(
|
||||
for (InstructionTemplate &IT : CT.Instructions) {
|
||||
IT.randomizeUnsetVariables(
|
||||
CT.ScratchSpacePointerInReg
|
||||
? RATC.getRegister(CT.ScratchSpacePointerInReg).aliasedBits()
|
||||
: RATC.emptyRegisters());
|
||||
BC.Instructions.push_back(IB.build());
|
||||
BC.Instructions.push_back(IT.build());
|
||||
}
|
||||
if (CT.ScratchSpacePointerInReg)
|
||||
BC.LiveIns.push_back(CT.ScratchSpacePointerInReg);
|
||||
@ -58,27 +58,27 @@ SnippetGenerator::generateConfigurations(unsigned Opcode) const {
|
||||
}
|
||||
|
||||
std::vector<RegisterValue> SnippetGenerator::computeRegisterInitialValues(
|
||||
const std::vector<InstructionBuilder> &Instructions) const {
|
||||
const std::vector<InstructionTemplate> &Instructions) const {
|
||||
// Collect all register uses and create an assignment for each of them.
|
||||
// Ignore memory operands which are handled separately.
|
||||
// Loop invariant: DefinedRegs[i] is true iif it has been set at least once
|
||||
// before the current instruction.
|
||||
llvm::BitVector DefinedRegs = RATC.emptyRegisters();
|
||||
std::vector<RegisterValue> RIV;
|
||||
for (const InstructionBuilder &IB : Instructions) {
|
||||
for (const InstructionTemplate &IT : Instructions) {
|
||||
// Returns the register that this Operand sets or uses, or 0 if this is not
|
||||
// a register.
|
||||
const auto GetOpReg = [&IB](const Operand &Op) -> unsigned {
|
||||
const auto GetOpReg = [&IT](const Operand &Op) -> unsigned {
|
||||
if (Op.IsMem)
|
||||
return 0;
|
||||
if (Op.ImplicitReg)
|
||||
return *Op.ImplicitReg;
|
||||
if (Op.IsExplicit && IB.getValueFor(Op).isReg())
|
||||
return IB.getValueFor(Op).getReg();
|
||||
if (Op.IsExplicit && IT.getValueFor(Op).isReg())
|
||||
return IT.getValueFor(Op).getReg();
|
||||
return 0;
|
||||
};
|
||||
// Collect used registers that have never been def'ed.
|
||||
for (const Operand &Op : IB.Instr.Operands) {
|
||||
for (const Operand &Op : IT.Instr.Operands) {
|
||||
if (!Op.IsDef) {
|
||||
const unsigned Reg = GetOpReg(Op);
|
||||
if (Reg > 0 && !DefinedRegs.test(Reg)) {
|
||||
@ -88,7 +88,7 @@ std::vector<RegisterValue> SnippetGenerator::computeRegisterInitialValues(
|
||||
}
|
||||
}
|
||||
// Mark defs as having been def'ed.
|
||||
for (const Operand &Op : IB.Instr.Operands) {
|
||||
for (const Operand &Op : IT.Instr.Operands) {
|
||||
if (Op.IsDef) {
|
||||
const unsigned Reg = GetOpReg(Op);
|
||||
if (Reg > 0)
|
||||
@ -106,16 +106,16 @@ llvm::Expected<CodeTemplate> SnippetGenerator::generateSelfAliasingCodeTemplate(
|
||||
return llvm::make_error<SnippetGeneratorFailure>("empty self aliasing");
|
||||
}
|
||||
CodeTemplate CT;
|
||||
InstructionBuilder IB(Instr);
|
||||
InstructionTemplate IT(Instr);
|
||||
if (SelfAliasing.hasImplicitAliasing()) {
|
||||
CT.Info = "implicit Self cycles, picking random values.";
|
||||
} else {
|
||||
CT.Info = "explicit self cycles, selecting one aliasing Conf.";
|
||||
// This is a self aliasing instruction so defs and uses are from the same
|
||||
// instance, hence twice IB in the following call.
|
||||
setRandomAliasing(SelfAliasing, IB, IB);
|
||||
// instance, hence twice IT in the following call.
|
||||
setRandomAliasing(SelfAliasing, IT, IT);
|
||||
}
|
||||
CT.Instructions.push_back(std::move(IB));
|
||||
CT.Instructions.push_back(std::move(IT));
|
||||
return std::move(CT);
|
||||
}
|
||||
|
||||
@ -127,4 +127,5 @@ SnippetGenerator::generateUnconstrainedCodeTemplate(const Instruction &Instr,
|
||||
CT.Instructions.emplace_back(Instr);
|
||||
return std::move(CT);
|
||||
}
|
||||
|
||||
} // namespace exegesis
|
||||
|
@ -50,7 +50,7 @@ public:
|
||||
|
||||
// Given a snippet, computes which registers the setup code needs to define.
|
||||
std::vector<RegisterValue> computeRegisterInitialValues(
|
||||
const std::vector<InstructionBuilder> &Snippet) const;
|
||||
const std::vector<InstructionTemplate> &Snippet) const;
|
||||
|
||||
protected:
|
||||
const LLVMState &State;
|
||||
|
@ -49,7 +49,7 @@ public:
|
||||
}
|
||||
|
||||
// Fills memory operands with references to the address at [Reg] + Offset.
|
||||
virtual void fillMemoryOperands(InstructionBuilder &IB, unsigned Reg,
|
||||
virtual void fillMemoryOperands(InstructionTemplate &IT, unsigned Reg,
|
||||
unsigned Offset) const {
|
||||
|
||||
llvm_unreachable(
|
||||
|
@ -127,23 +127,23 @@ UopsSnippetGenerator::~UopsSnippetGenerator() = default;
|
||||
|
||||
void UopsSnippetGenerator::instantiateMemoryOperands(
|
||||
const unsigned ScratchSpacePointerInReg,
|
||||
std::vector<InstructionBuilder> &Instructions) const {
|
||||
std::vector<InstructionTemplate> &Instructions) const {
|
||||
if (ScratchSpacePointerInReg == 0)
|
||||
return; // no memory operands.
|
||||
const auto &ET = State.getExegesisTarget();
|
||||
const unsigned MemStep = ET.getMaxMemoryAccessSize();
|
||||
const size_t OriginalInstructionsSize = Instructions.size();
|
||||
size_t I = 0;
|
||||
for (InstructionBuilder &IB : Instructions) {
|
||||
ET.fillMemoryOperands(IB, ScratchSpacePointerInReg, I * MemStep);
|
||||
for (InstructionTemplate &IT : Instructions) {
|
||||
ET.fillMemoryOperands(IT, ScratchSpacePointerInReg, I * MemStep);
|
||||
++I;
|
||||
}
|
||||
|
||||
while (Instructions.size() < kMinNumDifferentAddresses) {
|
||||
InstructionBuilder IB = Instructions[I % OriginalInstructionsSize];
|
||||
ET.fillMemoryOperands(IB, ScratchSpacePointerInReg, I * MemStep);
|
||||
InstructionTemplate IT = Instructions[I % OriginalInstructionsSize];
|
||||
ET.fillMemoryOperands(IT, ScratchSpacePointerInReg, I * MemStep);
|
||||
++I;
|
||||
Instructions.push_back(std::move(IB));
|
||||
Instructions.push_back(std::move(IT));
|
||||
}
|
||||
assert(I * MemStep < BenchmarkRunner::ScratchSpace::kSize &&
|
||||
"not enough scratch space");
|
||||
@ -178,16 +178,16 @@ UopsSnippetGenerator::generateCodeTemplate(unsigned Opcode) const {
|
||||
}
|
||||
|
||||
const AliasingConfigurations SelfAliasing(Instr, Instr);
|
||||
InstructionBuilder IB(Instr);
|
||||
InstructionTemplate IT(Instr);
|
||||
if (SelfAliasing.empty()) {
|
||||
CT.Info = "instruction is parallel, repeating a random one.";
|
||||
CT.Instructions.push_back(std::move(IB));
|
||||
CT.Instructions.push_back(std::move(IT));
|
||||
instantiateMemoryOperands(CT.ScratchSpacePointerInReg, CT.Instructions);
|
||||
return std::move(CT);
|
||||
}
|
||||
if (SelfAliasing.hasImplicitAliasing()) {
|
||||
CT.Info = "instruction is serial, repeating a random one.";
|
||||
CT.Instructions.push_back(std::move(IB));
|
||||
CT.Instructions.push_back(std::move(IT));
|
||||
instantiateMemoryOperands(CT.ScratchSpacePointerInReg, CT.Instructions);
|
||||
return std::move(CT);
|
||||
}
|
||||
@ -206,9 +206,9 @@ UopsSnippetGenerator::generateCodeTemplate(unsigned Opcode) const {
|
||||
for (const llvm::MCPhysReg Reg : Op.Tracker->sourceBits().set_bits()) {
|
||||
if (ScratchSpaceAliasedRegs && ScratchSpaceAliasedRegs->test(Reg))
|
||||
continue; // Do not use the scratch memory address register.
|
||||
InstructionBuilder TmpIB = IB;
|
||||
TmpIB.getValueFor(*Var) = llvm::MCOperand::createReg(Reg);
|
||||
CT.Instructions.push_back(std::move(TmpIB));
|
||||
InstructionTemplate TmpIT = IT;
|
||||
TmpIT.getValueFor(*Var) = llvm::MCOperand::createReg(Reg);
|
||||
CT.Instructions.push_back(std::move(TmpIT));
|
||||
}
|
||||
instantiateMemoryOperands(CT.ScratchSpacePointerInReg, CT.Instructions);
|
||||
return std::move(CT);
|
||||
@ -225,7 +225,7 @@ UopsSnippetGenerator::generateCodeTemplate(unsigned Opcode) const {
|
||||
assert(PossibleRegisters.any() && "No register left to choose from");
|
||||
const auto RandomReg = randomBit(PossibleRegisters);
|
||||
Defs.set(RandomReg);
|
||||
IB.getValueFor(Op) = llvm::MCOperand::createReg(RandomReg);
|
||||
IT.getValueFor(Op) = llvm::MCOperand::createReg(RandomReg);
|
||||
}
|
||||
}
|
||||
// And pick random use values that are not reserved and don't alias with defs.
|
||||
@ -240,12 +240,12 @@ UopsSnippetGenerator::generateCodeTemplate(unsigned Opcode) const {
|
||||
remove(PossibleRegisters, DefAliases);
|
||||
assert(PossibleRegisters.any() && "No register left to choose from");
|
||||
const auto RandomReg = randomBit(PossibleRegisters);
|
||||
IB.getValueFor(Op) = llvm::MCOperand::createReg(RandomReg);
|
||||
IT.getValueFor(Op) = llvm::MCOperand::createReg(RandomReg);
|
||||
}
|
||||
}
|
||||
CT.Info =
|
||||
"instruction has no tied variables picking Uses different from defs";
|
||||
CT.Instructions.push_back(std::move(IB));
|
||||
CT.Instructions.push_back(std::move(IT));
|
||||
instantiateMemoryOperands(CT.ScratchSpacePointerInReg, CT.Instructions);
|
||||
return std::move(CT);
|
||||
}
|
||||
@ -278,7 +278,7 @@ UopsBenchmarkRunner::runMeasurements(const ExecutableFunction &Function,
|
||||
};
|
||||
|
||||
std::vector<BenchmarkMeasure> Result;
|
||||
const auto& PfmCounters = SchedModel.getExtraProcessorInfo().PfmCounters;
|
||||
const auto &PfmCounters = SchedModel.getExtraProcessorInfo().PfmCounters;
|
||||
// Uops per port.
|
||||
for (unsigned ProcResIdx = 1;
|
||||
ProcResIdx < SchedModel.getNumProcResourceKinds(); ++ProcResIdx) {
|
||||
@ -286,7 +286,8 @@ UopsBenchmarkRunner::runMeasurements(const ExecutableFunction &Function,
|
||||
if (!Counters)
|
||||
continue;
|
||||
const double CounterValue = RunMeasurement(Counters);
|
||||
Result.push_back(BenchmarkMeasure::Create(SchedModel.getProcResource(ProcResIdx)->Name, CounterValue));
|
||||
Result.push_back(BenchmarkMeasure::Create(
|
||||
SchedModel.getProcResource(ProcResIdx)->Name, CounterValue));
|
||||
}
|
||||
// NumMicroOps.
|
||||
if (const char *const UopsCounter = PfmCounters.UopsCounter) {
|
||||
|
@ -56,9 +56,9 @@ private:
|
||||
// mov eax, [rdi + 128]
|
||||
// add eax, [rdi + 192]
|
||||
// mov eax, [rdi + 256]
|
||||
void
|
||||
instantiateMemoryOperands(unsigned ScratchSpaceReg,
|
||||
std::vector<InstructionBuilder> &Snippet) const;
|
||||
void instantiateMemoryOperands(
|
||||
unsigned ScratchSpaceReg,
|
||||
std::vector<InstructionTemplate> &SnippetTemplate) const;
|
||||
};
|
||||
|
||||
class UopsBenchmarkRunner : public BenchmarkRunner {
|
||||
|
@ -256,32 +256,32 @@ class ExegesisX86Target : public ExegesisTarget {
|
||||
|
||||
unsigned getMaxMemoryAccessSize() const override { return 64; }
|
||||
|
||||
void fillMemoryOperands(InstructionBuilder &IB, unsigned Reg,
|
||||
void fillMemoryOperands(InstructionTemplate &IT, unsigned Reg,
|
||||
unsigned Offset) const override {
|
||||
// FIXME: For instructions that read AND write to memory, we use the same
|
||||
// value for input and output.
|
||||
for (size_t I = 0, E = IB.Instr.Operands.size(); I < E; ++I) {
|
||||
const Operand *Op = &IB.Instr.Operands[I];
|
||||
for (size_t I = 0, E = IT.Instr.Operands.size(); I < E; ++I) {
|
||||
const Operand *Op = &IT.Instr.Operands[I];
|
||||
if (Op->IsExplicit && Op->IsMem) {
|
||||
// Case 1: 5-op memory.
|
||||
assert((I + 5 <= E) && "x86 memory references are always 5 ops");
|
||||
IB.getValueFor(*Op) = llvm::MCOperand::createReg(Reg); // BaseReg
|
||||
Op = &IB.Instr.Operands[++I];
|
||||
IT.getValueFor(*Op) = llvm::MCOperand::createReg(Reg); // BaseReg
|
||||
Op = &IT.Instr.Operands[++I];
|
||||
assert(Op->IsMem);
|
||||
assert(Op->IsExplicit);
|
||||
IB.getValueFor(*Op) = llvm::MCOperand::createImm(1); // ScaleAmt
|
||||
Op = &IB.Instr.Operands[++I];
|
||||
IT.getValueFor(*Op) = llvm::MCOperand::createImm(1); // ScaleAmt
|
||||
Op = &IT.Instr.Operands[++I];
|
||||
assert(Op->IsMem);
|
||||
assert(Op->IsExplicit);
|
||||
IB.getValueFor(*Op) = llvm::MCOperand::createReg(0); // IndexReg
|
||||
Op = &IB.Instr.Operands[++I];
|
||||
IT.getValueFor(*Op) = llvm::MCOperand::createReg(0); // IndexReg
|
||||
Op = &IT.Instr.Operands[++I];
|
||||
assert(Op->IsMem);
|
||||
assert(Op->IsExplicit);
|
||||
IB.getValueFor(*Op) = llvm::MCOperand::createImm(Offset); // Disp
|
||||
Op = &IB.Instr.Operands[++I];
|
||||
IT.getValueFor(*Op) = llvm::MCOperand::createImm(Offset); // Disp
|
||||
Op = &IT.Instr.Operands[++I];
|
||||
assert(Op->IsMem);
|
||||
assert(Op->IsExplicit);
|
||||
IB.getValueFor(*Op) = llvm::MCOperand::createReg(0); // Segment
|
||||
IT.getValueFor(*Op) = llvm::MCOperand::createReg(0); // Segment
|
||||
// Case2: segment:index addressing. We assume that ES is 0.
|
||||
}
|
||||
}
|
||||
|
@ -88,10 +88,10 @@ TEST_F(LatencySnippetGeneratorTest, ImplicitSelfDependency) {
|
||||
const CodeTemplate CT = checkAndGetCodeTemplate(Opcode);
|
||||
EXPECT_THAT(CT.Info, HasSubstr("implicit"));
|
||||
ASSERT_THAT(CT.Instructions, SizeIs(1));
|
||||
const InstructionBuilder &IB = CT.Instructions[0];
|
||||
EXPECT_THAT(IB.getOpcode(), Opcode);
|
||||
ASSERT_THAT(IB.VariableValues, SizeIs(1)); // Imm.
|
||||
EXPECT_THAT(IB.VariableValues[0], IsInvalid()) << "Immediate is not set";
|
||||
const InstructionTemplate &IT = CT.Instructions[0];
|
||||
EXPECT_THAT(IT.getOpcode(), Opcode);
|
||||
ASSERT_THAT(IT.VariableValues, SizeIs(1)); // Imm.
|
||||
EXPECT_THAT(IT.VariableValues[0], IsInvalid()) << "Immediate is not set";
|
||||
}
|
||||
|
||||
TEST_F(LatencySnippetGeneratorTest, ExplicitSelfDependency) {
|
||||
@ -106,11 +106,11 @@ TEST_F(LatencySnippetGeneratorTest, ExplicitSelfDependency) {
|
||||
const CodeTemplate CT = checkAndGetCodeTemplate(Opcode);
|
||||
EXPECT_THAT(CT.Info, HasSubstr("explicit"));
|
||||
ASSERT_THAT(CT.Instructions, SizeIs(1));
|
||||
const InstructionBuilder &IB = CT.Instructions[0];
|
||||
EXPECT_THAT(IB.getOpcode(), Opcode);
|
||||
ASSERT_THAT(IB.VariableValues, SizeIs(2));
|
||||
EXPECT_THAT(IB.VariableValues[0], IsReg()) << "Operand 0 and 1";
|
||||
EXPECT_THAT(IB.VariableValues[1], IsInvalid()) << "Operand 2 is not set";
|
||||
const InstructionTemplate &IT = CT.Instructions[0];
|
||||
EXPECT_THAT(IT.getOpcode(), Opcode);
|
||||
ASSERT_THAT(IT.VariableValues, SizeIs(2));
|
||||
EXPECT_THAT(IT.VariableValues[0], IsReg()) << "Operand 0 and 1";
|
||||
EXPECT_THAT(IT.VariableValues[1], IsInvalid()) << "Operand 2 is not set";
|
||||
}
|
||||
|
||||
TEST_F(LatencySnippetGeneratorTest, DependencyThroughOtherOpcode) {
|
||||
@ -123,10 +123,10 @@ TEST_F(LatencySnippetGeneratorTest, DependencyThroughOtherOpcode) {
|
||||
const CodeTemplate CT = checkAndGetCodeTemplate(Opcode);
|
||||
EXPECT_THAT(CT.Info, HasSubstr("cycle through"));
|
||||
ASSERT_THAT(CT.Instructions, SizeIs(2));
|
||||
const InstructionBuilder &IB = CT.Instructions[0];
|
||||
EXPECT_THAT(IB.getOpcode(), Opcode);
|
||||
ASSERT_THAT(IB.VariableValues, SizeIs(2));
|
||||
EXPECT_THAT(IB.VariableValues, AnyOf(ElementsAre(IsReg(), IsInvalid()),
|
||||
const InstructionTemplate &IT = CT.Instructions[0];
|
||||
EXPECT_THAT(IT.getOpcode(), Opcode);
|
||||
ASSERT_THAT(IT.VariableValues, SizeIs(2));
|
||||
EXPECT_THAT(IT.VariableValues, AnyOf(ElementsAre(IsReg(), IsInvalid()),
|
||||
ElementsAre(IsInvalid(), IsReg())));
|
||||
EXPECT_THAT(CT.Instructions[1].getOpcode(), Not(Opcode));
|
||||
// TODO: check that the two instructions alias each other.
|
||||
@ -137,9 +137,9 @@ TEST_F(LatencySnippetGeneratorTest, LAHF) {
|
||||
const CodeTemplate CT = checkAndGetCodeTemplate(Opcode);
|
||||
EXPECT_THAT(CT.Info, HasSubstr("cycle through"));
|
||||
ASSERT_THAT(CT.Instructions, SizeIs(2));
|
||||
const InstructionBuilder &IB = CT.Instructions[0];
|
||||
EXPECT_THAT(IB.getOpcode(), Opcode);
|
||||
ASSERT_THAT(IB.VariableValues, SizeIs(0));
|
||||
const InstructionTemplate &IT = CT.Instructions[0];
|
||||
EXPECT_THAT(IT.getOpcode(), Opcode);
|
||||
ASSERT_THAT(IT.VariableValues, SizeIs(0));
|
||||
}
|
||||
|
||||
TEST_F(UopsSnippetGeneratorTest, ParallelInstruction) {
|
||||
@ -152,11 +152,11 @@ TEST_F(UopsSnippetGeneratorTest, ParallelInstruction) {
|
||||
const CodeTemplate CT = checkAndGetCodeTemplate(Opcode);
|
||||
EXPECT_THAT(CT.Info, HasSubstr("parallel"));
|
||||
ASSERT_THAT(CT.Instructions, SizeIs(1));
|
||||
const InstructionBuilder &IB = CT.Instructions[0];
|
||||
EXPECT_THAT(IB.getOpcode(), Opcode);
|
||||
ASSERT_THAT(IB.VariableValues, SizeIs(2));
|
||||
EXPECT_THAT(IB.VariableValues[0], IsInvalid());
|
||||
EXPECT_THAT(IB.VariableValues[1], IsInvalid());
|
||||
const InstructionTemplate &IT = CT.Instructions[0];
|
||||
EXPECT_THAT(IT.getOpcode(), Opcode);
|
||||
ASSERT_THAT(IT.VariableValues, SizeIs(2));
|
||||
EXPECT_THAT(IT.VariableValues[0], IsInvalid());
|
||||
EXPECT_THAT(IT.VariableValues[1], IsInvalid());
|
||||
}
|
||||
|
||||
TEST_F(UopsSnippetGeneratorTest, SerialInstruction) {
|
||||
@ -169,9 +169,9 @@ TEST_F(UopsSnippetGeneratorTest, SerialInstruction) {
|
||||
const CodeTemplate CT = checkAndGetCodeTemplate(Opcode);
|
||||
EXPECT_THAT(CT.Info, HasSubstr("serial"));
|
||||
ASSERT_THAT(CT.Instructions, SizeIs(1));
|
||||
const InstructionBuilder &IB = CT.Instructions[0];
|
||||
EXPECT_THAT(IB.getOpcode(), Opcode);
|
||||
ASSERT_THAT(IB.VariableValues, SizeIs(0));
|
||||
const InstructionTemplate &IT = CT.Instructions[0];
|
||||
EXPECT_THAT(IT.getOpcode(), Opcode);
|
||||
ASSERT_THAT(IT.VariableValues, SizeIs(0));
|
||||
}
|
||||
|
||||
TEST_F(UopsSnippetGeneratorTest, StaticRenaming) {
|
||||
@ -188,9 +188,9 @@ TEST_F(UopsSnippetGeneratorTest, StaticRenaming) {
|
||||
constexpr const unsigned kInstructionCount = 15;
|
||||
ASSERT_THAT(CT.Instructions, SizeIs(kInstructionCount));
|
||||
std::unordered_set<unsigned> AllDefRegisters;
|
||||
for (const auto &IB : CT.Instructions) {
|
||||
ASSERT_THAT(IB.VariableValues, SizeIs(2));
|
||||
AllDefRegisters.insert(IB.VariableValues[0].getReg());
|
||||
for (const auto &IT : CT.Instructions) {
|
||||
ASSERT_THAT(IT.VariableValues, SizeIs(2));
|
||||
AllDefRegisters.insert(IT.VariableValues[0].getReg());
|
||||
}
|
||||
EXPECT_THAT(AllDefRegisters, SizeIs(kInstructionCount))
|
||||
<< "Each instruction writes to a different register";
|
||||
@ -209,14 +209,14 @@ TEST_F(UopsSnippetGeneratorTest, NoTiedVariables) {
|
||||
const CodeTemplate CT = checkAndGetCodeTemplate(Opcode);
|
||||
EXPECT_THAT(CT.Info, HasSubstr("no tied variables"));
|
||||
ASSERT_THAT(CT.Instructions, SizeIs(1));
|
||||
const InstructionBuilder &IB = CT.Instructions[0];
|
||||
EXPECT_THAT(IB.getOpcode(), Opcode);
|
||||
ASSERT_THAT(IB.VariableValues, SizeIs(4));
|
||||
EXPECT_THAT(IB.VariableValues[0].getReg(), Not(IB.VariableValues[1].getReg()))
|
||||
const InstructionTemplate &IT = CT.Instructions[0];
|
||||
EXPECT_THAT(IT.getOpcode(), Opcode);
|
||||
ASSERT_THAT(IT.VariableValues, SizeIs(4));
|
||||
EXPECT_THAT(IT.VariableValues[0].getReg(), Not(IT.VariableValues[1].getReg()))
|
||||
<< "Def is different from first Use";
|
||||
EXPECT_THAT(IB.VariableValues[0].getReg(), Not(IB.VariableValues[2].getReg()))
|
||||
EXPECT_THAT(IT.VariableValues[0].getReg(), Not(IT.VariableValues[2].getReg()))
|
||||
<< "Def is different from second Use";
|
||||
EXPECT_THAT(IB.VariableValues[3], IsInvalid());
|
||||
EXPECT_THAT(IT.VariableValues[3], IsInvalid());
|
||||
}
|
||||
|
||||
TEST_F(UopsSnippetGeneratorTest, MemoryUse) {
|
||||
@ -226,13 +226,13 @@ TEST_F(UopsSnippetGeneratorTest, MemoryUse) {
|
||||
EXPECT_THAT(CT.Info, HasSubstr("no tied variables"));
|
||||
ASSERT_THAT(CT.Instructions,
|
||||
SizeIs(UopsSnippetGenerator::kMinNumDifferentAddresses));
|
||||
const InstructionBuilder &IB = CT.Instructions[0];
|
||||
EXPECT_THAT(IB.getOpcode(), Opcode);
|
||||
ASSERT_THAT(IB.VariableValues, SizeIs(6));
|
||||
EXPECT_EQ(IB.VariableValues[2].getImm(), 1);
|
||||
EXPECT_EQ(IB.VariableValues[3].getReg(), 0u);
|
||||
EXPECT_EQ(IB.VariableValues[4].getImm(), 0);
|
||||
EXPECT_EQ(IB.VariableValues[5].getReg(), 0u);
|
||||
const InstructionTemplate &IT = CT.Instructions[0];
|
||||
EXPECT_THAT(IT.getOpcode(), Opcode);
|
||||
ASSERT_THAT(IT.VariableValues, SizeIs(6));
|
||||
EXPECT_EQ(IT.VariableValues[2].getImm(), 1);
|
||||
EXPECT_EQ(IT.VariableValues[3].getReg(), 0u);
|
||||
EXPECT_EQ(IT.VariableValues[4].getImm(), 0);
|
||||
EXPECT_EQ(IT.VariableValues[5].getReg(), 0u);
|
||||
}
|
||||
|
||||
TEST_F(UopsSnippetGeneratorTest, MemoryUse_Movsb) {
|
||||
@ -273,11 +273,11 @@ TEST_F(FakeSnippetGeneratorTest, ComputeRegisterInitialValuesAdd16ri) {
|
||||
// explicit use 1 : reg RegClass=GR16 | TIED_TO:0
|
||||
// explicit use 2 : imm
|
||||
// implicit def : EFLAGS
|
||||
InstructionBuilder IB(Generator.createInstruction(llvm::X86::ADD16ri));
|
||||
IB.getValueFor(IB.Instr.Variables[0]) =
|
||||
InstructionTemplate IT(Generator.createInstruction(llvm::X86::ADD16ri));
|
||||
IT.getValueFor(IT.Instr.Variables[0]) =
|
||||
llvm::MCOperand::createReg(llvm::X86::AX);
|
||||
std::vector<InstructionBuilder> Snippet;
|
||||
Snippet.push_back(std::move(IB));
|
||||
std::vector<InstructionTemplate> Snippet;
|
||||
Snippet.push_back(std::move(IT));
|
||||
const auto RIV = Generator.computeRegisterInitialValues(Snippet);
|
||||
EXPECT_THAT(RIV, ElementsAre(IsRegisterValue(llvm::X86::AX, llvm::APInt())));
|
||||
}
|
||||
@ -287,16 +287,16 @@ TEST_F(FakeSnippetGeneratorTest, ComputeRegisterInitialValuesAdd64rr) {
|
||||
// mov64ri rax, 42
|
||||
// add64rr rax, rax, rbx
|
||||
// -> only rbx needs defining.
|
||||
std::vector<InstructionBuilder> Snippet;
|
||||
std::vector<InstructionTemplate> Snippet;
|
||||
{
|
||||
InstructionBuilder Mov(Generator.createInstruction(llvm::X86::MOV64ri));
|
||||
InstructionTemplate Mov(Generator.createInstruction(llvm::X86::MOV64ri));
|
||||
Mov.getValueFor(Mov.Instr.Variables[0]) =
|
||||
llvm::MCOperand::createReg(llvm::X86::RAX);
|
||||
Mov.getValueFor(Mov.Instr.Variables[1]) = llvm::MCOperand::createImm(42);
|
||||
Snippet.push_back(std::move(Mov));
|
||||
}
|
||||
{
|
||||
InstructionBuilder Add(Generator.createInstruction(llvm::X86::ADD64rr));
|
||||
InstructionTemplate Add(Generator.createInstruction(llvm::X86::ADD64rr));
|
||||
Add.getValueFor(Add.Instr.Variables[0]) =
|
||||
llvm::MCOperand::createReg(llvm::X86::RAX);
|
||||
Add.getValueFor(Add.Instr.Variables[1]) =
|
||||
|
Loading…
x
Reference in New Issue
Block a user