mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-12-14 03:29:57 +00:00
[llvm-exegesis][NFC] internal changes
Summary: BitVectors are now cached to lower memory utilization. Instructions have reference semantics. Reviewers: courbet Subscribers: sdardis, tschuett, jrtc27, atanasyan, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D71653
This commit is contained in:
parent
d3d1ca14ce
commit
32d384c020
@ -15,8 +15,8 @@ CodeTemplate::CodeTemplate(CodeTemplate &&) = default;
|
||||
|
||||
CodeTemplate &CodeTemplate::operator=(CodeTemplate &&) = default;
|
||||
|
||||
InstructionTemplate::InstructionTemplate(const Instruction &Instr)
|
||||
: Instr(Instr), VariableValues(Instr.Variables.size()) {}
|
||||
InstructionTemplate::InstructionTemplate(const Instruction *Instr)
|
||||
: Instr(Instr), VariableValues(Instr->Variables.size()) {}
|
||||
|
||||
InstructionTemplate::InstructionTemplate(InstructionTemplate &&) = default;
|
||||
|
||||
@ -29,7 +29,7 @@ InstructionTemplate &InstructionTemplate::
|
||||
operator=(const InstructionTemplate &) = default;
|
||||
|
||||
unsigned InstructionTemplate::getOpcode() const {
|
||||
return Instr.Description->getOpcode();
|
||||
return Instr->Description.getOpcode();
|
||||
}
|
||||
|
||||
MCOperand &InstructionTemplate::getValueFor(const Variable &Var) {
|
||||
@ -41,23 +41,23 @@ const MCOperand &InstructionTemplate::getValueFor(const Variable &Var) const {
|
||||
}
|
||||
|
||||
MCOperand &InstructionTemplate::getValueFor(const Operand &Op) {
|
||||
return getValueFor(Instr.Variables[Op.getVariableIndex()]);
|
||||
return getValueFor(Instr->Variables[Op.getVariableIndex()]);
|
||||
}
|
||||
|
||||
const MCOperand &InstructionTemplate::getValueFor(const Operand &Op) const {
|
||||
return getValueFor(Instr.Variables[Op.getVariableIndex()]);
|
||||
return getValueFor(Instr->Variables[Op.getVariableIndex()]);
|
||||
}
|
||||
|
||||
bool InstructionTemplate::hasImmediateVariables() const {
|
||||
return any_of(Instr.Variables, [this](const Variable &Var) {
|
||||
return Instr.getPrimaryOperand(Var).isImmediate();
|
||||
return any_of(Instr->Variables, [this](const Variable &Var) {
|
||||
return Instr->getPrimaryOperand(Var).isImmediate();
|
||||
});
|
||||
}
|
||||
|
||||
MCInst InstructionTemplate::build() const {
|
||||
MCInst Result;
|
||||
Result.setOpcode(Instr.Description->Opcode);
|
||||
for (const auto &Op : Instr.Operands)
|
||||
Result.setOpcode(Instr->Description.Opcode);
|
||||
for (const auto &Op : Instr->Operands)
|
||||
if (Op.isExplicit())
|
||||
Result.addOperand(getValueFor(Op));
|
||||
return Result;
|
||||
|
@ -23,7 +23,7 @@ namespace exegesis {
|
||||
|
||||
// A template for an Instruction holding values for each of its Variables.
|
||||
struct InstructionTemplate {
|
||||
InstructionTemplate(const Instruction &Instr);
|
||||
InstructionTemplate(const Instruction *Instr);
|
||||
|
||||
InstructionTemplate(const InstructionTemplate &); // default
|
||||
InstructionTemplate &operator=(const InstructionTemplate &); // default
|
||||
@ -36,13 +36,16 @@ struct InstructionTemplate {
|
||||
MCOperand &getValueFor(const Operand &Op);
|
||||
const MCOperand &getValueFor(const Operand &Op) const;
|
||||
bool hasImmediateVariables() const;
|
||||
const Instruction &getInstr() const { return *Instr; }
|
||||
ArrayRef<MCOperand> getVariableValues() const { return VariableValues; }
|
||||
|
||||
// Builds an MCInst from this InstructionTemplate setting its operands
|
||||
// to the corresponding variable values. Precondition: All VariableValues must
|
||||
// be set.
|
||||
MCInst build() const;
|
||||
|
||||
Instruction Instr;
|
||||
private:
|
||||
const Instruction *Instr;
|
||||
SmallVector<MCOperand, 4> VariableValues;
|
||||
};
|
||||
|
||||
|
@ -37,8 +37,8 @@ struct ExecutionClass {
|
||||
|
||||
static constexpr size_t kMaxAliasingInstructions = 10;
|
||||
|
||||
static std::vector<Instruction>
|
||||
computeAliasingInstructions(const LLVMState &State, const Instruction &Instr,
|
||||
static std::vector<const Instruction *>
|
||||
computeAliasingInstructions(const LLVMState &State, const Instruction *Instr,
|
||||
size_t MaxAliasingInstructions,
|
||||
const BitVector &ForbiddenRegisters) {
|
||||
// Randomly iterate the set of instructions.
|
||||
@ -47,15 +47,15 @@ computeAliasingInstructions(const LLVMState &State, const Instruction &Instr,
|
||||
std::iota(Opcodes.begin(), Opcodes.end(), 0U);
|
||||
std::shuffle(Opcodes.begin(), Opcodes.end(), randomGenerator());
|
||||
|
||||
std::vector<Instruction> AliasingInstructions;
|
||||
std::vector<const Instruction *> AliasingInstructions;
|
||||
for (const unsigned OtherOpcode : Opcodes) {
|
||||
if (OtherOpcode == Instr.Description->getOpcode())
|
||||
if (OtherOpcode == Instr->Description.getOpcode())
|
||||
continue;
|
||||
const Instruction &OtherInstr = State.getIC().getInstr(OtherOpcode);
|
||||
if (OtherInstr.hasMemoryOperands())
|
||||
continue;
|
||||
if (Instr.hasAliasingRegistersThrough(OtherInstr, ForbiddenRegisters))
|
||||
AliasingInstructions.push_back(OtherInstr);
|
||||
if (Instr->hasAliasingRegistersThrough(OtherInstr, ForbiddenRegisters))
|
||||
AliasingInstructions.push_back(&OtherInstr);
|
||||
if (AliasingInstructions.size() >= MaxAliasingInstructions)
|
||||
break;
|
||||
}
|
||||
@ -81,7 +81,7 @@ static ExecutionMode getExecutionModes(const Instruction &Instr,
|
||||
}
|
||||
|
||||
static void appendCodeTemplates(const LLVMState &State,
|
||||
const Instruction &Instr,
|
||||
const Instruction *Instr,
|
||||
const BitVector &ForbiddenRegisters,
|
||||
ExecutionMode ExecutionModeBit,
|
||||
StringRef ExecutionClassDescription,
|
||||
@ -109,7 +109,7 @@ static void appendCodeTemplates(const LLVMState &State,
|
||||
case ExecutionMode::SERIAL_VIA_EXPLICIT_REGS: {
|
||||
// Making the execution of this instruction serial by selecting one def
|
||||
// register to alias with one use register.
|
||||
const AliasingConfigurations SelfAliasing(Instr, Instr);
|
||||
const AliasingConfigurations SelfAliasing(*Instr, *Instr);
|
||||
assert(!SelfAliasing.empty() && !SelfAliasing.hasImplicitAliasing() &&
|
||||
"Instr must alias itself explicitly");
|
||||
InstructionTemplate IT(Instr);
|
||||
@ -125,10 +125,10 @@ static void appendCodeTemplates(const LLVMState &State,
|
||||
}
|
||||
case ExecutionMode::SERIAL_VIA_NON_MEMORY_INSTR: {
|
||||
// Select back-to-back non-memory instruction.
|
||||
for (const auto OtherInstr : computeAliasingInstructions(
|
||||
for (const auto *OtherInstr : computeAliasingInstructions(
|
||||
State, Instr, kMaxAliasingInstructions, ForbiddenRegisters)) {
|
||||
const AliasingConfigurations Forward(Instr, OtherInstr);
|
||||
const AliasingConfigurations Back(OtherInstr, Instr);
|
||||
const AliasingConfigurations Forward(*Instr, *OtherInstr);
|
||||
const AliasingConfigurations Back(*OtherInstr, *Instr);
|
||||
InstructionTemplate ThisIT(Instr);
|
||||
InstructionTemplate OtherIT(OtherInstr);
|
||||
if (!Forward.hasImplicitAliasing())
|
||||
@ -158,7 +158,7 @@ LatencySnippetGenerator::generateCodeTemplates(
|
||||
const ExecutionMode EM = getExecutionModes(Instr, ForbiddenRegisters);
|
||||
for (const auto EC : kExecutionClasses) {
|
||||
for (const auto ExecutionModeBit : getExecutionModeBits(EM & EC.Mask))
|
||||
appendCodeTemplates(State, Instr, ForbiddenRegisters, ExecutionModeBit,
|
||||
appendCodeTemplates(State, &Instr, ForbiddenRegisters, ExecutionModeBit,
|
||||
EC.Description, Results);
|
||||
if (!Results.empty())
|
||||
break;
|
||||
|
@ -17,10 +17,7 @@
|
||||
namespace llvm {
|
||||
namespace exegesis {
|
||||
|
||||
unsigned Variable::getIndex() const {
|
||||
assert(Index >= 0 && "Index must be set");
|
||||
return Index;
|
||||
}
|
||||
unsigned Variable::getIndex() const { return *Index; }
|
||||
|
||||
unsigned Variable::getPrimaryOperandIndex() const {
|
||||
assert(!TiedOperands.empty());
|
||||
@ -36,10 +33,7 @@ bool Variable::hasTiedOperands() const {
|
||||
return TiedOperands.size() > 1;
|
||||
}
|
||||
|
||||
unsigned Operand::getIndex() const {
|
||||
assert(Index >= 0 && "Index must be set");
|
||||
return Index;
|
||||
}
|
||||
unsigned Operand::getIndex() const { return *Index; }
|
||||
|
||||
bool Operand::isExplicit() const { return Info; }
|
||||
|
||||
@ -53,9 +47,9 @@ bool Operand::isUse() const { return !IsDef; }
|
||||
|
||||
bool Operand::isReg() const { return Tracker; }
|
||||
|
||||
bool Operand::isTied() const { return TiedToIndex >= 0; }
|
||||
bool Operand::isTied() const { return TiedToIndex.hasValue(); }
|
||||
|
||||
bool Operand::isVariable() const { return VariableIndex >= 0; }
|
||||
bool Operand::isVariable() const { return VariableIndex.hasValue(); }
|
||||
|
||||
bool Operand::isMemory() const {
|
||||
return isExplicit() &&
|
||||
@ -67,17 +61,9 @@ bool Operand::isImmediate() const {
|
||||
getExplicitOperandInfo().OperandType == MCOI::OPERAND_IMMEDIATE;
|
||||
}
|
||||
|
||||
unsigned Operand::getTiedToIndex() const {
|
||||
assert(isTied() && "Operand must be tied to get the tied index");
|
||||
assert(TiedToIndex >= 0 && "TiedToIndex must be set");
|
||||
return TiedToIndex;
|
||||
}
|
||||
unsigned Operand::getTiedToIndex() const { return *TiedToIndex; }
|
||||
|
||||
unsigned Operand::getVariableIndex() const {
|
||||
assert(isVariable() && "Operand must be variable to get the Variable index");
|
||||
assert(VariableIndex >= 0 && "VariableIndex must be set");
|
||||
return VariableIndex;
|
||||
}
|
||||
unsigned Operand::getVariableIndex() const { return *VariableIndex; }
|
||||
|
||||
unsigned Operand::getImplicitReg() const {
|
||||
assert(ImplicitReg);
|
||||
@ -94,11 +80,36 @@ const MCOperandInfo &Operand::getExplicitOperandInfo() const {
|
||||
return *Info;
|
||||
}
|
||||
|
||||
Instruction::Instruction(const MCInstrInfo &InstrInfo,
|
||||
const RegisterAliasingTrackerCache &RATC,
|
||||
unsigned Opcode)
|
||||
: Description(&InstrInfo.get(Opcode)), Name(InstrInfo.getName(Opcode)) {
|
||||
const BitVector *BitVectorCache::getUnique(BitVector &&BV) const {
|
||||
for (const auto &Entry : Cache)
|
||||
if (*Entry == BV)
|
||||
return Entry.get();
|
||||
Cache.push_back(std::make_unique<BitVector>());
|
||||
auto &Entry = Cache.back();
|
||||
Entry->swap(BV);
|
||||
return Entry.get();
|
||||
}
|
||||
|
||||
Instruction::Instruction(const MCInstrDesc *Description, StringRef Name,
|
||||
SmallVector<Operand, 8> Operands,
|
||||
SmallVector<Variable, 4> Variables,
|
||||
const BitVector *ImplDefRegs,
|
||||
const BitVector *ImplUseRegs,
|
||||
const BitVector *AllDefRegs,
|
||||
const BitVector *AllUseRegs)
|
||||
: Description(*Description), Name(Name), Operands(std::move(Operands)),
|
||||
Variables(std::move(Variables)), ImplDefRegs(*ImplDefRegs),
|
||||
ImplUseRegs(*ImplUseRegs), AllDefRegs(*AllDefRegs),
|
||||
AllUseRegs(*AllUseRegs) {}
|
||||
|
||||
std::unique_ptr<Instruction>
|
||||
Instruction::create(const MCInstrInfo &InstrInfo,
|
||||
const RegisterAliasingTrackerCache &RATC,
|
||||
const BitVectorCache &BVC, unsigned Opcode) {
|
||||
const llvm::MCInstrDesc *const Description = &InstrInfo.get(Opcode);
|
||||
unsigned OpIndex = 0;
|
||||
SmallVector<Operand, 8> Operands;
|
||||
SmallVector<Variable, 4> Variables;
|
||||
for (; OpIndex < Description->getNumOperands(); ++OpIndex) {
|
||||
const auto &OpInfo = Description->opInfo_begin()[OpIndex];
|
||||
Operand Operand;
|
||||
@ -107,8 +118,11 @@ Instruction::Instruction(const MCInstrInfo &InstrInfo,
|
||||
// TODO(gchatelet): Handle isLookupPtrRegClass.
|
||||
if (OpInfo.RegClass >= 0)
|
||||
Operand.Tracker = &RATC.getRegisterClass(OpInfo.RegClass);
|
||||
Operand.TiedToIndex =
|
||||
Description->getOperandConstraint(OpIndex, MCOI::TIED_TO);
|
||||
int TiedToIndex = Description->getOperandConstraint(OpIndex, MCOI::TIED_TO);
|
||||
assert(TiedToIndex == -1 ||
|
||||
TiedToIndex < std::numeric_limits<uint8_t>::max());
|
||||
if (TiedToIndex >= 0)
|
||||
Operand.TiedToIndex = TiedToIndex;
|
||||
Operand.Info = &OpInfo;
|
||||
Operands.push_back(Operand);
|
||||
}
|
||||
@ -130,28 +144,29 @@ Instruction::Instruction(const MCInstrInfo &InstrInfo,
|
||||
Operand.ImplicitReg = MCPhysReg;
|
||||
Operands.push_back(Operand);
|
||||
}
|
||||
// Assigning Variables to non tied explicit operands.
|
||||
Variables.reserve(Operands.size()); // Variables.size() <= Operands.size()
|
||||
// Assigning Variables to non tied explicit operands.
|
||||
for (auto &Op : Operands)
|
||||
if (Op.isExplicit() && !Op.isTied()) {
|
||||
const size_t VariableIndex = Variables.size();
|
||||
assert(VariableIndex < std::numeric_limits<uint8_t>::max());
|
||||
Op.VariableIndex = VariableIndex;
|
||||
Variables.emplace_back();
|
||||
Variables.back().Index = VariableIndex;
|
||||
}
|
||||
// Assigning Variables to tied operands.
|
||||
for (auto &Op : Operands)
|
||||
if (Op.isTied())
|
||||
if (Op.isExplicit() && Op.isTied())
|
||||
Op.VariableIndex = Operands[Op.getTiedToIndex()].getVariableIndex();
|
||||
// Assigning Operands to Variables.
|
||||
for (auto &Op : Operands)
|
||||
if (Op.isVariable())
|
||||
Variables[Op.getVariableIndex()].TiedOperands.push_back(Op.getIndex());
|
||||
// Processing Aliasing.
|
||||
ImplDefRegs = RATC.emptyRegisters();
|
||||
ImplUseRegs = RATC.emptyRegisters();
|
||||
AllDefRegs = RATC.emptyRegisters();
|
||||
AllUseRegs = RATC.emptyRegisters();
|
||||
BitVector ImplDefRegs = RATC.emptyRegisters();
|
||||
BitVector ImplUseRegs = RATC.emptyRegisters();
|
||||
BitVector AllDefRegs = RATC.emptyRegisters();
|
||||
BitVector AllUseRegs = RATC.emptyRegisters();
|
||||
for (const auto &Op : Operands) {
|
||||
if (Op.isReg()) {
|
||||
const auto &AliasingBits = Op.getRegisterAliasing().aliasedBits();
|
||||
@ -165,6 +180,13 @@ Instruction::Instruction(const MCInstrInfo &InstrInfo,
|
||||
ImplUseRegs |= AliasingBits;
|
||||
}
|
||||
}
|
||||
// Can't use make_unique because constructor is private.
|
||||
return std::unique_ptr<Instruction>(new Instruction(
|
||||
Description, InstrInfo.getName(Opcode), std::move(Operands),
|
||||
std::move(Variables), BVC.getUnique(std::move(ImplDefRegs)),
|
||||
BVC.getUnique(std::move(ImplUseRegs)),
|
||||
BVC.getUnique(std::move(AllDefRegs)),
|
||||
BVC.getUnique(std::move(AllUseRegs))));
|
||||
}
|
||||
|
||||
const Operand &Instruction::getPrimaryOperand(const Variable &Var) const {
|
||||
@ -284,7 +306,7 @@ InstructionsCache::InstructionsCache(const MCInstrInfo &InstrInfo,
|
||||
const Instruction &InstructionsCache::getInstr(unsigned Opcode) const {
|
||||
auto &Found = Instructions[Opcode];
|
||||
if (!Found)
|
||||
Found.reset(new Instruction(InstrInfo, RATC, Opcode));
|
||||
Found = Instruction::create(InstrInfo, RATC, BVC, Opcode);
|
||||
return *Found;
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,7 @@
|
||||
#ifndef LLVM_TOOLS_LLVM_EXEGESIS_MCINSTRDESCVIEW_H
|
||||
#define LLVM_TOOLS_LLVM_EXEGESIS_MCINSTRDESCVIEW_H
|
||||
|
||||
#include <memory>
|
||||
#include <random>
|
||||
#include <unordered_map>
|
||||
|
||||
@ -48,7 +49,7 @@ struct Variable {
|
||||
|
||||
// The index of this Variable in Instruction.Variables and its associated
|
||||
// Value in InstructionBuilder.VariableValues.
|
||||
int Index = -1;
|
||||
Optional<uint8_t> Index;
|
||||
};
|
||||
|
||||
// MCOperandInfo can only represents Explicit operands. This object gives a
|
||||
@ -81,20 +82,40 @@ struct Operand {
|
||||
const MCOperandInfo &getExplicitOperandInfo() const;
|
||||
|
||||
// Please use the accessors above and not the following fields.
|
||||
int Index = -1;
|
||||
Optional<uint8_t> Index;
|
||||
bool IsDef = false;
|
||||
const RegisterAliasingTracker *Tracker = nullptr; // Set for Register Op.
|
||||
const MCOperandInfo *Info = nullptr; // Set for Explicit Op.
|
||||
int TiedToIndex = -1; // Set for Reg&Explicit Op.
|
||||
Optional<uint8_t> TiedToIndex; // Set for Reg&Explicit Op.
|
||||
const MCPhysReg *ImplicitReg = nullptr; // Set for Implicit Op.
|
||||
int VariableIndex = -1; // Set for Explicit Op.
|
||||
Optional<uint8_t> VariableIndex; // Set for Explicit Op.
|
||||
};
|
||||
|
||||
/// A cache of BitVector to reuse between Instructions.
|
||||
/// The cache will only be exercised during Instruction initialization.
|
||||
/// For X86, this is ~160 unique vectors for all of the ~15K Instructions.
|
||||
struct BitVectorCache {
|
||||
// Finds or allocates the provided BitVector in the cache and retrieves it's
|
||||
// unique instance.
|
||||
const BitVector *getUnique(BitVector &&BV) const;
|
||||
|
||||
private:
|
||||
mutable std::vector<std::unique_ptr<BitVector>> Cache;
|
||||
};
|
||||
|
||||
// A view over an MCInstrDesc offering a convenient interface to compute
|
||||
// Register aliasing.
|
||||
struct Instruction {
|
||||
Instruction(const MCInstrInfo &InstrInfo,
|
||||
const RegisterAliasingTrackerCache &RATC, unsigned Opcode);
|
||||
// Create an instruction for a particular Opcode.
|
||||
static std::unique_ptr<Instruction>
|
||||
create(const MCInstrInfo &InstrInfo, const RegisterAliasingTrackerCache &RATC,
|
||||
const BitVectorCache &BVC, unsigned Opcode);
|
||||
|
||||
// Prevent copy or move, instructions are allocated once and cached.
|
||||
Instruction(const Instruction &) = delete;
|
||||
Instruction(Instruction &&) = delete;
|
||||
Instruction &operator=(const Instruction &) = delete;
|
||||
Instruction &operator=(Instruction &&) = delete;
|
||||
|
||||
// Returns the Operand linked to this Variable.
|
||||
// In case the Variable is tied, the primary (i.e. Def) Operand is returned.
|
||||
@ -133,14 +154,20 @@ struct Instruction {
|
||||
const RegisterAliasingTrackerCache &RATC,
|
||||
raw_ostream &Stream) const;
|
||||
|
||||
const MCInstrDesc *Description; // Never nullptr.
|
||||
StringRef Name; // The name of this instruction.
|
||||
SmallVector<Operand, 8> Operands;
|
||||
SmallVector<Variable, 4> Variables;
|
||||
BitVector ImplDefRegs; // The set of aliased implicit def registers.
|
||||
BitVector ImplUseRegs; // The set of aliased implicit use registers.
|
||||
BitVector AllDefRegs; // The set of all aliased def registers.
|
||||
BitVector AllUseRegs; // The set of all aliased use registers.
|
||||
const MCInstrDesc &Description;
|
||||
const StringRef Name; // The name of this instruction.
|
||||
const SmallVector<Operand, 8> Operands;
|
||||
const SmallVector<Variable, 4> Variables;
|
||||
const BitVector &ImplDefRegs; // The set of aliased implicit def registers.
|
||||
const BitVector &ImplUseRegs; // The set of aliased implicit use registers.
|
||||
const BitVector &AllDefRegs; // The set of all aliased def registers.
|
||||
const BitVector &AllUseRegs; // The set of all aliased use registers.
|
||||
private:
|
||||
Instruction(const MCInstrDesc *Description, StringRef Name,
|
||||
SmallVector<Operand, 8> Operands,
|
||||
SmallVector<Variable, 4> Variables, const BitVector *ImplDefRegs,
|
||||
const BitVector *ImplUseRegs, const BitVector *AllDefRegs,
|
||||
const BitVector *AllUseRegs);
|
||||
};
|
||||
|
||||
// Instructions are expensive to instantiate. This class provides a cache of
|
||||
@ -157,6 +184,7 @@ private:
|
||||
const RegisterAliasingTrackerCache &RATC;
|
||||
mutable std::unordered_map<unsigned, std::unique_ptr<Instruction>>
|
||||
Instructions;
|
||||
const BitVectorCache BVC;
|
||||
};
|
||||
|
||||
// Represents the assignment of a Register to an Operand.
|
||||
|
@ -112,7 +112,7 @@ std::vector<RegisterValue> SnippetGenerator::computeRegisterInitialValues(
|
||||
return 0;
|
||||
};
|
||||
// Collect used registers that have never been def'ed.
|
||||
for (const Operand &Op : IT.Instr.Operands) {
|
||||
for (const Operand &Op : IT.getInstr().Operands) {
|
||||
if (Op.isUse()) {
|
||||
const unsigned Reg = GetOpReg(Op);
|
||||
if (Reg > 0 && !DefinedRegs.test(Reg)) {
|
||||
@ -122,7 +122,7 @@ std::vector<RegisterValue> SnippetGenerator::computeRegisterInitialValues(
|
||||
}
|
||||
}
|
||||
// Mark defs as having been def'ed.
|
||||
for (const Operand &Op : IT.Instr.Operands) {
|
||||
for (const Operand &Op : IT.getInstr().Operands) {
|
||||
if (Op.isDef()) {
|
||||
const unsigned Reg = GetOpReg(Op);
|
||||
if (Reg > 0)
|
||||
@ -141,7 +141,7 @@ generateSelfAliasingCodeTemplates(const Instruction &Instr) {
|
||||
std::vector<CodeTemplate> Result;
|
||||
Result.emplace_back();
|
||||
CodeTemplate &CT = Result.back();
|
||||
InstructionTemplate IT(Instr);
|
||||
InstructionTemplate IT(&Instr);
|
||||
if (SelfAliasing.hasImplicitAliasing()) {
|
||||
CT.Info = "implicit Self cycles, picking random values.";
|
||||
} else {
|
||||
@ -160,7 +160,7 @@ generateUnconstrainedCodeTemplates(const Instruction &Instr, StringRef Msg) {
|
||||
Result.emplace_back();
|
||||
CodeTemplate &CT = Result.back();
|
||||
CT.Info = formatv("{0}, repeating an unconstrained assignment", Msg);
|
||||
CT.Instructions.emplace_back(Instr);
|
||||
CT.Instructions.emplace_back(&Instr);
|
||||
return std::move(Result);
|
||||
}
|
||||
|
||||
@ -218,10 +218,11 @@ void setRandomAliasing(const AliasingConfigurations &AliasingConfigurations,
|
||||
void randomizeUnsetVariables(const ExegesisTarget &Target,
|
||||
const BitVector &ForbiddenRegs,
|
||||
InstructionTemplate &IT) {
|
||||
for (const Variable &Var : IT.Instr.Variables) {
|
||||
for (const Variable &Var : IT.getInstr().Variables) {
|
||||
MCOperand &AssignedValue = IT.getValueFor(Var);
|
||||
if (!AssignedValue.isValid())
|
||||
Target.randomizeMCOperand(IT.Instr, Var, AssignedValue, ForbiddenRegs);
|
||||
Target.randomizeMCOperand(IT.getInstr(), Var, AssignedValue,
|
||||
ForbiddenRegs);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -127,7 +127,7 @@ static std::vector<InstructionTemplate> generateSnippetUsingStaticRenaming(
|
||||
std::vector<BitVector> PossibleRegsForVar;
|
||||
for (const Variable *Var : TiedVariables) {
|
||||
assert(Var);
|
||||
const Operand &Op = IT.Instr.getPrimaryOperand(*Var);
|
||||
const Operand &Op = IT.getInstr().getPrimaryOperand(*Var);
|
||||
assert(Op.isReg());
|
||||
BitVector PossibleRegs = Op.getRegisterAliasing().sourceBits();
|
||||
remove(PossibleRegs, ForbiddenRegisters);
|
||||
@ -166,7 +166,7 @@ Expected<std::vector<CodeTemplate>> UopsSnippetGenerator::generateCodeTemplates(
|
||||
State.getTargetMachine().getTargetTriple())
|
||||
: 0;
|
||||
const AliasingConfigurations SelfAliasing(Instr, Instr);
|
||||
InstructionTemplate IT(Instr);
|
||||
InstructionTemplate IT(&Instr);
|
||||
if (SelfAliasing.empty()) {
|
||||
CT.Info = "instruction is parallel, repeating a random one.";
|
||||
CT.Instructions.push_back(std::move(IT));
|
||||
|
@ -25,7 +25,7 @@ namespace exegesis {
|
||||
// Returns an error if we cannot handle the memory references in this
|
||||
// instruction.
|
||||
static Error isInvalidMemoryInstr(const Instruction &Instr) {
|
||||
switch (Instr.Description->TSFlags & X86II::FormMask) {
|
||||
switch (Instr.Description.TSFlags & X86II::FormMask) {
|
||||
default:
|
||||
llvm_unreachable("Unknown FormMask value");
|
||||
// These have no memory access.
|
||||
@ -114,10 +114,10 @@ static Error isInvalidMemoryInstr(const Instruction &Instr) {
|
||||
case X86II::RawFrmImm8:
|
||||
return Error::success();
|
||||
case X86II::AddRegFrm:
|
||||
return (Instr.Description->Opcode == X86::POP16r ||
|
||||
Instr.Description->Opcode == X86::POP32r ||
|
||||
Instr.Description->Opcode == X86::PUSH16r ||
|
||||
Instr.Description->Opcode == X86::PUSH32r)
|
||||
return (Instr.Description.Opcode == X86::POP16r ||
|
||||
Instr.Description.Opcode == X86::POP32r ||
|
||||
Instr.Description.Opcode == X86::PUSH16r ||
|
||||
Instr.Description.Opcode == X86::PUSH32r)
|
||||
? make_error<Failure>(
|
||||
"unsupported opcode: unsupported memory access")
|
||||
: Error::success();
|
||||
@ -150,7 +150,7 @@ static Error isInvalidMemoryInstr(const Instruction &Instr) {
|
||||
|
||||
static Error IsInvalidOpcode(const Instruction &Instr) {
|
||||
const auto OpcodeName = Instr.Name;
|
||||
if ((Instr.Description->TSFlags & X86II::FormMask) == X86II::Pseudo)
|
||||
if ((Instr.Description.TSFlags & X86II::FormMask) == X86II::Pseudo)
|
||||
return make_error<Failure>("unsupported opcode: pseudo instruction");
|
||||
if (OpcodeName.startswith("POPF") || OpcodeName.startswith("PUSHF") ||
|
||||
OpcodeName.startswith("ADJCALLSTACK"))
|
||||
@ -172,13 +172,13 @@ static Error IsInvalidOpcode(const Instruction &Instr) {
|
||||
}
|
||||
|
||||
static unsigned getX86FPFlags(const Instruction &Instr) {
|
||||
return Instr.Description->TSFlags & X86II::FPTypeMask;
|
||||
return Instr.Description.TSFlags & X86II::FPTypeMask;
|
||||
}
|
||||
|
||||
// Helper to fill a memory operand with a value.
|
||||
static void setMemOp(InstructionTemplate &IT, int OpIdx,
|
||||
const MCOperand &OpVal) {
|
||||
const auto Op = IT.Instr.Operands[OpIdx];
|
||||
const auto Op = IT.getInstr().Operands[OpIdx];
|
||||
assert(Op.isExplicit() && "invalid memory pattern");
|
||||
IT.getValueFor(Op) = OpVal;
|
||||
}
|
||||
@ -190,7 +190,7 @@ static Expected<std::vector<CodeTemplate>> generateLEATemplatesCommon(
|
||||
const LLVMState &State, const SnippetGenerator::Options &Opts,
|
||||
std::function<unsigned(unsigned, unsigned)> GetDestReg) {
|
||||
assert(Instr.Operands.size() == 6 && "invalid LEA");
|
||||
assert(X86II::getMemoryOperandNo(Instr.Description->TSFlags) == 1 &&
|
||||
assert(X86II::getMemoryOperandNo(Instr.Description.TSFlags) == 1 &&
|
||||
"invalid LEA");
|
||||
|
||||
constexpr const int kDestOp = 0;
|
||||
@ -213,7 +213,7 @@ static Expected<std::vector<CodeTemplate>> generateLEATemplatesCommon(
|
||||
for (int LogScale = 0; LogScale <= 3; ++LogScale) {
|
||||
// FIXME: Add an option for controlling how we explore immediates.
|
||||
for (const int Disp : {0, 42}) {
|
||||
InstructionTemplate IT(Instr);
|
||||
InstructionTemplate IT(&Instr);
|
||||
const int64_t Scale = 1ull << LogScale;
|
||||
setMemOp(IT, 1, MCOperand::createReg(BaseReg));
|
||||
setMemOp(IT, 2, MCOperand::createImm(Scale));
|
||||
@ -259,7 +259,7 @@ X86LatencySnippetGenerator::generateCodeTemplates(
|
||||
return std::move(E);
|
||||
|
||||
// LEA gets special attention.
|
||||
const auto Opcode = Instr.Description->getOpcode();
|
||||
const auto Opcode = Instr.Description.getOpcode();
|
||||
if (Opcode == X86::LEA64r || Opcode == X86::LEA64_32r) {
|
||||
return generateLEATemplatesCommon(Instr, ForbiddenRegisters, State, Opts,
|
||||
[](unsigned BaseReg, unsigned IndexReg) {
|
||||
@ -310,7 +310,7 @@ X86UopsSnippetGenerator::generateCodeTemplates(
|
||||
return std::move(E);
|
||||
|
||||
// LEA gets special attention.
|
||||
const auto Opcode = Instr.Description->getOpcode();
|
||||
const auto Opcode = Instr.Description.getOpcode();
|
||||
if (Opcode == X86::LEA64r || Opcode == X86::LEA64_32r) {
|
||||
// Any destination register that is not used for adddressing is fine.
|
||||
auto PossibleDestRegs =
|
||||
@ -648,13 +648,13 @@ void ExegesisX86Target::randomizeMCOperand(
|
||||
void ExegesisX86Target::fillMemoryOperands(InstructionTemplate &IT,
|
||||
unsigned Reg,
|
||||
unsigned Offset) const {
|
||||
assert(!isInvalidMemoryInstr(IT.Instr) &&
|
||||
assert(!isInvalidMemoryInstr(IT.getInstr()) &&
|
||||
"fillMemoryOperands requires a valid memory instruction");
|
||||
int MemOpIdx = X86II::getMemoryOperandNo(IT.Instr.Description->TSFlags);
|
||||
int MemOpIdx = X86II::getMemoryOperandNo(IT.getInstr().Description.TSFlags);
|
||||
assert(MemOpIdx >= 0 && "invalid memory operand index");
|
||||
// getMemoryOperandNo() ignores tied operands, so we have to add them back.
|
||||
for (unsigned I = 0; I <= static_cast<unsigned>(MemOpIdx); ++I) {
|
||||
const auto &Op = IT.Instr.Operands[I];
|
||||
const auto &Op = IT.getInstr().Operands[I];
|
||||
if (Op.isTied() && Op.getTiedToIndex() < I) {
|
||||
++MemOpIdx;
|
||||
}
|
||||
|
@ -208,7 +208,7 @@ static Expected<std::vector<BenchmarkCode>>
|
||||
generateSnippets(const LLVMState &State, unsigned Opcode,
|
||||
const BitVector &ForbiddenRegs) {
|
||||
const Instruction &Instr = State.getIC().getInstr(Opcode);
|
||||
const MCInstrDesc &InstrDesc = *Instr.Description;
|
||||
const MCInstrDesc &InstrDesc = Instr.Description;
|
||||
// Ignore instructions that we cannot run.
|
||||
if (InstrDesc.isPseudo())
|
||||
return make_error<Failure>("Unsupported opcode: isPseudo");
|
||||
|
@ -81,8 +81,8 @@ TEST_F(LatencySnippetGeneratorTest, ImplicitSelfDependencyThroughExplicitRegs) {
|
||||
ASSERT_THAT(CT.Instructions, SizeIs(1));
|
||||
const InstructionTemplate &IT = CT.Instructions[0];
|
||||
EXPECT_THAT(IT.getOpcode(), Opcode);
|
||||
ASSERT_THAT(IT.VariableValues, SizeIs(3));
|
||||
EXPECT_THAT(IT.VariableValues,
|
||||
ASSERT_THAT(IT.getVariableValues(), SizeIs(3));
|
||||
EXPECT_THAT(IT.getVariableValues(),
|
||||
AnyOf(ElementsAre(IsReg(), IsInvalid(), IsReg()),
|
||||
ElementsAre(IsReg(), IsReg(), IsInvalid())))
|
||||
<< "Op0 is either set to Op1 or to Op2";
|
||||
|
@ -86,8 +86,8 @@ TEST_F(LatencySnippetGeneratorTest, ImplicitSelfDependencyThroughImplicitReg) {
|
||||
ASSERT_THAT(CT.Instructions, SizeIs(1));
|
||||
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";
|
||||
ASSERT_THAT(IT.getVariableValues(), SizeIs(1)); // Imm.
|
||||
EXPECT_THAT(IT.getVariableValues()[0], IsInvalid()) << "Immediate is not set";
|
||||
}
|
||||
|
||||
TEST_F(LatencySnippetGeneratorTest, ImplicitSelfDependencyThroughTiedRegs) {
|
||||
@ -109,9 +109,9 @@ TEST_F(LatencySnippetGeneratorTest, ImplicitSelfDependencyThroughTiedRegs) {
|
||||
ASSERT_THAT(CT.Instructions, SizeIs(1));
|
||||
const InstructionTemplate &IT = CT.Instructions[0];
|
||||
EXPECT_THAT(IT.getOpcode(), Opcode);
|
||||
ASSERT_THAT(IT.VariableValues, SizeIs(2));
|
||||
EXPECT_THAT(IT.VariableValues[0], IsInvalid()) << "Operand 1 is not set";
|
||||
EXPECT_THAT(IT.VariableValues[1], IsInvalid()) << "Operand 2 is not set";
|
||||
ASSERT_THAT(IT.getVariableValues(), SizeIs(2));
|
||||
EXPECT_THAT(IT.getVariableValues()[0], IsInvalid()) << "Operand 1 is not set";
|
||||
EXPECT_THAT(IT.getVariableValues()[1], IsInvalid()) << "Operand 2 is not set";
|
||||
}
|
||||
|
||||
TEST_F(LatencySnippetGeneratorTest, ImplicitSelfDependencyThroughExplicitRegs) {
|
||||
@ -131,8 +131,8 @@ TEST_F(LatencySnippetGeneratorTest, ImplicitSelfDependencyThroughExplicitRegs) {
|
||||
ASSERT_THAT(CT.Instructions, SizeIs(1));
|
||||
const InstructionTemplate &IT = CT.Instructions[0];
|
||||
EXPECT_THAT(IT.getOpcode(), Opcode);
|
||||
ASSERT_THAT(IT.VariableValues, SizeIs(3));
|
||||
EXPECT_THAT(IT.VariableValues,
|
||||
ASSERT_THAT(IT.getVariableValues(), SizeIs(3));
|
||||
EXPECT_THAT(IT.getVariableValues(),
|
||||
AnyOf(ElementsAre(IsReg(), IsInvalid(), IsReg()),
|
||||
ElementsAre(IsReg(), IsReg(), IsInvalid())))
|
||||
<< "Op0 is either set to Op1 or to Op2";
|
||||
@ -173,9 +173,10 @@ TEST_F(LatencySnippetGeneratorTest, DependencyThroughOtherOpcode) {
|
||||
ASSERT_THAT(CT.Instructions, SizeIs(2));
|
||||
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())));
|
||||
ASSERT_THAT(IT.getVariableValues(), SizeIs(2));
|
||||
EXPECT_THAT(IT.getVariableValues(),
|
||||
AnyOf(ElementsAre(IsReg(), IsInvalid()),
|
||||
ElementsAre(IsInvalid(), IsReg())));
|
||||
EXPECT_THAT(CT.Instructions[1].getOpcode(), Not(Opcode));
|
||||
// TODO: check that the two instructions alias each other.
|
||||
}
|
||||
@ -193,7 +194,7 @@ TEST_F(LatencySnippetGeneratorTest, LAHF) {
|
||||
ASSERT_THAT(CT.Instructions, SizeIs(2));
|
||||
const InstructionTemplate &IT = CT.Instructions[0];
|
||||
EXPECT_THAT(IT.getOpcode(), Opcode);
|
||||
ASSERT_THAT(IT.VariableValues, SizeIs(0));
|
||||
ASSERT_THAT(IT.getVariableValues(), SizeIs(0));
|
||||
}
|
||||
}
|
||||
|
||||
@ -212,9 +213,9 @@ TEST_F(UopsSnippetGeneratorTest, ParallelInstruction) {
|
||||
ASSERT_THAT(CT.Instructions, SizeIs(1));
|
||||
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());
|
||||
ASSERT_THAT(IT.getVariableValues(), SizeIs(2));
|
||||
EXPECT_THAT(IT.getVariableValues()[0], IsInvalid());
|
||||
EXPECT_THAT(IT.getVariableValues()[1], IsInvalid());
|
||||
}
|
||||
|
||||
TEST_F(UopsSnippetGeneratorTest, SerialInstruction) {
|
||||
@ -233,7 +234,7 @@ TEST_F(UopsSnippetGeneratorTest, SerialInstruction) {
|
||||
ASSERT_THAT(CT.Instructions, SizeIs(1));
|
||||
const InstructionTemplate &IT = CT.Instructions[0];
|
||||
EXPECT_THAT(IT.getOpcode(), Opcode);
|
||||
ASSERT_THAT(IT.VariableValues, SizeIs(0));
|
||||
ASSERT_THAT(IT.getVariableValues(), SizeIs(0));
|
||||
}
|
||||
|
||||
TEST_F(UopsSnippetGeneratorTest, StaticRenaming) {
|
||||
@ -260,8 +261,8 @@ TEST_F(UopsSnippetGeneratorTest, StaticRenaming) {
|
||||
ASSERT_THAT(CT.Instructions, SizeIs(kInstructionCount));
|
||||
std::unordered_set<unsigned> AllDefRegisters;
|
||||
for (const auto &IT : CT.Instructions) {
|
||||
ASSERT_THAT(IT.VariableValues, SizeIs(3));
|
||||
AllDefRegisters.insert(IT.VariableValues[0].getReg());
|
||||
ASSERT_THAT(IT.getVariableValues(), SizeIs(3));
|
||||
AllDefRegisters.insert(IT.getVariableValues()[0].getReg());
|
||||
}
|
||||
EXPECT_THAT(AllDefRegisters, SizeIs(kInstructionCount))
|
||||
<< "Each instruction writes to a different register";
|
||||
@ -291,12 +292,14 @@ TEST_F(UopsSnippetGeneratorTest, NoTiedVariables) {
|
||||
ASSERT_THAT(CT.Instructions, SizeIs(1));
|
||||
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()))
|
||||
ASSERT_THAT(IT.getVariableValues(), SizeIs(4));
|
||||
EXPECT_THAT(IT.getVariableValues()[0].getReg(),
|
||||
Not(IT.getVariableValues()[1].getReg()))
|
||||
<< "Def is different from first Use";
|
||||
EXPECT_THAT(IT.VariableValues[0].getReg(), Not(IT.VariableValues[2].getReg()))
|
||||
EXPECT_THAT(IT.getVariableValues()[0].getReg(),
|
||||
Not(IT.getVariableValues()[2].getReg()))
|
||||
<< "Def is different from second Use";
|
||||
EXPECT_THAT(IT.VariableValues[3], IsInvalid());
|
||||
EXPECT_THAT(IT.getVariableValues()[3], IsInvalid());
|
||||
}
|
||||
|
||||
TEST_F(UopsSnippetGeneratorTest, MemoryUse) {
|
||||
@ -326,11 +329,11 @@ TEST_F(UopsSnippetGeneratorTest, MemoryUse) {
|
||||
SizeIs(UopsSnippetGenerator::kMinNumDifferentAddresses));
|
||||
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);
|
||||
ASSERT_THAT(IT.getVariableValues(), SizeIs(6));
|
||||
EXPECT_EQ(IT.getVariableValues()[2].getImm(), 1);
|
||||
EXPECT_EQ(IT.getVariableValues()[3].getReg(), 0u);
|
||||
EXPECT_EQ(IT.getVariableValues()[4].getImm(), 0);
|
||||
EXPECT_EQ(IT.getVariableValues()[5].getReg(), 0u);
|
||||
}
|
||||
|
||||
class FakeSnippetGenerator : public SnippetGenerator {
|
||||
@ -338,10 +341,14 @@ public:
|
||||
FakeSnippetGenerator(const LLVMState &State, const Options &Opts)
|
||||
: SnippetGenerator(State, Opts) {}
|
||||
|
||||
Instruction createInstruction(unsigned Opcode) {
|
||||
const Instruction &getInstr(unsigned Opcode) {
|
||||
return State.getIC().getInstr(Opcode);
|
||||
}
|
||||
|
||||
InstructionTemplate getInstructionTemplate(unsigned Opcode) {
|
||||
return {&getInstr(Opcode)};
|
||||
}
|
||||
|
||||
private:
|
||||
Expected<std::vector<CodeTemplate>>
|
||||
generateCodeTemplates(const Instruction &, const BitVector &) const override {
|
||||
@ -389,8 +396,8 @@ TEST_F(FakeSnippetGeneratorTest, ComputeRegisterInitialValuesAdd16ri) {
|
||||
// explicit use 1 : reg RegClass=GR16 | TIED_TO:0
|
||||
// explicit use 2 : imm
|
||||
// implicit def : EFLAGS
|
||||
InstructionTemplate IT(Generator.createInstruction(X86::ADD16ri));
|
||||
IT.getValueFor(IT.Instr.Variables[0]) = MCOperand::createReg(X86::AX);
|
||||
InstructionTemplate IT = Generator.getInstructionTemplate(X86::ADD16ri);
|
||||
IT.getValueFor(IT.getInstr().Variables[0]) = MCOperand::createReg(X86::AX);
|
||||
std::vector<InstructionTemplate> Snippet;
|
||||
Snippet.push_back(std::move(IT));
|
||||
const auto RIV = Generator.computeRegisterInitialValues(Snippet);
|
||||
@ -404,15 +411,18 @@ TEST_F(FakeSnippetGeneratorTest, ComputeRegisterInitialValuesAdd64rr) {
|
||||
// -> only rbx needs defining.
|
||||
std::vector<InstructionTemplate> Snippet;
|
||||
{
|
||||
InstructionTemplate Mov(Generator.createInstruction(X86::MOV64ri));
|
||||
Mov.getValueFor(Mov.Instr.Variables[0]) = MCOperand::createReg(X86::RAX);
|
||||
Mov.getValueFor(Mov.Instr.Variables[1]) = MCOperand::createImm(42);
|
||||
InstructionTemplate Mov = Generator.getInstructionTemplate(X86::MOV64ri);
|
||||
Mov.getValueFor(Mov.getInstr().Variables[0]) =
|
||||
MCOperand::createReg(X86::RAX);
|
||||
Mov.getValueFor(Mov.getInstr().Variables[1]) = MCOperand::createImm(42);
|
||||
Snippet.push_back(std::move(Mov));
|
||||
}
|
||||
{
|
||||
InstructionTemplate Add(Generator.createInstruction(X86::ADD64rr));
|
||||
Add.getValueFor(Add.Instr.Variables[0]) = MCOperand::createReg(X86::RAX);
|
||||
Add.getValueFor(Add.Instr.Variables[1]) = MCOperand::createReg(X86::RBX);
|
||||
InstructionTemplate Add = Generator.getInstructionTemplate(X86::ADD64rr);
|
||||
Add.getValueFor(Add.getInstr().Variables[0]) =
|
||||
MCOperand::createReg(X86::RAX);
|
||||
Add.getValueFor(Add.getInstr().Variables[1]) =
|
||||
MCOperand::createReg(X86::RBX);
|
||||
Snippet.push_back(std::move(Add));
|
||||
}
|
||||
|
||||
|
@ -119,6 +119,10 @@ protected:
|
||||
Value);
|
||||
}
|
||||
|
||||
const Instruction &getInstr(unsigned OpCode) {
|
||||
return State.getIC().getInstr(OpCode);
|
||||
}
|
||||
|
||||
LLVMState State;
|
||||
};
|
||||
|
||||
@ -355,8 +359,8 @@ TEST_F(Core2TargetTest, SetRegToFP1_4Bits) {
|
||||
}
|
||||
|
||||
TEST_F(Core2Avx512TargetTest, FillMemoryOperands_ADD64rm) {
|
||||
Instruction I(State.getInstrInfo(), State.getRATC(), X86::ADD64rm);
|
||||
InstructionTemplate IT(I);
|
||||
const Instruction &I = getInstr(X86::ADD64rm);
|
||||
InstructionTemplate IT(&I);
|
||||
constexpr const int kOffset = 42;
|
||||
State.getExegesisTarget().fillMemoryOperands(IT, X86::RDI, kOffset);
|
||||
// Memory is operands 2-6.
|
||||
@ -368,8 +372,8 @@ TEST_F(Core2Avx512TargetTest, FillMemoryOperands_ADD64rm) {
|
||||
}
|
||||
|
||||
TEST_F(Core2Avx512TargetTest, FillMemoryOperands_VGATHERDPSZ128rm) {
|
||||
Instruction I(State.getInstrInfo(), State.getRATC(), X86::VGATHERDPSZ128rm);
|
||||
InstructionTemplate IT(I);
|
||||
const Instruction &I = getInstr(X86::VGATHERDPSZ128rm);
|
||||
InstructionTemplate IT(&I);
|
||||
constexpr const int kOffset = 42;
|
||||
State.getExegesisTarget().fillMemoryOperands(IT, X86::RDI, kOffset);
|
||||
// Memory is operands 4-8.
|
||||
|
Loading…
Reference in New Issue
Block a user