summaryrefslogtreecommitdiff
path: root/compiler_and_linker/FrontEnd/Optimizer/IroPropagate.c
diff options
context:
space:
mode:
Diffstat (limited to 'compiler_and_linker/FrontEnd/Optimizer/IroPropagate.c')
-rw-r--r--compiler_and_linker/FrontEnd/Optimizer/IroPropagate.c593
1 files changed, 593 insertions, 0 deletions
diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroPropagate.c b/compiler_and_linker/FrontEnd/Optimizer/IroPropagate.c
new file mode 100644
index 0000000..c5ad708
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/Optimizer/IroPropagate.c
@@ -0,0 +1,593 @@
+#include "IroPropagate.h"
+#include "IroCSE.h"
+#include "IroDump.h"
+#include "IroEval.h"
+#include "IroFlowgraph.h"
+#include "IroLinearForm.h"
+#include "IROUseDef.h"
+#include "IroUtil.h"
+#include "IroVars.h"
+#include "compiler/objects.h"
+#include "compiler/CExpr.h"
+#include "compiler/CompilerTools.h"
+#include "compiler/CParser.h"
+#include "compiler/InlineAsm.h"
+#include "compiler/InlineAsmPPC.h"
+
+IROAssign *IRO_FirstAssign;
+IROAssign *IRO_LastAssign;
+SInt32 IRO_NumAssign;
+
+static Boolean VarIsUsedInOtherFNodes(VarRecord *var, IRONode *node) {
+ if (var->defs && var->uses) {
+ IROUse *use;
+ IRODef *def = NULL;
+ for (use = var->uses; use; use = use->varnext) {
+ if (!def && use->node == node && use->linear && !(use->linear->flags & IROLF_Assigned)) {
+ for (def = var->defs; def; def = def->varnext) {
+ if (Bv_IsBitSet(def->index, use->x18))
+ break;
+ }
+ }
+ }
+
+ if (def) {
+ for (use = var->uses; use; use = use->varnext) {
+ if (use->node != node && use->linear && !(use->linear->flags & IROLF_Assigned)) {
+ if (Bv_IsBitSet(def->index, use->x18))
+ return 1;
+ }
+ }
+ }
+ } else {
+ IROLinear *linear;
+ IRONode *scan;
+ for (scan = IRO_FirstNode; scan; scan = scan->nextnode) {
+ if (scan != node) {
+ linear = scan->first;
+ while (1) {
+ if (!linear)
+ break;
+
+ if (IRO_IsVariable(linear) && !(linear->flags & IROLF_Assigned)) {
+ if (IRO_FindVar(linear->u.diadic.left->u.node->data.objref, 0, 1) == var)
+ return 1;
+ }
+
+ if (linear == scan->last)
+ break;
+ linear = linear->next;
+ }
+ }
+ }
+ IRO_CheckForUserBreak();
+ }
+
+ return 0;
+}
+
+static void GetExprUses(IROLinear *linear, Boolean isFirst) {
+ if (isFirst && IS_LINEAR_ENODE(linear, EOBJREF)) {
+ Object *obj = linear->u.node->data.objref;
+ if ((linear->flags & IROLF_Ind) && (!(linear->flags & IROLF_Assigned) || (linear->flags & IROLF_Used))) {
+ VarRecord *var = IRO_FindVar(obj, 0, 1);
+ if (var)
+ Bv_SetBit(var->index, IRO_VarKills);
+ }
+ }
+}
+
+static void GetExprKills(IROLinear *linear, Boolean isFirst) {
+ if (isFirst)
+ IRO_GetKills(linear);
+}
+
+static void CheckUnorderedRegionForDefs(IROLinear *linear, BitVector *a, BitVector *b, Boolean *flag) {
+ Bv_Clear(a);
+ Bv_Clear(IRO_VarKills);
+ IRO_WalkTree(linear, GetExprKills);
+ Bv_Or(IRO_VarKills, a);
+ if (Bv_BitsInCommon(a, b))
+ *flag = 1;
+}
+
+static void CheckUnorderedRegionsForDefs(IROLinear *linear1, IROLinear *linear2, BitVector *a, BitVector *b, Boolean *flag) {
+ int i;
+
+ switch (linear1->type) {
+ case IROLinearOp2Arg:
+ if (linear1->nodetype == ELAND) break;
+ if (linear1->nodetype == ELOR) break;
+ if (linear1->nodetype == ECOMMA) break;
+ if (linear1->u.diadic.left != linear2)
+ CheckUnorderedRegionForDefs(linear1->u.diadic.left, a, b, flag);
+ if (linear1->u.diadic.right != linear2)
+ CheckUnorderedRegionForDefs(linear1->u.diadic.right, a, b, flag);
+ break;
+ case IROLinearFunccall:
+ if (linear1->u.funccall.linear8 != linear2)
+ CheckUnorderedRegionForDefs(linear1->u.funccall.linear8, a, b, flag);
+ for (i = 0; !*flag && i < linear1->u.funccall.argCount; i++) {
+ if (linear1->u.funccall.args[i] != linear2)
+ CheckUnorderedRegionForDefs(linear1->u.funccall.args[i], a, b, flag);
+ }
+ break;
+ }
+}
+
+static Boolean PropagationHasDefsInUnorderedRegions(IROLinear *a, IROLinear *b) {
+ Boolean flag;
+ IROLinear *father;
+ BitVector *bv1;
+ BitVector *bv2;
+ VarRecord *var;
+
+ flag = 0;
+ if ((father = IRO_LocateFather(a))) {
+ Bv_AllocVector(&bv1, IRO_NumVars + 1);
+ Bv_AllocVector(&bv2, IRO_NumVars + 1);
+ Bv_AllocVector(&IRO_VarKills, IRO_NumVars + 1);
+ IRO_WalkTree(b, GetExprUses);
+ Bv_Or(IRO_VarKills, bv2);
+ var = IRO_FindVar(a->u.diadic.left->u.node->data.objref, 0, 1);
+ Bv_SetBit(var->index, bv2);
+ while (father && !flag) {
+ CheckUnorderedRegionsForDefs(father, a, bv1, bv2, &flag);
+ a = father;
+ father = IRO_LocateFather(father);
+ }
+ }
+
+ return flag;
+}
+
+int IRO_IsRegable(Object *obj) {
+ if (obj->datatype == DLOCAL && obj->u.var.info)
+ return obj->u.var.info->noregister == 0;
+ return 0;
+}
+
+static Boolean IsPropagatable(IROLinear *linear) {
+ Object *obj;
+ Object *obj2;
+
+ if (IS_LINEAR_DIADIC(linear, EASS) && (obj = IRO_IsVariable(linear->u.diadic.left)) && obj->type == linear->rtype && !is_volatile_object(obj)) {
+ if (linear->u.diadic.left->flags & IROLF_BitfieldIndirect) {
+ if (!IRO_IsConstant(linear->u.diadic.right))
+ return 0;
+ else
+ return 1;
+ }
+
+ if (IRO_IsConstant(linear->u.diadic.right))
+ return 1;
+
+ if ((obj2 = IRO_IsVariable(linear->u.diadic.right)) && !is_volatile_object(obj2) && IRO_TypesEqual(obj->type, linear->rtype)) {
+ if (!Inline_IsObjectData(linear->u.diadic.right->u.monadic->u.node->data.objref)) {
+ if (IRO_IsRegable(obj) && !IRO_IsRegable(obj2))
+ return 0;
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static Boolean IsIntGenKillCandidate(IROLinear *linear) {
+ if (linear->type == IROLinearFunccall)
+ return 1;
+
+ if (IRO_IsAssignOp[linear->nodetype] && (linear->type == IROLinearOp1Arg || linear->type == IROLinearOp2Arg))
+ return 1;
+
+ if (linear->type == IROLinearAsm)
+ return 1;
+
+ return 0;
+}
+
+static Boolean IsPropagatableExpr(IROLinear *linear, IROList *list) {
+ Object *obj;
+ if (IS_LINEAR_DIADIC(linear, EASS) && !(linear->flags & IROLF_Reffed)) {
+ if ((obj = IRO_IsVariable(linear->u.diadic.left)) && !is_volatile_object(obj) && !(linear->u.diadic.left->flags & IROLF_BitfieldIndirect)) {
+ if (!IRO_IsRegable(obj))
+ return 0;
+ if (IS_LINEAR_ENODE(linear->u.diadic.right, ESTRINGCONST))
+ return 0;
+
+ IRO_FindDepends(linear->u.diadic.right);
+ if (!IRO_NotSubable)
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static void ClearAvailibilityOnNode(IRONode *node, UInt32 bit) {
+ IRONode *scan;
+
+ for (scan = node->nextnode; scan; scan = scan->nextnode)
+ Bv_ClearBit(bit, scan->x16);
+}
+
+Boolean IRO_CopyAndConstantPropagation(void) {
+ IROAssign *ass2;
+ IROAssign *ass;
+ IROLinear *linear;
+ IRONode *node;
+ VarRecord *var;
+ BitVector *bv;
+ Boolean flag;
+ Boolean result;
+
+ IRO_FirstAssign = NULL;
+ IRO_NumAssign = 0;
+ result = 0;
+
+ for (node = IRO_FirstNode; node; node = node->nextnode) {
+ linear = node->first;
+ while (1) {
+ if (!linear)
+ break;
+
+ if (IsPropagatable(linear) && (var = IRO_FindAssigned(linear))) {
+ IROAssign *newass;
+ IRO_Dump("Found propagatable assignment at: %d\n", linear->index);
+ newass = oalloc(sizeof(IROAssign));
+ newass->linear = linear;
+ newass->next = NULL;
+ newass->index = ++IRO_NumAssign;
+ newass->varIndex = var->index;
+ newass->linear2 = linear->u.diadic.right;
+ newass->var = NULL;
+ newass->varObj = IRO_IsVariable(linear->u.diadic.right);
+ newass->node = node;
+ if (newass->varObj)
+ newass->var = IRO_FindVar(newass->varObj, 0, 1);
+ if (!IRO_FirstAssign)
+ IRO_FirstAssign = newass;
+ else
+ IRO_LastAssign->next = newass;
+ IRO_LastAssign = newass;
+ }
+
+ if (linear == node->last)
+ break;
+ linear = linear->next;
+ }
+ }
+
+ IRO_CheckForUserBreak();
+
+ node = IRO_FirstNode;
+ ass = IRO_FirstAssign;
+ Bv_AllocVector(&IRO_VarKills, IRO_NumVars + 1);
+ while (node) {
+ Bv_AllocVector(&node->x16, IRO_NumAssign);
+ if (node != IRO_FirstNode)
+ Bv_Set(node->x16);
+ Bv_AllocVector(&node->x22, IRO_NumAssign);
+ Bv_AllocVector(&node->x1E, IRO_NumAssign);
+ Bv_AllocVector(&node->x2A, IRO_NumAssign);
+ node->x1A = NULL;
+
+ linear = node->first;
+ while (1) {
+ if (!linear)
+ break;
+
+ if (IsIntGenKillCandidate(linear)) {
+ //IROAssign *ass2;
+ Bv_Clear(IRO_VarKills);
+ IRO_GetKills(linear);
+
+ for (ass2 = IRO_FirstAssign; ass2; ass2 = ass2->next) {
+ if (Bv_IsBitSet(ass2->varIndex, IRO_VarKills)) {
+ Bv_SetBit(ass2->index, node->x22);
+ Bv_ClearBit(ass2->index, node->x1E);
+ }
+ if (ass2->var && Bv_IsBitSet(ass2->var->index, IRO_VarKills)) {
+ Bv_SetBit(ass2->index, node->x22);
+ Bv_ClearBit(ass2->index, node->x1E);
+ }
+ }
+ }
+
+ while (ass && ass->linear == linear) {
+ Bv_SetBit(ass->index, node->x1E);
+ ass = ass->next;
+ }
+
+ if (linear == node->last)
+ break;
+ linear = linear->next;
+ }
+
+ Bv_Copy(node->x16, node->x2A);
+ Bv_Minus(node->x22, node->x2A);
+ Bv_Or(node->x1E, node->x2A);
+ node = node->nextnode;
+ }
+
+ IRO_CheckForUserBreak();
+
+ Bv_AllocVector(&bv, IRO_NumAssign);
+ do {
+ flag = 0;
+ for (node = IRO_FirstNode; node; node = node->nextnode) {
+ if (node == IRO_FirstNode) {
+ Bv_Clear(bv);
+ } else {
+ UInt16 i;
+ Bv_Set(bv);
+ for (i = 0; i < node->numpred; i++)
+ Bv_And(IRO_NodeTable[node->pred[i]]->x2A, bv);
+ }
+
+ if (!Bv_Compare(bv, node->x16)) {
+ flag = 1;
+ Bv_Copy(bv, node->x16);
+ }
+
+ Bv_Copy(node->x16, node->x2A);
+ Bv_Minus(node->x22, node->x2A);
+ Bv_Or(node->x1E, node->x2A);
+ }
+ } while (flag);
+
+ IRO_CheckForUserBreak();
+
+ node = IRO_FirstNode;
+ ass = IRO_FirstAssign;
+ while (node) {
+ IRO_Avail = node->x16;
+ linear = node->first;
+ while (1) {
+ if (!linear)
+ break;
+
+ if (IRO_IsVariable(linear) && !(linear->flags & IROLF_Assigned)) {
+ if ((var = IRO_FindVar(linear->u.diadic.left->u.node->data.objref, 0, 1))) {
+ //IROAssign *ass2;
+ for (ass2 = IRO_FirstAssign; ass2; ass2 = ass2->next) {
+ if (
+ ass2->varIndex == var->index &&
+ Bv_IsBitSet(ass2->index, IRO_Avail) &&
+ (IRO_IsConstant(ass2->linear2) || node->loopdepth <= ass2->node->loopdepth) &&
+ !PropagationHasDefsInUnorderedRegions(linear, ass2->linear2)
+ ) {
+ if (ass2->linear2->type == IROLinearOperand && IRO_is_CPtypeequal(linear->rtype, ass2->linear->u.diadic.left->rtype)) {
+ ENode *enode = IRO_NewENode(ass2->linear2->u.node->type);
+ *enode = *ass2->linear2->u.node;
+ if (enode->type == EINTCONST) {
+ if (linear->flags & IROLF_BitfieldIndirect) {
+ IRO_TruncateBitfieldValueToType(&enode->data.intval, linear->rtype, var->x1A);
+ enode->rtype = linear->rtype;
+ result = 1;
+ } else {
+ IRO_TruncateValueToType(&enode->data.intval, linear->rtype);
+ enode->rtype = linear->rtype;
+ }
+ }
+ linear->u.monadic->type = IROLinearNop;
+ linear->type = IROLinearOperand;
+ linear->u.node = enode;
+ } else if (ass2->varObj && IRO_is_CPtypeequal(linear->rtype, ass2->linear->rtype)) {
+ linear->u.diadic.left->u.node = create_objectrefnode(ass2->varObj);
+ if (ass2->linear2->flags & IROLF_BitfieldIndirect)
+ linear->flags |= IROLF_BitfieldIndirect;
+ }
+ IRO_Dump("Found propagation at %d from %d\n", linear->index, ass2->linear->index);
+ break;
+ }
+ }
+ }
+ } else if (linear->type == IROLinearAsm) {
+ IAEffects effects;
+ int i;
+ CodeGen_GetAsmEffects(linear->u.asm_stmt, &effects);
+
+ for (i = 0; i < effects.numoperands; i++) {
+ if (effects.operands[i].type == IAEffect_0 && effects.operands[i].offset == 0 && effects.operands[i].object->type->size == effects.operands[i].size) {
+ if ((var = IRO_FindVar(effects.operands[i].object, 0, 1))) {
+ //IROAssign *ass2;
+ for (ass2 = IRO_FirstAssign; ass2; ass2 = ass2->next) {
+ if (ass2->varIndex == var->index && Bv_IsBitSet(ass2->index, IRO_Avail) && ass2->linear->rtype->size == effects.operands[i].size) {
+ ENode *enode;
+ if (ass2->varObj)
+ enode = create_objectrefnode(ass2->varObj);
+ else if (ass2->linear2->type == IROLinearOperand)
+ enode = ass2->linear2->u.node;
+ else
+ CError_FATAL(768);
+ CodeGen_PropagateIntoAsm(linear->u.asm_stmt, effects.operands[i].object, enode);
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (IsIntGenKillCandidate(linear)) {
+ //IROAssign *ass2;
+ Bv_Clear(IRO_VarKills);
+ IRO_GetKills(linear);
+
+ for (ass2 = IRO_FirstAssign; ass2; ass2 = ass2->next) {
+ if (Bv_IsBitSet(ass2->varIndex, IRO_VarKills)) {
+ Bv_ClearBit(ass2->index, IRO_Avail);
+ }
+ if (ass2->var && Bv_IsBitSet(ass2->var->index, IRO_VarKills)) {
+ Bv_ClearBit(ass2->index, IRO_Avail);
+ }
+ }
+
+ while (ass && ass->linear == linear) {
+ Bv_SetBit(ass->index, IRO_Avail);
+ ass = ass->next;
+ }
+ }
+
+ if (linear == node->last)
+ break;
+ linear = linear->next;
+ }
+ node = node->nextnode;
+ }
+
+ IRO_CheckForUserBreak();
+
+ return result;
+}
+
+void IRO_ExpressionPropagation(void) {
+ IRONode *node;
+ IROLinear *linear;
+ Object *obj;
+ VarRecord *var;
+ IROAssign *ass;
+
+ for (node = IRO_FirstNode; node; node = node->nextnode) {
+ IRO_FirstAssign = NULL;
+ IRO_LastAssign = NULL;
+ IRO_NumAssign = 0;
+
+ linear = node->first;
+ while (1) {
+ IROList list;
+ if (!linear)
+ break;
+
+ IRO_InitList(&list);
+ if (IsPropagatableExpr(linear, &list)) {
+ if ((var = IRO_FindAssigned(linear))) {
+ IRO_Dump("Found propagatable expression assignment at: %d\n", linear->index);
+ ass = oalloc(sizeof(IROAssign));
+ ass->linear = linear;
+ ass->next = NULL;
+ ass->index = ++IRO_NumAssign;
+ ass->varIndex = var->index;
+ ass->linear2 = linear->u.diadic.right;
+ ass->x20 = 0;
+ ass->node = node;
+ IRO_FindDepends(linear->u.diadic.right);
+ ass->depends = IRO_Depends;
+ if (!IRO_FirstAssign) {
+ IRO_FirstAssign = ass;
+ ass->prev = NULL;
+ } else {
+ IRO_LastAssign->next = ass;
+ ass->prev = IRO_LastAssign;
+ }
+ IRO_LastAssign = ass;
+ }
+ }
+
+ if (IRO_IsVariable(linear) && !(linear->flags & IROLF_Assigned)) {
+ if ((var = IRO_FindVar(linear->u.monadic->u.node->data.objref, 0, 1))) {
+ for (ass = IRO_LastAssign; ass; ass = ass->prev) {
+ if (ass->varIndex == var->index)
+ ass->x20++;
+ }
+ }
+ }
+
+ if (linear == node->last)
+ break;
+ linear = linear->next;
+ }
+
+ Bv_AllocVector(&IRO_Avail, IRO_NumAssign);
+
+ linear = node->first;
+ while (1) {
+ if (!linear)
+ break;
+
+ if (IRO_IsVariable(linear) && !(linear->flags & IROLF_Assigned)) {
+ if ((var = IRO_FindVar(linear->u.monadic->u.node->data.objref, 0, 1))) {
+ for (ass = IRO_FirstAssign; ass; ass = ass->next) {
+ if (ass->varIndex == var->index && Bv_IsBitSet(ass->index, IRO_Avail) && !PropagationHasDefsInUnorderedRegions(linear, ass->linear2)) {
+ if (ass->linear2->type == IROLinearOperand && IRO_is_CPtypeequal(linear->rtype, ass->linear->u.diadic.left->rtype)) {
+ ENode *enode = IRO_NewENode(ass->linear2->u.node->type);
+ *enode = *ass->linear2->u.node;
+ if (enode->type == EINTCONST) {
+ IRO_TruncateValueToType(&enode->data.intval, linear->rtype);
+ enode->rtype = linear->rtype;
+ } else if (enode->type == EOBJREF) {
+ IROLinear *tmp = IRO_LocateFather(linear);
+ if (tmp && (tmp->flags & IROLF_Assigned))
+ linear->flags |= IROLF_Assigned;
+ }
+ linear->u.monadic->type = IROLinearNop;
+ linear->type = IROLinearOperand;
+ linear->u.node = enode;
+ } else if (IRO_IsVariable(ass->linear2) && IRO_is_CPtypeequal(linear->rtype, ass->linear->rtype)) {
+ linear->u.monadic->u.node = create_objectrefnode(ass->linear2->u.monadic->u.node->data.objref);
+ if (ass->linear2->flags & IROLF_BitfieldIndirect)
+ linear->flags |= IROLF_BitfieldIndirect;
+ } else if (IRO_is_CPtypeequal(linear->rtype, ass->linear->rtype) && ass->x20 == 1 && !VarIsUsedInOtherFNodes(var, node)) {
+ IROList list;
+ IRO_InitList(&list);
+ IRO_DuplicateExpr(ass->linear->u.diadic.right, &list);
+ if (IS_TYPE_FLOAT(ass->linear->rtype)) {
+ IROLinear *tmp = IRO_NewLinear(IROLinearOp1Arg);
+ tmp->index = ++IRO_NumLinear;
+ tmp->rtype = ass->linear->rtype;
+ tmp->nodetype = ETYPCON;
+ tmp->nodeflags = ENODE_FLAG_80;
+ tmp->u.monadic = list.tail;
+ IRO_AddToList(tmp, &list);
+ }
+ IRO_PasteAfter(list.head, list.tail, linear);
+ IRO_LocateFather_Cut_And_Paste(linear, list.tail);
+ linear = list.tail;
+ }
+ IRO_Dump("Found expression propagation at %d from %d\n", linear->index, ass->linear->index);
+ break;
+ }
+ }
+ }
+ }
+
+ if (linear->type != IROLinearNop && IsIntGenKillCandidate(linear)) {
+ Bv_Clear(IRO_VarKills);
+ IRO_GetKills(linear);
+ for (ass = IRO_FirstAssign; ass; ass = ass->next) {
+ if (Bv_IsBitSet(ass->varIndex, IRO_VarKills))
+ Bv_ClearBit(ass->index, IRO_Avail);
+ if ((obj = IRO_IsVariable(ass->linear->u.diadic.right))) {
+ if ((var = IRO_FindVar(obj, 0, 1))) {
+ if (Bv_IsBitSet(var->index, IRO_VarKills))
+ Bv_ClearBit(ass->index, IRO_Avail);
+ }
+ } else {
+ IROList list;
+ IRO_InitList(&list);
+ IRO_Depends = ass->depends;
+ IRO_FindDepends_NoAlloc(ass->linear->u.diadic.right);
+ if (Bv_BitsInCommon(IRO_VarKills, ass->depends))
+ Bv_ClearBit(ass->index, IRO_Avail);
+ }
+ }
+
+ for (ass = IRO_FirstAssign; ass; ass = ass->next) {
+ IRO_Depends = ass->depends;
+ IRO_FindDepends_NoAlloc(ass->linear->u.diadic.right);
+ if (ass->linear == linear && !Bv_IsBitSet(ass->varIndex, ass->depends))
+ Bv_SetBit(ass->index, IRO_Avail);
+ }
+ }
+
+ if (linear == node->last)
+ break;
+ linear = linear->next;
+ }
+ }
+
+ IRO_CheckForUserBreak();
+}
+