mirror of https://git.wuffs.org/MWCC
370 lines
12 KiB
C
370 lines
12 KiB
C
#include "compiler/InterferenceGraph.h"
|
|
#include "compiler/CError.h"
|
|
#include "compiler/CParser.h"
|
|
#include "compiler/BitVectors.h"
|
|
#include "compiler/Coloring.h"
|
|
#include "compiler/LiveInfo.h"
|
|
#include "compiler/PCode.h"
|
|
#include "compiler/PCodeListing.h"
|
|
#include "compiler/PCodeUtilities.h"
|
|
#include "compiler/Registers.h"
|
|
#include "compiler/RegisterInfo.h"
|
|
#include "compiler/CompilerTools.h"
|
|
|
|
IGNode **interferencegraph;
|
|
static UInt32 *interferencematrix;
|
|
Boolean coalesced_nregisters;
|
|
static SInt16 *coalesced;
|
|
|
|
static void makeinterfere(UInt32 a, UInt32 b) {
|
|
if (a < b)
|
|
bitvectorsetbit(((b * b) / 2) + a, interferencematrix);
|
|
else if (a > b)
|
|
bitvectorsetbit(((a * a) / 2) + b, interferencematrix);
|
|
}
|
|
|
|
int interferes(UInt32 a, UInt32 b) {
|
|
if (a < b)
|
|
return bitvectorgetbit(((b * b) / 2) + a, interferencematrix) > 0;
|
|
else if (a > b)
|
|
return bitvectorgetbit(((a * a) / 2) + b, interferencematrix) > 0;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
static void buildinterferencematrix(void) {
|
|
UInt32 regs; // r31
|
|
PCodeBlock *block; // r30
|
|
PCode *instr; // r29
|
|
UInt32 *vec; // r28
|
|
PCodeArg *op;
|
|
int reg;
|
|
UInt32 i;
|
|
UInt32 j;
|
|
|
|
regs = used_virtual_registers[coloring_class];
|
|
interferencematrix = oalloc(4 * ((((regs * regs) / 2) + 31) >> 5));
|
|
bitvectorinitialize(interferencematrix, (regs * regs) / 2, 0);
|
|
|
|
for (i = 0; i < 32; i++)
|
|
for (j = 0; j < 32; j++)
|
|
if (i != j)
|
|
makeinterfere(i, j);
|
|
|
|
vec = oalloc(4 * ((regs + 31) >> 5));
|
|
for (block = pcbasicblocks; block; block = block->nextBlock) {
|
|
bitvectorcopy(vec, liveinfo[block->blockIndex].out, regs);
|
|
for (instr = block->lastPCode; instr; instr = instr->prevPCode) {
|
|
for (op = instr->args, i = instr->argCount; i--; op++) {
|
|
if (PC_OP_IS_WRITE_ANY_REGISTER(op, coloring_class)) {
|
|
reg = op->data.reg.reg;
|
|
bitvectorclearbit(reg, vec);
|
|
for (j = 0; j < regs; j++) {
|
|
if (bitvectorgetbit(j, vec)) {
|
|
if (
|
|
(instr->flags & fIsMove) &&
|
|
PC_OP_IS_ANY_REGISTER(&instr->args[0], coloring_class) &&
|
|
instr->args[1].data.reg.reg == j
|
|
)
|
|
continue;
|
|
makeinterfere(reg, j);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for (op = instr->args, i = instr->argCount; i--; op++) {
|
|
if (PC_OP_IS_READ_ANY_REGISTER(op, coloring_class)) {
|
|
reg = op->data.reg.reg;
|
|
if (bitvectorgetbit(op->data.reg.reg, vec) == 0)
|
|
op->data.reg.effect |= Effect4;
|
|
bitvectorsetbit(reg, vec);
|
|
}
|
|
}
|
|
|
|
if (coloring_class == RegClass_GPR) {
|
|
if (PCODE_FLAG_SET_F(instr) & (fIsRead | fIsWrite | fPCodeFlag400000)) {
|
|
if (instr->args[1].data.reg.reg >= n_real_registers[coloring_class])
|
|
makeinterfere(0, instr->args[1].data.reg.reg);
|
|
if (PCODE_FLAG_SET_F(instr) & fUpdatesPtr)
|
|
makeinterfere(instr->args[0].data.reg.reg, instr->args[1].data.reg.reg);
|
|
} else {
|
|
switch (instr->op) {
|
|
case PC_DCBF:
|
|
case PC_DCBST:
|
|
case PC_DCBT:
|
|
case PC_DCBTST:
|
|
case PC_DCBZ:
|
|
case PC_DCBI:
|
|
case PC_ICBI:
|
|
case PC_DCCCI:
|
|
case PC_ICBT:
|
|
case PC_ICCCI:
|
|
case PC_ICREAD:
|
|
case PC_DCBA:
|
|
case PC_DST:
|
|
case PC_DSTT:
|
|
case PC_DSTST:
|
|
case PC_DSTSTT:
|
|
if (instr->args[0].data.reg.reg >= n_real_registers[coloring_class])
|
|
makeinterfere(0, instr->args[0].data.reg.reg);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (coloring_class == RegClass_GPR && (instr->flags & fIsCall)) {
|
|
i = branch_count_volatiles();
|
|
op = instr->args;
|
|
CError_ASSERT(219, instr->argCount != 0);
|
|
|
|
while (op->kind != PCOp_REGISTER || !(op->data.reg.effect & EffectWrite)) {
|
|
i++;
|
|
op++;
|
|
CError_ASSERT(226, i <= instr->argCount);
|
|
}
|
|
|
|
op = instr->args + i;
|
|
while (i < instr->argCount) {
|
|
if (op->kind == PCOp_REGISTER && op->arg == RegClass_GPR) {
|
|
for (j = 0; j < n_scratch_registers[coloring_class]; j++)
|
|
makeinterfere(op->data.reg.reg, scratch_registers[coloring_class][j]);
|
|
}
|
|
i++;
|
|
op++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static short coalesced_path(short id) {
|
|
while (id != coalesced[id])
|
|
id = coalesced[id];
|
|
return id;
|
|
}
|
|
|
|
static void coalescenodes(void) {
|
|
PCodeArg *op;
|
|
UInt32 regs;
|
|
PCodeBlock *block;
|
|
PCode *instr;
|
|
UInt32 i;
|
|
short path1;
|
|
short path2;
|
|
short node1;
|
|
short node2;
|
|
|
|
regs = used_virtual_registers[coloring_class];
|
|
coalesced = oalloc(sizeof(SInt16) * regs);
|
|
|
|
for (i = 0; i < regs; i++)
|
|
coalesced[i] = i;
|
|
|
|
for (block = pcbasicblocks; block; block = block->nextBlock) {
|
|
for (instr = block->firstPCode; instr; instr = instr->nextPCode) {
|
|
if ((instr->flags & fIsMove) && !(instr->flags & fSideEffects)) {
|
|
if (PCODE_FLAG_SET_F(instr) & fRecordBit) {
|
|
CError_FATAL(309);
|
|
continue;
|
|
}
|
|
|
|
if (instr->argCount > 2) {
|
|
if (instr->argCount != 3 || instr->args[2].kind != PCOp_PLACEHOLDEROPERAND) {
|
|
CError_FATAL(316);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (PC_OP_IS_ANY_REGISTER(&instr->args[0], coloring_class)) {
|
|
path1 = coalesced_path(instr->args[0].data.reg.reg);
|
|
path2 = coalesced_path(instr->args[1].data.reg.reg);
|
|
if (path1 == path2) {
|
|
deletepcode(instr);
|
|
continue;
|
|
}
|
|
|
|
if (!interferes(path1, path2)) {
|
|
if (path1 >= n_real_registers[coloring_class] && path2 >= n_real_registers[coloring_class]) {
|
|
if (path1 < first_fe_temporary_register[coloring_class])
|
|
continue;
|
|
if (path1 > last_temporary_register[coloring_class])
|
|
continue;
|
|
if (path2 < first_fe_temporary_register[coloring_class])
|
|
continue;
|
|
if (path2 > last_temporary_register[coloring_class])
|
|
continue;
|
|
}
|
|
|
|
node1 = (path2 < path1) ? path2 : path1;
|
|
node2 = (path2 > path1) ? path2 : path1;
|
|
|
|
if (coloring_class == RegClass_GPR && node2 == _CALLER_SP_)
|
|
continue;
|
|
|
|
coalesced[node2] = node1;
|
|
for (i = 0; i < regs; i++) {
|
|
if (interferes(node2, i))
|
|
makeinterfere(node1, i);
|
|
}
|
|
|
|
deletepcode(instr);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for (block = pcbasicblocks; block; block = block->nextBlock) {
|
|
for (instr = block->firstPCode; instr; instr = instr->nextPCode) {
|
|
op = instr->args;
|
|
i = instr->argCount;
|
|
while (i--) {
|
|
if (PC_OP_IS_ANY_REGISTER(op, coloring_class) && op->data.reg.reg != coalesced[op->data.reg.reg])
|
|
op->data.reg.reg = coalesced_path(op->data.reg.reg);
|
|
op++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void buildadjacencyvectors(void) {
|
|
IGNode *node;
|
|
UInt32 regs;
|
|
UInt32 i;
|
|
UInt32 counter;
|
|
short *array;
|
|
short *dest;
|
|
short *src;
|
|
UInt32 j;
|
|
|
|
regs = used_virtual_registers[coloring_class];
|
|
interferencegraph = oalloc(sizeof(IGNode *) * regs);
|
|
array = oalloc(sizeof(short) * regs);
|
|
|
|
for (i = 0; i < regs; i++) {
|
|
counter = 0;
|
|
for (j = 0; j < regs; j++) {
|
|
if (interferes(i, j))
|
|
array[counter++] = j;
|
|
}
|
|
|
|
node = interferencegraph[i] = oalloc(sizeof(IGNode) + sizeof(short) * (counter - 1));
|
|
memclrw(node, sizeof(IGNode) + sizeof(short) * (counter - 1));
|
|
|
|
node->x10 = i;
|
|
node->x14 = -1;
|
|
node->arraySize = counter;
|
|
node->x12 = counter;
|
|
|
|
dest = node->array;
|
|
src = array;
|
|
for (j = 0; j < counter; j++)
|
|
*(dest++) = *(src++);
|
|
|
|
if (i != coalesced[i]) {
|
|
node->flags |= fCoalesced;
|
|
j = coalesced_path(i);
|
|
interferencegraph[j]->flags |= fCoalescedInto;
|
|
node->x14 = j;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void eliminatedeadcode(void) {
|
|
UInt32 regs;
|
|
PCodeBlock *block;
|
|
PCode *instr;
|
|
UInt32 *vec;
|
|
UInt32 i;
|
|
PCodeArg *op;
|
|
|
|
regs = used_virtual_registers[coloring_class];
|
|
vec = oalloc(4 * ((regs + 31) >> 5));
|
|
|
|
for (block = pcbasicblocks; block; block = block->nextBlock) {
|
|
bitvectorcopy(vec, liveinfo[block->blockIndex].out, regs);
|
|
for (instr = block->lastPCode; instr; instr = instr->prevPCode) {
|
|
if (dead(instr, coloring_class, vec)) {
|
|
deletepcode(instr);
|
|
continue;
|
|
}
|
|
|
|
op = instr->args;
|
|
i = instr->argCount;
|
|
while (i--) {
|
|
if (PC_OP_IS_WRITE_ANY_REGISTER(op, coloring_class))
|
|
bitvectorclearbit(op->data.reg.reg, vec);
|
|
op++;
|
|
}
|
|
|
|
op = instr->args;
|
|
i = instr->argCount;
|
|
while (i--) {
|
|
if (PC_OP_IS_READ_ANY_REGISTER(op, coloring_class)) {
|
|
int reg = op->data.reg.reg;
|
|
if (!bitvectorgetbit(reg, vec))
|
|
op->data.reg.effect |= Effect4;
|
|
bitvectorsetbit(reg, vec);
|
|
}
|
|
op++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void findrematerializations(void) {
|
|
UInt32 regs;
|
|
UInt32 i;
|
|
PCodeBlock *block;
|
|
PCode *instr;
|
|
PCodeArg *op;
|
|
IGNode *node;
|
|
|
|
regs = used_virtual_registers[coloring_class];
|
|
|
|
for (block = pcbasicblocks; block; block = block->nextBlock) {
|
|
for (instr = block->lastPCode; instr; instr = instr->prevPCode) {
|
|
op = instr->args;
|
|
i = instr->argCount;
|
|
while (i--) {
|
|
if (
|
|
PC_OP_IS_WRITE_ANY_REGISTER(op, coloring_class) &&
|
|
op->data.reg.reg >= n_real_registers[coloring_class] &&
|
|
!(interferencegraph[op->data.reg.reg]->flags & (fPairLow | fPairHigh)) &&
|
|
!(interferencegraph[op->data.reg.reg]->flags & fIGNode40)
|
|
)
|
|
{
|
|
node = interferencegraph[op->data.reg.reg];
|
|
if (!node->instr8) {
|
|
node->instr8 = instr;
|
|
} else {
|
|
node->instr8 = NULL;
|
|
node->flags |= fIGNode40;
|
|
}
|
|
}
|
|
op++;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < regs; i++) {
|
|
node = interferencegraph[i];
|
|
if (node->instr8 && !is_location_independent(node->instr8))
|
|
node->instr8 = NULL;
|
|
}
|
|
}
|
|
|
|
void buildinterferencegraph(Object *proc) {
|
|
int regs = used_virtual_registers[coloring_class];
|
|
|
|
computelivevariables(proc);
|
|
eliminatedeadcode();
|
|
buildinterferencematrix();
|
|
if (copts.debuglisting)
|
|
pclistinterferences(register_class_format[coloring_class], regs);
|
|
coalescenodes();
|
|
buildadjacencyvectors();
|
|
findrematerializations();
|
|
}
|