mirror of https://git.wuffs.org/MWCC
907 lines
30 KiB
C
907 lines
30 KiB
C
#include "compiler/CodeMotion.h"
|
|
#include "compiler/Alias.h"
|
|
#include "compiler/BitVectors.h"
|
|
#include "compiler/LoopDetection.h"
|
|
#include "compiler/LoopOptimization.h"
|
|
#include "compiler/CompilerTools.h"
|
|
#include "compiler/PCode.h"
|
|
#include "compiler/UseDefChains.h"
|
|
#include "compiler/RegisterInfo.h"
|
|
|
|
int movedloopinvariantcode;
|
|
int unswitchedinvariantcode;
|
|
|
|
static int isloopinvariant(PCode *pcode, Loop *loop, UInt32 *vec, int flag1, int flag2) {
|
|
PCodeArg *op;
|
|
RegUseOrDef *list;
|
|
int i;
|
|
|
|
if (pcode->flags & (fIsRead | fIsWrite | fPCodeFlag20000 | fPCodeFlag40000)) {
|
|
if (pcode->alias) {
|
|
if (pcode->alias->type == AliasType2 || (pcode->flags & (fIsVolatile | fSideEffects)))
|
|
return 0;
|
|
|
|
if (pcode->flags & fIsRead) {
|
|
for (list = findobjectusedef(pcode->alias->object)->defs; list; list = list->next) {
|
|
if (
|
|
may_alias(pcode, Defs[list->id].pcode) &&
|
|
bitvectorgetbit(list->id, vec) &&
|
|
bitvectorgetbit(Defs[list->id].pcode->block->blockIndex, loop->memberblocks)
|
|
)
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if (pcode->flags & fIsWrite) {
|
|
for (list = findobjectusedef(pcode->alias->object)->uses; list; list = list->next) {
|
|
if (
|
|
may_alias(pcode, Uses[list->id].pcode) &&
|
|
bitvectorgetbit(Uses[list->id].pcode->block->blockIndex, loop->memberblocks)
|
|
)
|
|
return 0;
|
|
}
|
|
}
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if ((pcode->flags & fIsWrite) && !bitvectorgetbit(pcode->block->blockIndex, loop->vec2C))
|
|
return 0;
|
|
|
|
op = pcode->args;
|
|
i = pcode->argCount;
|
|
while (i--) {
|
|
switch (op->kind) {
|
|
case PCOp_MEMORY:
|
|
if ((pcode->flags & fIsRead) && ((pcode->flags == 0) & 0x40)) {
|
|
for (list = findobjectusedef(op->data.mem.obj)->defs; list; list = list->next) {
|
|
if (
|
|
may_alias(pcode, Defs[list->id].pcode) &&
|
|
bitvectorgetbit(list->id, vec) &&
|
|
bitvectorgetbit(Defs[list->id].pcode->block->blockIndex, loop->memberblocks)
|
|
)
|
|
return 0;
|
|
}
|
|
}
|
|
if (pcode->flags & fIsWrite) {
|
|
for (list = findobjectusedef(op->data.mem.obj)->uses; list; list = list->next) {
|
|
if (
|
|
may_alias(pcode, Uses[list->id].pcode) &&
|
|
bitvectorgetbit(Uses[list->id].pcode->block->blockIndex, loop->memberblocks)
|
|
)
|
|
return 0;
|
|
}
|
|
}
|
|
break;
|
|
case PCOp_REGISTER:
|
|
if (op->data.reg.effect & (EffectRead | EffectWrite)) {
|
|
if (op->kind == PCOp_REGISTER && op->arg == RegClass_GPR) {
|
|
if (op->data.reg.reg == _FP_)
|
|
break;
|
|
if (op->data.reg.reg == _CALLER_SP_)
|
|
break;
|
|
if (op->data.reg.reg == 2)
|
|
break;
|
|
}
|
|
if (op->data.reg.reg < n_real_registers[op->arg]) {
|
|
if (op->arg == RegClass_CRFIELD) {
|
|
if (!flag2 || (op->data.reg.effect & EffectRead))
|
|
return 0;
|
|
} else if (op->arg == RegClass_SPR) {
|
|
if (!flag1)
|
|
return 0;
|
|
} else {
|
|
return 0;
|
|
}
|
|
} else if (op->data.reg.effect & EffectRead) {
|
|
if (flag1 && op->kind == PCOp_REGISTER && op->arg == RegClass_SPR)
|
|
break;
|
|
if (op->kind == PCOp_REGISTER && op->arg == RegClass_GPR) {
|
|
if (op->data.reg.reg == _FP_)
|
|
break;
|
|
if (op->data.reg.reg == _CALLER_SP_)
|
|
break;
|
|
if (op->data.reg.reg == 2)
|
|
break;
|
|
}
|
|
|
|
for (list = reg_Defs[op->arg][op->data.reg.reg]; list; list = list->next) {
|
|
if (
|
|
bitvectorgetbit(list->id, vec) &&
|
|
bitvectorgetbit(Defs[list->id].pcode->block->blockIndex, loop->memberblocks)
|
|
)
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
op++;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int isuniquedefinition(PCode *pcode, Loop *loop) {
|
|
RegUseOrDef *list;
|
|
int defID;
|
|
UseOrDef *def;
|
|
|
|
defID = pcode->defID;
|
|
def = &Defs[defID];
|
|
if (defID >= number_of_Defs)
|
|
return 0;
|
|
if (def->pcode != pcode)
|
|
return 0;
|
|
if ((defID + 1) < number_of_Defs && def[1].pcode == pcode)
|
|
return 0;
|
|
|
|
if (def->v.kind == PCOp_REGISTER) {
|
|
for (list = reg_Defs[def->v.arg][def->v.u.reg]; list; list = list->next) {
|
|
if (
|
|
bitvectorgetbit(Defs[list->id].pcode->block->blockIndex, loop->memberblocks) &&
|
|
list->id != defID
|
|
)
|
|
return 0;
|
|
}
|
|
} else if (def->v.kind == PCOp_MEMORY) {
|
|
for (list = findobjectusedef(def->v.u.object)->defs; list; list = list->next) {
|
|
if (
|
|
may_alias(pcode, Defs[list->id].pcode) &&
|
|
bitvectorgetbit(Defs[list->id].pcode->block->blockIndex, loop->memberblocks) &&
|
|
list->id != defID
|
|
)
|
|
return 0;
|
|
}
|
|
} else {
|
|
CError_FATAL(292);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int uniquelyreachesuse(int defID, int useID) {
|
|
UseOrDef *def;
|
|
UseOrDef *use;
|
|
RegUseOrDef *list;
|
|
PCode *pcode;
|
|
|
|
def = &Defs[defID];
|
|
use = &Uses[useID];
|
|
if (def->v.kind == PCOp_REGISTER) {
|
|
for (list = reg_Defs[def->v.arg][def->v.u.reg]; list; list = list->next) {
|
|
if (
|
|
list->id != defID &&
|
|
bitvectorgetbit(list->id, usedefinfo[use->pcode->block->blockIndex].defvec8)
|
|
)
|
|
break;
|
|
}
|
|
} else if (def->v.kind == PCOp_MEMORY) {
|
|
for (list = findobjectusedef(def->v.u.object)->defs; list; list = list->next) {
|
|
if (
|
|
may_alias(def->pcode, Defs[list->id].pcode) &&
|
|
list->id != defID &&
|
|
bitvectorgetbit(list->id, usedefinfo[use->pcode->block->blockIndex].defvec8)
|
|
)
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!list)
|
|
return 1;
|
|
|
|
if (def->pcode->block == use->pcode->block) {
|
|
for (pcode = use->pcode->prevPCode; pcode; pcode = pcode->prevPCode) {
|
|
if (pcode == def->pcode)
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int uniquelyreachesalluses(int defID, Loop *loop) {
|
|
UseOrDef *def;
|
|
RegUseOrDef *list;
|
|
|
|
def = &Defs[defID];
|
|
|
|
if (def->v.kind == PCOp_REGISTER) {
|
|
for (list = reg_Uses[def->v.arg][def->v.u.reg]; list; list = list->next) {
|
|
if (
|
|
bitvectorgetbit(list->id, usedefinfo[loop->preheader->blockIndex].usevec1C) ||
|
|
(bitvectorgetbit(Uses[list->id].pcode->block->blockIndex, loop->memberblocks) && !uniquelyreachesuse(defID, list->id))
|
|
)
|
|
return 0;
|
|
}
|
|
} else if (def->v.kind == PCOp_MEMORY) {
|
|
for (list = findobjectusedef(def->v.u.object)->uses; list; list = list->next) {
|
|
if (may_alias(def->pcode, Uses[list->id].pcode)) {
|
|
if (
|
|
bitvectorgetbit(list->id, usedefinfo[loop->preheader->blockIndex].usevec1C) ||
|
|
(bitvectorgetbit(Uses[list->id].pcode->block->blockIndex, loop->memberblocks) && !uniquelyreachesuse(defID, list->id))
|
|
)
|
|
return 0;
|
|
}
|
|
}
|
|
} else {
|
|
CError_FATAL(382);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int isliveonexit(TinyValue *v, Loop *loop) {
|
|
RegUseOrDef *list;
|
|
UInt32 *vec;
|
|
|
|
vec = usedefinfo[loop->preheader->blockIndex].usevec1C;
|
|
|
|
if (v->kind == PCOp_REGISTER) {
|
|
for (list = reg_Uses[v->arg][v->u.reg]; list; list = list->next) {
|
|
if (
|
|
bitvectorgetbit(list->id, vec) &&
|
|
!bitvectorgetbit(Uses[list->id].pcode->block->blockIndex, loop->memberblocks)
|
|
)
|
|
return 1;
|
|
}
|
|
} else if (v->kind == PCOp_MEMORY) {
|
|
for (list = findobjectusedef(v->u.object)->uses; list; list = list->next) {
|
|
if (
|
|
bitvectorgetbit(list->id, vec) &&
|
|
!bitvectorgetbit(Uses[list->id].pcode->block->blockIndex, loop->memberblocks)
|
|
)
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int dominatesallexits(PCode *pcode, Loop *loop) {
|
|
return bitvectorgetbit(pcode->block->blockIndex, loop->vec28) != 0;
|
|
}
|
|
|
|
static int maymove(PCode *pcode, Loop *loop) {
|
|
short reg;
|
|
|
|
if (!isuniquedefinition(pcode, loop))
|
|
return 0;
|
|
if (!uniquelyreachesalluses(pcode->defID, loop))
|
|
return 0;
|
|
if (!dominatesallexits(pcode, loop) && isliveonexit(&Defs[pcode->defID].v, loop))
|
|
return 0;
|
|
|
|
if (loop->bodySize > 25) {
|
|
switch (pcode->op) {
|
|
case PC_LI:
|
|
if (
|
|
pcode->nextPCode &&
|
|
pcode->nextPCode->op == PC_LVX &&
|
|
(pcode->nextPCode->flags & fIsConst)
|
|
) {
|
|
reg = pcode->args[0].data.reg.reg;
|
|
if (pcode->nextPCode->args[1].data.reg.reg == reg ||
|
|
pcode->nextPCode->args[2].data.reg.reg == reg)
|
|
return 1;
|
|
}
|
|
case PC_VSPLTISB:
|
|
case PC_VSPLTISH:
|
|
case PC_VSPLTISW:
|
|
return 0;
|
|
default:
|
|
if (!bitvectorgetbit(pcode->block->blockIndex, loop->vec2C))
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static void moveinvariantcomputation(PCode *pcode, Loop *loop) {
|
|
ObjectUseDef *oud;
|
|
BlockList *blocklist;
|
|
RegUseOrDef *list;
|
|
UseOrDef *def;
|
|
int defID;
|
|
|
|
defID = pcode->defID;
|
|
def = &Defs[defID];
|
|
deletepcode(pcode);
|
|
insertpcodebefore(loop->preheader->lastPCode, pcode);
|
|
loop->bodySize--;
|
|
movedloopinvariantcode = 1;
|
|
|
|
if (def->v.kind == PCOp_REGISTER) {
|
|
for (blocklist = loop->blocks; blocklist; blocklist = blocklist->next) {
|
|
for (list = reg_Defs[def->v.arg][def->v.u.reg]; list; list = list->next)
|
|
bitvectorclearbit(list->id, usedefinfo[blocklist->block->blockIndex].defvec8);
|
|
bitvectorsetbit(defID, usedefinfo[blocklist->block->blockIndex].defvec8);
|
|
}
|
|
} else if (def->v.kind == PCOp_MEMORY) {
|
|
oud = findobjectusedef(def->v.u.object);
|
|
for (blocklist = loop->blocks; blocklist; blocklist = blocklist->next) {
|
|
for (list = oud->defs; list; list = list->next) {
|
|
if (uniquely_aliases(pcode, Defs[list->id].pcode))
|
|
bitvectorclearbit(list->id, usedefinfo[blocklist->block->blockIndex].defvec8);
|
|
}
|
|
bitvectorsetbit(defID, usedefinfo[blocklist->block->blockIndex].defvec8);
|
|
}
|
|
} else {
|
|
CError_FATAL(545);
|
|
}
|
|
}
|
|
|
|
static int srawi_addze_maymove(PCode *pcode, Loop *loop) {
|
|
RegUseOrDef *list;
|
|
UseOrDef *def;
|
|
int defID;
|
|
int nextDefID;
|
|
|
|
defID = pcode->defID;
|
|
nextDefID = pcode->nextPCode->defID;
|
|
|
|
def = &Defs[defID];
|
|
if (defID >= number_of_Defs)
|
|
return 0;
|
|
if (def->pcode != pcode)
|
|
return 0;
|
|
if ((defID + 1) < number_of_Defs && def[1].pcode == pcode)
|
|
return 0;
|
|
|
|
if (def->v.kind == PCOp_REGISTER && def->v.arg == RegClass_GPR) {
|
|
for (list = reg_Defs[RegClass_GPR][def->v.u.reg]; list; list = list->next) {
|
|
if (
|
|
bitvectorgetbit(Defs[list->id].pcode->block->blockIndex, loop->memberblocks) &&
|
|
list->id != defID &&
|
|
list->id != nextDefID
|
|
)
|
|
return 0;
|
|
}
|
|
} else {
|
|
CError_FATAL(582);
|
|
}
|
|
|
|
if (!uniquelyreachesalluses(pcode->defID, loop))
|
|
return 0;
|
|
if (!dominatesallexits(pcode, loop) && isliveonexit(&Defs[pcode->defID].v, loop))
|
|
return 0;
|
|
if (!dominatesallexits(pcode->nextPCode, loop) && isliveonexit(&Defs[pcode->nextPCode->defID].v, loop))
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int srawi_addze_isloopinvariant(PCode *pcode, Loop *loop, UInt32 *vec) {
|
|
static PCode *oldNextInstr;
|
|
PCode *nextInstr;
|
|
|
|
nextInstr = pcode->nextPCode;
|
|
if (
|
|
pcode->op == PC_ADDZE &&
|
|
oldNextInstr == pcode
|
|
) {
|
|
oldNextInstr = NULL;
|
|
return 1;
|
|
} else if (
|
|
pcode->op == PC_SRAWI &&
|
|
nextInstr &&
|
|
nextInstr->op == PC_ADDZE &&
|
|
pcode->args[0].data.reg.reg == nextInstr->args[0].data.reg.reg &&
|
|
nextInstr->args[0].data.reg.reg == nextInstr->args[1].data.reg.reg &&
|
|
!(pcode->flags & (fIsCall | fIsPtrOp | fIsVolatile | fSideEffects)) &&
|
|
!(nextInstr->flags & (fIsCall | fIsPtrOp | fIsVolatile | fSideEffects)) &&
|
|
isloopinvariant(pcode, loop, vec, 1, 0) &&
|
|
srawi_addze_maymove(pcode, loop)
|
|
) {
|
|
oldNextInstr = nextInstr;
|
|
return 1;
|
|
} else {
|
|
oldNextInstr = NULL;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static void removeblockfromloop(Loop *loop, PCodeBlock *block) {
|
|
BlockList *list;
|
|
BlockList **ptr;
|
|
|
|
bitvectorclearbit(block->blockIndex, loop->memberblocks);
|
|
bitvectorclearbit(block->blockIndex, loop->vec24);
|
|
bitvectorclearbit(block->blockIndex, loop->vec28);
|
|
bitvectorclearbit(block->blockIndex, loop->vec2C);
|
|
loop->bodySize -= block->pcodeCount;
|
|
|
|
ptr = &loop->blocks;
|
|
while ((list = *ptr)) {
|
|
if (list->block == block)
|
|
*ptr = list->next;
|
|
else
|
|
ptr = &list->next;
|
|
}
|
|
}
|
|
|
|
static void changesuccessor(PCodeBlock *block, PCodeBlock *from, PCodeBlock *to) {
|
|
PCLink **ptr;
|
|
PCLink *link;
|
|
|
|
for (link = block->successors; link; link = link->nextLink) {
|
|
if (link->block == from)
|
|
link->block = to;
|
|
}
|
|
|
|
ptr = &from->predecessors;
|
|
while ((link = *ptr)) {
|
|
if (link->block == block) {
|
|
*ptr = link->nextLink;
|
|
link->nextLink = to->predecessors;
|
|
to->predecessors = link;
|
|
} else {
|
|
ptr = &link->nextLink;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void movesuccessor(PCodeBlock *to, PCodeBlock *from, PCodeBlock *block) {
|
|
PCLink **ptr;
|
|
PCLink *link;
|
|
|
|
for (link = block->predecessors; link; link = link->nextLink) {
|
|
if (link->block == from)
|
|
link->block = to;
|
|
}
|
|
|
|
ptr = &from->successors;
|
|
while ((link = *ptr)) {
|
|
if (link->block == block) {
|
|
*ptr = link->nextLink;
|
|
link->nextLink = to->successors;
|
|
to->successors = link;
|
|
} else {
|
|
ptr = &link->nextLink;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void movecmptopreheader(Loop *loop, PCodeBlock *block, PCode *pc1, PCode *pc2, PCodeArg *op) {
|
|
PCodeBlock *preheader;
|
|
PCode *pc3;
|
|
|
|
preheader = loop->preheader;
|
|
if (PCODE_FLAG_SET_F(pc1) & fRecordBit) {
|
|
moveinvariantcomputation(pc1, loop);
|
|
} else {
|
|
deletepcode(pc1);
|
|
insertpcodebefore(loop->preheader->lastPCode, pc1);
|
|
loop->bodySize--;
|
|
movedloopinvariantcode = 1;
|
|
}
|
|
loop->preheader = NULL;
|
|
|
|
insertpreheaderblock(loop);
|
|
|
|
pc3 = preheader->lastPCode;
|
|
CError_ASSERT(775, pc3->op == PC_B);
|
|
deletepcode(pc3);
|
|
deletepcode(pc2);
|
|
appendpcode(preheader, pc2);
|
|
movesuccessor(preheader, block, op->data.label.label->block);
|
|
}
|
|
|
|
static PCodeBlock *appendheadercopy(Loop *loop, PCodeBlock *block1, PCodeBlock *block2, PCodeBlock *block3) {
|
|
PCodeBlock *newblock1;
|
|
PCodeBlock *newblock2;
|
|
PCLink *link;
|
|
PCode *scan;
|
|
|
|
newblock1 = lalloc(sizeof(PCodeBlock));
|
|
newblock2 = lalloc(sizeof(PCodeBlock));
|
|
|
|
newblock1->labels = NULL;
|
|
newblock1->predecessors = newblock1->successors = NULL;
|
|
newblock1->firstPCode = newblock1->lastPCode = NULL;
|
|
newblock1->pcodeCount = 0;
|
|
newblock1->loopWeight = loop->body->loopWeight;
|
|
newblock1->flags = 0;
|
|
newblock1->blockIndex = pcblockcount++;
|
|
|
|
newblock2->labels = NULL;
|
|
newblock2->predecessors = newblock2->successors = NULL;
|
|
newblock2->firstPCode = newblock2->lastPCode = NULL;
|
|
newblock2->pcodeCount = 0;
|
|
newblock2->loopWeight = loop->body->loopWeight;
|
|
newblock2->flags = 0;
|
|
newblock2->blockIndex = pcblockcount++;
|
|
|
|
newblock1->nextBlock = newblock2;
|
|
newblock2->prevBlock = newblock1;
|
|
newblock1->prevBlock = block1;
|
|
newblock2->nextBlock = block1->nextBlock;
|
|
block1->nextBlock = newblock1;
|
|
newblock2->nextBlock->prevBlock = newblock2;
|
|
|
|
pclabel(newblock1, makepclabel());
|
|
pclabel(newblock2, makepclabel());
|
|
|
|
changesuccessor(block1, block1->successors->block, newblock1);
|
|
|
|
link = lalloc(sizeof(PCLink));
|
|
link->block = newblock2;
|
|
link->nextLink = newblock1->successors;
|
|
newblock1->successors = link;
|
|
|
|
link = lalloc(sizeof(PCLink));
|
|
link->block = newblock1;
|
|
link->nextLink = newblock2->predecessors;
|
|
newblock2->predecessors = link;
|
|
|
|
appendpcode(newblock2, makepcode(PC_B, block2->nextBlock->labels));
|
|
pcbranch(newblock2, block2->nextBlock->labels);
|
|
pccomputepredecessors1(newblock2);
|
|
|
|
for (scan = block2->firstPCode; scan; scan = scan->nextPCode)
|
|
appendpcode(newblock1, copypcode(scan));
|
|
|
|
pcbranch(newblock1, block3->labels);
|
|
|
|
link = lalloc(sizeof(PCLink));
|
|
link->block = newblock1;
|
|
link->nextLink = block3->predecessors;
|
|
block3->predecessors = link;
|
|
|
|
addblocktoloop(loop, newblock1);
|
|
if (bitvectorgetbit(block2->blockIndex, loop->vec28))
|
|
bitvectorsetbit(newblock1->blockIndex, loop->vec28);
|
|
if (bitvectorgetbit(block2->blockIndex, loop->vec2C))
|
|
bitvectorsetbit(newblock1->blockIndex, loop->vec2C);
|
|
|
|
for (loop = loop->parent; loop; loop = loop->parent) {
|
|
addblocktoloop(loop, newblock1);
|
|
if (bitvectorgetbit(block2->blockIndex, loop->vec28))
|
|
bitvectorsetbit(newblock1->blockIndex, loop->vec28);
|
|
if (bitvectorgetbit(block2->blockIndex, loop->vec2C))
|
|
bitvectorsetbit(newblock1->blockIndex, loop->vec2C);
|
|
|
|
addblocktoloop(loop, newblock2);
|
|
if (bitvectorgetbit(block2->blockIndex, loop->vec28))
|
|
bitvectorsetbit(newblock2->blockIndex, loop->vec28);
|
|
if (bitvectorgetbit(block2->blockIndex, loop->vec2C))
|
|
bitvectorsetbit(newblock2->blockIndex, loop->vec2C);
|
|
}
|
|
|
|
return newblock1;
|
|
}
|
|
|
|
static BlockList *findswitchpath(Loop *loop, PCodeBlock *block) {
|
|
BlockList *head;
|
|
BlockList *tail;
|
|
BlockList *node;
|
|
PCodeBlock *scan;
|
|
|
|
head = NULL;
|
|
tail = NULL;
|
|
|
|
for (scan = block; scan && scan != loop->body; scan = scan->successors->block) {
|
|
if (!bitvectorgetbit(scan->blockIndex, loop->memberblocks))
|
|
return NULL;
|
|
if (scan->successors && scan->successors->nextLink)
|
|
return NULL;
|
|
|
|
node = oalloc(sizeof(BlockList));
|
|
node->block = scan;
|
|
node->next = NULL;
|
|
if (head) {
|
|
tail->next = node;
|
|
tail = node;
|
|
} else {
|
|
head = node;
|
|
tail = node;
|
|
}
|
|
}
|
|
|
|
return head;
|
|
}
|
|
|
|
static void simpleunswitchloop(Loop *loop) {
|
|
PCode *pc29;
|
|
PCodeArg *op27;
|
|
UInt32 *myvec;
|
|
PCodeBlock *block26;
|
|
PCode *pc25; // r25
|
|
BlockList *path2_24;
|
|
PCodeArg *op23;
|
|
PCode *pc23; // r23
|
|
BlockList *scanlist; // r23
|
|
BlockList *bestpath1; // r23
|
|
BlockList *bestpath2; // r22
|
|
PCodeBlock *headercopy; // r22
|
|
Loop *newloop; // r21
|
|
PCodeBlock *preheader21;
|
|
BlockList *path20;
|
|
PCode *scan20;
|
|
PCode *lastpcode;
|
|
int i;
|
|
BlockList *pathiter1;
|
|
BlockList *pathiter2;
|
|
|
|
if (!(lastpcode = loop->body->lastPCode))
|
|
return;
|
|
if (lastpcode->op != PC_BT && lastpcode->op != PC_BF)
|
|
return;
|
|
if (lastpcode->args[2].kind != PCOp_LABEL)
|
|
return;
|
|
if (!bitvectorgetbit(lastpcode->args[2].data.label.label->block->blockIndex, loop->memberblocks))
|
|
return;
|
|
if (loop->x57)
|
|
return;
|
|
if (loop->x4D)
|
|
return;
|
|
if (bitvectorgetbit(loop->body->nextBlock->blockIndex, loop->memberblocks))
|
|
return;
|
|
|
|
for (block26 = pcbasicblocks; block26; block26 = block26->nextBlock) {
|
|
if (bitvectorgetbit(block26->blockIndex, loop->memberblocks))
|
|
break;
|
|
}
|
|
|
|
if (!block26)
|
|
return;
|
|
|
|
myvec = oalloc(4 * ((number_of_Defs + 31) >> 5));
|
|
bitvectorcopy(myvec, usedefinfo[block26->blockIndex].defvec8, number_of_Defs);
|
|
for (pc25 = loop->preheader->nextBlock->firstPCode; pc25; pc25 = pc25->nextPCode) {
|
|
if (!(PCODE_FLAG_SET_F(pc25) & (fIsCall | fIsPtrOp | fIsVolatile | fSideEffects | fRecordBit))) {
|
|
if (isloopinvariant(pc25, loop, myvec, 0, 1))
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!pc25 || pc25->argCount < 1)
|
|
return;
|
|
|
|
if (
|
|
pc25->argCount < 1 ||
|
|
pc25->args[0].kind != PCOp_REGISTER ||
|
|
pc25->args[0].arg != RegClass_CRFIELD
|
|
)
|
|
return;
|
|
|
|
pc29 = pc25->block->lastPCode;
|
|
if (
|
|
!pc29 ||
|
|
!(pc29->flags & fIsBranch) ||
|
|
pc29->args[0].kind != PCOp_REGISTER ||
|
|
pc29->args[0].arg != RegClass_CRFIELD
|
|
)
|
|
return;
|
|
|
|
if (pc29->args[0].data.reg.reg != pc25->args[0].data.reg.reg)
|
|
return;
|
|
|
|
op27 = NULL;
|
|
for (i = 0; i < pc29->argCount; i++) {
|
|
if (pc29->args[i].kind == PCOp_LABEL)
|
|
op27 = &pc29->args[i];
|
|
}
|
|
|
|
if (op27) {
|
|
preheader21 = loop->preheader;
|
|
|
|
path20 = findswitchpath(loop, block26->nextBlock);
|
|
if (!path20)
|
|
return;
|
|
|
|
path2_24 = findswitchpath(loop, op27->data.label.label->block);
|
|
if (!path2_24)
|
|
return;
|
|
|
|
bestpath1 = NULL;
|
|
bestpath2 = NULL;
|
|
for (pathiter1 = path20; pathiter1; pathiter1 = pathiter1->next) {
|
|
for (pathiter2 = path2_24; pathiter2; pathiter2 = pathiter2->next) {
|
|
if (pathiter1->block == pathiter2->block) {
|
|
bestpath1 = pathiter1;
|
|
break;
|
|
}
|
|
}
|
|
if (bestpath1)
|
|
break;
|
|
bestpath2 = pathiter1;
|
|
}
|
|
|
|
CError_ASSERT(1192, bestpath2->block);
|
|
|
|
if (bestpath2->block->lastPCode && bestpath2->block->lastPCode->op == PC_B)
|
|
deletepcode(bestpath2->block->lastPCode);
|
|
|
|
while (bestpath1) {
|
|
for (scan20 = bestpath1->block->firstPCode; scan20; scan20 = scan20->nextPCode) {
|
|
if (scan20->op != PC_B)
|
|
appendpcode(bestpath2->block, copypcode(scan20));
|
|
}
|
|
bestpath1 = bestpath1->next;
|
|
}
|
|
|
|
headercopy = appendheadercopy(loop, bestpath2->block, loop->body, block26);
|
|
movecmptopreheader(loop, block26, pc25, pc29, op27);
|
|
|
|
if (block26->pcodeCount) {
|
|
if (path2_24->block->firstPCode) {
|
|
pc23 = path2_24->block->firstPCode;
|
|
for (scan20 = block26->firstPCode; scan20; scan20 = scan20->nextPCode) {
|
|
if (scan20->op != PC_B)
|
|
insertpcodebefore(pc23, copypcode(scan20));
|
|
}
|
|
} else {
|
|
for (scan20 = block26->firstPCode; scan20; scan20 = scan20->nextPCode) {
|
|
if (scan20->op != PC_B)
|
|
appendpcode(path2_24->block, copypcode(scan20));
|
|
}
|
|
}
|
|
}
|
|
|
|
op23 = NULL;
|
|
for (i = 0; i < loop->body->lastPCode->argCount; i++) {
|
|
if (loop->body->lastPCode->args[i].kind == PCOp_LABEL)
|
|
op23 = &loop->body->lastPCode->args[i];
|
|
}
|
|
|
|
CError_ASSERT(1250, op23 != NULL);
|
|
|
|
changesuccessor(loop->body, op23->data.label.label->block, path2_24->block);
|
|
op23->data.label.label = path2_24->block->labels;
|
|
|
|
op23 = NULL;
|
|
for (i = 0; i < preheader21->lastPCode->argCount; i++) {
|
|
if (preheader21->lastPCode->args[i].kind == PCOp_LABEL)
|
|
op23 = &preheader21->lastPCode->args[i];
|
|
}
|
|
|
|
CError_ASSERT(1267, op23 != NULL);
|
|
|
|
changesuccessor(preheader21, op23->data.label.label->block, loop->body);
|
|
op23->data.label.label = loop->body->labels;
|
|
|
|
op23 = NULL;
|
|
for (i = 0; i < loop->preheader->lastPCode->argCount; i++) {
|
|
if (loop->preheader->lastPCode->args[i].kind == PCOp_LABEL)
|
|
op23 = &loop->preheader->lastPCode->args[i];
|
|
}
|
|
|
|
CError_ASSERT(1284, op23 != NULL);
|
|
|
|
changesuccessor(loop->preheader, op23->data.label.label->block, headercopy);
|
|
op23->data.label.label = headercopy->labels;
|
|
|
|
newloop = lalloc(sizeof(Loop));
|
|
newloop->parent = loop->parent;
|
|
newloop->children = NULL;
|
|
newloop->nextSibling = loop->nextSibling;
|
|
loop->nextSibling = newloop;
|
|
newloop->body = loop->body;
|
|
newloop->preheader = NULL;
|
|
newloop->blocks = NULL;
|
|
newloop->basicInductionVars = NULL;
|
|
newloop->footer = NULL;
|
|
newloop->pc18 = NULL;
|
|
newloop->loopWeight = loop->loopWeight;
|
|
|
|
bitvectorinitialize(newloop->memberblocks = lalloc(4 * ((loopdetection_nblocks + 31) >> 5)), loopdetection_nblocks, 0);
|
|
bitvectorinitialize(newloop->vec24 = lalloc(4 * ((loopdetection_nblocks + 31) >> 5)), loopdetection_nblocks, 0);
|
|
bitvectorinitialize(newloop->vec28 = lalloc(4 * ((loopdetection_nblocks + 31) >> 5)), loopdetection_nblocks, 0);
|
|
bitvectorinitialize(newloop->vec2C = lalloc(4 * ((loopdetection_nblocks + 31) >> 5)), loopdetection_nblocks, 0);
|
|
|
|
removeblockfromloop(loop, newloop->body);
|
|
addblocktoloop(newloop, newloop->body);
|
|
|
|
bitvectorsetbit(newloop->body->blockIndex, newloop->vec24);
|
|
bitvectorsetbit(newloop->body->blockIndex, newloop->vec2C);
|
|
bitvectorsetbit(newloop->body->blockIndex, newloop->vec28);
|
|
|
|
for (scanlist = path2_24; scanlist; scanlist = scanlist->next) {
|
|
removeblockfromloop(loop, scanlist->block);
|
|
addblocktoloop(newloop, scanlist->block);
|
|
bitvectorsetbit(scanlist->block->blockIndex, newloop->vec2C);
|
|
}
|
|
|
|
newloop->preheader = NULL;
|
|
insertpreheaderblock(newloop);
|
|
analyzeloop(newloop);
|
|
|
|
loop->body = headercopy;
|
|
|
|
for (scanlist = loop->blocks; scanlist; scanlist = scanlist->next)
|
|
bitvectorsetbit(scanlist->block->blockIndex, loop->vec2C);
|
|
|
|
bitvectorsetbit(headercopy->blockIndex, loop->vec24);
|
|
analyzeloop(loop);
|
|
|
|
unswitchedinvariantcode = 1;
|
|
}
|
|
}
|
|
|
|
static void simpleunswitchloops(Loop *loop) {
|
|
while (loop) {
|
|
if (loop->children)
|
|
simpleunswitchloops(loop->children);
|
|
else if (!loop->x4F)
|
|
simpleunswitchloop(loop);
|
|
loop = loop->nextSibling;
|
|
}
|
|
}
|
|
|
|
static void moveinvariantsfromloop(Loop *loop) {
|
|
RegUseOrDef *list;
|
|
BlockList *blocklist;
|
|
PCode *instr;
|
|
PCode *nextInstr;
|
|
UInt32 *myvec;
|
|
UseOrDef *def;
|
|
int defID;
|
|
int flag;
|
|
PCodeBlock *block;
|
|
|
|
myvec = oalloc(4 * ((number_of_Defs + 31) >> 5));
|
|
do {
|
|
flag = 0;
|
|
for (blocklist = loop->blocks; blocklist; blocklist = blocklist->next) {
|
|
block = blocklist->block;
|
|
bitvectorcopy(myvec, usedefinfo[block->blockIndex].defvec8, number_of_Defs);
|
|
for (instr = block->firstPCode; instr; instr = nextInstr) {
|
|
nextInstr = instr->nextPCode;
|
|
if (!(instr->flags & fIsBranch) && instr->argCount) {
|
|
if (
|
|
!(instr->flags & (fIsCall | fIsPtrOp | fIsVolatile | fSideEffects)) &&
|
|
isloopinvariant(instr, loop, myvec, 0, 0) &&
|
|
maymove(instr, loop)
|
|
) {
|
|
moveinvariantcomputation(instr, loop);
|
|
flag = 1;
|
|
} else if (srawi_addze_isloopinvariant(instr, loop, myvec)) {
|
|
moveinvariantcomputation(instr, loop);
|
|
flag = 1;
|
|
}
|
|
|
|
for (def = &Defs[defID = instr->defID]; defID < number_of_Defs && def->pcode == instr; def++, defID++) {
|
|
if (def->v.kind == PCOp_REGISTER) {
|
|
for (list = reg_Defs[def->v.arg][def->v.u.reg]; list; list = list->next)
|
|
bitvectorclearbit(list->id, myvec);
|
|
} else if (def->v.kind == PCOp_MEMORY) {
|
|
if (def->v.arg == PCOpMemory0) {
|
|
for (list = findobjectusedef(def->v.u.object)->defs; list; list = list->next) {
|
|
if (uniquely_aliases(instr, Defs[list->id].pcode))
|
|
bitvectorclearbit(list->id, myvec);
|
|
}
|
|
}
|
|
} else {
|
|
CError_FATAL(1434);
|
|
}
|
|
|
|
bitvectorsetbit(defID, myvec);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} while (flag);
|
|
}
|
|
|
|
static void moveinvariantsfromloops(Loop *loop) {
|
|
while (loop) {
|
|
if (loop->children)
|
|
moveinvariantsfromloops(loop->children);
|
|
moveinvariantsfromloop(loop);
|
|
loop = loop->nextSibling;
|
|
}
|
|
}
|
|
|
|
void moveloopinvariantcode(void) {
|
|
unswitchedinvariantcode = 0;
|
|
movedloopinvariantcode = 0;
|
|
if (loopsinflowgraph) {
|
|
moveinvariantsfromloops(loopsinflowgraph);
|
|
simpleunswitchloops(loopsinflowgraph);
|
|
}
|
|
freeoheap();
|
|
}
|