mirror of https://git.wuffs.org/MWCC
472 lines
16 KiB
C
472 lines
16 KiB
C
#include "compiler/CopyPropagation.h"
|
|
#include "compiler/CMangler.h"
|
|
#include "compiler/CParser.h"
|
|
#include "compiler/BitVectors.h"
|
|
#include "compiler/CompilerTools.h"
|
|
#include "compiler/PCode.h"
|
|
#include "compiler/PCodeListing.h"
|
|
#include "compiler/RegisterInfo.h"
|
|
#include "compiler/UseDefChains.h"
|
|
|
|
int propagatedcopies;
|
|
int propagated_instructions;
|
|
int recursive_propagation;
|
|
int number_of_candidates;
|
|
Candidate *Candidates;
|
|
PropInfo *propinfo;
|
|
int *ncandidatesinblock;
|
|
int *firstcandidateinblock;
|
|
static int moreaggressiveoptimization;
|
|
static PropagateAndFinishFunc propagateandfinish;
|
|
static PropagatesToUseFunc propagatestouse;
|
|
static IsCandidateFunc is_candidate;
|
|
|
|
static void precomputecanidatecounts(void) {
|
|
PCodeBlock *block;
|
|
PCode *pcode;
|
|
int count;
|
|
|
|
ncandidatesinblock = oalloc(sizeof(int) * pcblockcount);
|
|
firstcandidateinblock = oalloc(sizeof(int) * pcblockcount);
|
|
number_of_candidates = 0;
|
|
|
|
for (block = pcbasicblocks; block; block = block->nextBlock) {
|
|
firstcandidateinblock[block->blockIndex] = number_of_candidates;
|
|
|
|
count = 0;
|
|
for (pcode = block->firstPCode; pcode; pcode = pcode->nextPCode) {
|
|
if (is_candidate(pcode)) {
|
|
number_of_candidates++;
|
|
count++;
|
|
}
|
|
}
|
|
ncandidatesinblock[block->blockIndex] = count;
|
|
}
|
|
}
|
|
|
|
static void computecandidatelist(void) {
|
|
RegUseOrDef *list; // r23
|
|
PCodeBlock *block; // r22
|
|
PCode *pcode; // r21
|
|
Candidate *candidate; // r20
|
|
UInt32 *vec; // r19
|
|
int reg;
|
|
RegUseOrDef *newlist;
|
|
UseOrDef *def;
|
|
UseOrDef *use;
|
|
int defID;
|
|
int useID;
|
|
|
|
Candidates = oalloc(sizeof(Candidate) * number_of_candidates);
|
|
vec = oalloc(4 * ((number_of_Uses + 31) >> 5));
|
|
|
|
for (block = pcbasicblocks; block; block = block->nextBlock) {
|
|
if (ncandidatesinblock[block->blockIndex]) {
|
|
bitvectorcopy(vec, usedefinfo[block->blockIndex].usevec1C, number_of_Uses);
|
|
candidate = &Candidates[firstcandidateinblock[block->blockIndex] + ncandidatesinblock[block->blockIndex] - 1];
|
|
for (pcode = block->lastPCode; pcode; pcode = pcode->prevPCode) {
|
|
if (!(pcode->flags & fPCodeFlag1) && pcode->argCount) {
|
|
if (is_candidate(pcode)) {
|
|
reg = pcode->args[0].data.reg.reg;
|
|
candidate->pcode = pcode;
|
|
candidate->list = NULL;
|
|
|
|
for (list = reg_Uses[pcode->args[0].arg][reg]; list; list = list->next) {
|
|
if (bitvectorgetbit(list->id, vec)) {
|
|
newlist = oalloc(sizeof(RegUseOrDef));
|
|
newlist->id = list->id;
|
|
newlist->next = candidate->list;
|
|
candidate->list = newlist;
|
|
}
|
|
}
|
|
|
|
if ((pcode->flags & fPCodeFlag2 | fPCodeFlag4) && (pcode->flags & fPCodeFlag2000000)) {
|
|
for (list = reg_Uses[pcode->args[1].arg][pcode->args[1].data.reg.reg]; list; list = list->next) {
|
|
if (bitvectorgetbit(list->id, vec)) {
|
|
newlist = oalloc(sizeof(RegUseOrDef));
|
|
newlist->id = list->id;
|
|
newlist->next = candidate->list;
|
|
candidate->list = newlist;
|
|
}
|
|
}
|
|
}
|
|
|
|
candidate--;
|
|
}
|
|
|
|
for (def = &Defs[defID = pcode->defID]; defID < number_of_Defs && def->pcode == pcode; def++, defID++) {
|
|
if (def->v.kind == PCOp_REGISTER) {
|
|
for (list = reg_Uses[def->v.arg][def->v.u.reg]; list; list = list->next)
|
|
bitvectorclearbit(list->id, vec);
|
|
}
|
|
}
|
|
for (use = &Uses[useID = pcode->useID]; useID < number_of_Uses && use->pcode == pcode; use++, useID++) {
|
|
if (use->v.kind == PCOp_REGISTER)
|
|
bitvectorsetbit(useID, vec);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void allocatepropinfo(void) {
|
|
PropInfo *info;
|
|
int i;
|
|
|
|
propinfo = oalloc(sizeof(PropInfo) * pcblockcount);
|
|
for (i = 0, info = propinfo; i < pcblockcount; i++, info++) {
|
|
info->vec0 = oalloc(4 * ((number_of_candidates + 31) >> 5));
|
|
info->vec4 = oalloc(4 * ((number_of_candidates + 31) >> 5));
|
|
info->vec8 = oalloc(4 * ((number_of_candidates + 31) >> 5));
|
|
info->vecC = oalloc(4 * ((number_of_candidates + 31) >> 5));
|
|
}
|
|
}
|
|
|
|
static void computelocalpropinfo(Boolean flag) {
|
|
PropInfo *info;
|
|
PCode *pcode;
|
|
PCodeBlock *block;
|
|
UInt32 *vec0;
|
|
UInt32 *vec4;
|
|
int index;
|
|
PCodeArg *op;
|
|
PCodeArg *candOp;
|
|
int i;
|
|
int j;
|
|
int cndi;
|
|
Candidate *candidate;
|
|
|
|
for (block = pcbasicblocks; block; block = block->nextBlock) {
|
|
info = &propinfo[block->blockIndex];
|
|
vec0 = info->vec0;
|
|
vec4 = info->vec4;
|
|
bitvectorinitialize(vec0, number_of_candidates, 0);
|
|
bitvectorinitialize(vec4, number_of_candidates, 0);
|
|
index = firstcandidateinblock[block->blockIndex];
|
|
|
|
if (flag) {
|
|
for (pcode = block->firstPCode; pcode; pcode = pcode->nextPCode) {
|
|
if (!(pcode->flags & fPCodeFlag1) && pcode->argCount) {
|
|
i = pcode->argCount;
|
|
op = pcode->args;
|
|
while (i--) {
|
|
if (op->kind == PCOp_REGISTER && op->arg == RegClass_GPR && (op->data.reg.effect & EffectWrite)) {
|
|
for (cndi = 0, candidate = Candidates; cndi < number_of_candidates; cndi++, candidate++) {
|
|
for (j = 0; j < candidate->pcode->argCount; j++) {
|
|
candOp = candidate->pcode->args + j;
|
|
if (candOp->kind == PCOp_REGISTER && candOp->arg == RegClass_GPR && candOp->data.reg.reg == op->data.reg.reg) {
|
|
if (candidate->pcode->block == block)
|
|
bitvectorclearbit(cndi, vec0);
|
|
else
|
|
bitvectorsetbit(cndi, vec4);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
op++;
|
|
}
|
|
|
|
if (is_candidate(pcode)) {
|
|
bitvectorsetbit(index, vec0);
|
|
index++;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
for (pcode = block->firstPCode; pcode; pcode = pcode->nextPCode) {
|
|
if (!(pcode->flags & fPCodeFlag1) && pcode->argCount) {
|
|
i = pcode->argCount;
|
|
op = pcode->args;
|
|
while (i--) {
|
|
if (op->kind == PCOp_REGISTER && (op->data.reg.effect & EffectWrite)) {
|
|
for (cndi = 0, candidate = Candidates; cndi < number_of_candidates; cndi++, candidate++) {
|
|
for (j = 0; j < candidate->pcode->argCount; j++) {
|
|
candOp = candidate->pcode->args + j;
|
|
if (candOp->kind == PCOp_REGISTER && candOp->arg == op->arg) {
|
|
if (candOp->data.reg.reg == op->data.reg.reg) {
|
|
if (candidate->pcode->block == block)
|
|
bitvectorclearbit(cndi, vec0);
|
|
else
|
|
bitvectorsetbit(cndi, vec4);
|
|
break;
|
|
}
|
|
} else {
|
|
if (j == 0)
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
op++;
|
|
}
|
|
|
|
if (is_candidate(pcode)) {
|
|
bitvectorsetbit(index, vec0);
|
|
index++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void computeglobalpropinfo(void) {
|
|
PropInfo *info;
|
|
PCodeBlock *block;
|
|
int bitvecsize;
|
|
UInt32 *vec0;
|
|
UInt32 *vec4;
|
|
UInt32 *vec8;
|
|
UInt32 *vecC;
|
|
int i;
|
|
int blockIndex;
|
|
int flag;
|
|
PCLink *preds;
|
|
UInt32 val;
|
|
|
|
bitvecsize = (number_of_candidates + 31) >> 5;
|
|
flag = 1;
|
|
info = &propinfo[pcbasicblocks->blockIndex];
|
|
bitvectorinitialize(info->vec8, number_of_candidates, 0);
|
|
bitvectorcopy(info->vecC, info->vec0, number_of_candidates);
|
|
|
|
for (block = pcbasicblocks->nextBlock; block; block = block->nextBlock) {
|
|
info = &propinfo[block->blockIndex];
|
|
vecC = info->vecC;
|
|
vec4 = info->vec4;
|
|
for (i = 0; i < bitvecsize; vecC++, vec4++, i++)
|
|
*vecC = ~*vec4;
|
|
}
|
|
|
|
while (flag) {
|
|
flag = 0;
|
|
for (blockIndex = 0; blockIndex < pcblockcount; blockIndex++) {
|
|
if (depthfirstordering[blockIndex]) {
|
|
info = &propinfo[depthfirstordering[blockIndex]->blockIndex];
|
|
if ((preds = depthfirstordering[blockIndex]->predecessors)) {
|
|
vec8 = info->vec8;
|
|
bitvectorcopy(vec8, propinfo[preds->block->blockIndex].vecC, number_of_candidates);
|
|
for (preds = preds->nextLink; preds; preds = preds->nextLink)
|
|
bitvectorintersect(vec8, propinfo[preds->block->blockIndex].vecC, number_of_candidates);
|
|
}
|
|
|
|
vecC = info->vecC;
|
|
vec8 = info->vec8;
|
|
vec0 = info->vec0;
|
|
vec4 = info->vec4;
|
|
for (i = 0; i < bitvecsize; i++) {
|
|
val = *vec0 | (*vec8 & ~*vec4);
|
|
if (val != *vecC) {
|
|
*vecC = val;
|
|
flag = 1;
|
|
}
|
|
vec8++;
|
|
vecC++;
|
|
vec4++;
|
|
vec0++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int precedes(PCode *a, PCode *b) {
|
|
PCode *scan;
|
|
|
|
for (scan = a->nextPCode; scan; scan = scan->nextPCode) {
|
|
if (scan == b)
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int canidatepropagatestoalluses(int id) {
|
|
RegUseOrDef *list;
|
|
|
|
if (PCODE_FLAG_SET_F(Candidates[id].pcode) & (fPCodeFlag20000000 | fSideEffects))
|
|
return 0;
|
|
|
|
for (list = Candidates[id].list; list; list = list->next) {
|
|
if (!propagatestouse(id, list->id))
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static void propagatecandidates(void) {
|
|
int i;
|
|
|
|
for (i = 0; i < number_of_candidates; i++) {
|
|
if (canidatepropagatestoalluses(i))
|
|
propagateandfinish(i);
|
|
}
|
|
}
|
|
|
|
void propagateinstructions(Object *proc, Propagation *config, int passCount, Boolean localflag) {
|
|
char buf[64];
|
|
|
|
is_candidate = config->is_candidate;
|
|
propagatestouse = config->propagatestouse;
|
|
propagateandfinish = config->propagateandfinish;
|
|
propagated_instructions = 0;
|
|
|
|
while (1) {
|
|
recursive_propagation = 0;
|
|
precomputecanidatecounts();
|
|
if (number_of_candidates <= 0) {
|
|
freeoheap();
|
|
if (config->computesUseDefChains)
|
|
computeusedefchains(0);
|
|
return;
|
|
}
|
|
|
|
computeusedefchains(0);
|
|
computecandidatelist();
|
|
allocatepropinfo();
|
|
computelocalpropinfo(localflag);
|
|
computedepthfirstordering();
|
|
computeglobalpropinfo();
|
|
propagatecandidates();
|
|
passCount--;
|
|
|
|
if (propagated_instructions && copts.debuglisting) {
|
|
sprintf(buf, "AFTER %s PROPAGATION", config->name);
|
|
pclistblocks(CMangler_GetLinkName(proc)->name, buf);
|
|
}
|
|
|
|
if (!passCount || !recursive_propagation) {
|
|
if (!config->computesUseDefChains)
|
|
freeoheap();
|
|
return;
|
|
}
|
|
|
|
freeoheap();
|
|
}
|
|
}
|
|
|
|
static int is_copy(PCode *pcode) {
|
|
return (pcode->flags & fPCodeFlag10) && (pcode->args[0].data.reg.reg >= n_real_registers[pcode->args[0].arg]);
|
|
}
|
|
|
|
static int copypropagatestouse(int candidateID, int useID) {
|
|
UseOrDef *use;
|
|
short reg1;
|
|
short reg2;
|
|
RegClass rclass;
|
|
PCode *pcode;
|
|
int i;
|
|
PCode *scan;
|
|
PCodeArg *op;
|
|
|
|
pcode = Candidates[candidateID].pcode;
|
|
use = Uses + useID;
|
|
rclass = pcode->args[0].arg;
|
|
reg1 = pcode->args[0].data.reg.reg;
|
|
reg2 = pcode->args[1].data.reg.reg;
|
|
|
|
if (use->pcode->flags & fPCodeFlag10)
|
|
return 0;
|
|
|
|
if (rclass == RegClass_GPR && use->pcode->op == PC_RLWIMI && use->pcode->args[0].data.reg.reg == reg1)
|
|
return 0;
|
|
|
|
if (pcode->block == use->pcode->block && precedes(pcode, use->pcode)) {
|
|
for (scan = pcode->nextPCode; scan && scan != use->pcode; scan = scan->nextPCode) {
|
|
op = scan->args;
|
|
i = scan->argCount;
|
|
while (i--) {
|
|
if (
|
|
op->kind == PCOp_REGISTER &&
|
|
op->arg == rclass &&
|
|
(op->data.reg.effect & EffectWrite) &&
|
|
op->data.reg.reg == reg2
|
|
)
|
|
return 0;
|
|
op++;
|
|
}
|
|
}
|
|
} else {
|
|
if (!bitvectorgetbit(candidateID, propinfo[use->pcode->block->blockIndex].vec8))
|
|
return 0;
|
|
|
|
for (scan = use->pcode->block->firstPCode; scan; scan = scan->nextPCode) {
|
|
op = scan->args;
|
|
i = scan->argCount;
|
|
while (i--) {
|
|
if (
|
|
op->kind == PCOp_REGISTER &&
|
|
op->arg == rclass &&
|
|
(op->data.reg.effect & EffectWrite) &&
|
|
op->data.reg.reg == reg2
|
|
)
|
|
return 0;
|
|
op++;
|
|
}
|
|
if (scan == use->pcode)
|
|
break;
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static void propagateandremovecopy(int id) {
|
|
Candidate *candidate;
|
|
RegClass rclass;
|
|
short reg1;
|
|
short reg2;
|
|
RegUseOrDef *list;
|
|
int i;
|
|
PCodeArg *op;
|
|
|
|
candidate = &Candidates[id];
|
|
rclass = candidate->pcode->args[0].arg;
|
|
reg1 = candidate->pcode->args[0].data.reg.reg;
|
|
reg2 = candidate->pcode->args[1].data.reg.reg;
|
|
|
|
if (rclass == RegClass_GPR && reg1 >= 32 && reg1 <= last_exception_register[RegClass_GPR])
|
|
return;
|
|
|
|
if (!moreaggressiveoptimization && reg2 < n_real_registers[rclass])
|
|
return;
|
|
|
|
for (list = candidate->list; list; list = list->next) {
|
|
op = Uses[list->id].pcode->args;
|
|
i = Uses[list->id].pcode->argCount;
|
|
while (i--) {
|
|
if (
|
|
op->kind == PCOp_REGISTER &&
|
|
op->arg == rclass &&
|
|
op->data.reg.reg == reg1 &&
|
|
(op->data.reg.effect & EffectRead)
|
|
)
|
|
op->data.reg.reg = reg2;
|
|
op++;
|
|
}
|
|
}
|
|
|
|
deletepcode(candidate->pcode);
|
|
propagated_instructions = 1;
|
|
}
|
|
|
|
static Propagation copy_prop = {
|
|
&is_copy,
|
|
©propagatestouse,
|
|
&propagateandremovecopy,
|
|
"COPY",
|
|
"COPIES",
|
|
"c%ld",
|
|
0
|
|
};
|
|
|
|
void propagatecopyinstructions(Object *proc, int flag) {
|
|
moreaggressiveoptimization = flag;
|
|
propagateinstructions(proc, ©_prop, 1, 0);
|
|
propagatedcopies = propagated_instructions;
|
|
}
|
|
|