Introduce HexagonGlobalRegion, a data structure that the upcoming Hexagon scheduler work will build on. It relies on the new HexagonLiveVariables analysis to keep per-block liveness up to date when the scheduler moves instructions across basic blocks. Author: Sergei Larin <slarin@qti.qualcomm.com> Patch By: Fateme Hosseini <fhossein@qti.qualcomm.com>
253 lines
8.6 KiB
C++
253 lines
8.6 KiB
C++
//===-- HexagonGlobalRegion.cpp - VLIW global scheduling infrastructure ---===//
|
|
//
|
|
// 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
// Basic infrastructure for global scheduling. Liveness update.
|
|
// This is the least complete portion. Basically it is empty infrastructure
|
|
// to be extended and improved.
|
|
// Currently in place only trace region formation routines and non fully
|
|
// functional skeleton for incremental liveness update.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
#define DEBUG_TYPE "global_sched"
|
|
#include "HexagonGlobalRegion.h"
|
|
#include "HexagonTargetMachine.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
|
|
using namespace llvm;
|
|
|
|
LivenessInfo::LivenessInfo(const TargetInstrInfo *TII,
|
|
const TargetRegisterInfo *TRI,
|
|
MachineBasicBlock *MBB)
|
|
: TII(TII), TRI(TRI) {
|
|
LiveIns.resize(TRI->getNumRegs());
|
|
LiveOuts.resize(TRI->getNumRegs());
|
|
|
|
LiveIns.reset();
|
|
LiveOuts.reset();
|
|
|
|
// Live-ins are simple, just copy from MBB.
|
|
for (const auto &LI : MBB->liveins())
|
|
setUsed(LiveIns, LI.PhysReg);
|
|
|
|
// Live-outs are concatenation of all the BB successors.
|
|
// As of now, we are only dealing with a-cyclic regions
|
|
// with side exits, but no side entrances.
|
|
for (const MachineBasicBlock *Succ : MBB->successors())
|
|
for (const auto &LI : Succ->liveins())
|
|
setUsed(LiveOuts, LI.PhysReg);
|
|
}
|
|
|
|
// Pessimistically check if at least one def of this register in this
|
|
// instruction (bundle or not) is done under predication.
|
|
static bool isPredicatedDef(MachineInstr *MI, unsigned Reg,
|
|
const HexagonInstrInfo *QII) {
|
|
if (!MI->isBundle())
|
|
return QII->isPredicated(*MI);
|
|
MachineBasicBlock *Parent = MI->getParent();
|
|
if (!Parent)
|
|
return false;
|
|
MachineBasicBlock::instr_iterator MII = MI->getIterator();
|
|
MachineBasicBlock::instr_iterator MIIE = Parent->instr_end();
|
|
for (++MII; MII != MIIE && MII->isInsideBundle(); ++MII) {
|
|
if (!QII->isPredicated(*MII))
|
|
continue;
|
|
for (unsigned i = 0, e = MII->getNumOperands(); i != e; ++i) {
|
|
const MachineOperand &MO = MII->getOperand(i);
|
|
if (!MO.isReg())
|
|
continue;
|
|
if (MO.isDef() && !MO.isDead() && MO.getReg() == Reg) {
|
|
LLVM_DEBUG(dbgs() << "\t\tCond def: "; MII->dump());
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/// Determine def/use set for MI.
|
|
/// Beware, if def is conditional, like here:
|
|
/// BUNDLE %PC<imp-def>, %R0<imp-def>, %P0<imp-use,kill>, %R16<imp-use>
|
|
/// * %R0<def> = LDriuh_cdnNotPt %P0<kill,internal>, %R16, 0;
|
|
/// * %P0<def> = C2_cmpeqi %R16, 0;
|
|
/// It is not a statefull definition of R0.
|
|
///
|
|
void LivenessInfo::parseOperands(MachineInstr *MI, BitVector &Gen,
|
|
BitVector &Kill, BitVector &Use) {
|
|
const auto *QII = static_cast<const HexagonInstrInfo *>(TII);
|
|
|
|
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
|
|
const MachineOperand &MO = MI->getOperand(i);
|
|
if (!MO.isReg())
|
|
continue;
|
|
// If it is a predicated instruction, it may, or may not
|
|
// be setting its destination, and we do not know it
|
|
// at the compile time.
|
|
if (MO.isDef() && !MO.isDead()) {
|
|
if (isPredicatedDef(MI, MO.getReg(), QII))
|
|
LLVM_DEBUG(dbgs() << "\tConditional define of "
|
|
<< printReg(MO.getReg(), TRI) << " in ";
|
|
MI->dump());
|
|
else
|
|
setUsed(Gen, MO.getReg());
|
|
}
|
|
if (MO.isKill())
|
|
setUsed(Kill, MO.getReg());
|
|
if (MO.isUse())
|
|
setUsed(Use, MO.getReg());
|
|
}
|
|
}
|
|
|
|
void LivenessInfo::parseOperandsWithReset(MachineInstr *MI, BitVector &Gen,
|
|
BitVector &Kill, BitVector &Use) {
|
|
Gen.reset();
|
|
Use.reset();
|
|
Kill.reset();
|
|
parseOperands(MI, Gen, Kill, Use);
|
|
}
|
|
|
|
/// setUsed - Set the register and its sub-registers as being used.
|
|
/// Taken from RegScavenger::setUsed().
|
|
void LivenessInfo::setUsed(BitVector &Set, unsigned Reg) {
|
|
Set.set(Reg);
|
|
|
|
for (MCSubRegIterator SubRegs(Reg, TRI); SubRegs.isValid(); ++SubRegs)
|
|
Set.set(*SubRegs);
|
|
}
|
|
|
|
#ifndef NDEBUG
|
|
static void dumpRI(const TargetRegisterInfo *TRI, BitVector &Set) {
|
|
for (unsigned i = 0; i < Set.size(); i++)
|
|
if (Set.test(i))
|
|
LLVM_DEBUG(dbgs() << " " << printReg(i, TRI));
|
|
}
|
|
#endif
|
|
|
|
// This function incrementally updates liveness for the given BB.
|
|
// First it gathers LiveOut set, and then iterates bottom-up
|
|
// over bundles/instructions while updating live set.
|
|
void LivenessInfo::UpdateLiveness(MachineBasicBlock *MBB) {
|
|
BitVector NewLiveIns(TRI->getNumRegs());
|
|
BitVector NewLiveOuts(TRI->getNumRegs());
|
|
BitVector LiveIns(TRI->getNumRegs());
|
|
BitVector LocalGen(TRI->getNumRegs());
|
|
BitVector LocalUse(TRI->getNumRegs());
|
|
BitVector LocalKill(TRI->getNumRegs());
|
|
|
|
NewLiveIns.reset();
|
|
NewLiveOuts.reset();
|
|
|
|
LLVM_DEBUG(dbgs() << "\n\t\tUpdateLiveness for BB(" << MBB->getNumber()
|
|
<< ")\n");
|
|
|
|
// Original Live-ins are simple, just copy from MBB.
|
|
for (const auto &LI : MBB->liveins())
|
|
setUsed(NewLiveIns, LI.PhysReg);
|
|
|
|
// Live-outs are concatenation of all the BB successors.
|
|
// As of now, we are only dealing with a-cyclic regions
|
|
// with side exits, but no side entrances.
|
|
for (const MachineBasicBlock *Succ : MBB->successors())
|
|
for (const auto &LI : Succ->liveins())
|
|
setUsed(NewLiveOuts, LI.PhysReg);
|
|
|
|
LiveIns = NewLiveIns;
|
|
// This needs to be a sequential walk, not parallel update.
|
|
LLVM_DEBUG(dbgs() << "\t\tOriginal live ins :\t"; dumpRI(TRI, NewLiveIns);
|
|
dbgs() << "\n");
|
|
LLVM_DEBUG(dbgs() << "\t\tOriginal live outs:\t"; dumpRI(TRI, NewLiveOuts);
|
|
dbgs() << "\n");
|
|
|
|
NewLiveIns = NewLiveOuts;
|
|
// Scan BB backwards to get exposed uses.
|
|
// TODO: Handle predicates if needed.
|
|
std::vector<MachineInstr *> BundleList;
|
|
for (MachineBasicBlock::iterator MI = MBB->begin(), MIE = MBB->end();
|
|
MI != MIE; ++MI)
|
|
if (!MI->isDebugInstr())
|
|
BundleList.push_back(&*MI);
|
|
|
|
while (!BundleList.empty()) {
|
|
MachineInstr *MI = BundleList.back();
|
|
BundleList.pop_back();
|
|
parseOperandsWithReset(MI, LocalGen, LocalKill, LocalUse);
|
|
LLVM_DEBUG(dbgs() << "\t\tIncr gen:\t"; dumpRI(TRI, LocalGen);
|
|
dbgs() << "\n");
|
|
LLVM_DEBUG(dbgs() << "\t\tIncr use:\t"; dumpRI(TRI, LocalUse);
|
|
dbgs() << "\n");
|
|
// NewLiveIns = (NewLiveIns - LocalGen) U LocalUse.
|
|
BitVector NotGen(LocalGen);
|
|
NotGen.flip();
|
|
NewLiveIns &= NotGen;
|
|
NewLiveIns |= LocalUse;
|
|
}
|
|
|
|
LLVM_DEBUG(dbgs() << "\t\tAnswer:\t"; dumpRI(TRI, NewLiveIns);
|
|
dbgs() << "\n");
|
|
|
|
// TODO: Consider implementing a register aliasing filter if duplicate
|
|
// live-in entries become problematic.
|
|
|
|
// Set new live in.
|
|
LLVM_DEBUG(dbgs() << "\t\tNew LiveIn :\t");
|
|
|
|
for (unsigned i = 0; i < LiveIns.size(); ++i) {
|
|
if (NewLiveIns.test(i))
|
|
LLVM_DEBUG(dbgs() << " " << printReg(i, TRI));
|
|
if (LiveIns.test(i) == NewLiveIns.test(i))
|
|
continue;
|
|
if (LiveIns.test(i))
|
|
MBB->removeLiveIn(i);
|
|
if (NewLiveIns.test(i))
|
|
MBB->addLiveIn(i);
|
|
}
|
|
LLVM_DEBUG(dbgs() << "\n");
|
|
}
|
|
|
|
void LivenessInfo::dump() {
|
|
for (unsigned i = 0; i < LiveIns.size(); i++)
|
|
if (LiveIns.test(i))
|
|
LLVM_DEBUG(dbgs() << "\t\tlive-in: " << printReg(i, TRI) << "\n");
|
|
for (unsigned i = 0; i < LiveOuts.size(); i++)
|
|
if (LiveOuts.test(i))
|
|
LLVM_DEBUG(dbgs() << "\t\tlive-out: " << printReg(i, TRI) << "\n");
|
|
}
|
|
|
|
///
|
|
/// BasicBlockRegion Methods.
|
|
///
|
|
BasicBlockRegion::BasicBlockRegion(const TargetInstrInfo *TII,
|
|
const TargetRegisterInfo *TRI,
|
|
MachineBasicBlock *MBB)
|
|
: TII(TII), TRI(TRI) {
|
|
// Should be the root BB.
|
|
Elements.push_back(MBB);
|
|
ElementIndex[MBB] = 0;
|
|
LiveInfo[MBB] = std::make_unique<LivenessInfo>(TII, TRI, MBB);
|
|
}
|
|
|
|
BasicBlockRegion::~BasicBlockRegion() {
|
|
LiveInfo.clear();
|
|
Elements.clear();
|
|
ElementIndex.clear();
|
|
}
|
|
|
|
LivenessInfo *BasicBlockRegion::getLivenessInfoForBB(MachineBasicBlock *MBB) {
|
|
auto It = LiveInfo.find(MBB);
|
|
assert(It != LiveInfo.end() && "Missing Liveness info");
|
|
assert(It->second && "Missing Liveness info");
|
|
return It->second.get();
|
|
}
|
|
|
|
void BasicBlockRegion::addBBtoRegion(MachineBasicBlock *MBB) {
|
|
// It is OK to have duplicates if we reparse for additional BBs.
|
|
if (LiveInfo.find(MBB) != LiveInfo.end())
|
|
return;
|
|
ElementIndex[MBB] = static_cast<unsigned>(Elements.size());
|
|
Elements.push_back(MBB);
|
|
LiveInfo[MBB] = std::make_unique<LivenessInfo>(TII, TRI, MBB);
|
|
}
|