blob: 049cc68b4fb976a55f3fe785c2eb6241e552adf5 [file] [log] [blame]
//===-- MCInstrDescView.cpp -------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "MCInstrDescView.h"
#include <iterator>
#include <map>
#include <tuple>
#include "llvm/ADT/STLExtras.h"
namespace llvm {
namespace exegesis {
unsigned Variable::getIndex() const { return *Index; }
unsigned Variable::getPrimaryOperandIndex() const {
assert(!TiedOperands.empty());
return TiedOperands[0];
}
bool Variable::hasTiedOperands() const {
assert(TiedOperands.size() <= 2 &&
"No more than two operands can be tied together");
// By definition only Use and Def operands can be tied together.
// TiedOperands[0] is the Def operand (LLVM stores defs first).
// TiedOperands[1] is the Use operand.
return TiedOperands.size() > 1;
}
unsigned 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.hasValue(); }
bool Operand::isVariable() const { return VariableIndex.hasValue(); }
bool Operand::isMemory() const {
return isExplicit() &&
getExplicitOperandInfo().OperandType == MCOI::OPERAND_MEMORY;
}
bool Operand::isImmediate() const {
return isExplicit() &&
getExplicitOperandInfo().OperandType == MCOI::OPERAND_IMMEDIATE;
}
unsigned Operand::getTiedToIndex() const { return *TiedToIndex; }
unsigned Operand::getVariableIndex() const { return *VariableIndex; }
unsigned Operand::getImplicitReg() const {
assert(ImplicitReg);
return *ImplicitReg;
}
const RegisterAliasingTracker &Operand::getRegisterAliasing() const {
assert(Tracker);
return *Tracker;
}
const MCOperandInfo &Operand::getExplicitOperandInfo() const {
assert(Info);
return *Info;
}
const BitVector *BitVectorCache::getUnique(BitVector &&BV) const {
for (const auto &Entry : Cache)
if (*Entry == BV)
return Entry.get();
Cache.push_back(std::make_unique<BitVector>());
auto &Entry = Cache.back();
Entry->swap(BV);
return Entry.get();
}
Instruction::Instruction(const MCInstrDesc *Description, StringRef Name,
SmallVector<Operand, 8> Operands,
SmallVector<Variable, 4> Variables,
const BitVector *ImplDefRegs,
const BitVector *ImplUseRegs,
const BitVector *AllDefRegs,
const BitVector *AllUseRegs)
: Description(*Description), Name(Name), Operands(std::move(Operands)),
Variables(std::move(Variables)), ImplDefRegs(*ImplDefRegs),
ImplUseRegs(*ImplUseRegs), AllDefRegs(*AllDefRegs),
AllUseRegs(*AllUseRegs) {}
std::unique_ptr<Instruction>
Instruction::create(const MCInstrInfo &InstrInfo,
const RegisterAliasingTrackerCache &RATC,
const BitVectorCache &BVC, unsigned Opcode) {
const llvm::MCInstrDesc *const Description = &InstrInfo.get(Opcode);
unsigned OpIndex = 0;
SmallVector<Operand, 8> Operands;
SmallVector<Variable, 4> Variables;
for (; OpIndex < Description->getNumOperands(); ++OpIndex) {
const auto &OpInfo = Description->opInfo_begin()[OpIndex];
Operand Operand;
Operand.Index = OpIndex;
Operand.IsDef = (OpIndex < Description->getNumDefs());
// TODO(gchatelet): Handle isLookupPtrRegClass.
if (OpInfo.RegClass >= 0)
Operand.Tracker = &RATC.getRegisterClass(OpInfo.RegClass);
int TiedToIndex = Description->getOperandConstraint(OpIndex, MCOI::TIED_TO);
assert((TiedToIndex == -1 ||
(0 <= TiedToIndex &&
TiedToIndex < std::numeric_limits<uint8_t>::max())) &&
"Unknown Operand Constraint");
if (TiedToIndex >= 0)
Operand.TiedToIndex = TiedToIndex;
Operand.Info = &OpInfo;
Operands.push_back(Operand);
}
for (const MCPhysReg *MCPhysReg = Description->getImplicitDefs();
MCPhysReg && *MCPhysReg; ++MCPhysReg, ++OpIndex) {
Operand Operand;
Operand.Index = OpIndex;
Operand.IsDef = true;
Operand.Tracker = &RATC.getRegister(*MCPhysReg);
Operand.ImplicitReg = MCPhysReg;
Operands.push_back(Operand);
}
for (const MCPhysReg *MCPhysReg = Description->getImplicitUses();
MCPhysReg && *MCPhysReg; ++MCPhysReg, ++OpIndex) {
Operand Operand;
Operand.Index = OpIndex;
Operand.IsDef = false;
Operand.Tracker = &RATC.getRegister(*MCPhysReg);
Operand.ImplicitReg = MCPhysReg;
Operands.push_back(Operand);
}
Variables.reserve(Operands.size()); // Variables.size() <= Operands.size()
// Assigning Variables to non tied explicit operands.
for (auto &Op : Operands)
if (Op.isExplicit() && !Op.isTied()) {
const size_t VariableIndex = Variables.size();
assert(VariableIndex < std::numeric_limits<uint8_t>::max());
Op.VariableIndex = VariableIndex;
Variables.emplace_back();
Variables.back().Index = VariableIndex;
}
// Assigning Variables to tied operands.
for (auto &Op : Operands)
if (Op.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.
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();
if (Op.isDef())
AllDefRegs |= AliasingBits;
if (Op.isUse())
AllUseRegs |= AliasingBits;
if (Op.isDef() && Op.isImplicit())
ImplDefRegs |= AliasingBits;
if (Op.isUse() && Op.isImplicit())
ImplUseRegs |= AliasingBits;
}
}
// Can't use make_unique because constructor is private.
return std::unique_ptr<Instruction>(new Instruction(
Description, InstrInfo.getName(Opcode), std::move(Operands),
std::move(Variables), BVC.getUnique(std::move(ImplDefRegs)),
BVC.getUnique(std::move(ImplUseRegs)),
BVC.getUnique(std::move(AllDefRegs)),
BVC.getUnique(std::move(AllUseRegs))));
}
const Operand &Instruction::getPrimaryOperand(const Variable &Var) const {
const auto PrimaryOperandIndex = Var.getPrimaryOperandIndex();
assert(PrimaryOperandIndex < Operands.size());
return Operands[PrimaryOperandIndex];
}
bool Instruction::hasMemoryOperands() const {
return any_of(Operands, [](const Operand &Op) {
return Op.isReg() && Op.isExplicit() && Op.isMemory();
});
}
bool Instruction::hasAliasingImplicitRegisters() const {
return ImplDefRegs.anyCommon(ImplUseRegs);
}
// Returns true if there are registers that are both in `A` and `B` but not in
// `Forbidden`.
static bool anyCommonExcludingForbidden(const BitVector &A, const BitVector &B,
const BitVector &Forbidden) {
assert(A.size() == B.size() && B.size() == Forbidden.size());
const auto Size = A.size();
for (int AIndex = A.find_first(); AIndex != -1;) {
const int BIndex = B.find_first_in(AIndex, Size);
if (BIndex == -1)
return false;
if (AIndex == BIndex && !Forbidden.test(AIndex))
return true;
AIndex = A.find_first_in(BIndex + 1, Size);
}
return false;
}
bool Instruction::hasAliasingRegistersThrough(
const Instruction &OtherInstr, const BitVector &ForbiddenRegisters) const {
return anyCommonExcludingForbidden(AllDefRegs, OtherInstr.AllUseRegs,
ForbiddenRegisters) &&
anyCommonExcludingForbidden(OtherInstr.AllDefRegs, AllUseRegs,
ForbiddenRegisters);
}
bool Instruction::hasTiedRegisters() const {
return any_of(Variables,
[](const Variable &Var) { return Var.hasTiedOperands(); });
}
bool Instruction::hasAliasingRegisters(
const BitVector &ForbiddenRegisters) const {
return anyCommonExcludingForbidden(AllDefRegs, AllUseRegs,
ForbiddenRegisters);
}
bool Instruction::hasOneUseOrOneDef() const {
return AllDefRegs.count() || AllUseRegs.count();
}
void Instruction::dump(const MCRegisterInfo &RegInfo,
const RegisterAliasingTrackerCache &RATC,
raw_ostream &Stream) const {
Stream << "- " << Name << "\n";
for (const auto &Op : Operands) {
Stream << "- Op" << Op.getIndex();
if (Op.isExplicit())
Stream << " Explicit";
if (Op.isImplicit())
Stream << " Implicit";
if (Op.isUse())
Stream << " Use";
if (Op.isDef())
Stream << " Def";
if (Op.isImmediate())
Stream << " Immediate";
if (Op.isMemory())
Stream << " Memory";
if (Op.isReg()) {
if (Op.isImplicitReg())
Stream << " Reg(" << RegInfo.getName(Op.getImplicitReg()) << ")";
else
Stream << " RegClass("
<< RegInfo.getRegClassName(
&RegInfo.getRegClass(Op.Info->RegClass))
<< ")";
}
if (Op.isTied())
Stream << " TiedToOp" << Op.getTiedToIndex();
Stream << "\n";
}
for (const auto &Var : Variables) {
Stream << "- Var" << Var.getIndex();
Stream << " [";
bool IsFirst = true;
for (auto OperandIndex : Var.TiedOperands) {
if (!IsFirst)
Stream << ",";
Stream << "Op" << OperandIndex;
IsFirst = false;
}
Stream << "]";
Stream << "\n";
}
if (hasMemoryOperands())
Stream << "- hasMemoryOperands\n";
if (hasAliasingImplicitRegisters())
Stream << "- hasAliasingImplicitRegisters (execution is always serial)\n";
if (hasTiedRegisters())
Stream << "- hasTiedRegisters (execution is always serial)\n";
if (hasAliasingRegisters(RATC.emptyRegisters()))
Stream << "- hasAliasingRegisters\n";
}
InstructionsCache::InstructionsCache(const MCInstrInfo &InstrInfo,
const RegisterAliasingTrackerCache &RATC)
: InstrInfo(InstrInfo), RATC(RATC), BVC() {}
const Instruction &InstructionsCache::getInstr(unsigned Opcode) const {
auto &Found = Instructions[Opcode];
if (!Found)
Found = Instruction::create(InstrInfo, RATC, BVC, Opcode);
return *Found;
}
bool RegisterOperandAssignment::
operator==(const RegisterOperandAssignment &Other) const {
return std::tie(Op, Reg) == std::tie(Other.Op, Other.Reg);
}
bool AliasingRegisterOperands::
operator==(const AliasingRegisterOperands &Other) const {
return std::tie(Defs, Uses) == std::tie(Other.Defs, Other.Uses);
}
static void
addOperandIfAlias(const MCPhysReg Reg, bool SelectDef,
ArrayRef<Operand> Operands,
SmallVectorImpl<RegisterOperandAssignment> &OperandValues) {
for (const auto &Op : Operands) {
if (Op.isReg() && Op.isDef() == SelectDef) {
const int SourceReg = Op.getRegisterAliasing().getOrigin(Reg);
if (SourceReg >= 0)
OperandValues.emplace_back(&Op, SourceReg);
}
}
}
bool AliasingRegisterOperands::hasImplicitAliasing() const {
const auto HasImplicit = [](const RegisterOperandAssignment &ROV) {
return ROV.Op->isImplicit();
};
return any_of(Defs, HasImplicit) && any_of(Uses, HasImplicit);
}
bool AliasingConfigurations::empty() const { return Configurations.empty(); }
bool AliasingConfigurations::hasImplicitAliasing() const {
return any_of(Configurations, [](const AliasingRegisterOperands &ARO) {
return ARO.hasImplicitAliasing();
});
}
AliasingConfigurations::AliasingConfigurations(
const Instruction &DefInstruction, const Instruction &UseInstruction) {
if (UseInstruction.AllUseRegs.anyCommon(DefInstruction.AllDefRegs)) {
auto CommonRegisters = UseInstruction.AllUseRegs;
CommonRegisters &= DefInstruction.AllDefRegs;
for (const MCPhysReg Reg : CommonRegisters.set_bits()) {
AliasingRegisterOperands ARO;
addOperandIfAlias(Reg, true, DefInstruction.Operands, ARO.Defs);
addOperandIfAlias(Reg, false, UseInstruction.Operands, ARO.Uses);
if (!ARO.Defs.empty() && !ARO.Uses.empty() &&
!is_contained(Configurations, ARO))
Configurations.push_back(std::move(ARO));
}
}
}
void DumpMCOperand(const MCRegisterInfo &MCRegisterInfo, const MCOperand &Op,
raw_ostream &OS) {
if (!Op.isValid())
OS << "Invalid";
else if (Op.isReg())
OS << MCRegisterInfo.getName(Op.getReg());
else if (Op.isImm())
OS << Op.getImm();
else if (Op.isDFPImm())
OS << bit_cast<double>(Op.getDFPImm());
else if (Op.isSFPImm())
OS << bit_cast<float>(Op.getSFPImm());
else if (Op.isExpr())
OS << "Expr";
else if (Op.isInst())
OS << "SubInst";
}
void DumpMCInst(const MCRegisterInfo &MCRegisterInfo,
const MCInstrInfo &MCInstrInfo, const MCInst &MCInst,
raw_ostream &OS) {
OS << MCInstrInfo.getName(MCInst.getOpcode());
for (unsigned I = 0, E = MCInst.getNumOperands(); I < E; ++I) {
if (I > 0)
OS << ',';
OS << ' ';
DumpMCOperand(MCRegisterInfo, MCInst.getOperand(I), OS);
}
}
} // namespace exegesis
} // namespace llvm