mirror of https://git.wuffs.org/MWCC
268 lines
9.3 KiB
C
268 lines
9.3 KiB
C
#include "compiler/IroJump.h"
|
|
#include "compiler/IroDump.h"
|
|
#include "compiler/IroFlowgraph.h"
|
|
#include "compiler/IroLinearForm.h"
|
|
#include "compiler/IroUtil.h"
|
|
#include "compiler/CFunc.h"
|
|
#include "compiler/Exceptions.h"
|
|
|
|
static Boolean CheckChain(CLabel **labelptr) {
|
|
IRONode *node;
|
|
|
|
for (node = IRO_FirstNode; node; node = node->nextnode) {
|
|
if (node->first && node->first->type == IROLinearLabel && node->first->u.label.label == *labelptr) {
|
|
IROLinear *linear;
|
|
CLabel *lab;
|
|
for (linear = node->first->next, lab = NULL; linear && (linear->type == IROLinearLabel || linear->type == IROLinearNop); linear = linear->next) {
|
|
if (linear->type == IROLinearLabel)
|
|
lab = linear->u.label.label;
|
|
}
|
|
|
|
if (linear->type == IROLinearGoto && *labelptr != linear->u.label.label) {
|
|
*labelptr = linear->u.label.label;
|
|
IRO_Dump("Chaining goto at %d\n", linear->index);
|
|
return 1;
|
|
}
|
|
|
|
if (lab && *labelptr != lab)
|
|
*labelptr = lab;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
Boolean IRO_DoJumpChaining(void) {
|
|
IRONode *node;
|
|
IROLinear *linear;
|
|
Boolean flag;
|
|
SwitchInfo *info;
|
|
SwitchCase *curcase;
|
|
Boolean result;
|
|
|
|
result = 0;
|
|
do {
|
|
flag = 0;
|
|
for (node = IRO_FirstNode; node; node = node->nextnode) {
|
|
if (node->first) {
|
|
linear = node->last;
|
|
switch (linear->type) {
|
|
case IROLinearGoto:
|
|
if (CheckChain(&linear->u.label.label))
|
|
flag = 1;
|
|
break;
|
|
case IROLinearIf:
|
|
case IROLinearIfNot:
|
|
if (CheckChain(&linear->u.label.label))
|
|
flag = 1;
|
|
break;
|
|
case IROLinearSwitch:
|
|
info = linear->u.swtch.info;
|
|
for (curcase = info->cases; curcase; curcase = curcase->next) {
|
|
if (CheckChain(&curcase->label))
|
|
flag = 1;
|
|
}
|
|
if (CheckChain(&info->defaultlabel))
|
|
flag = 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
result |= flag;
|
|
IRO_CheckForUserBreak();
|
|
} while (flag);
|
|
|
|
return result;
|
|
}
|
|
|
|
void IRO_MakeReachable(IRONode *node) {
|
|
UInt16 i;
|
|
Boolean flag;
|
|
|
|
node->x36 = 1;
|
|
do {
|
|
flag = 0;
|
|
for (node = IRO_FirstNode; node; node = node->nextnode) {
|
|
if (node->x36 && !node->x37) {
|
|
for (i = 0; i < node->numsucc; i++) {
|
|
if (!IRO_NodeTable[node->succ[i]]->x36) {
|
|
flag = 1;
|
|
IRO_NodeTable[node->succ[i]]->x36 = 1;
|
|
}
|
|
}
|
|
node->x37 = 1;
|
|
}
|
|
}
|
|
} while (flag);
|
|
}
|
|
|
|
Boolean IRO_RemoveUnreachable(void) {
|
|
IRONode *node2;
|
|
IRONode *node1;
|
|
IROLinear *scan;
|
|
IROLinear *linear;
|
|
Boolean result;
|
|
ExceptionAction **actptr;
|
|
ExceptionAction *act;
|
|
|
|
result = 0;
|
|
IRO_ComputeSuccPred();
|
|
IRO_MakeReachable(IRO_FirstNode);
|
|
node1 = IRO_FirstNode;
|
|
for (node2 = IRO_FirstNode->nextnode; node2; node2 = node2->nextnode) {
|
|
if (node2->first && !node2->x36) {
|
|
IRO_Dump("Removing unreachable code at: %d\n", node2->index);
|
|
node1->nextnode = node2->nextnode;
|
|
node1->last->next = node2->last->next;
|
|
result = 1;
|
|
for (linear = node2->first; linear && linear->type == IROLinearLabel && linear != node2->last->next; linear = linear->next) {
|
|
for (scan = IRO_FirstLinear; scan; scan = scan->next) {
|
|
if (scan->stmt)
|
|
scan->stmt->marked = 0;
|
|
}
|
|
|
|
for (scan = IRO_FirstLinear; scan; scan = scan->next) {
|
|
if (scan->stmt && !scan->stmt->marked) {
|
|
scan->stmt->marked = 1;
|
|
for (actptr = &scan->stmt->dobjstack; (act = *actptr); actptr = &act->prev) {
|
|
if (
|
|
(act->type == EAT_CATCHBLOCK && act->data.catch_block.catch_label == linear->u.label.label) ||
|
|
(act->type == EAT_SPECIFICATION && act->data.specification.unexp_label == linear->u.label.label)) {
|
|
*actptr = act->prev;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (node2 == IRO_LastNode)
|
|
IRO_LastNode = node1;
|
|
} else {
|
|
node1 = node2;
|
|
}
|
|
}
|
|
|
|
if (result) {
|
|
IRO_ComputeSuccPred();
|
|
IRO_ComputeDom();
|
|
}
|
|
|
|
IRO_CheckForUserBreak();
|
|
return result;
|
|
}
|
|
|
|
Boolean IRO_RemoveRedundantJumps(void) {
|
|
IRONode *node;
|
|
IROLinear *linear;
|
|
IROLinear *scan;
|
|
IROLinear *scan2;
|
|
SwitchInfo *info;
|
|
SwitchCase *curcase;
|
|
Boolean result;
|
|
|
|
result = 0;
|
|
for (node = IRO_FirstNode; node; node = node->nextnode) {
|
|
if (node->first) {
|
|
linear = node->last;
|
|
switch (linear->type) {
|
|
case IROLinearGoto:
|
|
scan = linear->next;
|
|
while (scan && ((scan->type == IROLinearNop) || (scan->type == IROLinearLabel && scan->u.label.label != linear->u.label.label)))
|
|
scan = scan->next;
|
|
while (1) {
|
|
if (!scan) break;
|
|
if (scan->type != IROLinearLabel) break;
|
|
if (scan->u.label.label == linear->u.label.label) {
|
|
IRO_Dump("Removing goto next at %d\n", linear->index);
|
|
linear->type = IROLinearNop;
|
|
result = 1;
|
|
break;
|
|
}
|
|
scan = scan->next;
|
|
}
|
|
break;
|
|
|
|
case IROLinearIf:
|
|
case IROLinearIfNot:
|
|
scan = linear->next;
|
|
while (scan && scan->type == IROLinearNop)
|
|
scan = scan->next;
|
|
if (scan && scan->type == IROLinearGoto) {
|
|
scan2 = scan->next;
|
|
while (scan2 && ((scan2->type == IROLinearNop) || (scan2->type == IROLinearLabel && scan2->u.label.label != linear->u.label.label)))
|
|
scan2 = scan2->next;
|
|
|
|
if (scan2 && scan2->type == IROLinearLabel && scan2->u.label.label == linear->u.label.label) {
|
|
if (linear->type == IROLinearIf)
|
|
linear->type = IROLinearIfNot;
|
|
else
|
|
linear->type = IROLinearIf;
|
|
|
|
linear->u.label.label = scan->u.label.label;
|
|
scan->type = IROLinearNop;
|
|
IRO_Dump("Removing branch around goto at %d\n", linear->index);
|
|
result = 1;
|
|
}
|
|
}
|
|
|
|
scan2 = linear->next;
|
|
while (scan2 && ((scan2->type == IROLinearNop) || (scan2->type == IROLinearLabel && scan2->u.label.label != linear->u.label.label)))
|
|
scan2 = scan2->next;
|
|
while (1) {
|
|
if (!scan2) break;
|
|
if (scan2->type != IROLinearLabel) break;
|
|
if (scan2->u.label.label == linear->u.label.label) {
|
|
IRO_Dump("Removing If/IfNot_Goto next at %d\n", linear->index);
|
|
linear->type = IROLinearNop;
|
|
IRO_CheckSideEffect(linear->u.label.x4);
|
|
result = 1;
|
|
break;
|
|
}
|
|
scan2 = scan2->next;
|
|
}
|
|
break;
|
|
|
|
case IROLinearSwitch:
|
|
info = linear->u.swtch.info;
|
|
curcase = info->cases;
|
|
while (curcase && curcase->label == info->defaultlabel)
|
|
curcase = curcase->next;
|
|
if (!curcase) {
|
|
IRO_Dump("Removing Switch next at %d\n", linear->index);
|
|
IRO_CheckSideEffect(linear->u.swtch.x4);
|
|
linear->type = IROLinearGoto;
|
|
linear->u.label.label = info->defaultlabel;
|
|
result = 1;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (result) {
|
|
IRO_ComputeSuccPred();
|
|
IRO_ComputeDom();
|
|
}
|
|
|
|
IRO_CheckForUserBreak();
|
|
return result;
|
|
}
|
|
|
|
Boolean IRO_RemoveLabels(void) {
|
|
Boolean result;
|
|
IRONode *node;
|
|
|
|
result = 0;
|
|
IRO_ComputeSuccPred();
|
|
for (node = IRO_FirstNode; node; node = node->nextnode) {
|
|
if (node->first && node->first->type == IROLinearLabel && !node->x39) {
|
|
node->first->type = IROLinearNop;
|
|
node->first->flags &= ~IROLF_1;
|
|
result = 1;
|
|
}
|
|
}
|
|
|
|
IRO_CheckForUserBreak();
|
|
return result;
|
|
}
|