1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-10-26 22:42:46 +02:00
llvm-mirror/lib/Target/AMDGPU/SIFixSGPRLiveRanges.cpp
Matt Arsenault 3ad7a3466f AMDGPU/SI: Only look at live out SGPR defs
When trying to fix SGPR live ranges, skip defs that are
killed in the same block as the def. I don't think
we need to worry about these cases as long as the
live ranges of the SGPRs in dominating blocks are
correct.

This reduces the number of elements the second
loop over the function needs to look at, and makes
it generally easier to understand. The second loop
also only considers if the live range is live
in to a block, which logically means it
must have been live out from another.

llvm-svn: 245150
2015-08-15 02:58:49 +00:00

219 lines
7.2 KiB
C++

//===-- SIFixSGPRLiveRanges.cpp - Fix SGPR live ranges ----------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
/// \file SALU instructions ignore the execution mask, so we need to modify the
/// live ranges of the registers they define in some cases.
///
/// The main case we need to handle is when a def is used in one side of a
/// branch and not another. For example:
///
/// %def
/// IF
/// ...
/// ...
/// ELSE
/// %use
/// ...
/// ENDIF
///
/// Here we need the register allocator to avoid assigning any of the defs
/// inside of the IF to the same register as %def. In traditional live
/// interval analysis %def is not live inside the IF branch, however, since
/// SALU instructions inside of IF will be executed even if the branch is not
/// taken, there is the chance that one of the instructions will overwrite the
/// value of %def, so the use in ELSE will see the wrong value.
///
/// The strategy we use for solving this is to add an extra use after the ENDIF:
///
/// %def
/// IF
/// ...
/// ...
/// ELSE
/// %use
/// ...
/// ENDIF
/// %use
///
/// Adding this use will make the def live throughout the IF branch, which is
/// what we want.
#include "AMDGPU.h"
#include "SIInstrInfo.h"
#include "SIRegisterInfo.h"
#include "llvm/CodeGen/LiveIntervalAnalysis.h"
#include "llvm/CodeGen/LiveVariables.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachinePostDominators.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetMachine.h"
using namespace llvm;
#define DEBUG_TYPE "si-fix-sgpr-live-ranges"
namespace {
class SIFixSGPRLiveRanges : public MachineFunctionPass {
public:
static char ID;
public:
SIFixSGPRLiveRanges() : MachineFunctionPass(ID) {
initializeSIFixSGPRLiveRangesPass(*PassRegistry::getPassRegistry());
}
bool runOnMachineFunction(MachineFunction &MF) override;
const char *getPassName() const override {
return "SI Fix SGPR live ranges";
}
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.addRequired<LiveIntervals>();
AU.addRequired<MachinePostDominatorTree>();
AU.setPreservesCFG();
//AU.addPreserved<SlotIndexes>(); // XXX - This might be OK
AU.addPreserved<LiveIntervals>();
MachineFunctionPass::getAnalysisUsage(AU);
}
};
} // End anonymous namespace.
INITIALIZE_PASS_BEGIN(SIFixSGPRLiveRanges, DEBUG_TYPE,
"SI Fix SGPR Live Ranges", false, false)
INITIALIZE_PASS_DEPENDENCY(LiveIntervals)
INITIALIZE_PASS_DEPENDENCY(LiveVariables)
INITIALIZE_PASS_DEPENDENCY(MachinePostDominatorTree)
INITIALIZE_PASS_END(SIFixSGPRLiveRanges, DEBUG_TYPE,
"SI Fix SGPR Live Ranges", false, false)
char SIFixSGPRLiveRanges::ID = 0;
char &llvm::SIFixSGPRLiveRangesID = SIFixSGPRLiveRanges::ID;
FunctionPass *llvm::createSIFixSGPRLiveRangesPass() {
return new SIFixSGPRLiveRanges();
}
bool SIFixSGPRLiveRanges::runOnMachineFunction(MachineFunction &MF) {
MachineRegisterInfo &MRI = MF.getRegInfo();
const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
const SIRegisterInfo *TRI = static_cast<const SIRegisterInfo *>(
MF.getSubtarget().getRegisterInfo());
MachinePostDominatorTree *PDT = &getAnalysis<MachinePostDominatorTree>();
std::vector<std::pair<unsigned, LiveRange *>> SGPRLiveRanges;
LiveIntervals *LIS = &getAnalysis<LiveIntervals>();
LiveVariables *LV = getAnalysisIfAvailable<LiveVariables>();
// First pass, collect all live intervals for SGPRs
for (const MachineBasicBlock &MBB : MF) {
for (const MachineInstr &MI : MBB) {
for (const MachineOperand &MO : MI.defs()) {
if (MO.isImplicit())
continue;
unsigned Def = MO.getReg();
if (TargetRegisterInfo::isVirtualRegister(Def)) {
if (TRI->isSGPRClass(MRI.getRegClass(Def))) {
// Only consider defs that are live outs. We don't care about def /
// use within the same block.
LiveRange &LR = LIS->getInterval(Def);
if (LIS->isLiveOutOfMBB(LR, &MBB))
SGPRLiveRanges.push_back(std::make_pair(Def, &LR));
}
} else if (TRI->isSGPRClass(TRI->getPhysRegClass(Def))) {
SGPRLiveRanges.push_back(
std::make_pair(Def, &LIS->getRegUnit(Def)));
}
}
}
}
// Second pass fix the intervals
for (MachineFunction::iterator BI = MF.begin(), BE = MF.end();
BI != BE; ++BI) {
MachineBasicBlock &MBB = *BI;
if (MBB.succ_size() < 2)
continue;
// We have structured control flow, so the number of successors should be
// two.
assert(MBB.succ_size() == 2);
MachineBasicBlock *SuccA = *MBB.succ_begin();
MachineBasicBlock *SuccB = *(++MBB.succ_begin());
MachineBasicBlock *NCD = PDT->findNearestCommonDominator(SuccA, SuccB);
if (!NCD)
continue;
MachineBasicBlock::iterator NCDTerm = NCD->getFirstTerminator();
if (NCDTerm != NCD->end() && NCDTerm->getOpcode() == AMDGPU::SI_ELSE) {
assert(NCD->succ_size() == 2);
// We want to make sure we insert the Use after the ENDIF, not after
// the ELSE.
NCD = PDT->findNearestCommonDominator(*NCD->succ_begin(),
*(++NCD->succ_begin()));
}
for (std::pair<unsigned, LiveRange*> RegLR : SGPRLiveRanges) {
unsigned Reg = RegLR.first;
LiveRange *LR = RegLR.second;
// FIXME: We could be smarter here. If the register is Live-In to one
// block, but the other doesn't have any SGPR defs, then there won't be a
// conflict. Also, if the branch condition is uniform then there will be
// no conflict.
bool LiveInToA = LIS->isLiveInToMBB(*LR, SuccA);
bool LiveInToB = LIS->isLiveInToMBB(*LR, SuccB);
if ((!LiveInToA && !LiveInToB) ||
(LiveInToA && LiveInToB))
continue;
// This interval is live in to one successor, but not the other, so
// we need to update its range so it is live in to both.
DEBUG(dbgs() << "Possible SGPR conflict detected " << " in " << *LR <<
" BB#" << SuccA->getNumber() << ", BB#" <<
SuccB->getNumber() <<
" with NCD = " << NCD->getNumber() << '\n');
assert(TargetRegisterInfo::isVirtualRegister(Reg) &&
"Not expecting to extend live range of physreg");
// FIXME: Need to figure out how to update LiveRange here so this pass
// will be able to preserve LiveInterval analysis.
MachineInstr *NCDSGPRUse =
BuildMI(*NCD, NCD->getFirstNonPHI(), DebugLoc(),
TII->get(AMDGPU::SGPR_USE))
.addReg(Reg, RegState::Implicit);
SlotIndex SI = LIS->InsertMachineInstrInMaps(NCDSGPRUse);
LIS->extendToIndices(*LR, SI.getRegSlot());
if (LV) {
// TODO: This won't work post-SSA
LV->HandleVirtRegUse(Reg, NCD, NCDSGPRUse);
}
DEBUG(NCDSGPRUse->dump());
}
}
return false;
}