mirror of
https://github.com/RPCS3/llvm.git
synced 2026-08-27 11:01:30 -04:00
77072b3170
coloring pass. Turn the logic into "look for an insert point and then move things past the insert point". No functional change intended. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@253626 91177308-0d34-0410-b5e6-96231b3b80d8
211 lines
7.6 KiB
C++
211 lines
7.6 KiB
C++
//===-- WebAssemblyRegColoring.cpp - Register coloring --------------------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
///
|
|
/// \file
|
|
/// \brief This file implements a virtual register coloring pass.
|
|
///
|
|
/// WebAssembly doesn't have a fixed number of registers, but it is still
|
|
/// desirable to minimize the total number of registers used in each function.
|
|
///
|
|
/// This code is modeled after lib/CodeGen/StackSlotColoring.cpp.
|
|
///
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "WebAssembly.h"
|
|
#include "WebAssemblyMachineFunctionInfo.h"
|
|
#include "MCTargetDesc/WebAssemblyMCTargetDesc.h" // for WebAssembly::ARGUMENT_*
|
|
#include "llvm/CodeGen/LiveIntervalAnalysis.h"
|
|
#include "llvm/CodeGen/MachineBlockFrequencyInfo.h"
|
|
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
|
#include "llvm/CodeGen/Passes.h"
|
|
#include "llvm/Support/Debug.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
using namespace llvm;
|
|
|
|
#define DEBUG_TYPE "wasm-reg-coloring"
|
|
|
|
namespace {
|
|
class WebAssemblyRegColoring final : public MachineFunctionPass {
|
|
public:
|
|
static char ID; // Pass identification, replacement for typeid
|
|
WebAssemblyRegColoring() : MachineFunctionPass(ID) {}
|
|
|
|
const char *getPassName() const override {
|
|
return "WebAssembly Register Coloring";
|
|
}
|
|
|
|
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
|
AU.setPreservesCFG();
|
|
AU.addRequired<LiveIntervals>();
|
|
AU.addRequired<MachineBlockFrequencyInfo>();
|
|
AU.addPreserved<MachineBlockFrequencyInfo>();
|
|
AU.addPreservedID(MachineDominatorsID);
|
|
AU.addRequired<SlotIndexes>(); // for ARGUMENT fixups
|
|
MachineFunctionPass::getAnalysisUsage(AU);
|
|
}
|
|
|
|
bool runOnMachineFunction(MachineFunction &MF) override;
|
|
|
|
private:
|
|
};
|
|
} // end anonymous namespace
|
|
|
|
char WebAssemblyRegColoring::ID = 0;
|
|
FunctionPass *llvm::createWebAssemblyRegColoring() {
|
|
return new WebAssemblyRegColoring();
|
|
}
|
|
|
|
// Compute the total spill weight for VReg.
|
|
static float computeWeight(const MachineRegisterInfo *MRI,
|
|
const MachineBlockFrequencyInfo *MBFI,
|
|
unsigned VReg) {
|
|
float weight = 0.0f;
|
|
for (MachineOperand &MO : MRI->reg_nodbg_operands(VReg))
|
|
weight += LiveIntervals::getSpillWeight(MO.isDef(), MO.isUse(), MBFI,
|
|
MO.getParent());
|
|
return weight;
|
|
}
|
|
|
|
bool WebAssemblyRegColoring::runOnMachineFunction(MachineFunction &MF) {
|
|
DEBUG({
|
|
dbgs() << "********** Register Coloring **********\n"
|
|
<< "********** Function: " << MF.getName() << '\n';
|
|
});
|
|
|
|
// If there are calls to setjmp or sigsetjmp, don't perform coloring. Virtual
|
|
// registers could be modified before the longjmp is executed, resulting in
|
|
// the wrong value being used afterwards. (See <rdar://problem/8007500>.)
|
|
// TODO: Does WebAssembly need to care about setjmp for register coloring?
|
|
if (MF.exposesReturnsTwice())
|
|
return false;
|
|
|
|
MachineRegisterInfo *MRI = &MF.getRegInfo();
|
|
LiveIntervals *Liveness = &getAnalysis<LiveIntervals>();
|
|
const MachineBlockFrequencyInfo *MBFI =
|
|
&getAnalysis<MachineBlockFrequencyInfo>();
|
|
WebAssemblyFunctionInfo &MFI = *MF.getInfo<WebAssemblyFunctionInfo>();
|
|
|
|
// Gather all register intervals into a list and sort them.
|
|
unsigned NumVRegs = MRI->getNumVirtRegs();
|
|
SmallVector<LiveInterval *, 0> SortedIntervals;
|
|
SortedIntervals.reserve(NumVRegs);
|
|
|
|
// FIXME: If scheduling has moved an ARGUMENT virtual register, move it back,
|
|
// and recompute liveness. This is a temporary hack.
|
|
bool MovedArg = false;
|
|
MachineBasicBlock &EntryMBB = MF.front();
|
|
MachineBasicBlock::iterator InsertPt = EntryMBB.end();
|
|
// Look for the first NonArg instruction.
|
|
for (auto MII = EntryMBB.begin(), MIE = EntryMBB.end(); MII != MIE; ++MII) {
|
|
MachineInstr *MI = MII;
|
|
if (MI->getOpcode() != WebAssembly::ARGUMENT_I32 &&
|
|
MI->getOpcode() != WebAssembly::ARGUMENT_I64 &&
|
|
MI->getOpcode() != WebAssembly::ARGUMENT_F32 &&
|
|
MI->getOpcode() != WebAssembly::ARGUMENT_F64) {
|
|
InsertPt = MII;
|
|
break;
|
|
}
|
|
}
|
|
// Now move any argument instructions later in the block
|
|
// to before our first NonArg instruction.
|
|
for (auto I = InsertPt, E = EntryMBB.end(); I != E; ++I) {
|
|
MachineInstr *MI = I;
|
|
if (MI->getOpcode() == WebAssembly::ARGUMENT_I32 ||
|
|
MI->getOpcode() == WebAssembly::ARGUMENT_I64 ||
|
|
MI->getOpcode() == WebAssembly::ARGUMENT_F32 ||
|
|
MI->getOpcode() == WebAssembly::ARGUMENT_F64) {
|
|
EntryMBB.insert(InsertPt, MI->removeFromParent());
|
|
MovedArg = true;
|
|
}
|
|
}
|
|
if (MovedArg) {
|
|
SlotIndexes &Slots = getAnalysis<SlotIndexes>();
|
|
Liveness->releaseMemory();
|
|
Slots.releaseMemory();
|
|
Slots.runOnMachineFunction(MF);
|
|
Liveness->runOnMachineFunction(MF);
|
|
}
|
|
|
|
DEBUG(dbgs() << "Interesting register intervals:\n");
|
|
for (unsigned i = 0; i < NumVRegs; ++i) {
|
|
unsigned VReg = TargetRegisterInfo::index2VirtReg(i);
|
|
if (MFI.isVRegStackified(VReg))
|
|
continue;
|
|
|
|
LiveInterval *LI = &Liveness->getInterval(VReg);
|
|
assert(LI->weight == 0.0f);
|
|
LI->weight = computeWeight(MRI, MBFI, VReg);
|
|
DEBUG(LI->dump());
|
|
SortedIntervals.push_back(LI);
|
|
}
|
|
DEBUG(dbgs() << '\n');
|
|
|
|
// Sort them to put arguments first (since we don't want to rename live-in
|
|
// registers), by weight next, and then by position.
|
|
// TODO: Investigate more intelligent sorting heuristics. For starters, we
|
|
// should try to coalesce adjacent live intervals before non-adjacent ones.
|
|
std::sort(SortedIntervals.begin(), SortedIntervals.end(),
|
|
[MRI](LiveInterval *LHS, LiveInterval *RHS) {
|
|
if (MRI->isLiveIn(LHS->reg) != MRI->isLiveIn(RHS->reg))
|
|
return MRI->isLiveIn(LHS->reg);
|
|
if (LHS->weight != RHS->weight)
|
|
return LHS->weight > RHS->weight;
|
|
if (LHS->empty() || RHS->empty())
|
|
return !LHS->empty() && RHS->empty();
|
|
return *LHS < *RHS;
|
|
});
|
|
|
|
DEBUG(dbgs() << "Coloring register intervals:\n");
|
|
SmallVector<unsigned, 16> SlotMapping(SortedIntervals.size(), -1u);
|
|
SmallVector<SmallVector<LiveInterval *, 4>, 16> Assignments(
|
|
SortedIntervals.size());
|
|
BitVector UsedColors(SortedIntervals.size());
|
|
bool Changed = false;
|
|
for (size_t i = 0, e = SortedIntervals.size(); i < e; ++i) {
|
|
LiveInterval *LI = SortedIntervals[i];
|
|
unsigned Old = LI->reg;
|
|
size_t Color = i;
|
|
const TargetRegisterClass *RC = MRI->getRegClass(Old);
|
|
|
|
// Check if it's possible to reuse any of the used colors.
|
|
if (!MRI->isLiveIn(Old))
|
|
for (int C(UsedColors.find_first()); C != -1;
|
|
C = UsedColors.find_next(C)) {
|
|
if (MRI->getRegClass(SortedIntervals[C]->reg) != RC)
|
|
continue;
|
|
for (LiveInterval *OtherLI : Assignments[C])
|
|
if (!OtherLI->empty() && OtherLI->overlaps(*LI))
|
|
goto continue_outer;
|
|
Color = C;
|
|
break;
|
|
continue_outer:;
|
|
}
|
|
|
|
unsigned New = SortedIntervals[Color]->reg;
|
|
SlotMapping[i] = New;
|
|
Changed |= Old != New;
|
|
UsedColors.set(Color);
|
|
Assignments[Color].push_back(LI);
|
|
DEBUG(dbgs() << "Assigning vreg"
|
|
<< TargetRegisterInfo::virtReg2Index(LI->reg) << " to vreg"
|
|
<< TargetRegisterInfo::virtReg2Index(New) << "\n");
|
|
}
|
|
if (!Changed)
|
|
return false;
|
|
|
|
// Rewrite register operands.
|
|
for (size_t i = 0, e = SortedIntervals.size(); i < e; ++i) {
|
|
unsigned Old = SortedIntervals[i]->reg;
|
|
unsigned New = SlotMapping[i];
|
|
if (Old != New)
|
|
MRI->replaceRegWith(Old, New);
|
|
}
|
|
return true;
|
|
}
|