summaryrefslogtreecommitdiff
path: root/compiler_and_linker/FrontEnd/Optimizer/IroUtil.c
diff options
context:
space:
mode:
authorAsh Wolf <ninji@wuffs.org>2023-01-26 11:30:47 +0000
committerAsh Wolf <ninji@wuffs.org>2023-01-26 11:30:47 +0000
commit094b96ca1df4a035b5f93c351f773306c0241f3f (patch)
tree95ce05e3ebe816c7ee7996206bb37ea17d8ca33c /compiler_and_linker/FrontEnd/Optimizer/IroUtil.c
parentfc0c4c0df7b583b55a08317cf1ef6a71d27c0440 (diff)
downloadMWCC-main.tar.gz
MWCC-main.zip
move lots of source files around to match their actual placement in the original treemain
Diffstat (limited to 'compiler_and_linker/FrontEnd/Optimizer/IroUtil.c')
-rw-r--r--compiler_and_linker/FrontEnd/Optimizer/IroUtil.c1262
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();
+ }
+}