Index: tools/llvm-exegesis/lib/CodeTemplate.cpp =================================================================== --- tools/llvm-exegesis/lib/CodeTemplate.cpp +++ tools/llvm-exegesis/lib/CodeTemplate.cpp @@ -33,32 +33,26 @@ } llvm::MCOperand &InstructionTemplate::getValueFor(const Variable &Var) { - return VariableValues[Var.Index]; + return VariableValues[Var.getIndex()]; } const llvm::MCOperand & InstructionTemplate::getValueFor(const Variable &Var) const { - return VariableValues[Var.Index]; + return VariableValues[Var.getIndex()]; } llvm::MCOperand &InstructionTemplate::getValueFor(const Operand &Op) { - assert(Op.VariableIndex >= 0); - return getValueFor(Instr.Variables[Op.VariableIndex]); + return getValueFor(Instr.Variables[Op.getVariableIndex()]); } const llvm::MCOperand & InstructionTemplate::getValueFor(const Operand &Op) const { - assert(Op.VariableIndex >= 0); - return getValueFor(Instr.Variables[Op.VariableIndex]); + return getValueFor(Instr.Variables[Op.getVariableIndex()]); } 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; + return Instr.getPrimaryOperand(Var).isImmediate(); }); } @@ -66,7 +60,7 @@ llvm::MCInst Result; Result.setOpcode(Instr.Description->Opcode); for (const auto &Op : Instr.Operands) - if (Op.IsExplicit) + if (Op.isExplicit()) Result.addOperand(getValueFor(Op)); return Result; } Index: tools/llvm-exegesis/lib/MCInstrDescView.h =================================================================== --- tools/llvm-exegesis/lib/MCInstrDescView.h +++ tools/llvm-exegesis/lib/MCInstrDescView.h @@ -30,11 +30,18 @@ namespace exegesis { -struct Operand; // forward declaration. - // A variable represents the value associated to an Operand or a set of Operands // if they are tied together. struct Variable { + // Returns the index of this Variable inside Instruction's Variable. + unsigned getIndex() const; + + // Returns the index of the Operand linked to this Variable. + unsigned getPrimaryOperandIndex() const; + + // Returns whether this Variable has more than one Operand linked to it. + bool hasTiedOperands() const; + // The indices of the operands tied to this Variable. llvm::SmallVector TiedOperands; llvm::MCOperand AssignedValue; @@ -45,7 +52,6 @@ // MCOperandInfo can only represents Explicit operands. This object gives a // uniform view of Implicit and Explicit Operands. -// // - Index: can be used to refer to MCInstrDesc::operands for Explicit operands. // - Tracker: is set for Register Operands and is used to keep track of possible // registers and the registers reachable from them (aliasing registers). @@ -56,10 +62,26 @@ // - VariableIndex: the index of the Variable holding the value for this Operand // or -1 if this operand is implicit. struct Operand { + bool getIndex() const; + bool isExplicit() const; + bool isImplicit() const; + bool isImplicitReg() const; + bool isDef() const; + bool isUse() const; + bool isReg() const; + bool isTied() const; + bool isVariable() const; + bool isMemory() const; + bool isImmediate() const; + int getTiedToIndex() const; + int getVariableIndex() const; + unsigned getImplicitReg() const; + const RegisterAliasingTracker &getRegisterAliasing() const; + const llvm::MCOperandInfo &getExplicitOperandInfo() const; + + // Please use the accessors above and not the following fields. unsigned Index = 0; bool IsDef = false; - bool IsMem = false; - bool IsExplicit = false; const RegisterAliasingTracker *Tracker = nullptr; // Set for Register Op. const llvm::MCOperandInfo *Info = nullptr; // Set for Explicit Op. int TiedToIndex = -1; // Set for Reg&Explicit Op. @@ -73,13 +95,36 @@ Instruction(const llvm::MCInstrDesc &MCInstrDesc, const RegisterAliasingTrackerCache &ATC); + // Returns the Operand linked to this Variable. + // In case the Variable is tied, the primary (i.e. Def) Operand is returned. + const Operand &getPrimaryOperand(const Variable &Var) const; + + // Returns whether this instruction has Memory Operands. + // Repeating this instruction executes sequentially with an instruction that + // reads or write the same memory region. bool hasMemoryOperands() const; + // Whether this instruction is self aliasing through its implicit registers. + // Repeating this instruction is guaranteed to executes sequentially. + bool hasAliasingImplicitRegisters() const; + + // Whether this instruction is self aliasing through its tied registers. + // Repeating this instruction is guaranteed to executes sequentially. + bool hasTiedRegisters() const; + + // Whether this instruction is self aliasing through some registers. + // Repeating this instruction may execute sequentially by picking aliasing + // Use and Def registers. It may also execute in parallel by picking non + // aliasing Use and Def registers. + bool hasAliasingRegisters() const; + const llvm::MCInstrDesc *Description; // Never nullptr. llvm::SmallVector Operands; llvm::SmallVector Variables; - llvm::BitVector DefRegisters; // The union of the aliased def registers. - llvm::BitVector UseRegisters; // The union of the aliased use registers. + llvm::BitVector ImplDefRegs; // The set of aliased implicit def registers. + llvm::BitVector ImplUseRegs; // The set of aliased implicit use registers. + llvm::BitVector AllDefRegs; // The set of all aliased def registers. + llvm::BitVector AllUseRegs; // The set of all aliased use registers. }; // Represents the assignment of a Register to an Operand. Index: tools/llvm-exegesis/lib/MCInstrDescView.cpp =================================================================== --- tools/llvm-exegesis/lib/MCInstrDescView.cpp +++ tools/llvm-exegesis/lib/MCInstrDescView.cpp @@ -17,6 +17,70 @@ namespace exegesis { +unsigned Variable::getIndex() const { + assert(Index >= 0); + return Index; +} +unsigned Variable::getPrimaryOperandIndex() const { + assert(!TiedOperands.empty()); + return TiedOperands[0]; +} + +bool Variable::hasTiedOperands() const { return TiedOperands.size() > 1; } + +bool Operand::getIndex() const { return Index; } + +bool Operand::isExplicit() const { return Info; } + +bool Operand::isImplicit() const { return !Info; } + +bool Operand::isImplicitReg() const { return ImplicitReg; } + +bool Operand::isDef() const { return IsDef; } + +bool Operand::isUse() const { return !IsDef; } + +bool Operand::isReg() const { return Tracker; } + +bool Operand::isTied() const { return TiedToIndex >= 0; } + +bool Operand::isVariable() const { return VariableIndex >= 0; } + +bool Operand::isMemory() const { + return isExplicit() && + getExplicitOperandInfo().OperandType == llvm::MCOI::OPERAND_MEMORY; +} + +bool Operand::isImmediate() const { + return isExplicit() && + getExplicitOperandInfo().OperandType == llvm::MCOI::OPERAND_IMMEDIATE; +} + +int Operand::getTiedToIndex() const { + assert(isTied()); + return TiedToIndex; +} + +int Operand::getVariableIndex() const { + assert(isVariable()); + return VariableIndex; +} + +unsigned Operand::getImplicitReg() const { + assert(ImplicitReg); + return *ImplicitReg; +} + +const RegisterAliasingTracker &Operand::getRegisterAliasing() const { + assert(Tracker); + return *Tracker; +} + +const llvm::MCOperandInfo &Operand::getExplicitOperandInfo() const { + assert(Info); + return *Info; +} + Instruction::Instruction(const llvm::MCInstrDesc &MCInstrDesc, const RegisterAliasingTrackerCache &RATC) : Description(&MCInstrDesc) { @@ -26,8 +90,6 @@ Operand Operand; Operand.Index = OpIndex; Operand.IsDef = (OpIndex < MCInstrDesc.getNumDefs()); - Operand.IsMem = OpInfo.OperandType == llvm::MCOI::OPERAND_MEMORY; - Operand.IsExplicit = true; // TODO(gchatelet): Handle isLookupPtrRegClass. if (OpInfo.RegClass >= 0) Operand.Tracker = &RATC.getRegisterClass(OpInfo.RegClass); @@ -41,7 +103,6 @@ Operand Operand; Operand.Index = OpIndex; Operand.IsDef = true; - Operand.IsExplicit = false; Operand.Tracker = &RATC.getRegister(*MCPhysReg); Operand.ImplicitReg = MCPhysReg; Operands.push_back(Operand); @@ -51,7 +112,6 @@ Operand Operand; Operand.Index = OpIndex; Operand.IsDef = false; - Operand.IsExplicit = false; Operand.Tracker = &RATC.getRegister(*MCPhysReg); Operand.ImplicitReg = MCPhysReg; Operands.push_back(Operand); @@ -59,7 +119,7 @@ // Assigning Variables to non tied explicit operands. Variables.reserve(Operands.size()); // Variables.size() <= Operands.size() for (auto &Op : Operands) - if (Op.IsExplicit && Op.TiedToIndex < 0) { + if (Op.isExplicit() && !Op.isTied()) { const size_t VariableIndex = Variables.size(); Op.VariableIndex = VariableIndex; Variables.emplace_back(); @@ -67,26 +127,55 @@ } // Assigning Variables to tied operands. for (auto &Op : Operands) - if (Op.TiedToIndex >= 0) - Op.VariableIndex = Operands[Op.TiedToIndex].VariableIndex; + if (Op.isTied()) + Op.VariableIndex = Operands[Op.getTiedToIndex()].getVariableIndex(); // Assigning Operands to Variables. for (auto &Op : Operands) - if (Op.VariableIndex >= 0) - Variables[Op.VariableIndex].TiedOperands.push_back(Op.Index); + if (Op.isVariable()) + Variables[Op.getVariableIndex()].TiedOperands.push_back(Op.getIndex()); // Processing Aliasing. - DefRegisters = RATC.emptyRegisters(); - UseRegisters = RATC.emptyRegisters(); + ImplDefRegs = RATC.emptyRegisters(); + ImplUseRegs = RATC.emptyRegisters(); + AllDefRegs = RATC.emptyRegisters(); + AllUseRegs = RATC.emptyRegisters(); for (const auto &Op : Operands) { - if (Op.Tracker) { - auto &Registers = Op.IsDef ? DefRegisters : UseRegisters; - Registers |= Op.Tracker->aliasedBits(); + if (Op.isReg()) { + const auto &AliasingBits = Op.getRegisterAliasing().aliasedBits(); + if (Op.isDef()) + AllDefRegs |= AliasingBits; + if (Op.isUse()) + AllUseRegs |= AliasingBits; + if (Op.isDef() && Op.isImplicit()) + ImplDefRegs |= AliasingBits; + if (Op.isUse() && Op.isImplicit()) + ImplUseRegs |= AliasingBits; } } } +const Operand &Instruction::getPrimaryOperand(const Variable &Var) const { + const auto PrimaryOperandIndex = Var.getPrimaryOperandIndex(); + assert(PrimaryOperandIndex < Operands.size()); + return Operands[PrimaryOperandIndex]; +} + bool Instruction::hasMemoryOperands() const { - return std::any_of(Operands.begin(), Operands.end(), - [](const Operand &Op) { return Op.IsMem; }); + return std::any_of(Operands.begin(), Operands.end(), [](const Operand &Op) { + return Op.isReg() && Op.isExplicit() && Op.isMemory(); + }); +} + +bool Instruction::hasAliasingImplicitRegisters() const { + return ImplDefRegs.anyCommon(ImplUseRegs); +} + +bool Instruction::hasTiedRegisters() const { + return llvm::any_of( + Variables, [this](const Variable &Var) { return Var.hasTiedOperands(); }); +} + +bool Instruction::hasAliasingRegisters() const { + return AllDefRegs.anyCommon(AllUseRegs); } bool RegisterOperandAssignment:: @@ -103,8 +192,8 @@ const llvm::MCPhysReg Reg, bool SelectDef, llvm::ArrayRef Operands, llvm::SmallVectorImpl &OperandValues) { for (const auto &Op : Operands) { - if (Op.Tracker && Op.IsDef == SelectDef) { - const int SourceReg = Op.Tracker->getOrigin(Reg); + if (Op.isReg() && Op.isDef() == SelectDef) { + const int SourceReg = Op.getRegisterAliasing().getOrigin(Reg); if (SourceReg >= 0) OperandValues.emplace_back(&Op, SourceReg); } @@ -113,7 +202,7 @@ bool AliasingRegisterOperands::hasImplicitAliasing() const { const auto HasImplicit = [](const RegisterOperandAssignment &ROV) { - return !ROV.Op->IsExplicit; + return ROV.Op->isImplicit(); }; return llvm::any_of(Defs, HasImplicit) && llvm::any_of(Uses, HasImplicit); } @@ -129,9 +218,9 @@ AliasingConfigurations::AliasingConfigurations( const Instruction &DefInstruction, const Instruction &UseInstruction) : DefInstruction(DefInstruction), UseInstruction(UseInstruction) { - if (UseInstruction.UseRegisters.anyCommon(DefInstruction.DefRegisters)) { - auto CommonRegisters = UseInstruction.UseRegisters; - CommonRegisters &= DefInstruction.DefRegisters; + if (UseInstruction.AllUseRegs.anyCommon(DefInstruction.AllDefRegs)) { + auto CommonRegisters = UseInstruction.AllUseRegs; + CommonRegisters &= DefInstruction.AllDefRegs; for (const llvm::MCPhysReg Reg : CommonRegisters.set_bits()) { AliasingRegisterOperands ARO; addOperandIfAlias(Reg, true, DefInstruction.Operands, ARO.Defs); Index: tools/llvm-exegesis/lib/SnippetGenerator.cpp =================================================================== --- tools/llvm-exegesis/lib/SnippetGenerator.cpp +++ tools/llvm-exegesis/lib/SnippetGenerator.cpp @@ -70,17 +70,17 @@ // Returns the register that this Operand sets or uses, or 0 if this is not // a register. const auto GetOpReg = [&IT](const Operand &Op) -> unsigned { - if (Op.IsMem) + if (Op.isMemory()) return 0; - if (Op.ImplicitReg) - return *Op.ImplicitReg; - if (Op.IsExplicit && IT.getValueFor(Op).isReg()) + if (Op.isImplicitReg()) + return Op.getImplicitReg(); + 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 : IT.Instr.Operands) { - if (!Op.IsDef) { + if (Op.isUse()) { const unsigned Reg = GetOpReg(Op); if (Reg > 0 && !DefinedRegs.test(Reg)) { RIV.push_back(RegisterValue{Reg, llvm::APInt()}); @@ -90,7 +90,7 @@ } // Mark defs as having been def'ed. for (const Operand &Op : IT.Instr.Operands) { - if (Op.IsDef) { + if (Op.isDef()) { const unsigned Reg = GetOpReg(Op); if (Reg > 0) DefinedRegs.set(Reg); @@ -149,18 +149,15 @@ 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) { + const Operand &Op = Instr.getPrimaryOperand(Var); + switch (Op.getExplicitOperandInfo().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(Op.isReg()); + auto AllowedRegs = Op.getRegisterAliasing().sourceBits(); assert(AllowedRegs.size() == ForbiddenRegs.size()); for (auto I : ForbiddenRegs.set_bits()) AllowedRegs.reset(I); @@ -175,7 +172,7 @@ static void setRegisterOperandValue(const RegisterOperandAssignment &ROV, InstructionTemplate &IB) { assert(ROV.Op); - if (ROV.Op->IsExplicit) { + if (ROV.Op->isExplicit()) { auto &AssignedValue = IB.getValueFor(*ROV.Op); if (AssignedValue.isValid()) { assert(AssignedValue.isReg() && AssignedValue.getReg() == ROV.Reg); @@ -183,8 +180,8 @@ } AssignedValue = llvm::MCOperand::createReg(ROV.Reg); } else { - assert(ROV.Op->ImplicitReg != nullptr); - assert(ROV.Reg == *ROV.Op->ImplicitReg); + assert(ROV.Op->isImplicitReg()); + assert(ROV.Reg == ROV.Op->getImplicitReg()); } } Index: tools/llvm-exegesis/lib/Uops.cpp =================================================================== --- tools/llvm-exegesis/lib/Uops.cpp +++ tools/llvm-exegesis/lib/Uops.cpp @@ -93,25 +93,11 @@ return llvm::Error::success(); } -// Returns whether this Variable ties Use and Def operands together. -static bool hasTiedOperands(const Instruction &Instr, const Variable &Var) { - bool HasUse = false; - bool HasDef = false; - for (const unsigned OpIndex : Var.TiedOperands) { - const Operand &Op = Instr.Operands[OpIndex]; - if (Op.IsDef) - HasDef = true; - else - HasUse = true; - } - return HasUse && HasDef; -} - static llvm::SmallVector -getTiedVariables(const Instruction &Instr) { +getVariablesWithTiedOperands(const Instruction &Instr) { llvm::SmallVector Result; for (const auto &Var : Instr.Variables) - if (hasTiedOperands(Instr, Var)) + if (Var.hasTiedOperands()) Result.push_back(&Var); return Result; } @@ -170,8 +156,8 @@ // If the instruction implicitly writes to ScratchSpacePointerInReg , abort. // FIXME: We could make a copy of the scratch register. for (const auto &Op : Instr.Operands) { - if (Op.IsDef && Op.ImplicitReg && - ScratchSpaceAliasedRegs->test(*Op.ImplicitReg)) + if (Op.isDef() && Op.isImplicitReg() && + ScratchSpaceAliasedRegs->test(Op.getImplicitReg())) return llvm::make_error( "Infeasible : memory instruction uses scratch memory register"); } @@ -191,7 +177,7 @@ instantiateMemoryOperands(CT.ScratchSpacePointerInReg, CT.Instructions); return std::move(CT); } - const auto TiedVariables = getTiedVariables(Instr); + const auto TiedVariables = getVariablesWithTiedOperands(Instr); if (!TiedVariables.empty()) { if (TiedVariables.size() > 1) return llvm::make_error( @@ -199,11 +185,11 @@ llvm::inconvertibleErrorCode()); const Variable *Var = TiedVariables.front(); assert(Var); - assert(!Var->TiedOperands.empty()); - const Operand &Op = Instr.Operands[Var->TiedOperands.front()]; - assert(Op.Tracker); + const Operand &Op = Instr.getPrimaryOperand(*Var); + assert(Op.isReg()); CT.Info = "instruction has tied variables using static renaming."; - for (const llvm::MCPhysReg Reg : Op.Tracker->sourceBits().set_bits()) { + for (const llvm::MCPhysReg Reg : + Op.getRegisterAliasing().sourceBits().set_bits()) { if (ScratchSpaceAliasedRegs && ScratchSpaceAliasedRegs->test(Reg)) continue; // Do not use the scratch memory address register. InstructionTemplate TmpIT = IT; @@ -216,8 +202,8 @@ // No tied variables, we pick random values for defs. llvm::BitVector Defs(State.getRegInfo().getNumRegs()); for (const auto &Op : Instr.Operands) { - if (Op.Tracker && Op.IsExplicit && Op.IsDef && !Op.IsMem) { - auto PossibleRegisters = Op.Tracker->sourceBits(); + if (Op.isReg() && Op.isExplicit() && Op.isDef() && !Op.isMemory()) { + auto PossibleRegisters = Op.getRegisterAliasing().sourceBits(); remove(PossibleRegisters, RATC.reservedRegisters()); // Do not use the scratch memory address register. if (ScratchSpaceAliasedRegs) @@ -231,8 +217,8 @@ // And pick random use values that are not reserved and don't alias with defs. const auto DefAliases = getAliasedBits(State.getRegInfo(), Defs); for (const auto &Op : Instr.Operands) { - if (Op.Tracker && Op.IsExplicit && !Op.IsDef && !Op.IsMem) { - auto PossibleRegisters = Op.Tracker->sourceBits(); + if (Op.isReg() && Op.isExplicit() && Op.isUse() && !Op.isMemory()) { + auto PossibleRegisters = Op.getRegisterAliasing().sourceBits(); remove(PossibleRegisters, RATC.reservedRegisters()); // Do not use the scratch memory address register. if (ScratchSpaceAliasedRegs) Index: tools/llvm-exegesis/lib/X86/Target.cpp =================================================================== --- tools/llvm-exegesis/lib/X86/Target.cpp +++ tools/llvm-exegesis/lib/X86/Target.cpp @@ -262,25 +262,25 @@ // value for input and output. 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) { + if (Op->isExplicit() && Op->isMemory()) { // Case 1: 5-op memory. assert((I + 5 <= E) && "x86 memory references are always 5 ops"); IT.getValueFor(*Op) = llvm::MCOperand::createReg(Reg); // BaseReg Op = &IT.Instr.Operands[++I]; - assert(Op->IsMem); - assert(Op->IsExplicit); + assert(Op->isMemory()); + assert(Op->isExplicit()); IT.getValueFor(*Op) = llvm::MCOperand::createImm(1); // ScaleAmt Op = &IT.Instr.Operands[++I]; - assert(Op->IsMem); - assert(Op->IsExplicit); + assert(Op->isMemory()); + assert(Op->isExplicit()); IT.getValueFor(*Op) = llvm::MCOperand::createReg(0); // IndexReg Op = &IT.Instr.Operands[++I]; - assert(Op->IsMem); - assert(Op->IsExplicit); + assert(Op->isMemory()); + assert(Op->isExplicit()); IT.getValueFor(*Op) = llvm::MCOperand::createImm(Offset); // Disp Op = &IT.Instr.Operands[++I]; - assert(Op->IsMem); - assert(Op->IsExplicit); + assert(Op->isMemory()); + assert(Op->isExplicit()); IT.getValueFor(*Op) = llvm::MCOperand::createReg(0); // Segment // Case2: segment:index addressing. We assume that ES is 0. }