//===-- RenameIndependentSubregs.cpp - Live Interval Analysis -------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
//
/// Rename independent subregisters looks for virtual registers with
/// independently used subregisters and renames them to new virtual registers.
/// Example: In the following:
///   %0:sub0<read-undef> = ...
///   %0:sub1 = ...
///   use %0:sub0
///   %0:sub0 = ...
///   use %0:sub0
///   use %0:sub1
/// sub0 and sub1 are never used together, and we have two independent sub0
/// definitions. This pass will rename to:
///   %0:sub0<read-undef> = ...
///   %1:sub1<read-undef> = ...
///   use %1:sub1
///   %2:sub1<read-undef> = ...
///   use %2:sub1
///   use %0:sub0
//
//===----------------------------------------------------------------------===//

#include "LiveRangeUtils.h"
#include "PHIEliminationUtils.h"
#include "llvm/CodeGen/LiveInterval.h"
#include "llvm/CodeGen/LiveIntervals.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/CodeGen/TargetInstrInfo.h"

using namespace llvm;

#define DEBUG_TYPE "rename-independent-subregs"

namespace {

class RenameIndependentSubregs : public MachineFunctionPass {
public:
  static char ID;
  RenameIndependentSubregs() : MachineFunctionPass(ID) {}

  StringRef getPassName() const override {
    return "Rename Disconnected Subregister Components";
  }

  void getAnalysisUsage(AnalysisUsage &AU) const override {
    AU.setPreservesCFG();
    AU.addRequired<LiveIntervals>();
    AU.addPreserved<LiveIntervals>();
    AU.addRequired<SlotIndexes>();
    AU.addPreserved<SlotIndexes>();
    MachineFunctionPass::getAnalysisUsage(AU);
  }

  bool runOnMachineFunction(MachineFunction &MF) override;

private:
  struct SubRangeInfo {
    ConnectedVNInfoEqClasses ConEQ;
    LiveInterval::SubRange *SR;
    unsigned Index;

    SubRangeInfo(LiveIntervals &LIS, LiveInterval::SubRange &SR,
                 unsigned Index)
      : ConEQ(LIS), SR(&SR), Index(Index) {}
  };

  /// Split unrelated subregister components and rename them to new vregs.
  bool renameComponents(LiveInterval &LI) const;

  /// Build a vector of SubRange infos and a union find set of
  /// equivalence classes.
  /// Returns true if more than 1 equivalence class was found.
  bool findComponents(IntEqClasses &Classes,
                      SmallVectorImpl<SubRangeInfo> &SubRangeInfos,
                      LiveInterval &LI) const;

  /// Distribute the LiveInterval segments into the new LiveIntervals
  /// belonging to their class.
  void distribute(const IntEqClasses &Classes,
                  const SmallVectorImpl<SubRangeInfo> &SubRangeInfos,
                  const SmallVectorImpl<LiveInterval*> &Intervals) const;

  /// Constructs main liverange and add missing undef+dead flags.
  void computeMainRangesFixFlags(const IntEqClasses &Classes,
      const SmallVectorImpl<SubRangeInfo> &SubRangeInfos,
      const SmallVectorImpl<LiveInterval*> &Intervals) const;

  /// Rewrite Machine Operands to use the new vreg belonging to their class.
  void rewriteOperands(const IntEqClasses &Classes,
                       const SmallVectorImpl<SubRangeInfo> &SubRangeInfos,
                       const SmallVectorImpl<LiveInterval*> &Intervals) const;


  LiveIntervals *LIS;
  MachineRegisterInfo *MRI;
  const TargetInstrInfo *TII;
};

} // end anonymous namespace

char RenameIndependentSubregs::ID;

char &llvm::RenameIndependentSubregsID = RenameIndependentSubregs::ID;

INITIALIZE_PASS_BEGIN(RenameIndependentSubregs, DEBUG_TYPE,
                      "Rename Independent Subregisters", false, false)
INITIALIZE_PASS_DEPENDENCY(SlotIndexes)
INITIALIZE_PASS_DEPENDENCY(LiveIntervals)
INITIALIZE_PASS_END(RenameIndependentSubregs, DEBUG_TYPE,
                    "Rename Independent Subregisters", false, false)

