mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-13 20:32:21 +00:00
36ba7962a4
The previous implementation was extending the live range of SGPRs by modifying the live intervals directly. This was causing a lot of machine verification errors when the machine scheduler was enabled. The new implementation adds pseudo instructions with implicit uses to extend the live ranges of SGPRs, which works much better. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@218351 91177308-0d34-0410-b5e6-96231b3b80d8
192 lines
6.4 KiB
C++
192 lines
6.4 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 control flow, 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 thoughout 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/MachineFunctionPass.h"
|
|
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
|
#include "llvm/CodeGen/MachinePostDominators.h"
|
|
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
|
#include "llvm/Support/Debug.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();
|
|
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(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());
|
|
LiveIntervals *LIS = &getAnalysis<LiveIntervals>();
|
|
MachinePostDominatorTree *PDT = &getAnalysis<MachinePostDominatorTree>();
|
|
std::vector<std::pair<unsigned, LiveRange *>> SGPRLiveRanges;
|
|
|
|
// 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)))
|
|
SGPRLiveRanges.push_back(
|
|
std::make_pair(Def, &LIS->getInterval(Def)));
|
|
} 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 number of succesors 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()));
|
|
}
|
|
assert(SuccA && SuccB);
|
|
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 decision is based on
|
|
// a value in an SGPR, 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');
|
|
|
|
// FIXME: Need to figure out how to update LiveRange here so this pass
|
|
// will be able to preserve LiveInterval analysis.
|
|
BuildMI(*NCD, NCD->getFirstNonPHI(), DebugLoc(),
|
|
TII->get(AMDGPU::SGPR_USE))
|
|
.addReg(Reg, RegState::Implicit);
|
|
DEBUG(NCD->getFirstNonPHI()->dump());
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|