forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			399 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			399 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C++
		
	
	
	
//===-- 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.isFPImm())
 | 
						|
    OS << Op.getFPImm();
 | 
						|
  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
 |