bool RenameIndependentSubregs::renameComponents(LiveInterval &LI) const {
  // Shortcut: We cannot have split components with a single definition.
  if (LI.valnos.size() < 2)
    return false;

  SmallVector<SubRangeInfo, 4> SubRangeInfos;
  IntEqClasses Classes;
  if (!findComponents(Classes, SubRangeInfos, LI))
    return false;

  // Create a new VReg for each class.
  unsigned Reg = LI.reg;
  const TargetRegisterClass *RegClass = MRI->getRegClass(Reg);
  SmallVector<LiveInterval*, 4> Intervals;
  Intervals.push_back(&LI);
  LLVM_DEBUG(dbgs() << printReg(Reg) << ": Found " << Classes.getNumClasses()
                    << " equivalence classes.\n");
  LLVM_DEBUG(dbgs() << printReg(Reg) << ": Splitting into newly created:");
  for (unsigned I = 1, NumClasses = Classes.getNumClasses(); I < NumClasses;
       ++I) {
    unsigned NewVReg = MRI->createVirtualRegister(RegClass);
    LiveInterval &NewLI = LIS->createEmptyInterval(NewVReg);
    Intervals.push_back(&NewLI);
    LLVM_DEBUG(dbgs() << ' ' << printReg(NewVReg));
  }
  LLVM_DEBUG(dbgs() << '\n');

  rewriteOperands(Classes, SubRangeInfos, Intervals);
  distribute(Classes, SubRangeInfos, Intervals);
  computeMainRangesFixFlags(Classes, SubRangeInfos, Intervals);
  return true;
}

bool RenameIndependentSubregs::findComponents(IntEqClasses &Classes,
    SmallVectorImpl<RenameIndependentSubregs::SubRangeInfo> &SubRangeInfos,
    LiveInterval &LI) const {
  // First step: Create connected components for the VNInfos inside the
  // subranges and count the global number of such components.
  unsigned NumComponents = 0;
  for (LiveInterval::SubRange &SR : LI.subranges()) {
    SubRangeInfos.push_back(SubRangeInfo(*LIS, SR, NumComponents));
    ConnectedVNInfoEqClasses &ConEQ = SubRangeInfos.back().ConEQ;

    unsigned NumSubComponents = ConEQ.Classify(SR);
    NumComponents += NumSubComponents;
  }
  // Shortcut: With only 1 subrange, the normal separate component tests are
  // enough and we do not need to perform the union-find on the subregister
  // segments.
  if (SubRangeInfos.size() < 2)
    return false;

  // Next step: Build union-find structure over all subranges and merge classes
  // across subranges when they are affected by the same MachineOperand.
  const TargetRegisterInfo &TRI = *MRI->getTargetRegisterInfo();
  Classes.grow(NumComponents);
  unsigned Reg = LI.reg;
  for (const MachineOperand &MO : MRI->reg_nodbg_operands(Reg)) {
    if (!MO.isDef() && !MO.readsReg())
      continue;
    unsigned SubRegIdx = MO.getSubReg();
    LaneBitmask LaneMask = TRI.getSubRegIndexLaneMask(SubRegIdx);
    unsigned MergedID = ~0u;
    for (RenameIndependentSubregs::SubRangeInfo &SRInfo : SubRangeInfos) {
      const LiveInterval::SubRange &SR = *SRInfo.SR;
      if ((SR.LaneMask & LaneMask).none())
        continue;
      SlotIndex Pos = LIS->getInstructionIndex(*MO.getParent());
      Pos = MO.isDef() ? Pos.getRegSlot(MO.isEarlyClobber())
                       : Pos.getBaseIndex();
      const VNInfo *VNI = SR.getVNInfoAt(Pos);
      if (VNI == nullptr)
        continue;

      // Map to local representant ID.
      unsigned LocalID = SRInfo.ConEQ.getEqClass(VNI);
      // Global ID
      unsigned ID = LocalID + SRInfo.Index;
      // Merge other sets
      MergedID = MergedID == ~0u ? ID : Classes.join(MergedID, ID);
    }
  }

  // Early exit if we ended up with a single equivalence class.
  Classes.compress();
  unsigned NumClasses = Classes.getNumClasses();
  return NumClasses > 1;
}

