llvm-project/llvm/lib/Target/Hexagon/HexagonGlobalRegion.cpp
Fateme Hosseini 28042a8702
[Hexagon] Add global region scaffolding (#179541)
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>
2026-02-06 12:07:45 -06:00

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);
}