mirror of https://git.wuffs.org/MWCC
775 lines
27 KiB
C
775 lines
27 KiB
C
#include "compiler/IroRangePropagation.h"
|
|
#include "compiler/IroDump.h"
|
|
#include "compiler/IroFlowgraph.h"
|
|
#include "compiler/IroLinearForm.h"
|
|
#include "compiler/IroMalloc.h"
|
|
#include "compiler/IroPointerAnalysis.h"
|
|
#include "compiler/IroUtil.h"
|
|
#include "compiler/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 %ld; 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;
|
|
}
|