void RenameIndependentSubregs::rewriteOperands(const IntEqClasses &Classes,
    const SmallVectorImpl<SubRangeInfo> &SubRangeInfos,
    const SmallVectorImpl<LiveInterval*> &Intervals) const {
  const TargetRegisterInfo &TRI = *MRI->getTargetRegisterInfo();
  unsigned Reg = Intervals[0]->reg;
  for (MachineRegisterInfo::reg_nodbg_iterator I = MRI->reg_nodbg_begin(Reg),
       E = MRI->reg_nodbg_end(); I != E; ) {
    MachineOperand &MO = *I++;
    if (!MO.isDef() && !MO.readsReg())
      continue;

    auto *MI = MO.getParent();
    SlotIndex Pos = LIS->getInstructionIndex(*MI);
    Pos = MO.isDef() ? Pos.getRegSlot(MO.isEarlyClobber())
                     : Pos.getBaseIndex();
    unsigned SubRegIdx = MO.getSubReg();
    LaneBitmask LaneMask = TRI.getSubRegIndexLaneMask(SubRegIdx);

    unsigned ID = ~0u;
    for (const SubRangeInfo &SRInfo : SubRangeInfos) {
      const LiveInterval::SubRange &SR = *SRInfo.SR;
      if ((SR.LaneMask & LaneMask).none())
        continue;
      const VNInfo *VNI = SR.getVNInfoAt(Pos);
      if (VNI == nullptr)
        continue;

      // Map to local representant ID.
      unsigned LocalID = SRInfo.ConEQ.getEqClass(VNI);
      // Global ID
      ID = Classes[LocalID + SRInfo.Index];
      break;
    }

    unsigned VReg = Intervals[ID]->reg;
    MO.setReg(VReg);

    if (MO.isTied() && Reg != VReg) {
      /// Undef use operands are not tracked in the equivalence class,
      /// but need to be updated if they are tied; take care to only
      /// update the tied operand.
      unsigned OperandNo = MI->getOperandNo(&MO);
      unsigned TiedIdx = MI->findTiedOperandIdx(OperandNo);
      MI->getOperand(TiedIdx).setReg(VReg);

      // above substitution breaks the iterator, so restart.
      I = MRI->reg_nodbg_begin(Reg);
    }
  }
  // TODO: We could attempt to recompute new register classes while visiting
  // the operands: Some of the split register may be fine with less constraint
  // classes than the original vreg.
}

void RenameIndependentSubregs::distribute(const IntEqClasses &Classes,
    const SmallVectorImpl<SubRangeInfo> &SubRangeInfos,
    const SmallVectorImpl<LiveInterval*> &Intervals) const {
  unsigned NumClasses = Classes.getNumClasses();
  SmallVector<unsigned, 8> VNIMapping;
  SmallVector<LiveInterval::SubRange*, 8> SubRanges;
  BumpPtrAllocator &Allocator = LIS->getVNInfoAllocator();
  for (const SubRangeInfo &SRInfo : SubRangeInfos) {
    LiveInterval::SubRange &SR = *SRInfo.SR;
    unsigned NumValNos = SR.valnos.size();
    VNIMapping.clear();
    VNIMapping.reserve(NumValNos);
    SubRanges.clear();
    SubRanges.resize(NumClasses-1, nullptr);
    for (unsigned I = 0; I < NumValNos; ++I) {
      const VNInfo &VNI = *SR.valnos[I];
      unsigned LocalID = SRInfo.ConEQ.getEqClass(&VNI);
      unsigned ID = Classes[LocalID + SRInfo.Index];
      VNIMapping.push_back(ID);
      if (ID > 0 && SubRanges[ID-1] == nullptr)
        SubRanges[ID-1] = Intervals[ID]->createSubRange(Allocator, SR.LaneMask);
    }
    DistributeRange(SR, SubRanges.data(), VNIMapping);
  }
}

static bool subRangeLiveAt(const LiveInterval &LI, SlotIndex Pos) {
  for (const LiveInterval::SubRange &SR : LI.subranges()) {
    if (SR.liveAt(Pos))
      return true;
  }
  return false;
}

