diff --git a/llvm/tools/llvm-exegesis/lib/CodeTemplate.cpp b/llvm/tools/llvm-exegesis/lib/CodeTemplate.cpp index 9d01c7d40b0d21..9840a08c2536e7 100644 --- a/llvm/tools/llvm-exegesis/lib/CodeTemplate.cpp +++ b/llvm/tools/llvm-exegesis/lib/CodeTemplate.cpp @@ -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; diff --git a/llvm/tools/llvm-exegesis/lib/CodeTemplate.h b/llvm/tools/llvm-exegesis/lib/CodeTemplate.h index 3556f6fe2ec2c4..51978147ba09d3 100644 --- a/llvm/tools/llvm-exegesis/lib/CodeTemplate.h +++ b/llvm/tools/llvm-exegesis/lib/CodeTemplate.h @@ -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 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 VariableValues; }; diff --git a/llvm/tools/llvm-exegesis/lib/Latency.cpp b/llvm/tools/llvm-exegesis/lib/Latency.cpp index 45a0e7e362dbba..7030658a46031b 100644 --- a/llvm/tools/llvm-exegesis/lib/Latency.cpp +++ b/llvm/tools/llvm-exegesis/lib/Latency.cpp @@ -37,8 +37,8 @@ struct ExecutionClass { static constexpr size_t kMaxAliasingInstructions = 10; -static std::vector -computeAliasingInstructions(const LLVMState &State, const Instruction &Instr, +static std::vector +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 AliasingInstructions; + std::vector 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; diff --git a/llvm/tools/llvm-exegesis/lib/MCInstrDescView.cpp b/llvm/tools/llvm-exegesis/lib/MCInstrDescView.cpp index 9b3c50f8d9ec8e..487f6641d50797 100644 --- a/llvm/tools/llvm-exegesis/lib/MCInstrDescView.cpp +++ b/llvm/tools/llvm-exegesis/lib/MCInstrDescView.cpp @@ -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()); + auto &Entry = Cache.back(); + Entry->swap(BV); + return Entry.get(); +} + +Instruction::Instruction(const MCInstrDesc *Description, StringRef Name, + SmallVector Operands, + SmallVector 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::create(const MCInstrInfo &InstrInfo, + const RegisterAliasingTrackerCache &RATC, + const BitVectorCache &BVC, unsigned Opcode) { + const llvm::MCInstrDesc *const Description = &InstrInfo.get(Opcode); unsigned OpIndex = 0; + SmallVector Operands; + SmallVector 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::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::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(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; } diff --git a/llvm/tools/llvm-exegesis/lib/MCInstrDescView.h b/llvm/tools/llvm-exegesis/lib/MCInstrDescView.h index 4455bbb396e7c7..8c7e0b2e01d34d 100644 --- a/llvm/tools/llvm-exegesis/lib/MCInstrDescView.h +++ b/llvm/tools/llvm-exegesis/lib/MCInstrDescView.h @@ -18,6 +18,7 @@ #ifndef LLVM_TOOLS_LLVM_EXEGESIS_MCINSTRDESCVIEW_H #define LLVM_TOOLS_LLVM_EXEGESIS_MCINSTRDESCVIEW_H +#include #include #include @@ -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 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 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 TiedToIndex; // Set for Reg&Explicit Op. const MCPhysReg *ImplicitReg = nullptr; // Set for Implicit Op. - int VariableIndex = -1; // Set for Explicit Op. + Optional 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> 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 + 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 Operands; - SmallVector 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 Operands; + const SmallVector 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 Operands, + SmallVector 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 @@ struct InstructionsCache { const RegisterAliasingTrackerCache &RATC; mutable std::unordered_map> Instructions; + const BitVectorCache BVC; }; // Represents the assignment of a Register to an Operand. diff --git a/llvm/tools/llvm-exegesis/lib/SnippetGenerator.cpp b/llvm/tools/llvm-exegesis/lib/SnippetGenerator.cpp index 65cc954a4696ec..d1f168fe43bfdb 100644 --- a/llvm/tools/llvm-exegesis/lib/SnippetGenerator.cpp +++ b/llvm/tools/llvm-exegesis/lib/SnippetGenerator.cpp @@ -112,7 +112,7 @@ std::vector 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 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 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); } } diff --git a/llvm/tools/llvm-exegesis/lib/Uops.cpp b/llvm/tools/llvm-exegesis/lib/Uops.cpp index db7dce8971873f..66319e37ce8105 100644 --- a/llvm/tools/llvm-exegesis/lib/Uops.cpp +++ b/llvm/tools/llvm-exegesis/lib/Uops.cpp @@ -127,7 +127,7 @@ static std::vector generateSnippetUsingStaticRenaming( std::vector 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> 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)); diff --git a/llvm/tools/llvm-exegesis/lib/X86/Target.cpp b/llvm/tools/llvm-exegesis/lib/X86/Target.cpp index 61da38e5f5dd46..c67630fdebfc5f 100644 --- a/llvm/tools/llvm-exegesis/lib/X86/Target.cpp +++ b/llvm/tools/llvm-exegesis/lib/X86/Target.cpp @@ -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( "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("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> generateLEATemplatesCommon( const LLVMState &State, const SnippetGenerator::Options &Opts, std::function 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> 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(MemOpIdx); ++I) { - const auto &Op = IT.Instr.Operands[I]; + const auto &Op = IT.getInstr().Operands[I]; if (Op.isTied() && Op.getTiedToIndex() < I) { ++MemOpIdx; } diff --git a/llvm/tools/llvm-exegesis/llvm-exegesis.cpp b/llvm/tools/llvm-exegesis/llvm-exegesis.cpp index d16f88e47370a8..45929fee5f760e 100644 --- a/llvm/tools/llvm-exegesis/llvm-exegesis.cpp +++ b/llvm/tools/llvm-exegesis/llvm-exegesis.cpp @@ -208,7 +208,7 @@ static Expected> 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("Unsupported opcode: isPseudo"); diff --git a/llvm/unittests/tools/llvm-exegesis/Mips/SnippetGeneratorTest.cpp b/llvm/unittests/tools/llvm-exegesis/Mips/SnippetGeneratorTest.cpp index 79d0b708274ca5..b9280ab6d685cc 100644 --- a/llvm/unittests/tools/llvm-exegesis/Mips/SnippetGeneratorTest.cpp +++ b/llvm/unittests/tools/llvm-exegesis/Mips/SnippetGeneratorTest.cpp @@ -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"; diff --git a/llvm/unittests/tools/llvm-exegesis/X86/SnippetGeneratorTest.cpp b/llvm/unittests/tools/llvm-exegesis/X86/SnippetGeneratorTest.cpp index 463eec2c21ddc3..0f898d9d7bbe9b 100644 --- a/llvm/unittests/tools/llvm-exegesis/X86/SnippetGeneratorTest.cpp +++ b/llvm/unittests/tools/llvm-exegesis/X86/SnippetGeneratorTest.cpp @@ -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 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 @@ class FakeSnippetGenerator : public SnippetGenerator { 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> 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 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 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)); } diff --git a/llvm/unittests/tools/llvm-exegesis/X86/TargetTest.cpp b/llvm/unittests/tools/llvm-exegesis/X86/TargetTest.cpp index e15b7f2dbba359..eefed6dd5441b2 100644 --- a/llvm/unittests/tools/llvm-exegesis/X86/TargetTest.cpp +++ b/llvm/unittests/tools/llvm-exegesis/X86/TargetTest.cpp @@ -119,6 +119,10 @@ class X86TargetTest : public ::testing::Test { 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.