Index: tools/llvm-exegesis/lib/BenchmarkCode.h =================================================================== --- tools/llvm-exegesis/lib/BenchmarkCode.h +++ tools/llvm-exegesis/lib/BenchmarkCode.h @@ -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 #include 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. Index: tools/llvm-exegesis/lib/CodeTemplate.h =================================================================== --- tools/llvm-exegesis/lib/CodeTemplate.h +++ tools/llvm-exegesis/lib/CodeTemplate.h @@ -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 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 @@ // Some information about how this template has been created. std::string Info; // The list of the instructions for this template. - std::vector Instructions; + std::vector 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 Index: tools/llvm-exegesis/lib/CodeTemplate.cpp =================================================================== --- tools/llvm-exegesis/lib/CodeTemplate.cpp +++ tools/llvm-exegesis/lib/CodeTemplate.cpp @@ -15,4 +15,150 @@ 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 +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 Index: tools/llvm-exegesis/lib/Latency.cpp =================================================================== --- tools/llvm-exegesis/lib/Latency.cpp +++ tools/llvm-exegesis/lib/Latency.cpp @@ -62,17 +62,17 @@ 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( Index: tools/llvm-exegesis/lib/MCInstrDescView.h =================================================================== --- tools/llvm-exegesis/lib/MCInstrDescView.h +++ tools/llvm-exegesis/lib/MCInstrDescView.h @@ -82,35 +82,6 @@ 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 VariableValues; -}; - // Represents the assignment of a Register to an Operand. struct RegisterOperandAssignment { RegisterOperandAssignment(const Operand *Operand, llvm::MCPhysReg Reg) @@ -153,20 +124,6 @@ llvm::SmallVector 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. Index: tools/llvm-exegesis/lib/MCInstrDescView.cpp =================================================================== --- tools/llvm-exegesis/lib/MCInstrDescView.cpp +++ tools/llvm-exegesis/lib/MCInstrDescView.cpp @@ -89,76 +89,6 @@ [](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 @@ } } -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 -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()) Index: tools/llvm-exegesis/lib/RegisterValue.h =================================================================== --- tools/llvm-exegesis/lib/RegisterValue.h +++ tools/llvm-exegesis/lib/RegisterValue.h @@ -15,9 +15,16 @@ //===----------------------------------------------------------------------===// #include +#include 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 Index: tools/llvm-exegesis/lib/SnippetGenerator.h =================================================================== --- tools/llvm-exegesis/lib/SnippetGenerator.h +++ tools/llvm-exegesis/lib/SnippetGenerator.h @@ -50,7 +50,7 @@ // Given a snippet, computes which registers the setup code needs to define. std::vector computeRegisterInitialValues( - const std::vector &Snippet) const; + const std::vector &Snippet) const; protected: const LLVMState &State; Index: tools/llvm-exegesis/lib/SnippetGenerator.cpp =================================================================== --- tools/llvm-exegesis/lib/SnippetGenerator.cpp +++ tools/llvm-exegesis/lib/SnippetGenerator.cpp @@ -40,12 +40,12 @@ { 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 @@ } std::vector SnippetGenerator::computeRegisterInitialValues( - const std::vector &Instructions) const { + const std::vector &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 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 @@ } } // 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 @@ return llvm::make_error("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 @@ CT.Instructions.emplace_back(Instr); return std::move(CT); } + } // namespace exegesis Index: tools/llvm-exegesis/lib/Target.h =================================================================== --- tools/llvm-exegesis/lib/Target.h +++ tools/llvm-exegesis/lib/Target.h @@ -49,7 +49,7 @@ } // 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( Index: tools/llvm-exegesis/lib/Uops.h =================================================================== --- tools/llvm-exegesis/lib/Uops.h +++ tools/llvm-exegesis/lib/Uops.h @@ -56,9 +56,9 @@ // mov eax, [rdi + 128] // add eax, [rdi + 192] // mov eax, [rdi + 256] - void - instantiateMemoryOperands(unsigned ScratchSpaceReg, - std::vector &Snippet) const; + void instantiateMemoryOperands( + unsigned ScratchSpaceReg, + std::vector &SnippetTemplate) const; }; class UopsBenchmarkRunner : public BenchmarkRunner { Index: tools/llvm-exegesis/lib/Uops.cpp =================================================================== --- tools/llvm-exegesis/lib/Uops.cpp +++ tools/llvm-exegesis/lib/Uops.cpp @@ -127,23 +127,23 @@ void UopsSnippetGenerator::instantiateMemoryOperands( const unsigned ScratchSpacePointerInReg, - std::vector &Instructions) const { + std::vector &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 @@ } 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 @@ 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 @@ 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 @@ 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 @@ }; std::vector 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 @@ 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) { Index: tools/llvm-exegesis/lib/X86/Target.cpp =================================================================== --- tools/llvm-exegesis/lib/X86/Target.cpp +++ tools/llvm-exegesis/lib/X86/Target.cpp @@ -256,32 +256,32 @@ 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. } } Index: unittests/tools/llvm-exegesis/X86/SnippetGeneratorTest.cpp =================================================================== --- unittests/tools/llvm-exegesis/X86/SnippetGeneratorTest.cpp +++ unittests/tools/llvm-exegesis/X86/SnippetGeneratorTest.cpp @@ -88,10 +88,10 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ constexpr const unsigned kInstructionCount = 15; ASSERT_THAT(CT.Instructions, SizeIs(kInstructionCount)); std::unordered_set 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 @@ 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 @@ 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 @@ // 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 Snippet; - Snippet.push_back(std::move(IB)); + std::vector 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 @@ // mov64ri rax, 42 // add64rr rax, rax, rbx // -> only rbx needs defining. - std::vector Snippet; + std::vector 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]) =