зеркало из https://github.com/mozilla/gecko-dev.git
Eliminating New* files, which are old snapshots of other files
This commit is contained in:
Родитель
87b2f10d35
Коммит
45afc91a9b
|
@ -1,659 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#include "Fundamentals.h"
|
||||
|
||||
#define INCLUDE_EMITTER
|
||||
#include "CpuInfo.h"
|
||||
|
||||
#include "RegisterAllocator.h"
|
||||
#include "VirtualRegister.h"
|
||||
#include "DoublyLinkedList.h"
|
||||
#include "ControlNodes.h"
|
||||
#include "Instruction.h"
|
||||
|
||||
#include "Liveness.h"
|
||||
|
||||
#if !defined(DEBUG_LOG) || !defined(DEBUG_laurentm)
|
||||
#define NO_TIMER
|
||||
#endif // !DEBUG_LOG || !DEBUG_laurentm
|
||||
#include "Timer.h"
|
||||
|
||||
//
|
||||
// Annotate the phi nodes. We call an annotation a VirtualRegister assignment to a DataProducer.
|
||||
// Phi nodes are special data nodes that will not generate an instruction. For this reason,
|
||||
// it is possible that after code generation, some DataProducer were not annotated.
|
||||
// The RegisterAllocator assumes that each DataProducer has been annotated. So we must annotate
|
||||
// the DataProducer that were not.
|
||||
//
|
||||
void RegisterAllocator::annotatePhiNodes()
|
||||
{
|
||||
for (Uint32 n = 0; n < nNodes; n++) { // For each nodes in this graph.
|
||||
DoublyLinkedList<PhiNode>& phiNodes = dfsList[n]->getPhiNodes();
|
||||
|
||||
for (DoublyLinkedList<PhiNode>::iterator p = phiNodes.begin(); !phiNodes.done(p); p = phiNodes.advance(p)) { // For each phi nodes.
|
||||
PhiNode& phiNode = phiNodes.get(p);
|
||||
|
||||
VirtualRegisterKind constraint;
|
||||
switch (phiNode.getKind()) {
|
||||
case vkCond:
|
||||
case vkMemory:
|
||||
continue; // Condition and Memory phi nodes are not seen after code generation.
|
||||
|
||||
case vkInt:
|
||||
constraint = IntegerRegister;
|
||||
break;
|
||||
case vkLong:
|
||||
constraint = IntegerRegister; // FIXME: But should annotate 2 registers.
|
||||
break;
|
||||
case vkFloat:
|
||||
constraint = FloatingPointRegister;
|
||||
break;
|
||||
case vkDouble:
|
||||
constraint = FloatingPointRegister; // FIXME: Is it always the case ?.
|
||||
break;
|
||||
case vkAddr:
|
||||
constraint = IntegerRegister;
|
||||
break;
|
||||
default:
|
||||
PR_ASSERT(!"Unhandled kind of phi node");
|
||||
}
|
||||
// Check the outgoing edge annotation. We do not check the consumers because
|
||||
// they must be or have been defined by either a primitive or another phi node.
|
||||
if (phiNode.getVirtualRegisterAnnotation() == NULL)
|
||||
phiNode.annotate(vrManager.newVirtualRegister(constraint));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Get the liveness information and build the interference graph. The interference graph
|
||||
// is represented by a bitmatrix. Each row of this bitmatrix represents a VirtualRegister,
|
||||
// and each bits on this row an interference with another VirtualRegister.
|
||||
// 2 registers will interfere if they are live at the same time. A register is alive between
|
||||
// its definition and its last use.
|
||||
//
|
||||
void RegisterAllocator::buildInterferenceGraph()
|
||||
{
|
||||
// To get the number of VirtualRegisters in the manager, we must be sure
|
||||
// that no one will try to allocate new VirtualRegisters.
|
||||
// We are locking the manager for the entire method.
|
||||
DEBUG_ONLY(TIMER_SAFE(vrManager.lockAllocation()));
|
||||
|
||||
Uint32 nVirtualRegisters = vrManager.getSize(); // Maximum of allocated VirtualRegister.
|
||||
|
||||
// ControlNodes hold some fields for the register allocation (liveAtBegin, liveAtEnd, etc ...).
|
||||
// We need to reset these fields and allocate the memory fro the bitsets.
|
||||
for (Uint32 n = 0; n < nNodes; n++) {
|
||||
ControlNode& node = *dfsList[n];
|
||||
|
||||
node.liveAtBegin.sizeToAndClear(pool, nVirtualRegisters);
|
||||
node.liveAtEnd.sizeToAndClear(pool, nVirtualRegisters);
|
||||
node.hasNewLiveAtEnd = true;
|
||||
node.liveAtBeginIsValid = false;
|
||||
}
|
||||
|
||||
// Reset the interference matrix. This matrix must hold nVirtualRegisters rows and
|
||||
// nVirtualRegisters column.
|
||||
interferenceMatrix.sizeToAndClear(pool, nVirtualRegisters, nVirtualRegisters);
|
||||
DEBUG_ONLY(interferenceMatrixSize = nVirtualRegisters);
|
||||
|
||||
FastBitSet currentLive(pool, nVirtualRegisters); // Bitset for the registers currently alive.
|
||||
|
||||
while(true) {
|
||||
bool needsToLoop = false;
|
||||
|
||||
for (Int32 n = (nNodes - 1); n >= 0; n--) { // For each nodes in this graph.
|
||||
ControlNode& node = *dfsList[n];
|
||||
|
||||
// We skip the nodes that we already looked at and that do
|
||||
// not have any new liveness information at the end.
|
||||
if (node.liveAtBeginIsValid && !node.hasNewLiveAtEnd)
|
||||
continue;
|
||||
|
||||
// The register currently alive are the register alive at
|
||||
// the end of this node.
|
||||
currentLive = node.liveAtEnd;
|
||||
// We are looking at this node so for now it doesn't have
|
||||
// any new liveness information at the end.
|
||||
node.hasNewLiveAtEnd = false;
|
||||
|
||||
// We walk backward all the instructions defined in this node.
|
||||
// A register becomes alive with its last use (first found), interfere with
|
||||
// all the registers alive at its definition, and is killed by its definition.
|
||||
InstructionList& instructions = node.getInstructions();
|
||||
for (InstructionList::iterator i = instructions.end(); !instructions.done(i); i = instructions.retreat(i)) {
|
||||
Instruction& instruction = instructions.get(i);
|
||||
InstructionUse* useBegin = instruction.getInstructionUseBegin();
|
||||
InstructionUse* useEnd = instruction.getInstructionUseEnd();
|
||||
InstructionUse* usePtr;
|
||||
InstructionDefine* defBegin = instruction.getInstructionDefineBegin();
|
||||
InstructionDefine* defEnd = instruction.getInstructionDefineEnd();
|
||||
InstructionDefine* defPtr;
|
||||
|
||||
InstructionFlags flags = instruction.getFlags();
|
||||
|
||||
// Move is handled specially to avoid adding an interference between the
|
||||
// source and the destination. If an interference exists between these
|
||||
// registers another instruction will set it. For now the source register
|
||||
// and the destination register will contain the same value.
|
||||
if (flags & ifCopy) {
|
||||
PR_ASSERT(useBegin[0].isVirtualRegister());
|
||||
currentLive.clear(useBegin[0].getVirtualRegister().index);
|
||||
}
|
||||
|
||||
// Registers are defined. This definition has an interference with all the
|
||||
// registers currently alive.
|
||||
for (defPtr = defBegin; defPtr < defEnd; defPtr++)
|
||||
if (defPtr->isVirtualRegister()) {
|
||||
VirtualRegisterIndex index = defPtr->getVirtualRegister().index;
|
||||
interferenceMatrix.orRows(index, currentLive, index);
|
||||
}
|
||||
|
||||
// The definition just killed these registers.
|
||||
for (defPtr = defBegin; defPtr < defEnd; defPtr++)
|
||||
if (defPtr->isVirtualRegister())
|
||||
currentLive.clear(defPtr->getVirtualRegister().index);
|
||||
|
||||
// If this instruction is a Call instruction, we want all the caller-save
|
||||
// registers to interfere with the current live registers. We do not want an
|
||||
// interference with the callee-save registers because the call will save &
|
||||
// restore these registers.
|
||||
if (flags & ifCall) {
|
||||
// FIXME
|
||||
}
|
||||
|
||||
if (flags & ifSpecialCall) {
|
||||
// FIXME
|
||||
}
|
||||
|
||||
// Each use of a register makes it alive.
|
||||
for (usePtr = useBegin; usePtr < useEnd; usePtr++)
|
||||
if (usePtr->isVirtualRegister())
|
||||
currentLive.set(usePtr->getVirtualRegister().index);
|
||||
}
|
||||
|
||||
// If the liveness information is different than the previous one, we
|
||||
// need to propagate the changes to each predecessor of this node.
|
||||
// We also need to add the liveness information from the phi nodes.
|
||||
if (currentLive != node.liveAtBegin) {
|
||||
FastBitSet liveAtEnd(pool, nVirtualRegisters); // Bitset for the registers alive at the end of a predecessor of this node.
|
||||
|
||||
DoublyLinkedList<PhiNode>& phiNodes = node.getPhiNodes();
|
||||
const DoublyLinkedList<ControlEdge>& predecessors = node.getPredecessors();
|
||||
DoublyLinkedList<ControlEdge>::iterator i;
|
||||
Uint32 predecessorIndex;
|
||||
|
||||
for (predecessorIndex = 0, i = predecessors.begin(); !predecessors.done(i); predecessorIndex++, i = predecessors.advance(i)) {
|
||||
ControlNode& predecessor = predecessors.get(i).getSource();
|
||||
bool predecessorHasNewLiveAtEnd = false;
|
||||
|
||||
if (!phiNodes.empty()) {
|
||||
liveAtEnd = currentLive;
|
||||
|
||||
for (DoublyLinkedList<PhiNode>::iterator p = phiNodes.end(); !phiNodes.done(p); p = phiNodes.retreat(p)) {
|
||||
PhiNode& phiNode = phiNodes.get(p);
|
||||
|
||||
if (isStorableKind(phiNode.getKind())) {
|
||||
DataNode& producer = phiNode.nthInput(predecessorIndex).getVariable();
|
||||
VirtualRegisterIndex use = producer.getVirtualRegisterAnnotation()->index;
|
||||
VirtualRegisterIndex define = phiNode.getVirtualRegisterAnnotation()->index;
|
||||
|
||||
// If this phi node has been coalesced then the producer and the consumer for this
|
||||
// edge hold the same VirtualRegister. In this case we don't update the liveness
|
||||
// information.
|
||||
if (define != use) {
|
||||
// A phiNode, if not coalesced will generate a Copy instruction. So we do
|
||||
// not want the use and the definition to interfere.
|
||||
liveAtEnd.clear(use);
|
||||
interferenceMatrix.orRows(define, liveAtEnd, define);
|
||||
liveAtEnd.clear(define);
|
||||
liveAtEnd.set(use);
|
||||
}
|
||||
}
|
||||
}
|
||||
predecessorHasNewLiveAtEnd |= predecessor.liveAtEnd.set(liveAtEnd);
|
||||
} else { // phiNode.empty() == true
|
||||
predecessorHasNewLiveAtEnd = predecessor.liveAtEnd.set(currentLive);
|
||||
}
|
||||
|
||||
predecessor.hasNewLiveAtEnd |= predecessorHasNewLiveAtEnd;
|
||||
needsToLoop |= predecessorHasNewLiveAtEnd;
|
||||
}
|
||||
}
|
||||
node.liveAtBegin = currentLive;
|
||||
node.liveAtBeginIsValid = true;
|
||||
}
|
||||
|
||||
// If this graph is an acyclic graph we are sure that after the first pass all
|
||||
// the interferences are found. We stop this loop in this case and also
|
||||
// if no new live registers are found.
|
||||
if (!needsToLoop || isAcyclic)
|
||||
break;
|
||||
}
|
||||
|
||||
// Summarize the interference matrix. This matrix must be diagonale and some interferences
|
||||
// are not valid (i.e. IntegerRegister with FloatingPointRegister, 2 precolored registers
|
||||
// to different colors.
|
||||
|
||||
FastBitMatrix trans(pool, nVirtualRegisters, nVirtualRegisters);
|
||||
for (VirtualRegisterIndex r = vrManager.first(); !vrManager.done(r); r = vrManager.advance(r)) {
|
||||
interferenceMatrix.clear(r, r); // A register do not interfere with itself;
|
||||
|
||||
FastBitSet row(interferenceMatrix.getRowBits(r), nVirtualRegisters);
|
||||
for (Int32 i = row.firstOne(); !row.done(i); i = row.nextOne(i))
|
||||
trans.set(i, r);
|
||||
}
|
||||
|
||||
for (VirtualRegisterIndex s = vrManager.first(); !vrManager.done(s); s = vrManager.advance(s)) {
|
||||
interferenceMatrix.orRows(s, FastBitSet(trans.getRowBits(s), nVirtualRegisters), s);
|
||||
}
|
||||
|
||||
interferenceMatrix &= vrManager.getValidInterferencesMatrix();
|
||||
|
||||
// Get the interference degrees from the interference matrix.
|
||||
if (interferenceDegreesSize < nVirtualRegisters) {
|
||||
interferenceDegreesSize = nVirtualRegisters;
|
||||
interferenceDegrees = new(pool) Uint32[interferenceDegreesSize];
|
||||
}
|
||||
|
||||
for (Uint32 j = 0; j < nVirtualRegisters; j++)
|
||||
interferenceDegrees[j] = FastBitSet(interferenceMatrix.getRowBits(j), nVirtualRegisters).countOnes();
|
||||
|
||||
// We are done with this method. We can now unlock the VirtualRegisterManager.
|
||||
DEBUG_ONLY(TIMER_SAFE(vrManager.unlockAllocation()));
|
||||
}
|
||||
|
||||
//
|
||||
// Return true if the VirtualRegisters source to dest were coalesced.
|
||||
//
|
||||
bool RegisterAllocator::coalesceRegistersIfPossible(VirtualRegister& sourceRegister, VirtualRegister& destRegister)
|
||||
{
|
||||
VirtualRegisterIndex source = sourceRegister.index;
|
||||
VirtualRegisterIndex dest = destRegister.index;
|
||||
|
||||
if (source == dest)
|
||||
return true;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (sourceRegister.isPreColored())
|
||||
PR_ASSERT(destRegister.isPreColored());
|
||||
#endif // DEBUG
|
||||
|
||||
if (destRegister.isPreColored() && sourceRegister.isPreColored())
|
||||
if (sourceRegister.getPreColor() != destRegister.getPreColor())
|
||||
return false;
|
||||
else // 2 precolored registers cannot interfere.
|
||||
PR_ASSERT(!interferenceMatrix.test(source, dest));
|
||||
else if (interferenceMatrix.test(source, dest))
|
||||
return false;
|
||||
|
||||
Uint32 nVirtualRegisters = vrManager.getSize();
|
||||
FastBitSet sourceInterferences(interferenceMatrix.getRowBits(source), nVirtualRegisters);
|
||||
|
||||
tempBitSet.sizeTo(pool, nVirtualRegisters);
|
||||
tempBitSet = sourceInterferences;
|
||||
tempBitSet -= FastBitSet(interferenceMatrix.getRowBits(dest), nVirtualRegisters);
|
||||
|
||||
Uint32 nNewInterferences = tempBitSet.countOnes();
|
||||
if ((nNewInterferences + interferenceDegrees[dest]) >= virtualRegisterClasses[destRegister.kind]->getNumberOfColor())
|
||||
return false;
|
||||
|
||||
// Coalesce the registers.
|
||||
vrManager.coalesceVirtualRegisters(source, dest);
|
||||
|
||||
// Update the interference matrix.
|
||||
for (Int32 i = sourceInterferences.firstOne(); !sourceInterferences.done(i); i = sourceInterferences.nextOne(i)) {
|
||||
interferenceMatrix.clear(i, source);
|
||||
if (tempBitSet.test(i)) // This is a new interference for dest.
|
||||
interferenceMatrix.set(i, dest);
|
||||
else
|
||||
interferenceDegrees[i]--;
|
||||
}
|
||||
|
||||
interferenceDegrees[dest] += nNewInterferences;
|
||||
interferenceMatrix.orRows(source, dest, dest);
|
||||
|
||||
#ifdef DEBUG
|
||||
START_TIMER_SAFE
|
||||
interferenceMatrix.clear(source);
|
||||
interferenceDegrees[source] = 0;
|
||||
|
||||
// Check the validity of the dest row.
|
||||
PR_ASSERT(FastBitSet(interferenceMatrix.getRowBits(dest), nVirtualRegisters).countOnes() == interferenceDegrees[dest]);
|
||||
END_TIMER_SAFE
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// Check all Copy instructions & phiNodes for possible register coalescing.
|
||||
// If two registers are coalesced there's no need to keep the instruction (or the phiNode).
|
||||
// The ControlFlow graph is analysed from the most executed node to the least.
|
||||
//
|
||||
// TODO: loop nesting depth is not good enough (should analyse the program regions instead).
|
||||
//
|
||||
void RegisterAllocator::removeUneededCopyInstructions()
|
||||
{
|
||||
for (Int32 n = nNodes - 1; n >= 0; n--) {
|
||||
ControlNode& node = *lndList[n];
|
||||
|
||||
//
|
||||
// Check the Copy in the instruction list.
|
||||
//
|
||||
InstructionList& instructions = node.getInstructions();
|
||||
InstructionList::iterator i = instructions.begin();
|
||||
|
||||
while (!instructions.done(i)) { // For each instruction in this node.
|
||||
Instruction& instruction = instructions.get(i);
|
||||
i = instructions.advance(i);
|
||||
|
||||
if (instruction.getFlags() & ifCopy) { // This is a Copy Instruction
|
||||
PR_ASSERT(instruction.getInstructionUseBegin()[0].isVirtualRegister());
|
||||
PR_ASSERT(instruction.getInstructionDefineBegin()[0].isVirtualRegister());
|
||||
|
||||
VirtualRegister& sourceRegister = instruction.getInstructionUseBegin()[0].getVirtualRegister();
|
||||
VirtualRegister& destRegister = instruction.getInstructionDefineBegin()[0].getVirtualRegister();
|
||||
|
||||
// If a VirtualRegister is precolored then this register must be the destination
|
||||
// register if the coalescing is possible.
|
||||
if (destRegister.isPreColored()) {
|
||||
if (coalesceRegistersIfPossible(sourceRegister, destRegister))
|
||||
instruction.remove();
|
||||
} else {
|
||||
if (coalesceRegistersIfPossible(destRegister, sourceRegister))
|
||||
instruction.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Check the phi nodes.
|
||||
//
|
||||
DoublyLinkedList<PhiNode>& phiNodes = node.getPhiNodes();
|
||||
DoublyLinkedList<PhiNode>::iterator p = phiNodes.end();
|
||||
|
||||
while (!phiNodes.done(p)) { // For each phi nodes.
|
||||
PhiNode& phiNode = phiNodes.get(p);
|
||||
p = phiNodes.retreat(p);
|
||||
|
||||
if (isStorableKind(phiNode.getKind())) {
|
||||
bool canRemoveThisPhiNode = true; // Can we remove the phi node from the graph ?
|
||||
|
||||
DataConsumer* limit = phiNode.getInputsEnd();
|
||||
for (DataConsumer* consumer = phiNode.getInputsBegin(); consumer < limit; consumer++) {
|
||||
VirtualRegister& sourceRegister = *phiNode.getVirtualRegisterAnnotation();
|
||||
VirtualRegister& destRegister = *consumer->getVariable().getVirtualRegisterAnnotation();
|
||||
|
||||
|
||||
// If a VirtualRegister is precolored then this register must be the destination
|
||||
// register if the coalescing is possible.
|
||||
if (destRegister.isPreColored()) {
|
||||
if (!coalesceRegistersIfPossible(sourceRegister, destRegister))
|
||||
canRemoveThisPhiNode = false;
|
||||
} else {
|
||||
if (!coalesceRegistersIfPossible(destRegister, sourceRegister))
|
||||
canRemoveThisPhiNode = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (canRemoveThisPhiNode)
|
||||
phiNode.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Replace the remaining phi nodes by their equivalent instruction (Copy, Load, Store).
|
||||
// Return true if the register allocator needs one more pass.
|
||||
//
|
||||
bool RegisterAllocator::replacePhiNodesByCopyInstructions()
|
||||
{
|
||||
bool addedANode = false;
|
||||
bool needsRebuild = false;
|
||||
|
||||
for (Uint32 n = 0; n < nNodes; n++) { // For all nodes.
|
||||
ControlNode& node = *dfsList[n];
|
||||
|
||||
DoublyLinkedList<PhiNode>& phiNodes = node.getPhiNodes();
|
||||
const DoublyLinkedList<ControlEdge>& predecessors = node.getPredecessors();
|
||||
bool hasOnlyOneInput = predecessors.lengthIs(1);
|
||||
|
||||
// If this node has only one predecessor, it is possible to insert the copy instruction
|
||||
// at the begining of this node. To respect the interference order, we have to append
|
||||
// each phiNode in the same order they are in the linked list.
|
||||
DoublyLinkedList<PhiNode>::iterator i = hasOnlyOneInput ? phiNodes.begin() : phiNodes.end();
|
||||
while (!phiNodes.done(i)) {
|
||||
PhiNode& phiNode = phiNodes.get(i);
|
||||
i = hasOnlyOneInput ? phiNodes.advance(i) : phiNodes.retreat(i);
|
||||
|
||||
if (isStorableKind(phiNode.getKind())) {
|
||||
VirtualRegister& definedVR = *phiNode.getVirtualRegisterAnnotation();
|
||||
|
||||
DoublyLinkedList<ControlEdge>::iterator e = predecessors.begin();
|
||||
DataConsumer* limit = phiNode.getInputsEnd();
|
||||
for (DataConsumer* consumer = phiNode.getInputsBegin(); consumer < limit; consumer++) { // For each consumer
|
||||
ControlEdge& edge = predecessors.get(e);
|
||||
e = predecessors.advance(e);
|
||||
|
||||
VirtualRegister& usedVR = *consumer->getVariable().getVirtualRegisterAnnotation();
|
||||
|
||||
if (definedVR.index != usedVR.index) { // We have to emit an instruction.
|
||||
InstructionList::iterator place;
|
||||
|
||||
if (hasOnlyOneInput)
|
||||
place = node.getInstructions().begin()->prev;
|
||||
else {
|
||||
ControlNode& source = edge.getSource();
|
||||
if (source.nSuccessors() != 1) { // This predecessor has more than one outgoing edge. We need to add
|
||||
// a new ControlBlock to insert the copy instruction.
|
||||
ControlNode& cn = edge.getSource().controlGraph.newControlNode();
|
||||
cn.setControlBlock();
|
||||
ControlEdge& newEdge = cn.getNormalSuccessor();
|
||||
|
||||
newEdge.substituteTarget(edge);
|
||||
cn.addPredecessor(edge);
|
||||
|
||||
// append at the begin of this new node.
|
||||
place = cn.getInstructions().begin();
|
||||
addedANode = true;
|
||||
} else
|
||||
place = edge.getSource().getInstructions().end();
|
||||
}
|
||||
|
||||
needsRebuild |= emitter.emitCopyAfter(phiNode, place, usedVR, definedVR);
|
||||
}
|
||||
}
|
||||
phiNode.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (addedANode) {
|
||||
ControlGraph& cg = dfsList[0]->controlGraph;
|
||||
cg.dfsSearch();
|
||||
|
||||
if (needsRebuild) {
|
||||
nNodes = cg.nNodes;
|
||||
dfsList = cg.dfsList;
|
||||
cg.lndSearch();
|
||||
lndList = cg.lndList;
|
||||
}
|
||||
}
|
||||
|
||||
return needsRebuild;
|
||||
}
|
||||
|
||||
//
|
||||
// Calculate the spill cost for each VirtualRegister.
|
||||
//
|
||||
void RegisterAllocator::calculateSpillCosts()
|
||||
{
|
||||
Uint32 nVirtualRegisters = vrManager.getSize();
|
||||
FastBitSet currentLive(pool, nVirtualRegisters);
|
||||
|
||||
// Reset the spillCosts.
|
||||
for (VirtualRegisterIndex r = vrManager.first(); !vrManager.done(r); r = vrManager.advance(r)) {
|
||||
VirtualRegister& vReg = vrManager.getVirtualRegister(r);
|
||||
vReg.spillCosts.copyCosts = 0.;
|
||||
vReg.spillCosts.loadOrStoreCosts = 0.;
|
||||
}
|
||||
|
||||
for (Int32 n = (nNodes - 1); n >= 0; n--) { // For each node in this graph.
|
||||
ControlNode& node = *dfsList[n];
|
||||
|
||||
currentLive = node.liveAtEnd;
|
||||
|
||||
InstructionList& instructions = node.getInstructions();
|
||||
for (InstructionList::iterator i = instructions.end(); !instructions.done(i); i = instructions.retreat(i)) {
|
||||
Instruction& instruction = instructions.get(i);
|
||||
InstructionUse* useBegin = instruction.getInstructionUseBegin();
|
||||
InstructionUse* useEnd = instruction.getInstructionUseEnd();
|
||||
InstructionUse* usePtr;
|
||||
InstructionDefine* defBegin = instruction.getInstructionDefineBegin();
|
||||
InstructionDefine* defEnd = instruction.getInstructionDefineEnd();
|
||||
InstructionDefine* defPtr;
|
||||
|
||||
if (instruction.getFlags() & ifCopy) {
|
||||
PR_ASSERT(useBegin[0].isVirtualRegister() && defBegin[0].isVirtualRegister());
|
||||
// If one of these registers are spilled, this instruction will be replaced by a load or a store.
|
||||
useBegin[0].getVirtualRegister().spillCosts.copyCosts -= node.nVisited;
|
||||
defBegin[0].getVirtualRegister().spillCosts.copyCosts -= node.nVisited;
|
||||
}
|
||||
|
||||
// Handle the definition a new VirtualRegister.
|
||||
for (defPtr = defBegin; defPtr < defEnd; defPtr++)
|
||||
if (defPtr->isVirtualRegister()) {
|
||||
VirtualRegister& vReg = defPtr->getVirtualRegister();
|
||||
if (virtualRegisterClasses[vReg.kind]->canSpill()) {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RegisterAllocator::allocateRegisters()
|
||||
{
|
||||
//
|
||||
// Timer names.
|
||||
//
|
||||
const char* ANNOTATE_PHINODES = "RegAlloc.annotatePhiNodes";
|
||||
const char* BUILD_INTERFERENCEGRAPH = "RegAlloc.buildInterferenceGraph";
|
||||
const char* ALLOCATE_REGISTERS = "RegAlloc.allocateRegisters";
|
||||
const char* COALESCE_REGISTERS = "RegAlloc.coalesceRegisters";
|
||||
const char* REPLACE_PHI_NODES = "RegAlloc.replacePhiNodesByCopyInstructions";
|
||||
|
||||
startTimer(ALLOCATE_REGISTERS);
|
||||
|
||||
// Add the missing annotations to the phi nodes.
|
||||
startTimer(ANNOTATE_PHINODES);
|
||||
annotatePhiNodes();
|
||||
stopTimer(ANNOTATE_PHINODES);
|
||||
|
||||
// Build the interference matrix.
|
||||
startTimer(BUILD_INTERFERENCEGRAPH);
|
||||
buildInterferenceGraph();
|
||||
stopTimer(BUILD_INTERFERENCEGRAPH);
|
||||
|
||||
#if 0
|
||||
// Remove uneeded copy & phi nodes.
|
||||
startTimer(COALESCE_REGISTERS);
|
||||
removeUneededCopyInstructions();
|
||||
stopTimer(COALESCE_REGISTERS);
|
||||
|
||||
// Just to be sure that the coalescing didn't corrupt the interference matrix.
|
||||
DEBUG_ONLY(TIMER_SAFE(checkCoalescingValidity()));
|
||||
|
||||
// Get the cost for register spilling.
|
||||
calculateSpillCosts();
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
bool successfulColoring = colorRegisters();
|
||||
|
||||
if (!successfulColoring)
|
||||
insertSpillCode();
|
||||
|
||||
// Emit the instructions for the remaining phi nodes in the graph.
|
||||
startTimer(REPLACE_PHI_NODES);
|
||||
replacePhiNodesByCopyInstructions();
|
||||
stopTimer(REPLACE_PHI_NODES);
|
||||
#endif
|
||||
|
||||
stopTimer(ALLOCATE_REGISTERS);
|
||||
|
||||
|
||||
interferenceMatrix.printPretty(stdout);
|
||||
|
||||
#if 1
|
||||
for (VirtualRegisterIndex i = vrManager.first(); !vrManager.done(i); i = vrManager.advance(i)) {
|
||||
fprintf(stdout, "degree of vr%d = %d\n", i, interferenceDegrees[i]);
|
||||
vrManager.getVirtualRegister(i).setColor(0);
|
||||
}
|
||||
|
||||
for (Uint32 m = 0; m < nNodes; m++) {
|
||||
ControlNode& node = *dfsList[m];
|
||||
node.printRef(stdout);
|
||||
fprintf(stdout, "\n");
|
||||
|
||||
InstructionList& instructions = node.getInstructions();
|
||||
for(InstructionList::iterator i = instructions.begin(); !instructions.done(i); i = instructions.advance(i)) {
|
||||
instructions.get(i).printDebug(stdout);
|
||||
fprintf(stdout, "\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
ControlGraph& cg = dfsList[0]->controlGraph;
|
||||
Liveness liveness(pool);
|
||||
liveness.buildLivenessAnalysis(cg, vrManager);
|
||||
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
//
|
||||
//
|
||||
//
|
||||
void RegisterAllocator::checkCoalescingValidity()
|
||||
{
|
||||
FastBitMatrix backup(pool, interferenceMatrixSize, interferenceMatrixSize);
|
||||
backup = interferenceMatrix;
|
||||
|
||||
buildInterferenceGraph();
|
||||
if (backup != interferenceMatrix) {
|
||||
#ifdef DEBUG_LOG
|
||||
fprintf(stdout, "\n"
|
||||
"!!! RegisterAllocator Warning: Interference matrix is invalid after coalescing.\n"
|
||||
"!!! The RegisterAllocator will reconstruct a valid interferenceMatrix.\n"
|
||||
"!!!\n"
|
||||
"!!! Please mail your java source file to laurentm@netscape.com with\n"
|
||||
"!!! the subject \"RegAlloc Bug\". Thanks, Laurent.\n"
|
||||
"\n");
|
||||
#ifdef DEBUG_laurentm
|
||||
interferenceMatrix.printDiff(stdout, backup);
|
||||
#endif // DEBUG_laurentm
|
||||
#else // DEBUG_LOG
|
||||
PR_ASSERT(!"Invalid interferenceMatrix after coalescing");
|
||||
#endif // DEBUG_LOG
|
||||
}
|
||||
}
|
||||
#endif // DEBUG
|
|
@ -1,94 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _REGISTER_ALLOCATOR_H_
|
||||
#define _REGISTER_ALLOCATOR_H_
|
||||
|
||||
|
||||
#include "Fundamentals.h"
|
||||
|
||||
#define INCLUDE_EMITTER
|
||||
#include "CpuInfo.h"
|
||||
|
||||
#include "FastBitMatrix.h"
|
||||
#include "ControlGraph.h"
|
||||
|
||||
class Pool;
|
||||
class VirtualRegisterManager;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// RegisterAllocator
|
||||
|
||||
class RegisterAllocator
|
||||
{
|
||||
private:
|
||||
Pool& pool; // RegisterAllocator's pool.
|
||||
ControlNode** dfsList; // List of nodes in a Depth First Search order.
|
||||
ControlNode** lndList; // List of nodes in a Loop Nesting Depth order.
|
||||
Uint32 nNodes; // Number of nodes in this graph.
|
||||
bool isAcyclic; // True if the graph is acyclic.
|
||||
VirtualRegisterManager& vrManager; // VirtualRegister's manager.
|
||||
MdEmitter& emitter; // The machine dependant instruction emitter.
|
||||
|
||||
FastBitMatrix interferenceMatrix; // The interference matrix. Each row is assign to a VirtualRegister.
|
||||
#ifdef DEBUG
|
||||
Uint32 interferenceMatrixSize; // The number of rows and cols in the interference matrix.
|
||||
#endif // DEBUG
|
||||
Uint32* interferenceDegrees; // The interference degree of all the VirtualRegisters in the graph.
|
||||
Uint32 interferenceDegreesSize; // The size of interferenceDegrees.
|
||||
|
||||
FastBitSet tempBitSet; // Temporary bitset (one time allocation).
|
||||
|
||||
|
||||
// Annotate the phi nodes.
|
||||
void annotatePhiNodes();
|
||||
// Get the liveness information and build the interference graph.
|
||||
void buildInterferenceGraph();
|
||||
// Coalesce the VirtualRegisters source to dest if it is possible.
|
||||
bool coalesceRegistersIfPossible(VirtualRegister& sourceRegister, VirtualRegister& destRegister);
|
||||
// Remove uneeded compy instructions (when the source and destination don not interfere);
|
||||
void removeUneededCopyInstructions();
|
||||
// Replace the remaining phi nodes by their equivalent instruction (Copy, Load, Store).
|
||||
bool replacePhiNodesByCopyInstructions();
|
||||
// Get the spilling cost for each VirtualRegister.
|
||||
void calculateSpillCosts();
|
||||
|
||||
#ifdef DEBUG
|
||||
// Check if the coalescing didn't corrupt the interferenceMatrix.
|
||||
void checkCoalescingValidity();
|
||||
#endif // DEBUG
|
||||
|
||||
public:
|
||||
inline RegisterAllocator(Pool& pool, ControlGraph& graph, VirtualRegisterManager& vrManager, MdEmitter& emitter);
|
||||
|
||||
void allocateRegisters();
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Inlines
|
||||
|
||||
inline RegisterAllocator::RegisterAllocator(Pool& pool, ControlGraph& graph, VirtualRegisterManager& vrManager, MdEmitter& emitter) :
|
||||
pool(pool), vrManager(vrManager), emitter(emitter), interferenceDegreesSize(0)
|
||||
{
|
||||
dfsList = graph.dfsList;
|
||||
lndList = graph.lndList;
|
||||
nNodes = graph.nNodes;
|
||||
isAcyclic = !graph.hasBackEdges;
|
||||
}
|
||||
|
||||
#endif // _REGISTER_ALLOCATOR_H_
|
|
@ -1,240 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#include "Fundamentals.h"
|
||||
#include "VirtualRegister.h"
|
||||
#include "FastBitMatrix.h"
|
||||
#include "FastBitSet.h"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// VirtualRegister
|
||||
|
||||
#ifdef DEBUG_LOG
|
||||
//
|
||||
// Print this VirtualRegister.
|
||||
//
|
||||
void VirtualRegister::printPretty(FILE* f) const
|
||||
{
|
||||
virtualRegisterClasses[kind]->printPretty(f);
|
||||
fprintf(f, "%d: ", index);
|
||||
|
||||
if (isPreColored())
|
||||
fprintf(f, "preColor = %d ", getPreColor());
|
||||
if (isColored())
|
||||
fprintf(f, "color = %d ", getColor());
|
||||
else
|
||||
fprintf(f, "not yet colored ");
|
||||
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
#endif // DEBUG_LOG
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// VirtualRegisterManager
|
||||
|
||||
static BlocksHeader<VirtualRegisterHandle> nullVirtualRegisterHandlesHeader = {0, 0, {NULL}};
|
||||
static BlocksHeader<VirtualRegister> nullVirtualRegistersHeader = {0, 0, {NULL}};
|
||||
|
||||
//
|
||||
// Create a new VirtualRegisterManager.
|
||||
//
|
||||
VirtualRegisterManager::VirtualRegisterManager(Pool& pool) :
|
||||
pool(pool), machineRegisters(pool, NUMBER_OF_REGISTERS, NUMBER_OF_REGISTERS)
|
||||
{
|
||||
handlesHeader = nullVirtualRegisterHandlesHeader.allocateAnotherBlock(pool);
|
||||
registersHeader = nullVirtualRegistersHeader.allocateAnotherBlock(pool);
|
||||
|
||||
indexes = new(pool) FastBitSet(pool, registersHeader->numberOfElementsInABlock);
|
||||
firstFree = 0;
|
||||
biggestUsed = -1;
|
||||
|
||||
DEBUG_ONLY(lock = false);
|
||||
}
|
||||
|
||||
inline void *operator new(size_t, VirtualRegister* ptr) {return ptr;}
|
||||
|
||||
//
|
||||
// Allocate a new VirtualRegister of kind 'kind'.
|
||||
//
|
||||
VirtualRegister& VirtualRegisterManager::newVirtualRegister(VirtualRegisterKind kind)
|
||||
{
|
||||
// If we are lock, no new VirtualRegister can be created.
|
||||
PR_ASSERT(!lock);
|
||||
|
||||
// Get a new VirtualRegister.
|
||||
Int32 registerIndex = firstFree;
|
||||
indexes->set(registerIndex);
|
||||
firstFree = indexes->nextZero(firstFree);
|
||||
|
||||
if (firstFree == -1 || registersHeader->getBlockNumber(registerIndex) >= registersHeader->nBlocks) {
|
||||
registersHeader = registersHeader->allocateAnotherBlock(pool);
|
||||
FastBitSet& newIndexes = *new(pool) FastBitSet(pool, registersHeader->nBlocks * registersHeader->numberOfElementsInABlock);
|
||||
newIndexes = *indexes;
|
||||
indexes = &newIndexes;
|
||||
firstFree = indexes->nextZero(registerIndex);
|
||||
}
|
||||
if (Uint32(registerIndex) == registersHeader->next)
|
||||
registersHeader->next++;
|
||||
|
||||
if (registerIndex > biggestUsed)
|
||||
biggestUsed = registerIndex;
|
||||
|
||||
// Get a new handle.
|
||||
Uint32 handleIndex = handlesHeader->next++;
|
||||
if (handlesHeader->getBlockNumber(handleIndex) >= handlesHeader->nBlocks)
|
||||
handlesHeader = handlesHeader->allocateAnotherBlock(pool);
|
||||
|
||||
VirtualRegisterHandle* handle = handlesHeader->getElementPtr(handleIndex);
|
||||
|
||||
VirtualRegister& vReg = *new(registersHeader->getElementPtr(registerIndex)) VirtualRegister(handle, registerIndex, kind);
|
||||
|
||||
handle->ptr = &vReg;
|
||||
handle->next = handle;
|
||||
|
||||
return vReg;
|
||||
}
|
||||
|
||||
//
|
||||
// Coalesce the VirtualRegister at index from with the VirtualRegister at index to.
|
||||
//
|
||||
void VirtualRegisterManager::coalesceVirtualRegisters(VirtualRegisterIndex from, VirtualRegisterIndex to)
|
||||
{
|
||||
// When we coalesce the VirtualRegister 'from' to the VirtualRegister 'to' we must
|
||||
// update all from's handle to point to. 'from' has an unique handle index, but this
|
||||
// handle is chain to all the handle also pointing it.
|
||||
|
||||
VirtualRegister* toVR = &getVirtualRegister(to);
|
||||
|
||||
VirtualRegisterHandle* beginOfToChain = toVR->getHandle();
|
||||
VirtualRegisterHandle* endOfToChain = beginOfToChain;
|
||||
|
||||
// Get the end of to's handle chain.
|
||||
while (endOfToChain->next != beginOfToChain)
|
||||
endOfToChain = endOfToChain->next;
|
||||
|
||||
VirtualRegister* fromVR = &getVirtualRegister(from);
|
||||
VirtualRegisterHandle* beginOfFromChain = fromVR->getHandle();
|
||||
VirtualRegisterHandle* endOfFromChain = beginOfFromChain;
|
||||
|
||||
// For each from's handle update the pointer.
|
||||
while (true) {
|
||||
endOfFromChain->ptr = toVR;
|
||||
|
||||
if (endOfFromChain->next == beginOfFromChain)
|
||||
break;
|
||||
|
||||
endOfFromChain = endOfFromChain->next;
|
||||
}
|
||||
|
||||
// Merge the chains.
|
||||
endOfToChain->next = beginOfFromChain;
|
||||
endOfFromChain->next = beginOfToChain;
|
||||
|
||||
// Free the from register.
|
||||
indexes->clear(from);
|
||||
if (from < firstFree)
|
||||
firstFree = from;
|
||||
|
||||
if (from == biggestUsed)
|
||||
biggestUsed = indexes->previousOne(from);
|
||||
|
||||
if (fromVR->isPreColored())
|
||||
machineRegisters.clear(fromVR->getPreColor(), fromVR->index);
|
||||
}
|
||||
|
||||
//
|
||||
// PreColor the VirtualRegister at index with color.
|
||||
//
|
||||
void VirtualRegisterManager::preColorVirtualRegister(VirtualRegisterIndex index, VirtualRegisterColor color)
|
||||
{
|
||||
machineRegisters.set(color, index);
|
||||
getVirtualRegister(index).setPreColor(color);
|
||||
}
|
||||
|
||||
//
|
||||
// Return a Matrix of valid interferences.
|
||||
//
|
||||
FastBitMatrix& VirtualRegisterManager::getValidInterferencesMatrix() const
|
||||
{
|
||||
const Uint32 matrixSize = getSize();
|
||||
FastBitMatrix& matrix = *new(pool) FastBitMatrix(pool, matrixSize, matrixSize);
|
||||
FastBitSet* classesIndex = new FastBitSet[nVirtualRegisterKind](pool, matrixSize);
|
||||
|
||||
for (VirtualRegisterIndex i = first(); !done(i); i = advance(i))
|
||||
classesIndex[getVirtualRegister(i).kind].set(i);
|
||||
|
||||
for (VirtualRegisterIndex j = first(); !done(j); j = advance(j))
|
||||
matrix.copyRows(classesIndex[getVirtualRegister(j).kind], j);
|
||||
|
||||
return matrix;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_LOG
|
||||
//
|
||||
// Print all the VirtualRegisters in this manager.
|
||||
//
|
||||
void VirtualRegisterManager::printPretty(FILE* f) const
|
||||
{
|
||||
fprintf(f, "----- VirtualRegisters -----\n");
|
||||
for (VirtualRegisterIndex i = first(); !done(i); i = advance(i))
|
||||
getVirtualRegister(i).printPretty(f);
|
||||
|
||||
fprintf(f, "----- MachineRegisters -----\n");
|
||||
for (Uint32 j = 0; j < NUMBER_OF_REGISTERS; j++) {
|
||||
FastBitSet preColoredRegisters(machineRegisters.getRowBits(j), NUMBER_OF_REGISTERS);
|
||||
if (!preColoredRegisters.empty()) {
|
||||
fprintf(f, "preColored to %d: ", j);
|
||||
preColoredRegisters.printPrettyOnes(f);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(f, "----------------------------\n");
|
||||
}
|
||||
#endif // DEBUG_LOG
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// VirtualRegisterClass
|
||||
|
||||
static IntegerRegisterClass integerRegister;
|
||||
static FloatingPointRegisterClass floatingPointRegister;
|
||||
static MemoryRegisterClass memoryRegister;
|
||||
|
||||
const VirtualRegisterClass* virtualRegisterClasses[nVirtualRegisterKind] =
|
||||
{
|
||||
NULL, // InvalidRegisterKind
|
||||
&integerRegister,
|
||||
&floatingPointRegister,
|
||||
NULL, // FixedPointRegister
|
||||
&memoryRegister,
|
||||
NULL, // StackSlotRegister
|
||||
NULL, // MemoryArgumentRegister
|
||||
};
|
||||
|
||||
//
|
||||
// Return the kind of register for the given color.
|
||||
//
|
||||
VirtualRegisterKind VirtualRegisterClass::getKind(VirtualRegisterColor color)
|
||||
{
|
||||
for (Uint32 i = 0; i < nVirtualRegisterKind; i++)
|
||||
if (virtualRegisterClasses[i] != NULL) {
|
||||
const VirtualRegisterClass& vrClass = *virtualRegisterClasses[i];
|
||||
if (color >= vrClass.getMinColor() && color <= vrClass.getMaxColor())
|
||||
return vrClass.kind;
|
||||
}
|
||||
return InvalidRegisterKind;
|
||||
}
|
|
@ -1,352 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _VIRTUAL_REGISTER_H_
|
||||
#define _VIRTUAL_REGISTER_H_
|
||||
|
||||
#include "Fundamentals.h"
|
||||
#include "FastBitMatrix.h"
|
||||
#include "FastBitSet.h"
|
||||
|
||||
class Instruction;
|
||||
class Pool;
|
||||
|
||||
enum VirtualRegisterKind
|
||||
{
|
||||
InvalidRegisterKind,
|
||||
IntegerRegister,
|
||||
FloatingPointRegister,
|
||||
FixedPointRegister,
|
||||
MemoryRegister,
|
||||
StackSlotRegister,
|
||||
MemoryArgumentRegister,
|
||||
};
|
||||
const nVirtualRegisterKind = MemoryArgumentRegister + 1;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// VirtualRegister
|
||||
|
||||
// A VirtualRegisterIndex is an index to the VirtualRegisterManager table
|
||||
// of handles. It is an invalid index if its value is 'invalidRegisterIndex'.
|
||||
typedef Int32 VirtualRegisterIndex;
|
||||
typedef Uint8 VirtualRegisterColor;
|
||||
|
||||
const VirtualRegisterIndex invalidRegisterIndex = -1; // An invalid register index.
|
||||
const VirtualRegisterColor invalidRegisterColor = 255; // An invalid register color.
|
||||
|
||||
struct VirtualRegisterHandle;
|
||||
|
||||
const Flt32 copyCost = 1.;
|
||||
const Flt32 loadCost = 2.;
|
||||
const Flt32 storeCost = 2.;
|
||||
|
||||
class VirtualRegister
|
||||
{
|
||||
public:
|
||||
|
||||
VirtualRegisterIndex index; // This VirtualRegister's index.
|
||||
const VirtualRegisterKind kind; // This VirtualRegister kind (i.e. IntegerRegister, FloatingPointRegister ...).
|
||||
|
||||
struct SpillCost
|
||||
{
|
||||
Flt32 copyCosts;
|
||||
Flt32 loadOrStoreCosts;
|
||||
} spillCosts;
|
||||
|
||||
private:
|
||||
|
||||
Instruction* definingInstruction; // The instruction defining this register.
|
||||
VirtualRegisterHandle* handle; // This VirtualRegister's handle.
|
||||
|
||||
struct
|
||||
{
|
||||
VirtualRegisterColor color; // Register's color
|
||||
VirtualRegisterColor preColor; // PreColor or 255 if it is not precolored.
|
||||
} colorInfo;
|
||||
|
||||
private:
|
||||
|
||||
VirtualRegister(const VirtualRegister&); // No copy constructor.
|
||||
void operator = (const VirtualRegister&); // No copy operator.
|
||||
|
||||
public:
|
||||
|
||||
// Create a new VirtualRegister
|
||||
inline VirtualRegister(VirtualRegisterHandle* handle, VirtualRegisterIndex index, VirtualRegisterKind kind);
|
||||
|
||||
// Set the defining instruction (for code generation).
|
||||
void setDefiningInstruction(Instruction& instruction) {definingInstruction = &instruction;}
|
||||
// Get the defining instruction (for code generation).
|
||||
Instruction* getDefiningInstruction() {return definingInstruction;}
|
||||
|
||||
//
|
||||
// Helpers.
|
||||
//
|
||||
|
||||
// Get this VirtualRegister's handle.
|
||||
VirtualRegisterHandle* getHandle() {return handle;}
|
||||
|
||||
// Set the Register's color.
|
||||
void setColor(VirtualRegisterColor color) {colorInfo.color = color;}
|
||||
// Set the preColor (by setting the preColor this register becomes a preColored register).
|
||||
void setPreColor(VirtualRegisterColor color) {colorInfo.preColor = color;}
|
||||
// Return true is this register has been succesfully colored.
|
||||
bool isColored() const {return colorInfo.color != invalidRegisterColor;}
|
||||
// Return true is this register is preColored. (If this register is not colored then return invalidRegisterColor).
|
||||
bool isPreColored() const {return colorInfo.preColor != invalidRegisterColor;}
|
||||
// Return this register's color.
|
||||
VirtualRegisterColor getColor() const {return colorInfo.color;}
|
||||
// Return this register's preColor. (If this register is not preColored then return invalidRegisterColor).
|
||||
VirtualRegisterColor getPreColor() const {return colorInfo.preColor;}
|
||||
|
||||
#ifdef DEBUG_LOG
|
||||
// Print the register in the file f.
|
||||
void printPretty(FILE* f) const;
|
||||
#endif // DEBUG_LOG
|
||||
};
|
||||
|
||||
struct VirtualRegisterHandle
|
||||
{
|
||||
VirtualRegister* ptr;
|
||||
VirtualRegisterHandle* next;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// VirtualRegisterManager
|
||||
|
||||
template<class Class>
|
||||
struct BlocksHeader
|
||||
{
|
||||
const Uint32 numberOfElementsInABlock = 128; // Number of elements in a block.
|
||||
|
||||
Uint32 nBlocks; // Number of available blocks.
|
||||
Uint32 next; // Next available element.
|
||||
Class* blocks[1]; // Array of block pointers.
|
||||
|
||||
// Allocate another block and return the new this.
|
||||
BlocksHeader<Class>* allocateAnotherBlock(Pool& pool);
|
||||
// Get the block number for this element index.
|
||||
static Uint32 getBlockNumber(Uint32 index) {return index >> 7;}
|
||||
// Get the element's pointer at index.
|
||||
Class* getElementPtr(Uint32 index);
|
||||
};
|
||||
|
||||
#include "CpuInfo.h"
|
||||
|
||||
class VirtualRegisterManager
|
||||
{
|
||||
private:
|
||||
|
||||
Pool& pool; // This VirtualRegisterManager's allocation pool.
|
||||
BlocksHeader<VirtualRegisterHandle>* handlesHeader; // VirtualRegisterHandles blocks' header.
|
||||
BlocksHeader<VirtualRegister>* registersHeader; // VirtualRegisters blocks' header.
|
||||
FastBitMatrix machineRegisters; // Matrix of machine registers.
|
||||
#ifdef DEBUG
|
||||
bool lock; // If lock is true then no new register can be created.
|
||||
#endif // DEBUG
|
||||
|
||||
FastBitSet* indexes; // Register indexes currently used.
|
||||
|
||||
Int32 firstFree; // First free register index.
|
||||
Int32 biggestUsed; // Biggest used register index.
|
||||
|
||||
VirtualRegisterManager(const VirtualRegisterManager&); // No copy constructor.
|
||||
void operator = (const VirtualRegisterManager&); // No copy operator.
|
||||
|
||||
public:
|
||||
// Create a new VirtualRegisterManager.
|
||||
VirtualRegisterManager(Pool& pool);
|
||||
|
||||
// Return the maximum number of VirtualRegisters currently in use.
|
||||
Uint32 getSize() const {return biggestUsed + 1;}
|
||||
#ifdef DEBUG
|
||||
// Lock the manager. When it is locked no one can create new VirtualRegisters.
|
||||
void lockAllocation() {PR_ASSERT(!lock); lock = true;}
|
||||
// Unlock the manager.
|
||||
void unlockAllocation() {PR_ASSERT(lock); lock = false;}
|
||||
#endif // DEBUG
|
||||
|
||||
// Return the reference to the VirtualRegister at index.
|
||||
inline VirtualRegister& getVirtualRegister(VirtualRegisterIndex index) const;
|
||||
|
||||
// Allocate a new VirtualRegister of kind 'kind'.
|
||||
VirtualRegister& newVirtualRegister(VirtualRegisterKind kind);
|
||||
// Coalesce the VirtualRegister at index from with the VirtualRegister at index to.
|
||||
void coalesceVirtualRegisters(VirtualRegisterIndex from, VirtualRegisterIndex to);
|
||||
// PreColor the VirtualRegister at index with color.
|
||||
void preColorVirtualRegister(VirtualRegisterIndex index, VirtualRegisterColor color);
|
||||
|
||||
// Return the first valid VirtualRegisterIndex.
|
||||
VirtualRegisterIndex first() const {return advance(-1);}
|
||||
// Return the next valid VirtualRegister after index.
|
||||
inline VirtualRegisterIndex advance(VirtualRegisterIndex index) const {return indexes->nextOne(index);}
|
||||
// Return true is this index is outside the array of handles.
|
||||
bool done(VirtualRegisterIndex index) const {return (index < 0 || index > biggestUsed);}
|
||||
|
||||
// Return the matrix of valid interferences (i.e. a IntegerRegister interferes only with others IntegerRegisters).
|
||||
FastBitMatrix& getValidInterferencesMatrix() const;
|
||||
|
||||
#ifdef DEBUG_LOG
|
||||
// Print all the VirtualRegisters in this manager.
|
||||
void printPretty(FILE* f) const;
|
||||
#endif // DEBUG_LOG
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// VirtualRegisterClass(es)
|
||||
|
||||
class VirtualRegisterClass
|
||||
{
|
||||
private:
|
||||
|
||||
VirtualRegisterClass(const VirtualRegisterClass&); // No copy constructor.
|
||||
void operator = (const VirtualRegisterClass&); // No copy operator.
|
||||
|
||||
public:
|
||||
|
||||
VirtualRegisterKind kind; // This class kind.
|
||||
|
||||
VirtualRegisterClass(VirtualRegisterKind kind) : kind(kind) {}
|
||||
|
||||
// Return the VirtualRegisterKind this class can spill to.
|
||||
virtual VirtualRegisterKind willSpillTo() const {return InvalidRegisterKind;}
|
||||
// Return the smallest color index this register class can take.
|
||||
virtual Uint8 getMinColor() const = 0;
|
||||
// Return the bigest color index this register class can take.
|
||||
virtual Uint8 getMaxColor() const = 0;
|
||||
// Return the number of color available for this class.
|
||||
Uint8 getNumberOfColor() const {return getMaxColor() - getMinColor() + 1;}
|
||||
// Return true if this class canSpill;
|
||||
bool canSpill() const {return willSpillTo() != InvalidRegisterKind;}
|
||||
|
||||
// Return the kind of register for the given color.
|
||||
static VirtualRegisterKind getKind(VirtualRegisterColor color);
|
||||
#ifdef DEBUG_LOG
|
||||
// Print the class string for the VirtualRegisterClass.
|
||||
virtual void printPretty(FILE* f) const = 0;
|
||||
#endif // DEBUG_LOG
|
||||
};
|
||||
|
||||
// virtualRegisterClasses is an array of VirtualRegisterClass instances.
|
||||
// Each instance is a different class of registers (i.e. Integer, FP, memory).
|
||||
extern const VirtualRegisterClass* virtualRegisterClasses[];
|
||||
|
||||
//
|
||||
// An IntegerRegister's possible colors are [FIRST_GREGISTER ... LAST_GREGISTER].
|
||||
// It can spill in a MemoryRegister.
|
||||
//
|
||||
class IntegerRegisterClass : public VirtualRegisterClass
|
||||
{
|
||||
public:
|
||||
IntegerRegisterClass() : VirtualRegisterClass(IntegerRegister) {}
|
||||
|
||||
virtual VirtualRegisterKind willSpillTo() const {return MemoryRegister;}
|
||||
virtual Uint8 getMinColor() const {return FIRST_GREGISTER;}
|
||||
virtual Uint8 getMaxColor() const {return LAST_GREGISTER;}
|
||||
|
||||
#ifdef DEBUG_LOG
|
||||
virtual void printPretty(FILE* f) const {fprintf(f, "integer register ");}
|
||||
#endif // DEBUG_LOG
|
||||
};
|
||||
|
||||
//
|
||||
// A FloatingRegister's possible colors are [FIRST_FPREGISTER ... LAST_FPREGISTER].
|
||||
// It can spill in a MemoryRegister.
|
||||
//
|
||||
class FloatingPointRegisterClass : public VirtualRegisterClass
|
||||
{
|
||||
public:
|
||||
FloatingPointRegisterClass() : VirtualRegisterClass(FloatingPointRegister) {}
|
||||
|
||||
virtual VirtualRegisterKind willSpillTo() const {return MemoryRegister;}
|
||||
virtual Uint8 getMinColor() const {return FIRST_FPREGISTER;}
|
||||
virtual Uint8 getMaxColor() const {return LAST_FPREGISTER;}
|
||||
|
||||
#ifdef DEBUG_LOG
|
||||
virtual void printPretty(FILE* f) const {fprintf(f, "floating point register ");}
|
||||
#endif // DEBUG_LOG
|
||||
};
|
||||
|
||||
//
|
||||
// A MemoryRegister has an infinite color space. It cannot spill !
|
||||
//
|
||||
class MemoryRegisterClass : public VirtualRegisterClass
|
||||
{
|
||||
public:
|
||||
MemoryRegisterClass() : VirtualRegisterClass(MemoryRegister) {}
|
||||
|
||||
virtual Uint8 getMinColor() const {return 0;}
|
||||
virtual Uint8 getMaxColor() const {return ~0;} // Infinite space for a memory register.
|
||||
|
||||
#ifdef DEBUG_LOG
|
||||
virtual void printPretty(FILE* f) const {fprintf(f, "memory register ");}
|
||||
#endif // DEBUG_LOG
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Inlines
|
||||
|
||||
inline VirtualRegister& VirtualRegisterManager::getVirtualRegister(VirtualRegisterIndex index) const
|
||||
{
|
||||
PR_ASSERT(indexes->test(index));
|
||||
return *registersHeader->getElementPtr(index);
|
||||
}
|
||||
|
||||
inline VirtualRegister::VirtualRegister(VirtualRegisterHandle* handle, VirtualRegisterIndex index, VirtualRegisterKind kind) :
|
||||
index(index), kind(kind), definingInstruction(NULL), handle(handle)
|
||||
{
|
||||
setColor(invalidRegisterColor);
|
||||
setPreColor(invalidRegisterColor);
|
||||
}
|
||||
|
||||
//
|
||||
// Allocate another block and return the new this.
|
||||
//
|
||||
template<class Class>
|
||||
BlocksHeader<Class>* BlocksHeader<Class>::allocateAnotherBlock(Pool& pool)
|
||||
{
|
||||
// Get the number of 32bits words needed for this block. A block is composed by:
|
||||
// [BlockHeader] (nBlocks-1)*[pointers to block] numberOfElementsInABlock*[element Class].
|
||||
Uint32 blockSize = ((sizeof(BlocksHeader<Class>) + nBlocks * sizeof(Uint32) +
|
||||
(numberOfElementsInABlock * sizeof(Class))) + 3 & -4) >> 2;
|
||||
Uint32* ptr = new(pool) Uint32[blockSize];
|
||||
fill(ptr, &ptr[blockSize], 0);
|
||||
|
||||
BlocksHeader<Class>* newThis = static_cast<BlocksHeader<Class>*>(ptr);
|
||||
*newThis = *this;
|
||||
|
||||
if (nBlocks > 0)
|
||||
copy(&blocks[1], &blocks[nBlocks], &newThis->blocks[1]);
|
||||
|
||||
newThis->blocks[nBlocks] = static_cast<Class *>(&newThis->blocks[nBlocks + 1]);
|
||||
newThis->nBlocks++;
|
||||
|
||||
return newThis;
|
||||
}
|
||||
|
||||
//
|
||||
// Get the element's pointer at index.
|
||||
//
|
||||
template<class Class>
|
||||
Class* BlocksHeader<Class>::getElementPtr(Uint32 index)
|
||||
{
|
||||
PR_ASSERT((getBlockNumber(index) < nBlocks) && (index < next));
|
||||
return &(blocks[getBlockNumber(index)])[index & (numberOfElementsInABlock - 1)];
|
||||
}
|
||||
|
||||
#endif // _VIRTUAL_REGISTER_H_
|
Загрузка…
Ссылка в новой задаче