diff options
Diffstat (limited to 'compiler_and_linker/FrontEnd/Optimizer/IroUtil.c')
-rw-r--r-- | compiler_and_linker/FrontEnd/Optimizer/IroUtil.c | 1262 |
1 files changed, 1262 insertions, 0 deletions
diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroUtil.c b/compiler_and_linker/FrontEnd/Optimizer/IroUtil.c new file mode 100644 index 0000000..7e6321d --- /dev/null +++ b/compiler_and_linker/FrontEnd/Optimizer/IroUtil.c @@ -0,0 +1,1262 @@ +#include "IroUtil.h" +#include "IroCSE.h" +#include "IroDump.h" +#include "IroFlowgraph.h" +#include "IroLinearForm.h" +#include "IroLoop.h" +#include "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)->offset == TYPE_BITFIELD(b)->offset) && + (TYPE_BITFIELD(a)->bitlength == TYPE_BITFIELD(b)->bitlength)) + 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; +} + +CW_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(); + } +} |