MWCC/compiler_and_linker/unsorted/IroUtil.c

1263 lines
39 KiB
C

#include "compiler/IroUtil.h"
#include "compiler/IroCSE.h"
#include "compiler/IroDump.h"
#include "compiler/IroFlowgraph.h"
#include "compiler/IroLinearForm.h"
#include "compiler/IroLoop.h"
#include "compiler/IroVars.h"
#include "compiler/InlineAsmPPC.h"
#include "compiler/CompilerTools.h"
#include "compiler/CCompiler.h"
#include "compiler/CError.h"
#include "compiler/CException.h"
#include "compiler/CExpr.h"
#include "compiler/CFunc.h"
#include "compiler/CInt64.h"
#include "compiler/CMachine.h"
#include "compiler/CParser.h"
#include "compiler/Exceptions.h"
#include "compiler/objects.h"
#include "compiler/types.h"
#include "cos.h"
static UInt32 IRO_LastUserBreakTick;
static IROLinear *ExprStart;
static IROLinear *ExprEnd;
static IRONode *IRO_Node;
static SInt32 FuncLevel;
Object *FunctionName;
Boolean IRO_IsLeafFunction;
Boolean IRO_FunctionHasReturn;
Boolean DisableDueToAsm;
Boolean LoopOptimizerRun;
Object *IRO_IsVariable(IROLinear *linear) {
if (linear->type == IROLinearOp1Arg &&
linear->nodetype == EINDIRECT &&
linear->u.monadic->type == IROLinearOperand &&
linear->u.monadic->u.node->type == EOBJREF)
return linear->u.monadic->u.node->data.objref;
return NULL;
}
Boolean IRO_IsConstant(IROLinear *linear) {
if (linear->type == IROLinearOperand && ENODE_IS3(linear->u.node, EINTCONST, EVECTOR128CONST, EFLOATCONST))
return 1;
return 0;
}
Boolean IRO_IsPow2(IROLinear *linear, SInt32 *powvalue) {
UInt32 desired;
UInt32 value;
SInt32 i;
*powvalue = -1;
if (linear->type == IROLinearOperand && linear->u.node->type == EINTCONST) {
if (CTool_EndianReadWord32(&linear->u.node->data.intval.hi))
return 0;
desired = CInt64_GetULong(&linear->u.node->data.intval);
value = 1;
for (i = 0; i < 31; i++) {
if (value == desired) {
*powvalue = i;
return 1;
}
value += value;
}
}
return 0;
}
Boolean IRO_IsIntConstant(IROLinear *linear) {
if (linear->type == IROLinearOperand && ENODE_IS(linear->u.node, EINTCONST))
return 1;
return 0;
}
Boolean IRO_IsFloatConstant(IROLinear *linear) {
if (linear->type == IROLinearOperand && ENODE_IS(linear->u.node, EFLOATCONST))
return 1;
return 0;
}
Boolean IRO_IsVector128Constant(IROLinear *linear) {
if (linear->type == IROLinearOperand && ENODE_IS(linear->u.node, EVECTOR128CONST))
return 1;
return 0;
}
Boolean IRO_IsAssignment(IROLinear *linear) {
if (linear->type == IROLinearOp1Arg || linear->type == IROLinearOp2Arg) {
if (IRO_IsAssignOp[linear->nodetype])
return 1;
}
return 0;
}
static Boolean IRO_OperandsSame(ENode *a, ENode *b) {
if (a->type == b->type) {
switch (a->type) {
case EINTCONST:
return CInt64_Equal(a->data.intval, b->data.intval);
case ESTRINGCONST:
return 0;
case EFLOATCONST:
return a->data.floatval.value == b->data.floatval.value;
case EVECTOR128CONST:
return (a->data.vector128val.ul[0] == b->data.vector128val.ul[0]) &&
(a->data.vector128val.ul[1] == b->data.vector128val.ul[1]) &&
(a->data.vector128val.ul[2] == b->data.vector128val.ul[2]) &&
(a->data.vector128val.ul[3] == b->data.vector128val.ul[3]);
case EOBJREF:
return a->data.objref == b->data.objref;
}
}
return 0;
}
Boolean IRO_TypesEqual(Type *a, Type *b) {
if (IS_TYPE_BITFIELD(a)) {
if (IS_TYPE_BITFIELD(b)) {
if (
(TYPE_BITFIELD(a)->bitfieldtype == TYPE_BITFIELD(b)->bitfieldtype) &&
(TYPE_BITFIELD(a)->unkA == TYPE_BITFIELD(b)->unkA) &&
(TYPE_BITFIELD(a)->unkB == TYPE_BITFIELD(b)->unkB))
return 1;
}
return 0;
}
if (IS_TYPE_POINTER_ONLY(a) && IS_TYPE_POINTER_ONLY(b))
return 1;
return is_typeequal(a, b) != 0;
}
Type *IRO_UnsignedType(Type *type) {
if (IS_TYPE_ENUM(type) || IS_TYPE_POINTER_ONLY(type)) {
if (type->size == stunsignedchar.size)
return TYPE(&stunsignedchar);
if (type->size == stunsignedint.size)
return TYPE(&stunsignedint);
if (type->size == stunsignedshort.size)
return TYPE(&stunsignedshort);
if (type->size == stunsignedlong.size)
return TYPE(&stunsignedlong);
if (type->size == stunsignedlonglong.size)
return TYPE(&stunsignedlonglong);
CError_FATAL(281);
return NULL;
}
if (!IS_TYPE_INT(type)) {
CError_FATAL(287);
return NULL;
}
if (type == TYPE(&stbool) || type == TYPE(&stwchar))
return type;
if (type == TYPE(&stchar) || type == TYPE(&stsignedchar) || type == TYPE(&stunsignedchar))
return TYPE(&stunsignedchar);
if (type == TYPE(&stsignedshort) || type == TYPE(&stunsignedshort))
return TYPE(&stunsignedshort);
if (type == TYPE(&stsignedint) || type == TYPE(&stunsignedint))
return TYPE(&stunsignedint);
if (type == TYPE(&stsignedlong) || type == TYPE(&stunsignedlong))
return TYPE(&stunsignedlong);
if (type == TYPE(&stsignedlonglong) || type == TYPE(&stunsignedlonglong))
return TYPE(&stunsignedlonglong);
CError_FATAL(319);
return NULL;
}
Type *IRO_SignedType(Type *type) {
if (IS_TYPE_ENUM(type) || IS_TYPE_POINTER_ONLY(type)) {
if (type->size == stsignedchar.size)
return TYPE(&stsignedchar);
if (type->size == stsignedint.size)
return TYPE(&stsignedint);
if (type->size == stsignedshort.size)
return TYPE(&stsignedshort);
if (type->size == stsignedlong.size)
return TYPE(&stsignedlong);
if (type->size == stsignedlonglong.size)
return TYPE(&stsignedlonglong);
CError_FATAL(357);
return NULL;
}
if (!IS_TYPE_INT(type)) {
CError_FATAL(363);
return NULL;
}
if (type == TYPE(&stbool) && type->size == stsignedchar.size)
return TYPE(&stsignedchar);
if (type == TYPE(&stwchar) && type->size == stsignedshort.size)
return TYPE(&stsignedshort);
if (type == TYPE(&stchar) || type == TYPE(&stsignedchar) || type == TYPE(&stunsignedchar))
return TYPE(&stsignedchar);
if (type == TYPE(&stsignedshort) || type == TYPE(&stunsignedshort))
return TYPE(&stsignedshort);
if (type == TYPE(&stsignedint) || type == TYPE(&stunsignedint))
return TYPE(&stsignedint);
if (type == TYPE(&stsignedlong) || type == TYPE(&stunsignedlong))
return TYPE(&stsignedlong);
if (type == TYPE(&stsignedlonglong) || type == TYPE(&stunsignedlonglong))
return TYPE(&stsignedlonglong);
CError_FATAL(399);
return NULL;
}
Boolean IRO_is_CPtypeequal(Type *a, Type *b) {
if (IS_TYPE_POINTER_ONLY(a) && IS_TYPE_POINTER_ONLY(b))
return 1;
return is_typeequal(a, b) != 0;
}
Boolean IRO_ExprsSame(IROLinear *a, IROLinear *b) {
if (a->type == b->type && IRO_TypesEqual(a->rtype, b->rtype)) {
switch (a->type) {
case IROLinearOperand:
return IRO_OperandsSame(a->u.node, b->u.node);
case IROLinearOp1Arg:
if (a->nodetype == b->nodetype)
return IRO_ExprsSame(a->u.monadic, b->u.monadic);
return 0;
case IROLinearOp2Arg:
if (a->nodetype == b->nodetype)
return IRO_ExprsSame(a->u.diadic.left, b->u.diadic.left) &&
IRO_ExprsSame(a->u.diadic.right, b->u.diadic.right);
return 0;
case IROLinearOp3Arg:
if (a->nodetype == b->nodetype)
return IRO_ExprsSame(a->u.args3.a, b->u.args3.a) &&
IRO_ExprsSame(a->u.args3.b, b->u.args3.b) &&
IRO_ExprsSame(a->u.args3.c, b->u.args3.c);
return 0;
case IROLinearFunccall:
return 0;
default:
return 0;
}
}
return 0;
}
CLabel *IRO_NewLabel(void) {
CLabel *label = newlabel();
label->next = Labels;
Labels = label;
return label;
}
Boolean IRO_ExprsSameSemantically(IROLinear *a, IROLinear *b) {
if (a->type == b->type && IRO_TypesEqual(a->rtype, b->rtype)) {
Boolean flag = 0;
switch (a->type) {
case IROLinearOperand:
return IRO_OperandsSame(a->u.node, b->u.node);
case IROLinearOp1Arg:
if (a->nodetype == b->nodetype)
return IRO_ExprsSameSemantically(a->u.monadic, b->u.monadic);
return 0;
case IROLinearOp2Arg:
if (a->nodetype == b->nodetype) {
switch (a->nodetype) {
case EMUL:
case EADD:
case EAND:
case EXOR:
case EOR:
case ELAND:
case ELOR:
if (!IRO_HasSideEffect(a)) {
flag = IRO_ExprsSameSemantically(a->u.diadic.left, b->u.diadic.right) &&
IRO_ExprsSameSemantically(a->u.diadic.right, b->u.diadic.left);
}
}
return flag || (IRO_ExprsSameSemantically(a->u.diadic.left, b->u.diadic.left) &&
IRO_ExprsSameSemantically(a->u.diadic.right, b->u.diadic.right));
}
return 0;
case IROLinearOp3Arg:
if (a->nodetype == b->nodetype)
return IRO_ExprsSameSemantically(a->u.args3.a, b->u.args3.a) &&
IRO_ExprsSameSemantically(a->u.args3.b, b->u.args3.b) &&
IRO_ExprsSameSemantically(a->u.args3.c, b->u.args3.c);
return 0;
case IROLinearFunccall:
return 0;
default:
return 0;
}
}
return 0;
}
IROLinear *IRO_FindPrecedAfter(IROLinear *a, IROLinear *iter) {
IROLinear *prev = iter;
while (iter && iter != a) {
prev = iter;
iter = iter->next;
}
if (iter)
return prev;
return iter;
}
IROLinear *IRO_FindPreced(IROLinear *a) {
IROLinear *iter;
IROLinear *prev;
prev = iter = IRO_FirstLinear;
while (iter && iter != a) {
prev = iter;
iter = iter->next;
}
if (iter)
return prev;
return iter;
}
IROLinear *IRO_FindFirst(IROLinear *linear) {
short i;
switch (linear->type) {
case IROLinearOperand:
return linear;
case IROLinearOp1Arg:
return IRO_FindFirst(linear->u.monadic);
case IROLinearOp2Arg:
if (linear->u.diadic.right->index < linear->u.diadic.left->index)
return IRO_FindFirst(linear->u.diadic.right);
else
return IRO_FindFirst(linear->u.diadic.left);
case IROLinearOp3Arg:
if (linear->u.args3.a->index < linear->u.args3.b->index) {
if (linear->u.args3.b->index < linear->u.args3.c->index)
return IRO_FindFirst(linear->u.args3.a);
else
return IRO_FindFirst(linear->u.args3.c);
} else {
if (linear->u.args3.b->index < linear->u.args3.c->index)
return IRO_FindFirst(linear->u.args3.b);
else
return IRO_FindFirst(linear->u.args3.c);
}
case IROLinearFunccall:
i = linear->u.funccall.argCount - 1;
return IRO_FindFirst(linear->u.funccall.args[i]);
default:
CError_FATAL(641);
return NULL;
}
}
void IRO_CutAndPasteAfter(IROLinear *a, IROLinear *b, IROLinear *c) {
IROLinear *preced = IRO_FindPreced(a);
preced->next = b->next;
b->next = c->next;
c->next = a;
}
Boolean IRO_IsConstantZero(IROLinear *linear) {
return (IRO_IsIntConstant(linear) && CInt64_IsZero(&linear->u.node->data.intval)) ||
(IRO_IsFloatConstant(linear) && CMach_FloatIsZero(linear->u.node->data.floatval));
}
Boolean IRO_IsConstantOne(IROLinear *linear) {
return (IRO_IsIntConstant(linear) && CInt64_IsOne(&linear->u.node->data.intval)) ||
(IRO_IsFloatConstant(linear) && CMach_FloatIsOne(linear->u.node->data.floatval));
}
Boolean IRO_IsConstantNegativeOne(IROLinear *linear) {
CInt64 neg = CInt64_Neg(linear->u.node->data.intval);
return (IRO_IsIntConstant(linear) && CInt64_IsOne(&neg)) ||
(IRO_IsFloatConstant(linear) && CMach_FloatIsNegOne(linear->u.node->data.floatval));
}
static void ActNop(IROLinear *linear, Boolean isEntry) {
if (!isEntry) {
linear->type = IROLinearNop;
linear->expr = NULL;
}
}
void IRO_NopOut(IROLinear *linear) {
IRO_WalkTree(linear, ActNop);
}
static Boolean NotNoppable(IROLinear *linear) {
return (
(linear->type == IROLinearFunccall) ||
IRO_IsAssignment(linear) ||
((linear->type == IROLinearOperand) && ENODE_IS(linear->u.node, EINSTRUCTION)) ||
(linear->rtype && CParser_IsVolatile(linear->rtype, linear->nodeflags & ENODE_FLAG_QUALS)) ||
((linear->type == IROLinearOperand) && ENODE_IS(linear->u.node, EOBJREF) && is_volatile_object(linear->u.node->data.objref))
);
}
static void ActNopNonSideEffects(IROLinear *linear, Boolean isEntry) {
if (isEntry) {
if (NotNoppable(linear)) {
if (!FuncLevel)
linear->flags &= ~IROLF_Reffed;
FuncLevel++;
}
} else {
if (NotNoppable(linear)) {
FuncLevel--;
} else if (!FuncLevel) {
linear->type = IROLinearNop;
}
}
}
void IRO_NopNonSideEffects(IROLinear *linear, SInt32 level) {
FuncLevel = level;
IRO_WalkTree(linear, ActNopNonSideEffects);
}
void IRO_BuildList(IROLinear *linear, Boolean isEntry) {
if (!isEntry) {
linear->next = NULL;
IRO_AddToList(linear, &IRO_InitLList);
}
}
void IRO_WalkTree(IROLinear *linear, IROWalkTreeFunc func) {
int i;
func(linear, 1);
switch (linear->type) {
case IROLinearOperand:
break;
case IROLinearOp1Arg:
IRO_WalkTree(linear->u.monadic, func);
break;
case IROLinearOp2Arg:
IRO_WalkTree(linear->u.diadic.left, func);
IRO_WalkTree(linear->u.diadic.right, func);
break;
case IROLinearOp3Arg:
IRO_WalkTree(linear->u.args3.a, func);
IRO_WalkTree(linear->u.args3.b, func);
IRO_WalkTree(linear->u.args3.c, func);
break;
case IROLinearFunccall:
IRO_WalkTree(linear->u.funccall.linear8, func);
for (i = 0; i < linear->u.funccall.argCount; i++)
IRO_WalkTree(linear->u.funccall.args[i], func);
break;
}
func(linear, 0);
}
void IRO_WalkTreeToPropagateFlags(IROLinear *linear, IROWalkTreeFunc func) {
int i;
switch (linear->type) {
case IROLinearOperand:
break;
case IROLinearOp1Arg:
IRO_WalkTreeToPropagateFlags(linear->u.monadic, func);
break;
case IROLinearOp2Arg:
IRO_WalkTreeToPropagateFlags(linear->u.diadic.left, func);
IRO_WalkTreeToPropagateFlags(linear->u.diadic.right, func);
break;
case IROLinearOp3Arg:
IRO_WalkTreeToPropagateFlags(linear->u.args3.a, func);
IRO_WalkTreeToPropagateFlags(linear->u.args3.b, func);
IRO_WalkTreeToPropagateFlags(linear->u.args3.c, func);
break;
case IROLinearFunccall:
IRO_WalkTreeToPropagateFlags(linear->u.funccall.linear8, func);
for (i = 0; i < linear->u.funccall.argCount; i++)
IRO_WalkTreeToPropagateFlags(linear->u.funccall.args[i], func);
break;
}
func(linear, 0);
}
void IRO_WalkInts(IROLinear *a, IROLinear *b, IROWalkTreeFunc func) {
IROLinear *scan;
for (scan = a; scan; scan = scan->next) {
switch (scan->type) {
case IROLinearBeginCatch:
case IROLinearEndCatch:
case IROLinearEndCatchDtor:
IRO_WalkTree(scan->u.ctch.linear, func);
break;
case IROLinearOperand:
case IROLinearOp1Arg:
case IROLinearOp2Arg:
case IROLinearOp3Arg:
case IROLinearFunccall:
IRO_WalkTree(scan, func);
break;
case IROLinearIf:
case IROLinearIfNot:
IRO_WalkTree(scan->u.label.x4, func);
break;
case IROLinearReturn:
if (scan->u.monadic)
IRO_WalkTree(scan->u.monadic, func);
break;
case IROLinearSwitch:
IRO_WalkTree(scan->u.swtch.x4, func);
break;
case IROLinearAsm:
func(scan, 1);
func(scan, 0);
break;
case IROLinearEnd:
break;
}
if (scan == b)
break;
}
}
void IRO_Cut(IROLinear *a, IROLinear *b) {
IROLinear *scan;
IROLinear *prev;
IRONode *node;
scan = a;
while (1) {
scan->stmt = NULL;
if (scan == b)
break;
scan = scan->next;
}
prev = NULL;
for (scan = IRO_FirstLinear; scan && scan != a; scan = scan->next)
prev = scan;
CError_ASSERT(951, scan);
for (node = IRO_FirstNode; node; node = node->nextnode) {
if (node->first == a) {
if (node->last == b) {
node->first = node->last = NULL;
break;
} else {
node->first = b->next;
break;
}
} else if (node->last == b) {
node->last = prev;
break;
}
}
if (prev)
prev->next = b->next;
else
IRO_FirstLinear = b->next;
}
void IRO_Paste(IROLinear *a, IROLinear *b, IROLinear *c) {
IROLinear *prev;
IROLinear *scan;
IRONode *node;
CError_ASSERT(1002, c && c->type != IROLinearLabel);
prev = NULL;
for (scan = IRO_FirstLinear; scan && scan != c; scan = scan->next)
prev = scan;
CError_ASSERT(1016, scan);
for (node = IRO_FirstNode; node; node = node->nextnode) {
if (node->first == c) {
node->first = a;
break;
}
}
b->next = c;
if (prev)
prev->next = a;
else
IRO_FirstLinear = a;
}
void IRO_PasteAfter(IROLinear *a, IROLinear *b, IROLinear *c) {
IRONode *node;
switch (c->type) {
case IROLinearGoto:
case IROLinearIf:
case IROLinearIfNot:
case IROLinearSwitch:
CError_FATAL(1060);
}
for (node = IRO_FirstNode; node; node = node->nextnode) {
if (node->last == c) {
node->last = b;
break;
}
}
b->next = c->next;
c->next = a;
}
static void FindStart(IROLinear *linear, Boolean isEntry) {
IROLinear *scan;
if (isEntry) {
scan = linear;
do {
if (scan == ExprStart) {
ExprStart = linear;
return;
}
if (scan == ExprEnd)
return;
} while ((scan = scan->next));
}
}
void IRO_ClipExpr(IROExpr *expr) {
ExprStart = ExprEnd = expr->linear;
IRO_WalkTree(expr->linear, FindStart);
IRO_Cut(ExprStart, ExprEnd);
}
void IRO_ClipExprTree(IROLinear *linear) {
ExprStart = ExprEnd = linear;
IRO_WalkTree(linear, FindStart);
IRO_Cut(ExprStart, ExprEnd);
}
static void SetNodeNumInExprList(IROLinear *linear, Boolean isEntry) {
if (isEntry && linear->expr)
linear->expr->node = IRO_Node;
}
void IRO_MoveExpression(IROExpr *expr, IROLinear *linear) {
IRONode *node;
IROLinear *scan;
ExprStart = ExprEnd = expr->linear;
IRO_WalkTree(expr->linear, FindStart);
if (ExprStart != linear) {
IRO_Cut(ExprStart, ExprEnd);
IRO_Paste(ExprStart, ExprEnd, linear);
for (node = IRO_FirstNode; node; node = node->nextnode) {
for (scan = node->first; scan; scan = scan->next) {
if (scan == expr->linear) {
expr->node = node;
break;
}
if (scan == node->last)
break;
}
}
IRO_Node = expr->node;
IRO_WalkTree(expr->linear, SetNodeNumInExprList);
}
}
void IRO_InitList(IROList *list) {
list->head = list->tail = NULL;
}
void IRO_AddToList(IROLinear *linear, IROList *list) {
if (list->head)
list->tail->next = linear;
else
list->head = linear;
list->tail = linear;
while (list->tail->next)
list->tail = list->tail->next;
}
IROLinear *IRO_FindLabelNode(CLabel *label, IROLinear *linear) {
IROLinear *scan;
for (scan = linear; scan; scan = scan->next) {
if (scan->type == IROLinearLabel && scan->u.label.label == label)
break;
}
CError_ASSERT(1244, scan);
return scan;
}
void IRO_DuplicateExprRange(IROLinear *start, IROLinear *end, IROList *list) {
IROLinear *scan;
for (scan = start; scan; scan = scan->next) {
if (scan->type != IROLinearNop && !(scan->flags & IROLF_Reffed))
IRO_DuplicateExpr(scan, list);
if (scan == end)
break;
}
}
IROLinear *IRO_DuplicateExpr(IROLinear *linear, IROList *list) {
IROLinear *copy;
ENode *copynode;
int i;
copy = IRO_NewLinear(linear->type);
*copy = *linear;
copy->index = ++IRO_NumLinear;
copy->next = NULL;
copy->expr = NULL;
switch (copy->type) {
case IROLinearOperand:
copynode = lalloc(sizeof(ENode));
*copynode = *linear->u.node;
copy->u.node = copynode;
break;
case IROLinearOp1Arg:
copy->u.monadic = IRO_DuplicateExpr(copy->u.monadic, list);
break;
case IROLinearOp2Arg:
if (linear->flags & IROLF_8000) {
copy->u.diadic.right = IRO_DuplicateExpr(copy->u.diadic.right, list);
copy->u.diadic.left = IRO_DuplicateExpr(copy->u.diadic.left, list);
} else {
copy->u.diadic.left = IRO_DuplicateExpr(copy->u.diadic.left, list);
copy->u.diadic.right = IRO_DuplicateExpr(copy->u.diadic.right, list);
}
break;
case IROLinearOp3Arg:
copy->u.args3.a = IRO_DuplicateExpr(copy->u.args3.a, list);
copy->u.args3.b = IRO_DuplicateExpr(copy->u.args3.b, list);
copy->u.args3.c = IRO_DuplicateExpr(copy->u.args3.c, list);
break;
case IROLinearFunccall:
copy->u.funccall.linear8 = IRO_DuplicateExpr(copy->u.funccall.linear8, list);
copy->u.funccall.args = oalloc(sizeof(IROLinear *) * copy->u.funccall.argCount);
for (i = 0; i < copy->u.funccall.argCount; i++) {
copy->u.funccall.args[i] = IRO_DuplicateExpr(linear->u.funccall.args[i], list);
}
break;
case IROLinearAsm:
copy->u.asm_stmt = CodeGen_CopyAsmStat(linear->u.asm_stmt);
break;
}
IRO_AddToList(copy, list);
return copy;
}
IROLinear *IRO_TempReference(Object *obj, IROList *list) {
IROLinear *op;
IROLinear *ind;
op = IRO_NewLinear(IROLinearOperand);
op->u.node = create_objectrefnode(obj);
op->rtype = op->u.node->data.objref->type;
op->index = ++IRO_NumLinear;
op->flags |= IROLF_Reffed | IROLF_Ind;
IRO_AddToList(op, list);
ind = IRO_NewLinear(IROLinearOp1Arg);
ind->nodetype = EINDIRECT;
ind->rtype = obj->type;
ind->u.monadic = op;
ind->index = ++IRO_NumLinear;
ind->next = NULL;
IRO_AddToList(ind, list);
return ind;
}
inline IROLinear *LocateFatherHelper(IROLinear *linear, Boolean a, IROLinear ***b) {
IROLinear *scan;
SInt32 index;
int i;
for (scan = linear->next, index = 0; index < (a ? 2 : 1); index++) {
while (scan) {
switch (scan->type) {
case IROLinearIf:
case IROLinearIfNot:
if (scan->u.label.x4 == linear) {
if (b)
*b = &scan->u.label.x4;
return scan;
}
break;
case IROLinearReturn:
if (scan->u.monadic == linear) {
if (b)
*b = &scan->u.monadic;
return scan;
}
break;
case IROLinearOp1Arg:
if (scan->u.monadic == linear) {
if (b)
*b = &scan->u.monadic;
return scan;
}
break;
case IROLinearSwitch:
if (scan->u.swtch.x4 == linear) {
if (b)
*b = &scan->u.swtch.x4;
return scan;
}
break;
case IROLinearOp2Arg:
if (scan->u.diadic.left == linear) {
if (b)
*b = &scan->u.diadic.left;
return scan;
}
if (scan->u.diadic.right == linear) {
if (b)
*b = &scan->u.diadic.right;
return scan;
}
break;
case IROLinearOp3Arg:
if (scan->u.args3.a == linear) {
if (b)
*b = &scan->u.args3.a;
return scan;
}
if (scan->u.args3.b == linear) {
if (b)
*b = &scan->u.args3.b;
return scan;
}
if (scan->u.args3.c == linear) {
if (b)
*b = &scan->u.args3.c;
return scan;
}
break;
case IROLinearFunccall:
if (scan->u.funccall.linear8 == linear) {
if (b)
*b = &scan->u.funccall.linear8;
return scan;
}
for (i = 0; i < scan->u.funccall.argCount; i++) {
if (scan->u.funccall.args[i] == linear) {
if (b)
*b = &scan->u.funccall.args[i];
return scan;
}
}
break;
case IROLinearNop:
case IROLinearOperand:
case IROLinearGoto:
case IROLinearLabel:
case IROLinearEntry:
case IROLinearExit:
case IROLinearBeginCatch:
case IROLinearEndCatch:
case IROLinearEndCatchDtor:
case IROLinearAsm:
case IROLinearEnd:
break;
default:
CError_FATAL(1536);
}
scan = scan->next;
}
scan = IRO_FirstLinear;
}
if (b)
*b = NULL;
return NULL;
}
IROLinear *IRO_LocateFather(IROLinear *linear) {
return LocateFatherHelper(linear, 0, NULL);
}
IROLinear *IRO_LocateFather_Cut_And_Paste(IROLinear *a, IROLinear *b) {
IROLinear **p;
IROLinear *l = LocateFatherHelper(a, 0, &p);
if (l) {
CError_ASSERT(1568, p && *p);
IRO_NopOut(a);
*p = b;
}
return l;
}
IROLinear *IRO_LocateFather_Cut_And_Paste_Without_Nopping(IROLinear *a, IROLinear *b) {
IROLinear **p;
IROLinear *l = LocateFatherHelper(a, 0, &p);
if (l) {
CError_ASSERT(1585, p && *p);
*p = b;
}
return l;
}
void IRO_ReplaceReference(IROLinear *a, Object *obj, IROLinear *b) {
IROLinear **ptr;
IROList list;
if (LocateFatherHelper(a, 1, &ptr)) {
CError_ASSERT(1605, ptr && *ptr);
IRO_InitList(&list);
*ptr = IRO_TempReference(obj, &list);
IRO_PasteAfter(list.head, list.tail, b);
if (a->flags & IROLF_LoopInvariant)
list.tail->flags |= IROLF_LoopInvariant;
} else {
IRO_Dump("Oh, oh, did not find reference to replace\n");
}
}
void IRO_ReplaceReferenceWithNode(IROLinear *a, IROLinear *b) {
IROLinear **ptr;
IROList list;
if (LocateFatherHelper(a, 1, &ptr)) {
CError_ASSERT(1664, ptr && *ptr);
*ptr = b;
b->flags |= IROLF_Reffed;
} else {
IRO_Dump("Oh, oh, did not find reference to replace\n");
}
}
VarRecord *IRO_GetTemp(IROExpr *expr) {
expr->x8 = create_temp_object(expr->linear->rtype);
return IRO_FindVar(expr->x8, 1, 1);
}
IROLinear *IRO_AssignToTemp(IROExpr *expr) {
IROLinear *objref;
IROLinear *ind;
IROLinear *ass;
objref = IRO_NewLinear(IROLinearOperand);
objref->u.node = create_objectrefnode(expr->x8);
objref->rtype = objref->u.node->data.objref->type;
objref->index = ++IRO_NumLinear;
objref->flags |= IROLF_Reffed | IROLF_Assigned | IROLF_Ind;
ind = IRO_NewLinear(IROLinearOp1Arg);
ind->nodetype = EINDIRECT;
ind->rtype = expr->linear->rtype;
ind->u.monadic = objref;
ind->index = ++IRO_NumLinear;
ind->flags |= IROLF_Reffed | IROLF_Assigned;
ass = IRO_NewLinear(IROLinearOp2Arg);
ass->nodetype = EASS;
ass->u.diadic.left = ind;
ass->u.diadic.right = expr->linear;
ass->rtype = expr->linear->rtype;
ass->index = ++IRO_NumLinear;
objref->next = ind;
ind->next = ass;
IRO_PasteAfter(objref, ass, expr->linear);
return ass;
}
IROLinear *IRO_FindStart(IROLinear *linear) {
ExprStart = ExprEnd = linear;
IRO_WalkTree(linear, FindStart);
return ExprStart;
}
void IRO_DeleteCommaNode(IROLinear *linear, IROExpr *expr) {
IROLinear *scan;
for (scan = linear; scan; scan = scan->next) {
if (scan->nodetype == ECOMMA) {
if (scan != expr->linear) {
IRO_NopOut(scan->u.diadic.left);
IRO_LocateFather_Cut_And_Paste(scan, scan->u.diadic.right);
} else {
IRO_NopOut(scan->u.diadic.left);
expr->linear = scan->u.diadic.right;
}
}
}
}
void IRO_RemoveCommaNodeFromIR(void) {
IRONode *node;
IROLinear *linear;
for (node = IRO_FirstNode; node; node = node->nextnode) {
linear = node->first;
do {
if (!linear)
break;
if (linear->nodetype == ECOMMA) {
linear->u.diadic.left->flags = linear->u.diadic.left->flags & ~IROLF_Reffed;
IRO_LocateFather_Cut_And_Paste_Without_Nopping(linear, linear->u.diadic.right);
linear->type = IROLinearNop;
}
linear = linear->next;
} while (linear != node->last);
}
}
IROAddrRecord *IRO_InitAddrRecordPointer(IROLinear *linear) {
IROAddrRecord *rec = oalloc(sizeof(IROAddrRecord));
rec->numObjRefs = 0;
rec->objRefs = NULL;
rec->numMisc = 0;
rec->misc = NULL;
rec->numInts = 0;
rec->ints = NULL;
rec->x16 = 0;
rec->linear = linear;
return rec;
}
IROLinear *IRO_HasSideEffect(IROLinear *linear) {
IROLinear *tmp;
if (!linear)
return linear;
if (linear->rtype && CParser_IsVolatile(linear->rtype, linear->nodeflags & ENODE_FLAG_QUALS))
return linear;
switch (linear->type) {
case IROLinearAsm:
return linear;
case IROLinearOperand:
if (ENODE_IS(linear->u.node, EOBJREF) && is_volatile_object(linear->u.node->data.objref))
return linear;
return NULL;
case IROLinearOp1Arg:
if (IRO_IsAssignOp[linear->nodetype])
return linear;
else
return IRO_HasSideEffect(linear->u.monadic);
case IROLinearOp2Arg:
if (IRO_IsAssignOp[linear->nodetype])
return linear;
else if ((tmp = IRO_HasSideEffect(linear->u.diadic.left)))
return tmp;
else
return IRO_HasSideEffect(linear->u.diadic.right);
case IROLinearOp3Arg:
if ((tmp = IRO_HasSideEffect(linear->u.args3.a)))
return tmp;
else if ((tmp = IRO_HasSideEffect(linear->u.args3.b)))
return tmp;
else
return IRO_HasSideEffect(linear->u.args3.c);
case IROLinearFunccall:
return linear;
default:
return linear;
}
}
IROLinear *IRO_CheckSideEffect(IROLinear *linear) {
IROLinear *result;
IROLinear *tmp;
IROLinear *tmp2;
IROLinear *tmp3;
if (!linear)
return linear;
if (linear->rtype && CParser_IsVolatile(linear->rtype, linear->nodeflags & ENODE_FLAG_QUALS)) {
linear->flags &= ~IROLF_Reffed;
return linear;
}
result = NULL;
switch (linear->type) {
case IROLinearAsm:
linear->flags &= ~IROLF_Reffed;
return linear;
case IROLinearOperand:
if (ENODE_IS(linear->u.node, EOBJREF) && is_volatile_object(linear->u.node->data.objref)) {
linear->flags &= ~IROLF_Reffed;
return linear;
}
break;
case IROLinearOp1Arg:
if (IRO_IsAssignOp[linear->nodetype]) {
linear->flags &= ~IROLF_Reffed;
return linear;
}
if ((result = IRO_CheckSideEffect(linear->u.monadic))) {
if (linear->nodetype == EINDIRECT && linear->u.monadic->type == IROLinearOperand) {
linear->flags &= ~IROLF_Reffed;
return linear;
}
}
break;
case IROLinearOp2Arg:
if (IRO_IsAssignOp[linear->nodetype]) {
linear->flags &= ~IROLF_Reffed;
return linear;
}
tmp = IRO_CheckSideEffect(linear->u.diadic.left);
tmp2 = IRO_CheckSideEffect(linear->u.diadic.right);
if (tmp)
result = tmp;
else
result = tmp2;
break;
case IROLinearOp3Arg:
tmp = IRO_CheckSideEffect(linear->u.args3.a);
tmp2 = IRO_CheckSideEffect(linear->u.args3.b);
tmp3 = IRO_CheckSideEffect(linear->u.args3.c);
result = tmp ? tmp : tmp2 ? tmp2 : tmp3;
break;
case IROLinearFunccall:
linear->flags &= ~IROLF_Reffed;
return linear;
default:
return linear;
}
linear->type = IROLinearNop;
IRO_Dump("Nop out with side-effects checking at: %d\n", linear->index);
return result;
}
void IRO_WalkExcActions(ExceptionAction *action, WalkObjFunc func) {
while (action) {
switch (action->type) {
case EAT_DESTROYLOCAL:
func(action->data.destroy_local.local);
break;
case EAT_DESTROYLOCALCOND:
func(action->data.destroy_local_cond.local);
func(action->data.destroy_local_cond.cond);
break;
case EAT_DESTROYLOCALOFFSET:
func(action->data.destroy_local_offset.local);
break;
case EAT_DESTROYLOCALPOINTER:
func(action->data.destroy_local_pointer.pointer);
break;
case EAT_DESTROYLOCALARRAY:
func(action->data.destroy_local_array.localarray);
break;
case EAT_DESTROYPARTIALARRAY:
func(action->data.destroy_partial_array.arraypointer);
func(action->data.destroy_partial_array.arraycounter);
func(action->data.destroy_partial_array.element_size);
break;
case EAT_DESTROYBASE:
func(action->data.destroy_member.objectptr); // wrong union?
break;
case EAT_DESTROYMEMBER:
func(action->data.destroy_member.objectptr);
break;
case EAT_DESTROYMEMBERCOND:
func(action->data.destroy_member_cond.objectptr);
func(action->data.destroy_member_cond.cond);
break;
case EAT_DESTROYMEMBERARRAY:
func(action->data.destroy_member_array.objectptr);
break;
case EAT_DELETEPOINTER:
func(action->data.delete_pointer.pointerobject);
break;
case EAT_DELETEPOINTERCOND:
func(action->data.delete_pointer_cond.pointerobject);
func(action->data.delete_pointer_cond.cond);
break;
}
action = action->prev;
}
}
Boolean IRO_FunctionCallMightThrowException(IROLinear *linear) {
Object *obj;
if (linear->type == IROLinearFunccall) {
obj = NULL;
if (linear->u.funccall.linear8->type == IROLinearOperand && ENODE_IS(linear->u.funccall.linear8->u.node, EOBJREF))
obj = linear->u.funccall.linear8->u.node->data.objref;
if (!obj || CExcept_CanThrowException(obj, obj->datatype == DVFUNC && !(linear->nodeflags & ENODE_FLAG_80)))
return 1;
}
return 0;
}
IROLinear *IRO_NewIntConst(CInt64 val, Type *type) {
ENode *node;
IROLinear *linear;
node = IRO_NewENode(EINTCONST);
node->data.intval = val;
node->rtype = type;
linear = IRO_NewLinear(IROLinearOperand);
linear->index = ++IRO_NumLinear;
linear->rtype = type;
linear->u.node = node;
return linear;
}
IROLinear *IRO_NewFloatConst(const Float val, Type *type) {
ENode *node;
IROLinear *linear;
node = IRO_NewENode(EFLOATCONST);
node->data.floatval = val;
node->rtype = type;
linear = IRO_NewLinear(IROLinearOperand);
linear->index = ++IRO_NumLinear;
linear->rtype = type;
linear->u.node = node;
return linear;
}
Boolean IRO_IsAddressMultiply(IROLinear *linear) {
return 0;
}
void IRO_SetupForUserBreakChecking(void) {
IRO_LastUserBreakTick = 0;
}
void IRO_CheckForUserBreak(void) {
if (IRO_LastUserBreakTick + 8 < COS_GetTicks()) {
if (CWUserBreak(cparams.context))
CError_UserBreak();
IRO_LastUserBreakTick = COS_GetTicks();
}
}