void RenameIndependentSubregs::computeMainRangesFixFlags(
    const IntEqClasses &Classes,
    const SmallVectorImpl<SubRangeInfo> &SubRangeInfos,
    const SmallVectorImpl<LiveInterval*> &Intervals) const {
  BumpPtrAllocator &Allocator = LIS->getVNInfoAllocator();
  const SlotIndexes &Indexes = *LIS->getSlotIndexes();
  for (size_t I = 0, E = Intervals.size(); I < E; ++I) {
    LiveInterval &LI = *Intervals[I];
    unsigned Reg = LI.reg;

    LI.removeEmptySubRanges();

    // There must be a def (or live-in) before every use. Splitting vregs may
    // violate this principle as the splitted vreg may not have a definition on
    // every path. Fix this by creating IMPLICIT_DEF instruction as necessary.
    for (const LiveInterval::SubRange &SR : LI.subranges()) {
      // Search for "PHI" value numbers in the subranges. We must find a live
      // value in each predecessor block, add an IMPLICIT_DEF where it is
      // missing.
      for (unsigned I = 0; I < SR.valnos.size(); ++I) {
        const VNInfo &VNI = *SR.valnos[I];
        if (VNI.isUnused() || !VNI.isPHIDef())
          continue;

        SlotIndex Def = VNI.def;
        MachineBasicBlock &MBB = *Indexes.getMBBFromIndex(Def);
        for (MachineBasicBlock *PredMBB : MBB.predecessors()) {
          SlotIndex PredEnd = Indexes.getMBBEndIdx(PredMBB);
          if (subRangeLiveAt(LI, PredEnd.getPrevSlot()))
            continue;

          MachineBasicBlock::iterator InsertPos =
            llvm::findPHICopyInsertPoint(PredMBB, &MBB, Reg);
          const MCInstrDesc &MCDesc = TII->get(TargetOpcode::IMPLICIT_DEF);
          MachineInstrBuilder ImpDef = BuildMI(*PredMBB, InsertPos,
                                               DebugLoc(), MCDesc, Reg);
          SlotIndex DefIdx = LIS->InsertMachineInstrInMaps(*ImpDef);
          SlotIndex RegDefIdx = DefIdx.getRegSlot();
          for (LiveInterval::SubRange &SR : LI.subranges()) {
            VNInfo *SRVNI = SR.getNextValue(RegDefIdx, Allocator);
            SR.addSegment(LiveRange::Segment(RegDefIdx, PredEnd, SRVNI));
          }
        }
      }
    }

    for (MachineOperand &MO : MRI->reg_nodbg_operands(Reg)) {
      if (!MO.isDef())
        continue;
      unsigned SubRegIdx = MO.getSubReg();
      if (SubRegIdx == 0)
        continue;
      // After assigning the new vreg we may not have any other sublanes living
      // in and out of the instruction anymore. We need to add new dead and
      // undef flags in these cases.
      if (!MO.isUndef()) {
        SlotIndex Pos = LIS->getInstructionIndex(*MO.getParent());
        if (!subRangeLiveAt(LI, Pos))
          MO.setIsUndef();
      }
      if (!MO.isDead()) {
        SlotIndex Pos = LIS->getInstructionIndex(*MO.getParent()).getDeadSlot();
        if (!subRangeLiveAt(LI, Pos))
          MO.setIsDead();
      }
    }

    if (I == 0)
      LI.clear();
    LIS->constructMainRangeFromSubranges(LI);
    // A def of a subregister may be a use of other register lanes. Replacing
    // such a def with a def of a different register will eliminate the use,
    // and may cause the recorded live range to be larger than the actual
    // liveness in the program IR.
    LIS->shrinkToUses(&LI);
  }
}

bool RenameIndependentSubregs::runOnMachineFunction(MachineFunction &MF) {
  // Skip renaming if liveness of subregister is not tracked.
  MRI = &MF.getRegInfo();
  if (!MRI->subRegLivenessEnabled())
    return false;

  LLVM_DEBUG(dbgs() << "Renaming independent subregister live ranges in "
                    << MF.getName() << '\n');

  LIS = &getAnalysis<LiveIntervals>();
  TII = MF.getSubtarget().getInstrInfo();

  // Iterate over all vregs. Note that we query getNumVirtRegs() the newly
  // created vregs end up with higher numbers but do not need to be visited as
  // there can't be any further splitting.
  bool Changed = false;
  for (size_t I = 0, E = MRI->getNumVirtRegs(); I < E; ++I) {
    unsigned Reg = TargetRegisterInfo::index2VirtReg(I);
    if (!LIS->hasInterval(Reg))
      continue;
    LiveInterval &LI = LIS->getInterval(Reg);
    if (!LI.hasSubRanges())
      continue;

    Changed |= renameComponents(LI);
  }

  return Changed;
}
