summaryrefslogtreecommitdiff
path: root/compiler_and_linker/FrontEnd/Optimizer/IroRangePropagation.c
diff options
context:
space:
mode:
Diffstat (limited to 'compiler_and_linker/FrontEnd/Optimizer/IroRangePropagation.c')
-rw-r--r--compiler_and_linker/FrontEnd/Optimizer/IroRangePropagation.c774
1 files changed, 774 insertions, 0 deletions
diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroRangePropagation.c b/compiler_and_linker/FrontEnd/Optimizer/IroRangePropagation.c
new file mode 100644
index 0000000..737035f
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/Optimizer/IroRangePropagation.c
@@ -0,0 +1,774 @@
+#include "IroRangePropagation.h"
+#include "IroDump.h"
+#include "IroFlowgraph.h"
+#include "IroLinearForm.h"
+#include "IroMalloc.h"
+#include "IroPointerAnalysis.h"
+#include "IroUtil.h"
+#include "IroVars.h"
+#include "compiler/CInt64.h"
+#include "compiler/objects.h"
+#include "compiler/types.h"
+
+#ifdef __MWERKS__
+#pragma options align=mac68k
+#endif
+typedef enum ERangeType {
+ ERangeType0,
+ ERangeType1,
+ ERangeType2,
+ ERangeType3
+} ERangeType;
+
+typedef struct ERange {
+ ERangeType type;
+ CInt64 upper;
+ CInt64 lower;
+} ERange;
+
+typedef struct ERecord {
+ Object *object;
+ ERange *range;
+ struct ERecord *next;
+} ERecord;
+#ifdef __MWERKS__
+#pragma options align=reset
+#endif
+
+static ERecord *ERangeFirst;
+static ERecord *ERangeLast;
+
+static ERange *ERnewERange(ERangeType type) {
+ ERange *range;
+
+ range = oalloc(sizeof(ERange));
+ range->type = type;
+ return range;
+}
+
+static ERecord *ERnewRecord(Object *object, ERange *range) {
+ ERecord *record;
+
+ record = oalloc(sizeof(ERecord));
+ record->object = object;
+ record->range = range;
+ record->next = ERangeFirst;
+ ERangeFirst = record;
+ if (!ERangeLast)
+ ERangeLast = record;
+ return record;
+}
+
+static ERecord *ERecordFound(Object *obj) {
+ ERecord *scan;
+
+ scan = ERangeFirst;
+ while (scan && obj != scan->object)
+ scan = scan->next;
+
+ return scan;
+}
+
+static Boolean EREandHasNoUse(ERange *range, CInt64 val) {
+ UInt16 i;
+ CInt64 v11;
+ CInt64 work;
+
+ i = 0;
+ work = range->upper;
+ while (CInt64_NotEqual(work = CInt64_ShrU(work, cint64_one), cint64_zero))
+ i++;
+
+ if (CInt64_NotEqual(range->upper, cint64_zero))
+ i++;
+
+ CInt64_SetULong(&work, i);
+ v11 = CInt64_Sub(CInt64_Shl(cint64_one, work), cint64_one);
+ if (CInt64_NotEqual(cint64_zero, CInt64_And(CInt64_Inv(val), v11)))
+ return 0;
+ else
+ return 1;
+}
+
+static void ERcheckOverflow(ERange *range, Type *type) {
+ CInt64 typeSize;
+ CInt64 work;
+ CInt64 work2;
+ CInt64 value3;
+
+ if (!range)
+ return;
+
+ if (!IS_TYPE_INT(type)) {
+ range->type = ERangeType3;
+ return;
+ }
+
+ CInt64_SetLong(&typeSize, type->size);
+ CInt64_SetLong(&value3, 3);
+
+ if (IRO_IsUnsignedType(type)) {
+ if (type->size < 8) {
+ work = CInt64_Sub(CInt64_Shl(cint64_one, CInt64_Shl(typeSize, value3)), cint64_one);
+ if (CInt64_GreaterU(range->upper, work))
+ range->type = ERangeType3;
+ } else {
+ range->type = ERangeType3;
+ }
+ } else {
+ if (type->size < 8) {
+ work = CInt64_Sub(CInt64_Shl(cint64_one, CInt64_Sub(CInt64_Shl(typeSize, value3), cint64_one)), cint64_one);
+ work2 = CInt64_Shl(cint64_negone, CInt64_Sub(CInt64_Shl(typeSize, value3), cint64_one));
+ if (CInt64_Greater(range->upper, work) || CInt64_Less(range->lower, work2))
+ range->type = ERangeType3;
+ } else {
+ range->type = ERangeType3;
+ }
+ }
+}
+
+static void ERinvalidAll(void) {
+ ERecord *record;
+
+ for (record = ERangeFirst; record; record = record->next)
+ record->range->type = ERangeType3;
+}
+
+static void SetRangesForKillsByIndirectAssignment(IROLinear *nd) {
+ IROListNode *list;
+ IROListNode *scan;
+ IROLinear *inner;
+ Boolean failed;
+ IROListNode *resultList;
+ IROLinear *scannd;
+ Boolean foundObjRef;
+ ERecord *record;
+ ERange *range;
+ IROListNode *next;
+ Object *obj;
+ IROLinear *analysend;
+ Object *proc;
+
+ failed = 0;
+ if (nd->type == IROLinearOp2Arg)
+ inner = nd->u.diadic.left;
+ else
+ inner = nd->u.monadic;
+
+ if (
+ inner &&
+ inner->type == IROLinearOp1Arg &&
+ inner->nodetype == EINDIRECT &&
+ (analysend = inner->u.monadic) &&
+ copts.opt_pointer_analysis &&
+ analysend->pointsToFunction &&
+ (proc = FunctionName)
+ ) {
+ resultList = NULL;
+ PointerAnalysis_LookupLinearNodePointerExpr(proc, analysend, &resultList);
+
+ if ((list = resultList)) {
+ for (scan = list; scan; scan = scan->nextList) {
+ if (!scan->list.head || !scan->list.tail) {
+ failed = 1;
+ break;
+ }
+
+ foundObjRef = 0;
+ for (scannd = scan->list.head; scannd != scan->list.tail->next; scannd = scannd->next) {
+ if (scannd->type == IROLinearOperand && scannd->u.node->type == EOBJREF) {
+ foundObjRef = 1;
+ break;
+ }
+ }
+
+ if (!foundObjRef) {
+ failed = 1;
+ break;
+ }
+ }
+
+ if (!failed) {
+ for (; list; list = list->nextList) {
+ for (scannd = list->list.head; scannd != list->list.tail->next; scannd = scannd->next) {
+ if (scannd->type == IROLinearOperand && scannd->u.node->type == EOBJREF) {
+ obj = scannd->u.node->data.objref;
+ CError_ASSERT(302, obj != NULL);
+
+ range = nd->x16;
+ if (nd->nodetype == EPOSTINC || nd->nodetype == EPOSTDEC)
+ range = inner->x16;
+
+ record = ERecordFound(obj);
+ if (!record)
+ ERnewRecord(obj, range);
+ else
+ record->range = range;
+ }
+ }
+ }
+ }
+
+ while (resultList) {
+ next = resultList->nextList;
+ IRO_free(resultList);
+ resultList = next;
+ }
+ } else {
+ failed = 1;
+ }
+ } else {
+ failed = 1;
+ }
+
+ if (failed) {
+ ERinvalidAll();
+ nd->x16 = ERnewERange(ERangeType3);
+ }
+}
+
+static void InvalidateRangesForKillsByFunctionCall(IROLinear *nd) {
+ IROListNode *scan;
+ IROLinear *scannd;
+ Boolean failed;
+ Boolean foundObjRef;
+ IROListNode *list;
+ IROListNode *resultList;
+ ERecord *record;
+ IROListNode *next;
+ Object *obj;
+ IROLinear *analysend;
+ Object *proc;
+ ObjectList *olist;
+ ObjectList *killList;
+
+ failed = 0;
+
+ if (
+ (analysend = nd->u.funccall.linear8) &&
+ copts.opt_pointer_analysis &&
+ analysend->pointsToFunction &&
+ (proc = FunctionName)
+ ) {
+ resultList = NULL;
+ PointerAnalysis_LookupLinearNodePointerExpr(proc, analysend, &resultList);
+
+ if (resultList) {
+ for (scan = resultList; scan; scan = scan->nextList) {
+ if (!scan->list.head || !scan->list.tail) {
+ failed = 1;
+ break;
+ }
+
+ foundObjRef = 0;
+ for (scannd = scan->list.head; scannd != scan->list.tail->next; scannd = scannd->next) {
+ if (scannd->type == IROLinearOperand && scannd->u.node->type == EOBJREF) {
+ foundObjRef = 1;
+ obj = scannd->u.node->data.objref;
+ CError_ASSERT(385, obj != NULL);
+
+ killList = NULL;
+ PointerAnalysis_GetFunctionKills(obj, nd, &killList);
+
+ for (olist = killList; olist; olist = olist->next) {
+ if (!olist->object) {
+ failed = 1;
+ break;
+ }
+ }
+
+ while (killList) {
+ olist = killList->next;
+ IRO_free(killList);
+ killList = olist;
+ }
+
+ if (failed)
+ break;
+ }
+ }
+
+ if (!foundObjRef)
+ failed = 1;
+ if (failed)
+ break;
+ }
+
+ if (!failed) {
+ for (list = resultList; list; list = list->nextList) {
+ for (scannd = list->list.head; scannd != list->list.tail->next; scannd = scannd->next) {
+ if (scannd->type == IROLinearOperand && scannd->u.node->type == EOBJREF) {
+ obj = scannd->u.node->data.objref;
+ killList = NULL;
+ PointerAnalysis_GetFunctionKills(obj, nd, &killList);
+
+ for (olist = killList; olist; olist = olist->next) {
+ if ((record = ERecordFound(olist->object)))
+ record->range->type = ERangeType3;
+ }
+
+ while (killList) {
+ olist = killList->next;
+ IRO_free(killList);
+ killList = olist;
+ }
+ }
+ }
+ }
+ }
+
+ while (resultList) {
+ next = resultList->nextList;
+ IRO_free(resultList);
+ resultList = next;
+ }
+ } else {
+ failed = 1;
+ }
+ } else {
+ failed = 1;
+ }
+
+ if (failed)
+ ERinvalidAll();
+}
+
+static void ERfoldOperand(IROLinear *nd) {
+ switch (nd->u.node->type) {
+ case EOBJREF:
+ nd->x16 = NULL;
+ break;
+ case EINTCONST:
+ nd->x16 = ERnewERange(ERangeType0);
+ nd->x16->upper = nd->x16->lower = nd->u.node->data.intval;
+ break;
+ case EFLOATCONST:
+ case ESTRINGCONST:
+ nd->x16 = ERnewERange(ERangeType0);
+ break;
+ }
+}
+
+static Boolean ERfoldExpr(IROLinear *nd) {
+ ERecord *record;
+ ERange *range;
+ IROLinear *tmp;
+ IROLinear *inner;
+ Object *obj;
+
+ switch (nd->nodetype) {
+ case EINDIRECT:
+ inner = nd->u.monadic;
+ if (IS_TYPE_INT(nd->rtype)) {
+ if (inner->type == IROLinearOperand && inner->u.node->type == EOBJREF) {
+ if (!inner->x16 && (obj = inner->u.node->data.objref)) {
+ if ((record = ERecordFound(obj))) {
+ inner->x16 = ERnewERange(ERangeType3);
+ *inner->x16 = *record->range;
+ } else {
+ inner->x16 = ERnewERange(ERangeType3);
+ inner->x16->upper = cint64_max;
+ inner->x16->lower = cint64_min;
+ ERnewRecord(obj, inner->x16);
+ }
+ }
+ nd->x16 = inner->x16;
+ } else {
+ nd->x16 = ERnewERange(ERangeType3);
+ nd->x16->upper = cint64_max;
+ nd->x16->lower = cint64_min;
+ }
+ } else {
+ if (inner->type == IROLinearOperand && inner->u.node->type == EOBJREF && !inner->x16)
+ inner->x16 = ERnewERange(ERangeType3);
+ nd->x16 = ERnewERange(ERangeType3);
+ }
+ break;
+ case EAND:
+ case EANDASS:
+ if (IRO_IsIntConstant(nd->u.diadic.right)) {
+ CInt64 val = nd->u.diadic.right->u.node->data.intval;
+ nd->x16 = ERnewERange(ERangeType1);
+ nd->x16->upper = val;
+ nd->x16->lower = cint64_zero;
+ if (
+ (range = nd->u.diadic.left->x16) &&
+ range->type != ERangeType3 &&
+ CInt64_LessEqualU(range->upper, val) &&
+ CInt64_LessEqualU(range->lower, val) &&
+ EREandHasNoUse(range, val) &&
+ !IRO_HasSideEffect(nd->u.diadic.left)
+ ) {
+ IRO_Dump("eliminating redundant EAND %" PRId32 "; upperBound==0x%x, lowerBound==0x%x, Constant==0x%x\n",
+ nd->index,
+ CInt64_GetULong(&range->upper),
+ CInt64_GetULong(&range->upper),
+ CInt64_GetULong(&val)
+ );
+ IRO_NopOut(nd->u.diadic.right);
+ nd->type = IROLinearNop;
+ nd->expr = NULL;
+ tmp = nd->u.diadic.left;
+ nd->u.diadic.left = nd->u.diadic.right;
+ if (!IRO_LocateFather_Cut_And_Paste(nd, tmp)) {
+ tmp->flags &= ~IROLF_Reffed;
+ if (IRO_IsVariable(tmp))
+ IRO_NopOut(tmp);
+ }
+ }
+ } else {
+ if (nd->u.diadic.right->x16) {
+ nd->x16 = ERnewERange(ERangeType3);
+ *nd->x16 = *nd->u.diadic.right->x16;
+ }
+ }
+ ERcheckOverflow(nd->x16, nd->rtype);
+ break;
+ case ELOGNOT:
+ case ELESS:
+ case EGREATER:
+ case ELESSEQU:
+ case EGREATEREQU:
+ case EEQU:
+ case ENOTEQU:
+ case ELAND:
+ case ELOR:
+ nd->x16 = ERnewERange(ERangeType1);
+ nd->x16->upper = cint64_one;
+ nd->x16->lower = cint64_zero;
+ ERcheckOverflow(nd->x16, nd->rtype);
+ break;
+ case EBINNOT:
+ case EFORCELOAD:
+ case EXOR:
+ case EOR:
+ case EXORASS:
+ case EORASS:
+ case ECOMMA:
+ case ETYPCON:
+ case EBITFIELD:
+ case ECOND:
+ case ENULLCHECK:
+ nd->x16 = ERnewERange(ERangeType3);
+ nd->x16->upper = cint64_max;
+ nd->x16->lower = cint64_min;
+ break;
+ case EASS:
+ if (IS_TYPE_INT(nd->rtype))
+ nd->x16 = nd->u.diadic.right->x16;
+ break;
+ case EMUL:
+ case EMULV:
+ case EMULASS:
+ if (IS_TYPE_INT(nd->rtype)) {
+ if (nd->u.diadic.left->x16 && nd->u.diadic.left->x16->type != ERangeType3 &&
+ nd->u.diadic.right->x16 && nd->u.diadic.right->x16->type != ERangeType3) {
+ nd->x16 = ERnewERange(ERangeType2);
+ if (IRO_IsUnsignedType(nd->rtype)) {
+ nd->x16->upper = CInt64_MulU(nd->u.diadic.left->x16->upper, nd->u.diadic.right->x16->upper);
+ nd->x16->lower = CInt64_MulU(nd->u.diadic.left->x16->lower, nd->u.diadic.right->x16->lower);
+ } else {
+ nd->x16->upper = CInt64_Mul(nd->u.diadic.left->x16->upper, nd->u.diadic.right->x16->upper);
+ nd->x16->lower = CInt64_Mul(nd->u.diadic.left->x16->lower, nd->u.diadic.right->x16->lower);
+ }
+ } else {
+ nd->x16 = ERnewERange(ERangeType3);
+ nd->x16->upper = cint64_max;
+ nd->x16->lower = cint64_min;
+ }
+ }
+ ERcheckOverflow(nd->x16, nd->rtype);
+ break;
+ case EDIV:
+ case EDIVASS:
+ if (IS_TYPE_INT(nd->rtype)) {
+ if (nd->u.diadic.left->x16 && nd->u.diadic.left->x16->type != ERangeType3 &&
+ nd->u.diadic.right->x16 && nd->u.diadic.right->x16->type != ERangeType3) {
+ nd->x16 = ERnewERange(ERangeType2);
+ if (!CInt64_IsZero(&nd->u.diadic.right->x16->lower) && !CInt64_IsZero(&nd->u.diadic.right->x16->upper)) {
+ if (IRO_IsUnsignedType(nd->rtype)) {
+ nd->x16->upper = CInt64_DivU(nd->u.diadic.left->x16->upper, nd->u.diadic.right->x16->lower);
+ nd->x16->lower = CInt64_DivU(nd->u.diadic.left->x16->lower, nd->u.diadic.right->x16->upper);
+ } else {
+ nd->x16->upper = CInt64_Div(nd->u.diadic.left->x16->upper, nd->u.diadic.right->x16->lower);
+ nd->x16->lower = CInt64_Div(nd->u.diadic.left->x16->lower, nd->u.diadic.right->x16->upper);
+ }
+ } else {
+ nd->x16 = ERnewERange(ERangeType3);
+ nd->x16->upper = cint64_max;
+ nd->x16->lower = cint64_min;
+ }
+ } else {
+ nd->x16 = ERnewERange(ERangeType3);
+ nd->x16->upper = cint64_max;
+ nd->x16->lower = cint64_min;
+ }
+ }
+ ERcheckOverflow(nd->x16, nd->rtype);
+ break;
+ case EMODULO:
+ case EMODASS:
+ if (IS_TYPE_INT(nd->rtype)) {
+ if (nd->u.diadic.left->x16 && nd->u.diadic.left->x16->type != ERangeType3 &&
+ nd->u.diadic.right->x16 && nd->u.diadic.right->x16->type != ERangeType3) {
+ nd->x16 = ERnewERange(ERangeType2);
+ if (!CInt64_IsZero(&nd->u.diadic.right->x16->lower) && !CInt64_IsZero(&nd->u.diadic.right->x16->upper)) {
+ if (IRO_IsUnsignedType(nd->rtype)) {
+ nd->x16->upper = CInt64_ModU(nd->u.diadic.left->x16->upper, nd->u.diadic.right->x16->lower);
+ nd->x16->lower = CInt64_ModU(nd->u.diadic.left->x16->lower, nd->u.diadic.right->x16->upper);
+ } else {
+ nd->x16->upper = CInt64_Mod(nd->u.diadic.left->x16->upper, nd->u.diadic.right->x16->lower);
+ nd->x16->lower = CInt64_Mod(nd->u.diadic.left->x16->lower, nd->u.diadic.right->x16->upper);
+ }
+ } else {
+ nd->x16 = ERnewERange(ERangeType3);
+ nd->x16->upper = cint64_max;
+ nd->x16->lower = cint64_min;
+ }
+ } else {
+ nd->x16 = ERnewERange(ERangeType3);
+ nd->x16->upper = cint64_max;
+ nd->x16->lower = cint64_min;
+ }
+ }
+ ERcheckOverflow(nd->x16, nd->rtype);
+ break;
+ case EADDV:
+ case EADD:
+ case EADDASS:
+ if (IS_TYPE_INT(nd->rtype)) {
+ if (nd->u.diadic.left->x16 && nd->u.diadic.left->x16->type != ERangeType3 &&
+ nd->u.diadic.right->x16 && nd->u.diadic.right->x16->type != ERangeType3) {
+ nd->x16 = ERnewERange(ERangeType2);
+ nd->x16->upper = CInt64_Add(nd->u.diadic.left->x16->upper, nd->u.diadic.right->x16->upper);
+ nd->x16->lower = CInt64_Add(nd->u.diadic.left->x16->lower, nd->u.diadic.right->x16->lower);
+ } else {
+ nd->x16 = ERnewERange(ERangeType3);
+ nd->x16->upper = cint64_max;
+ nd->x16->lower = cint64_min;
+ }
+ }
+ ERcheckOverflow(nd->x16, nd->rtype);
+ break;
+ case ESUBV:
+ case ESUB:
+ case ESUBASS:
+ if (IS_TYPE_INT(nd->rtype)) {
+ if (nd->u.diadic.left->x16 && nd->u.diadic.left->x16->type != ERangeType3 &&
+ nd->u.diadic.right->x16 && nd->u.diadic.right->x16->type != ERangeType3) {
+ nd->x16 = ERnewERange(ERangeType2);
+ nd->x16->upper = CInt64_Sub(nd->u.diadic.left->x16->upper, nd->u.diadic.right->x16->lower);
+ nd->x16->lower = CInt64_Sub(nd->u.diadic.left->x16->lower, nd->u.diadic.right->x16->upper);
+ } else {
+ nd->x16 = ERnewERange(ERangeType3);
+ nd->x16->upper = cint64_max;
+ nd->x16->lower = cint64_min;
+ }
+ }
+ ERcheckOverflow(nd->x16, nd->rtype);
+ break;
+ case ESHL:
+ case ESHLASS:
+ if (IS_TYPE_INT(nd->rtype)) {
+ if (nd->u.diadic.left->x16 && nd->u.diadic.left->x16->type != ERangeType3 &&
+ nd->u.diadic.right->x16 && nd->u.diadic.right->x16->type != ERangeType3) {
+ nd->x16 = ERnewERange(ERangeType2);
+ nd->x16->upper = CInt64_Shl(nd->u.diadic.left->x16->upper, nd->u.diadic.right->x16->upper);
+ nd->x16->lower = CInt64_Shl(nd->u.diadic.left->x16->lower, nd->u.diadic.right->x16->lower);
+ } else {
+ nd->x16 = ERnewERange(ERangeType3);
+ nd->x16->upper = cint64_max;
+ nd->x16->lower = cint64_min;
+ }
+ }
+ ERcheckOverflow(nd->x16, nd->rtype);
+ break;
+ case ESHR:
+ case ESHRASS:
+ if (IS_TYPE_INT(nd->rtype)) {
+ if (nd->u.diadic.left->x16 && nd->u.diadic.left->x16->type != ERangeType3 &&
+ nd->u.diadic.right->x16 && nd->u.diadic.right->x16->type != ERangeType3) {
+ nd->x16 = ERnewERange(ERangeType2);
+ if (IRO_IsUnsignedType(nd->rtype)) {
+ nd->x16->upper = CInt64_ShrU(nd->u.diadic.left->x16->upper, nd->u.diadic.right->x16->lower);
+ nd->x16->lower = CInt64_ShrU(nd->u.diadic.left->x16->lower, nd->u.diadic.right->x16->upper);
+ } else {
+ nd->x16->upper = CInt64_Shr(nd->u.diadic.left->x16->upper, nd->u.diadic.right->x16->lower);
+ nd->x16->lower = CInt64_Shr(nd->u.diadic.left->x16->lower, nd->u.diadic.right->x16->upper);
+ }
+ } else {
+ nd->x16 = ERnewERange(ERangeType3);
+ nd->x16->upper = cint64_max;
+ nd->x16->lower = cint64_min;
+ }
+ }
+ ERcheckOverflow(nd->x16, nd->rtype);
+ break;
+ case EPOSTINC:
+ if (IS_TYPE_INT(nd->rtype)) {
+ if (nd->u.monadic->x16 && nd->u.monadic->x16->type != ERangeType3) {
+ nd->x16 = ERnewERange(ERangeType2);
+ range = nd->u.monadic->x16;
+ *nd->x16 = *range;
+ range->upper = CInt64_Add(range->upper, cint64_one);
+ range->lower = CInt64_Add(range->lower, cint64_one);
+ } else {
+ nd->x16 = ERnewERange(ERangeType3);
+ nd->x16->upper = cint64_max;
+ nd->x16->lower = cint64_min;
+ }
+ }
+ ERcheckOverflow(nd->x16, nd->rtype);
+ break;
+ case EPOSTDEC:
+ if (IS_TYPE_INT(nd->rtype)) {
+ if (nd->u.monadic->x16 && nd->u.monadic->x16->type != ERangeType3) {
+ nd->x16 = ERnewERange(ERangeType2);
+ range = nd->u.monadic->x16;
+ *nd->x16 = *range;
+ range->upper = CInt64_Sub(range->upper, cint64_one);
+ range->lower = CInt64_Sub(range->lower, cint64_one);
+ } else {
+ nd->x16 = ERnewERange(ERangeType3);
+ nd->x16->upper = cint64_max;
+ nd->x16->lower = cint64_min;
+ }
+ }
+ ERcheckOverflow(nd->x16, nd->rtype);
+ break;
+ case EPREINC:
+ if (IS_TYPE_INT(nd->rtype)) {
+ if (nd->u.monadic->x16 && nd->u.monadic->x16->type != ERangeType3) {
+ nd->x16 = ERnewERange(ERangeType2);
+ range = nd->u.monadic->x16;
+ nd->x16->upper = CInt64_Add(range->upper, cint64_one);
+ nd->x16->lower = CInt64_Add(range->lower, cint64_one);
+ } else {
+ nd->x16 = ERnewERange(ERangeType3);
+ nd->x16->upper = cint64_max;
+ nd->x16->lower = cint64_min;
+ }
+ }
+ ERcheckOverflow(nd->x16, nd->rtype);
+ break;
+ case EPREDEC:
+ if (IS_TYPE_INT(nd->rtype)) {
+ if (nd->u.monadic->x16 && nd->u.monadic->x16->type != ERangeType3) {
+ nd->x16 = ERnewERange(ERangeType2);
+ range = nd->u.monadic->x16;
+ nd->x16->upper = CInt64_Sub(range->upper, cint64_one);
+ nd->x16->lower = CInt64_Sub(range->lower, cint64_one);
+ } else {
+ nd->x16 = ERnewERange(ERangeType3);
+ nd->x16->upper = cint64_max;
+ nd->x16->lower = cint64_min;
+ }
+ }
+ ERcheckOverflow(nd->x16, nd->rtype);
+ break;
+ case EMONMIN:
+ nd->x16 = ERnewERange(ERangeType3);
+ nd->x16->upper = cint64_max;
+ nd->x16->lower = cint64_min;
+ break;
+ case EPMODULO:
+ case EROTL:
+ case EROTR:
+ case EBCLR:
+ case EBTST:
+ case EBSET:
+ nd->x16 = ERnewERange(ERangeType3);
+ nd->x16->upper = cint64_max;
+ nd->x16->lower = cint64_min;
+ break;
+ default:
+ ERcheckOverflow(nd->x16, nd->rtype);
+ break;
+ }
+
+ if (
+ (nd->type == IROLinearOp1Arg || nd->type == IROLinearOp2Arg) &&
+ IRO_IsAssignOp[nd->nodetype] &&
+ nd->x16 &&
+ IS_TYPE_INT(nd->rtype)
+ ) {
+ IROLinear *x = NULL;
+ if (nd->type == IROLinearOp2Arg)
+ x = nd->u.diadic.left;
+ else if (nd->type == IROLinearOp1Arg)
+ x = nd->u.monadic;
+
+ if (x->type == IROLinearOp1Arg &&
+ x->nodetype == EINDIRECT &&
+ (x->u.monadic->nodetype == EINDIRECT || x->u.monadic->nodetype == EADD)) {
+ SetRangesForKillsByIndirectAssignment(nd);
+ } else {
+ obj = NULL;
+ if (x)
+ obj = IRO_IsVariable(x);
+ if (!obj)
+ return 0;
+
+ range = nd->x16;
+ if (nd->nodetype == EPOSTINC || nd->nodetype == EPOSTDEC)
+ range = x->x16;
+
+ record = ERecordFound(obj);
+ if (!record)
+ ERnewRecord(obj, range);
+ else
+ record->range = range;
+ }
+ }
+
+ return nd->x16 != NULL;
+}
+
+static Boolean ERfoldLinear(IROLinear *nd) {
+ nd->x16 = 0;
+
+ switch (nd->type) {
+ case IROLinearNop:
+ case IROLinearEnd:
+ break;
+ case IROLinearOperand:
+ ERfoldOperand(nd);
+ break;
+ case IROLinearOp1Arg:
+ case IROLinearOp2Arg:
+ ERfoldExpr(nd);
+ break;
+ case IROLinearFunccall:
+ InvalidateRangesForKillsByFunctionCall(nd);
+ break;
+ case IROLinearAsm:
+ ERinvalidAll();
+ break;
+ }
+
+ return 0;
+}
+
+Boolean IRO_RangePropagateInFNode(void) {
+ IRONode *fnode;
+ IROLinear *nd;
+ Boolean result;
+
+ result = 0;
+
+ for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) {
+ ERangeFirst = ERangeLast = NULL;
+ for (nd = fnode->first; nd != fnode->last; nd = nd->next)
+ ERfoldLinear(nd);
+ if (ERfoldLinear(nd))
+ result = 1;
+ }
+
+ if (result) {
+ IRO_ComputeSuccPred();
+ IRO_ComputeDom();
+ }
+
+ IRO_CheckForUserBreak();
+ return result;
+}