[llvm-exegesis] Teach llvm-exegesis to handle instructions with multiple tied variables.
Reviewers: gchatelet Subscribers: tschuett, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D58285 llvm-svn: 354862
This commit is contained in:
parent
4f7bc0eee7
commit
0ddf81c43d
|
@ -0,0 +1,6 @@
|
||||||
|
# RUN: llvm-exegesis -mode=uops -opcode-name=XCHG64rr | FileCheck %s
|
||||||
|
|
||||||
|
CHECK: mode: uops
|
||||||
|
CHECK-NEXT: key:
|
||||||
|
CHECK-NEXT: instructions:
|
||||||
|
CHECK-NEXT: XCHG64rr
|
|
@ -123,6 +123,50 @@ void UopsSnippetGenerator::instantiateMemoryOperands(
|
||||||
"not enough scratch space");
|
"not enough scratch space");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::vector<InstructionTemplate> generateSnippetUsingStaticRenaming(
|
||||||
|
const LLVMState &State, const InstructionTemplate &IT,
|
||||||
|
const ArrayRef<const Variable *> TiedVariables,
|
||||||
|
const BitVector *ScratchSpaceAliasedRegs) {
|
||||||
|
std::vector<InstructionTemplate> Instructions;
|
||||||
|
// Assign registers to variables in a round-robin manner. This is simple but
|
||||||
|
// ensures that the most register-constrained variable does not get starved.
|
||||||
|
std::vector<BitVector> PossibleRegsForVar;
|
||||||
|
for (const Variable *Var : TiedVariables) {
|
||||||
|
assert(Var);
|
||||||
|
const Operand &Op = IT.Instr.getPrimaryOperand(*Var);
|
||||||
|
assert(Op.isReg());
|
||||||
|
BitVector PossibleRegs = State.getRATC().emptyRegisters();
|
||||||
|
if (ScratchSpaceAliasedRegs) {
|
||||||
|
PossibleRegs |= *ScratchSpaceAliasedRegs;
|
||||||
|
}
|
||||||
|
PossibleRegs.flip();
|
||||||
|
PossibleRegs &= Op.getRegisterAliasing().sourceBits();
|
||||||
|
PossibleRegsForVar.push_back(std::move(PossibleRegs));
|
||||||
|
}
|
||||||
|
SmallVector<int, 2> Iterators(TiedVariables.size(), 0);
|
||||||
|
while (true) {
|
||||||
|
InstructionTemplate TmpIT = IT;
|
||||||
|
// Find a possible register for each variable in turn, marking the
|
||||||
|
// register as taken.
|
||||||
|
for (size_t VarId = 0; VarId < TiedVariables.size(); ++VarId) {
|
||||||
|
const int NextPossibleReg =
|
||||||
|
PossibleRegsForVar[VarId].find_next(Iterators[VarId]);
|
||||||
|
if (NextPossibleReg <= 0) {
|
||||||
|
return Instructions;
|
||||||
|
}
|
||||||
|
TmpIT.getValueFor(*TiedVariables[VarId]) =
|
||||||
|
llvm::MCOperand::createReg(NextPossibleReg);
|
||||||
|
// Bump iterator.
|
||||||
|
Iterators[VarId] = NextPossibleReg;
|
||||||
|
// Prevent other variables from using the register.
|
||||||
|
for (BitVector &OtherPossibleRegs : PossibleRegsForVar) {
|
||||||
|
OtherPossibleRegs.reset(NextPossibleReg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Instructions.push_back(std::move(TmpIT));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
llvm::Expected<std::vector<CodeTemplate>>
|
llvm::Expected<std::vector<CodeTemplate>>
|
||||||
UopsSnippetGenerator::generateCodeTemplates(const Instruction &Instr) const {
|
UopsSnippetGenerator::generateCodeTemplates(const Instruction &Instr) const {
|
||||||
CodeTemplate CT;
|
CodeTemplate CT;
|
||||||
|
@ -162,23 +206,9 @@ UopsSnippetGenerator::generateCodeTemplates(const Instruction &Instr) const {
|
||||||
}
|
}
|
||||||
const auto TiedVariables = getVariablesWithTiedOperands(Instr);
|
const auto TiedVariables = getVariablesWithTiedOperands(Instr);
|
||||||
if (!TiedVariables.empty()) {
|
if (!TiedVariables.empty()) {
|
||||||
if (TiedVariables.size() > 1)
|
CT.Info = "instruction has tied variables, using static renaming.";
|
||||||
return llvm::make_error<llvm::StringError>(
|
CT.Instructions = generateSnippetUsingStaticRenaming(
|
||||||
"Infeasible : don't know how to handle several tied variables",
|
State, IT, TiedVariables, ScratchSpaceAliasedRegs);
|
||||||
llvm::inconvertibleErrorCode());
|
|
||||||
const Variable *Var = TiedVariables.front();
|
|
||||||
assert(Var);
|
|
||||||
const Operand &Op = Instr.getPrimaryOperand(*Var);
|
|
||||||
assert(Op.isReg());
|
|
||||||
CT.Info = "instruction has tied variables using static renaming.";
|
|
||||||
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;
|
|
||||||
TmpIT.getValueFor(*Var) = llvm::MCOperand::createReg(Reg);
|
|
||||||
CT.Instructions.push_back(std::move(TmpIT));
|
|
||||||
}
|
|
||||||
instantiateMemoryOperands(CT.ScratchSpacePointerInReg, CT.Instructions);
|
instantiateMemoryOperands(CT.ScratchSpacePointerInReg, CT.Instructions);
|
||||||
return getSingleton(std::move(CT));
|
return getSingleton(std::move(CT));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue