diff options
Diffstat (limited to 'compiler_and_linker/FrontEnd/Common')
-rw-r--r-- | compiler_and_linker/FrontEnd/Common/CIRTransform.c | 534 | ||||
-rw-r--r-- | compiler_and_linker/FrontEnd/Common/COptimizer.c | 1831 |
2 files changed, 2365 insertions, 0 deletions
diff --git a/compiler_and_linker/FrontEnd/Common/CIRTransform.c b/compiler_and_linker/FrontEnd/Common/CIRTransform.c new file mode 100644 index 0000000..b91f6af --- /dev/null +++ b/compiler_and_linker/FrontEnd/Common/CIRTransform.c @@ -0,0 +1,534 @@ +#include "compiler/CIRTransform.h" +#include "compiler/CError.h" +#include "compiler/CExpr.h" +#include "compiler/CFunc.h" +#include "compiler/CInit.h" +#include "compiler/CMachine.h" +#include "compiler/CParser.h" +#include "compiler/objects.h" +#include "compiler/types.h" +#include "compiler/CompilerTools.h" +#include "compiler/CDecl.h" + +#ifdef __MWERKS__ +#pragma options align=mac68k +#endif +typedef struct CIRTransTemp { + struct CIRTransTemp *next; + Object *object; + Boolean flag; +} CIRTransTemp; + +typedef struct MultiAccessOperand { + Object *object; + Object *tempobj; + ENode *ass; + Type *type; + Type *bitfieldType; +} MultiAccessOperand; + +// no idea what this is for... +typedef struct StrangeRuntimeFunction { + Object *object; + short unk; + char name[1]; +} StrangeRuntimeFunction; +#ifdef __MWERKS__ +#pragma options align=reset +#endif + +static TypeFunc cirtrans_rtfunc8 = { + TYPEFUNC, 0, NULL, NULL, TYPE(&void_ptr), 0, 0 +}; +static TypeFunc cirtrans_rtfunc4 = { + TYPEFUNC, 0, NULL, NULL, TYPE(&stunsignedlong), 0, 0 +}; +static TypeFunc cirtrans_rtfunc2 = { + TYPEFUNC, 0, NULL, NULL, TYPE(&stsignedshort), 0, 0 +}; + +static CIRTransTemp *cirtrans_temps; +Boolean modulo_generated; +Boolean bigswitch_generated; +Boolean alloca_called; + +// forward decls +static ENode *CIRTrans_TransExpr(ENode *expr, Boolean flag); + +void CIRTrans_Setup(void) { +} + +void CIRTrans_Cleanup(void) { +} + +static Object *CIRTrans_GetRuntimeFunction(StrangeRuntimeFunction *rtfunc, Type *type) { + Object *object; + + object = rtfunc->object; + if (!object) { + object = CParser_NewFunctionObject(NULL); + rtfunc->object = object; + + object->nspace = cscope_root; + object->name = GetHashNameNodeExport(rtfunc->name); + object->flags = OBJECT_INTERNAL; + + if (type) { + switch (type->size) { + case 2: + object->type = TYPE(&cirtrans_rtfunc2); + break; + case 4: + object->type = TYPE(&cirtrans_rtfunc4); + break; + case 8: + object->type = TYPE(&cirtrans_rtfunc8); + break; + default: + CError_FATAL(427); + } + } else { + object->type = TYPE(&cirtrans_rtfunc8); + } + } + + return object; +} + +static Object *CIRTrans_GetTemporary(Type *type) { + CIRTransTemp *temp; + + for (temp = cirtrans_temps; temp; temp = temp->next) { + if (temp->object->type->size == type->size && !temp->flag) { + temp->flag = 1; + return temp->object; + } + } + + temp = oalloc(sizeof(CIRTransTemp)); + temp->next = cirtrans_temps; + cirtrans_temps = temp; + + temp->object = create_temp_object(type); + temp->flag = 1; + return temp->object; +} + +static ENode *CIRTrans_CheckRuntimeAssign(ENode *expr) { + ENode *inner; + + if (ENODE_IS(expr->data.diadic.right, EINDIRECT)) { + inner = expr->data.diadic.right->data.monadic; + if ( + ENODE_IS(inner, EFUNCCALL) && + (inner->flags & ENODE_FLAG_80) && + inner->data.funccall.args && + ENODE_IS(inner->data.funccall.args->node, EOBJREF) + ) + { + CError_ASSERT(502, ENODE_IS(expr->data.diadic.left, EINDIRECT)); + inner->data.funccall.args->node = expr->data.diadic.left->data.monadic; + inner->flags &= ~ENODE_FLAG_80; + return expr->data.diadic.right; + } + } + + return expr; +} + +static void CIRTrans_SetupMultiAccessOperand(MultiAccessOperand *mop, ENode *expr) { + memclrw(mop, sizeof(MultiAccessOperand)); + + mop->type = expr->rtype; + + CError_ASSERT(522, ENODE_IS(expr, EINDIRECT)); + expr = expr->data.monadic; + + if (ENODE_IS(expr, EOBJREF)) { + mop->object = expr->data.objref; + } else { + if (ENODE_IS(expr, EBITFIELD)) { + mop->bitfieldType = expr->rtype; + expr = expr->data.monadic; + } + expr->rtype = CDecl_NewPointerType(mop->type); + mop->tempobj = create_temp_object(expr->rtype); + mop->ass = makediadicnode(create_objectnode(mop->tempobj), expr, EASS); + } +} + +static ENode *CIRTrans_GetMultiAccessOperand(MultiAccessOperand *mop) { + ENode *expr; + + if (mop->object == NULL) { + expr = create_objectnode(mop->tempobj); + if (mop->bitfieldType) { + expr = makemonadicnode(expr, EBITFIELD); + expr->rtype = mop->bitfieldType; + } + expr = makemonadicnode(expr, EINDIRECT); + } else { + expr = create_objectnode(mop->object); + } + + expr->rtype = mop->type; + return expr; +} + +static ENode *CIRTrans_InitMultiAccessExpression(MultiAccessOperand *mop, ENode *expr) { + if (mop->ass) { + expr = makediadicnode(mop->ass, expr, ECOMMA); + expr->rtype = expr->data.diadic.right->rtype; + } + return expr; +} + +ENode *CIRTrans_TransformOpAss(ENode *expr) { + ENodeType nt; + ENode *expr2; + MultiAccessOperand mop; + + if (!ENODE_IS(expr->data.diadic.left, EINDIRECT)) { + CError_Error(CErrorStr142); + return nullnode(); + } + + CIRTrans_SetupMultiAccessOperand(&mop, expr->data.diadic.left); + + switch (expr->type) { + case EMULASS: + nt = EMUL; + break; + case EDIVASS: + nt = EDIV; + break; + case EMODASS: + nt = EMODULO; + break; + case EADDASS: + nt = EADD; + break; + case ESUBASS: + nt = ESUB; + break; + case ESHLASS: + nt = ESHL; + break; + case ESHRASS: + nt = ESHR; + break; + case EANDASS: + nt = EAND; + break; + case EXORASS: + nt = EXOR; + break; + case EORASS: + nt = EOR; + break; + default: + CError_FATAL(622); + } + + expr2 = CIRTrans_GetMultiAccessOperand(&mop); + + if (!IS_TYPE_POINTER_ONLY(expr2->rtype)) { + expr2 = CExpr_NewDyadicNode(expr2, nt, expr->data.diadic.right); + if (expr2->rtype != expr->data.diadic.left->rtype) { + expr2 = makemonadicnode(expr2, ETYPCON); + expr2->rtype = expr->data.diadic.left->rtype; + } + } else { + expr2 = makediadicnode(expr2, expr->data.diadic.right, nt); + } + + if (IS_TYPE_FLOAT(expr2->rtype)) + expr2 = CExpr_BinaryFloatExpression(expr2); + + expr2 = makediadicnode(CIRTrans_GetMultiAccessOperand(&mop), expr2, EASS); + return CIRTrans_InitMultiAccessExpression(&mop, expr2); +} + +static void CIRTrans_TransIncDec() { + // empty, never called +} + +static ENode *CIRTrans_TransIntConst(ENode *expr) { + Object *obj; + UInt8 data[16]; + + CMach_InitIntMem(expr->rtype, expr->data.intval, data); + + obj = CParser_NewGlobalDataObject(NULL); + obj->name = CParser_GetUniqueName(); + obj->type = expr->rtype; + obj->sclass = TK_STATIC; + obj->datatype = DDATA; + CScope_AddGlobalObject(obj); + CInit_DeclareData(obj, data, NULL, obj->type->size); + return create_objectnode(obj); +} + +static ENode *CIRTrans_TransFloatConst(ENode *expr) { + Object *obj; + UInt8 data[16]; + + CMach_InitFloatMem(expr->rtype, expr->data.floatval, data); + + obj = CParser_NewGlobalDataObject(NULL); + obj->name = CParser_GetUniqueName(); + obj->type = expr->rtype; + obj->sclass = TK_STATIC; + obj->datatype = DDATA; + CScope_AddGlobalObject(obj); + CInit_DeclareData(obj, data, NULL, obj->type->size); + return create_objectnode(obj); +} + +static ENode *CIRTrans_TransUnary(ENode *expr, Type *type, StrangeRuntimeFunction *rtfunc) { + if (type->size > 4) { + expr = funccallexpr( + CIRTrans_GetRuntimeFunction(rtfunc, type), + create_objectrefnode(CIRTrans_GetTemporary(type)), + expr, + NULL, + NULL); + expr->flags |= ENODE_FLAG_80; + expr = makemonadicnode(expr, EINDIRECT); + expr->rtype = type; + return expr; + } else { + expr = funccallexpr( + CIRTrans_GetRuntimeFunction(rtfunc, type), + expr, + NULL, + NULL, + NULL); + expr->rtype = type; + return expr; + } +} + +static ENode *CIRTrans_TransBinary(ENode *expr, StrangeRuntimeFunction *rtfunc) { + ENode *expr2; + + if (expr->rtype->size > 4) { + expr2 = funccallexpr( + CIRTrans_GetRuntimeFunction(rtfunc, expr->rtype), + create_objectrefnode(CIRTrans_GetTemporary(expr->rtype)), + expr->data.diadic.left, + expr->data.diadic.right, + NULL); + expr2->flags |= ENODE_FLAG_80; + expr2 = makemonadicnode(expr2, EINDIRECT); + expr2->rtype = expr->rtype; + return expr2; + } else { + expr2 = funccallexpr( + CIRTrans_GetRuntimeFunction(rtfunc, expr->rtype), + expr->data.diadic.left, + expr->data.diadic.right, + NULL, + NULL); + expr2->rtype = expr->rtype; + return expr2; + } +} + +static ENodeList *CIRTrans_TransExprList(ENodeList *list) { + ENodeList *scan; + + for (scan = list; scan; scan = scan->next) + scan->node = CIRTrans_TransExpr(scan->node, 1); + + return list; +} + +static ENode *CIRTrans_TransExpr(ENode *expr, Boolean flag) { + switch (expr->type) { + case EINDIRECT: + case EFORCELOAD: + case EBITFIELD: + expr->data.monadic = CIRTrans_TransExpr(expr->data.monadic, flag); + break; + case EPOSTINC: + expr->data.monadic = CIRTrans_TransExpr(expr->data.monadic, 1); + break; + case EPOSTDEC: + expr->data.monadic = CIRTrans_TransExpr(expr->data.monadic, 1); + break; + case EPREINC: + expr->data.monadic = CIRTrans_TransExpr(expr->data.monadic, 1); + break; + case EPREDEC: + expr->data.monadic = CIRTrans_TransExpr(expr->data.monadic, 1); + break; + case ETYPCON: + expr->data.monadic = CIRTrans_TransExpr(expr->data.monadic, flag); + if (!flag) + return expr->data.monadic; + break; + case EBINNOT: + expr->data.monadic = CIRTrans_TransExpr(expr->data.monadic, flag); + break; + case ELOGNOT: + expr->data.monadic = CIRTrans_TransExpr(expr->data.monadic, flag); + break; + case EMONMIN: + expr->data.monadic = CIRTrans_TransExpr(expr->data.monadic, flag); + break; + case EADD: + expr->data.diadic.left = CIRTrans_TransExpr(expr->data.diadic.left, flag); + expr->data.diadic.right = CIRTrans_TransExpr(expr->data.diadic.right, flag); + break; + case ESUB: + expr->data.diadic.left = CIRTrans_TransExpr(expr->data.diadic.left, flag); + expr->data.diadic.right = CIRTrans_TransExpr(expr->data.diadic.right, flag); + break; + case EMUL: + expr->data.diadic.left = CIRTrans_TransExpr(expr->data.diadic.left, flag); + expr->data.diadic.right = CIRTrans_TransExpr(expr->data.diadic.right, flag); + case EDIV: + expr->data.diadic.left = CIRTrans_TransExpr(expr->data.diadic.left, flag); + expr->data.diadic.right = CIRTrans_TransExpr(expr->data.diadic.right, flag); + break; + case EMODULO: + expr->data.diadic.left = CIRTrans_TransExpr(expr->data.diadic.left, flag); + expr->data.diadic.right = CIRTrans_TransExpr(expr->data.diadic.right, flag); + break; + case ESHL: + expr->data.diadic.left = CIRTrans_TransExpr(expr->data.diadic.left, flag); + expr->data.diadic.right = CIRTrans_TransExpr(expr->data.diadic.right, flag); + break; + case ESHR: + expr->data.diadic.left = CIRTrans_TransExpr(expr->data.diadic.left, flag); + expr->data.diadic.right = CIRTrans_TransExpr(expr->data.diadic.right, flag); + break; + case EROTL: + expr->data.diadic.left = CIRTrans_TransExpr(expr->data.diadic.left, flag); + expr->data.diadic.right = CIRTrans_TransExpr(expr->data.diadic.right, flag); + break; + case EROTR: + expr->data.diadic.left = CIRTrans_TransExpr(expr->data.diadic.left, flag); + expr->data.diadic.right = CIRTrans_TransExpr(expr->data.diadic.right, flag); + break; + case EAND: + expr->data.diadic.left = CIRTrans_TransExpr(expr->data.diadic.left, flag); + expr->data.diadic.right = CIRTrans_TransExpr(expr->data.diadic.right, flag); + break; + case EXOR: + expr->data.diadic.left = CIRTrans_TransExpr(expr->data.diadic.left, flag); + expr->data.diadic.right = CIRTrans_TransExpr(expr->data.diadic.right, flag); + break; + case EOR: + expr->data.diadic.left = CIRTrans_TransExpr(expr->data.diadic.left, flag); + expr->data.diadic.right = CIRTrans_TransExpr(expr->data.diadic.right, flag); + break; + case ELESS: + case EGREATER: + case ELESSEQU: + case EGREATEREQU: + case EEQU: + case ENOTEQU: + expr->data.diadic.left = CIRTrans_TransExpr(expr->data.diadic.left, flag); + expr->data.diadic.right = CIRTrans_TransExpr(expr->data.diadic.right, flag); + if (!flag) { + expr->type = ECOMMA; + expr->rtype = expr->data.diadic.right->rtype; + return expr; + } + break; + case ELAND: + case ELOR: + expr->data.diadic.left = CIRTrans_TransExpr(expr->data.diadic.left, 1); + expr->data.diadic.right = CIRTrans_TransExpr(expr->data.diadic.right, flag); + break; + case EMULV: + case EADDV: + case ESUBV: + case EPMODULO: + case EBCLR: + case EBTST: + case EBSET: + expr->data.diadic.left = CIRTrans_TransExpr(expr->data.diadic.left, flag); + expr->data.diadic.right = CIRTrans_TransExpr(expr->data.diadic.right, flag); + break; + case EASS: + expr->data.diadic.left = CIRTrans_TransExpr(expr->data.diadic.left, 1); + expr->data.diadic.right = CIRTrans_TransExpr(expr->data.diadic.right, 1); + break; + case EMULASS: + case EDIVASS: + case EADDASS: + case ESUBASS: + expr->data.diadic.left = CIRTrans_TransExpr(expr->data.diadic.left, 1); + expr->data.diadic.right = CIRTrans_TransExpr(expr->data.diadic.right, 1); + break; + case EMODASS: + case ESHLASS: + case ESHRASS: + case EANDASS: + case EXORASS: + case EORASS: + expr->data.diadic.left = CIRTrans_TransExpr(expr->data.diadic.left, 1); + expr->data.diadic.right = CIRTrans_TransExpr(expr->data.diadic.right, 1); + break; + case ECOMMA: + expr->data.diadic.left = CIRTrans_TransExpr(expr->data.diadic.left, 0); + expr->data.diadic.right = CIRTrans_TransExpr(expr->data.diadic.right, flag); + break; + case ECOND: + expr->data.cond.cond = CIRTrans_TransExpr(expr->data.cond.cond, 1); + expr->data.cond.expr1 = CIRTrans_TransExpr(expr->data.cond.expr1, 1); + expr->data.cond.expr2 = CIRTrans_TransExpr(expr->data.cond.expr2, 1); + break; + case EMFPOINTER: + expr->data.mfpointer.accessnode = CIRTrans_TransExpr(expr->data.mfpointer.accessnode, flag); + expr->data.mfpointer.mfpointer = CIRTrans_TransExpr(expr->data.mfpointer.mfpointer, flag); + break; + case EFUNCCALL: + case EFUNCCALLP: + if ( + ENODE_IS(expr->data.funccall.funcref, EOBJREF) && + !strcmp(expr->data.funccall.funcref->data.objref->name->name, "__alloca") + ) + alloca_called = 1; + expr->data.funccall.funcref = CIRTrans_TransExpr(expr->data.funccall.funcref, 1); + expr->data.funccall.args = CIRTrans_TransExprList(expr->data.funccall.args); + break; + case ENULLCHECK: + expr->data.nullcheck.nullcheckexpr = CIRTrans_TransExpr(expr->data.nullcheck.nullcheckexpr, 1); + expr->data.nullcheck.condexpr = CIRTrans_TransExpr(expr->data.nullcheck.condexpr, 1); + break; + case ENEWEXCEPTION: + case ENEWEXCEPTIONARRAY: + expr->data.newexception.initexpr = CIRTrans_TransExpr(expr->data.newexception.initexpr, 1); + expr->data.newexception.tryexpr = CIRTrans_TransExpr(expr->data.newexception.tryexpr, 1); + break; + case EINITTRYCATCH: + expr->data.itc.initexpr = CIRTrans_TransExpr(expr->data.itc.initexpr, 1); + expr->data.itc.tryexpr = CIRTrans_TransExpr(expr->data.itc.tryexpr, 1); + expr->data.itc.catchexpr = CIRTrans_TransExpr(expr->data.itc.catchexpr, 1); + expr->data.itc.result = CIRTrans_TransExpr(expr->data.itc.result, 1); + break; + case EINTCONST: + case EFLOATCONST: + case ESTRINGCONST: + case EOBJREF: + case EPRECOMP: + case ETEMP: + case ELABEL: + case EMEMBER: + case EINSTRUCTION: + case EVECTOR128CONST: + break; + default: + CError_FATAL(1947); + } + + return expr; +} + +void CIRTrans_Transform(void) { + cirtrans_temps = NULL; +} diff --git a/compiler_and_linker/FrontEnd/Common/COptimizer.c b/compiler_and_linker/FrontEnd/Common/COptimizer.c new file mode 100644 index 0000000..3c83ae6 --- /dev/null +++ b/compiler_and_linker/FrontEnd/Common/COptimizer.c @@ -0,0 +1,1831 @@ +#include "compiler/COptimizer.h" +#include "compiler/CompilerTools.h" +#include "compiler/CClass.h" +#include "compiler/CDecl.h" +#include "compiler/CError.h" +#include "compiler/CExpr.h" +#include "compiler/CFunc.h" +#include "compiler/CInt64.h" +#include "compiler/CMachine.h" +#include "compiler/CParser.h" +#include "compiler/InlineAsm.h" +#include "compiler/enode.h" +#include "compiler/objects.h" +#include "compiler/CodeGen.h" +#include "compiler/Switch.h" +#include "compiler/Exceptions.h" +#include "../Optimizer/IrOptimizer.h" +#include "cos.h" + +COptBlock *basicblocks; +Boolean copt_isleaffunction; +static Boolean stmtchanged; +static COptBlock *currentblock; +static ENode *mexpr; +static short setbytes; +static COptCSE *csenodes[MAXEXPR]; +static COptCSEList *cselist; +static short extravars; +static Boolean cse_found; +static Boolean cse_invals; +static Boolean static_for_inlines; +static short replaces; +static ENode *objrefnode; +static int objrefnodes; + +static short bitmasks[] = { + 1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80, + 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000 +}; + +// forward decls +static COptCSE *cse_expression(ENode *expr); + +static COptCSE *cse_new(ENode *expr) { + COptCSE *cse = oalloc(sizeof(COptCSE)); + cse->expr = expr; + cse->replaced = NULL; + cse->block = currentblock; + cse->mexpr = mexpr; + cse->left = NULL; + cse->right = NULL; + cse->x1C = 1; + return cse; +} + +static COptCSE *cse_append(COptCSE *cse, ENode *expr) { + COptCSEList *list = oalloc(sizeof(COptCSEList)); + list->next = cselist; + cselist = list; + list->cse = cse; + list->expr = expr; + return cse; +} + +static void cse_cleanup(void) { + COptCSEList *scanlist; + COptCSEList *prevlist; + COptCSE *scan; + COptCSE *prev; + short op; + + scanlist = cselist; + while (scanlist && !scanlist->cse) + scanlist = scanlist->next; + cselist = scanlist; + + if (scanlist) { + do { + prevlist = scanlist; + do { + scanlist = scanlist->next; + } while (scanlist && !scanlist->cse); + prevlist->next = scanlist; + } while (scanlist); + } + + for (op = 0; op < MAXEXPR; op++) { + scan = csenodes[op]; + while (scan && scan->x1C < 0) + scan = scan->next; + csenodes[op] = scan; + + if (scan) { + do { + prev = scan; + do { + scan = scan->next; + } while (scan && scan->x1C < 0); + prev->next = scan; + } while (scan); + } + } +} + +static void cse_inval(COptCSE *cse) { + COptCSEList *scanlist; + COptCSE *scan; + short op; + + if (cse) { + for (scanlist = cselist; scanlist; scanlist = scanlist->next) { + if (scanlist->cse == cse) { + scanlist->cse = NULL; + scanlist->expr = NULL; + } + } + + cse->x1C = -1; + cse->left = NULL; + cse->right = NULL; + + for (op = 0; op < MAXEXPR; op++) { + for (scan = csenodes[op]; scan; scan = scan->next) { + if (scan->left == cse || scan->right == cse) + cse_inval(scan); + } + } + } +} + +static void cse_update_usages(COptCSE *cse, short amount) { + cse->x1C /= amount; + if (cse->left) + cse_update_usages(cse->left, amount); + if (cse->right) + cse_update_usages(cse->right, amount); +} + +static void cse_replace(ENode *expr, COptCSE *cse) { + COptCSEList *list; + + for (list = cselist; list; list = list->next) { + if (list->cse == cse) { + *list->expr = *expr; + replaces++; + list->cse = NULL; + list->expr = NULL; + } + } +} + +static short cse_objectcost(Object *obj) { + if (obj->datatype == DLOCAL && !obj->u.var.info->noregister) + return 0; + return 1; +} + +static void cse_treereplacemexpr(COptCSE *cse, ENode *from, ENode *to) { + if (cse->mexpr == from) + cse->mexpr = to; + if (cse->left) + cse_treereplacemexpr(cse->left, from, to); + if (cse->right) + cse_treereplacemexpr(cse->right, from, to); +} + +static Boolean cse_issubcse(COptCSE *a, COptCSE *b) { + if (a == b) + return 1; + if (b->left && cse_issubcse(a, b->left)) + return 1; + if (b->right && cse_issubcse(a, b->right)) + return 1; + + return 0; +} + +static short cse_cost(COptCSE *cse) { + short cost; + + if (cse) { + while (ENODE_IS(cse->expr, ETYPCON) && cse->expr->rtype->type == cse->expr->data.monadic->rtype->type && cse->expr->rtype->size == cse->expr->data.monadic->rtype->size) + cse = cse->left; + + if (ENODE_IS_INDIRECT_TO(cse->expr, EOBJREF)) + return cse_objectcost(cse->expr->data.monadic->data.objref); + + cost = 1; + if (!copts.optimizesize) { + if (ENODE_IS3(cse->expr, EMUL, EDIV, EMODULO)) + cost = 2; + } + return cse_cost(cse->left) + cse_cost(cse->right) + cost; + } + + return 0; +} + +static void cse_remove(void) { + short op; // r27 + COptCSE *cse; // r25 + COptCSE *best_cse; // r28 + int best_cost; // r30 + Object *obj; // r31 + Boolean did_replacement; // r24 + VarInfo *vi; // r27 + ObjectList *objlist; + ENode *expr1; + ENode *expr2; + ENode *expr3; + ENode *expr4; + ENode *mexprsave; + COptCSEList *list; + short cost; + + while (1) { + op = 0; + best_cse = NULL; + best_cost = 0; + did_replacement = 0; + + for (; op < MAXEXPR; op++) { + switch (op) { + case EINTCONST: + case EFLOATCONST: + case EOBJREF: + case EVECTOR128CONST: + break; + default: + for (cse = csenodes[op]; cse; cse = cse->next) { + if (cse->x1C > 1 && (cost = cse_cost(cse)) > 4) { + if (cse->replaced) { + replaces = 0; + cse_replace(cse->replaced, cse); + CError_ASSERT(348, replaces >= 1); + cse_found = 1; + did_replacement = 1; + cse_update_usages(cse, cse->x1C); + } else { + if ((cse->x1C * cost) > best_cost) { + best_cse = cse; + best_cost = cse->x1C * cost; + } + } + } + } + break; + } + } + + if (did_replacement) + continue; + if (!best_cse || extravars >= 256) + return; + + obj = lalloc(sizeof(Object)); + memclrw(obj, sizeof(Object)); + obj->name = CParser_GetUniqueName(); + obj->type = cse->expr->rtype; + obj->datatype = DLOCAL; + vi = CodeGen_GetNewVarInfo(); + obj->u.var.info = vi; + + objlist = lalloc(sizeof(ObjectList)); + objlist->object = obj; + objlist->next = locals; + locals = objlist; + + vi->used = 1; + vi->usage = cse->x1C + 1; + + expr1 = lalloc(sizeof(ENode)); + expr1->type = EOBJREF; + expr1->cost = 0; + expr1->flags = 0; + expr1->data.objref = obj; + expr1->rtype = CDecl_NewPointerType(obj->type); + + expr2 = lalloc(sizeof(ENode)); + expr2->type = EINDIRECT; + expr2->cost = 1; + expr2->flags = 0; + expr2->data.monadic = expr1; + expr2->rtype = obj->type; + + expr3 = lalloc(sizeof(ENode)); + expr3->type = EASS; + expr3->cost = -1; + expr3->flags = 0; + expr3->rtype = obj->type; + expr3->data.diadic.left = expr2; + expr3->data.diadic.right = lalloc(sizeof(ENode)); + + *expr3->data.diadic.right = *cse->expr; + cse->expr = expr3->data.diadic.right; + + replaces = 0; + cse_replace(expr2, cse); + cse->replaced = expr2; + + if (replaces < 2) + CError_FATAL(390); + else + cse_found = 1; + + expr4 = lalloc(sizeof(ENode)); + *expr4 = *cse->mexpr; + + cse->mexpr->type = ECOMMA; + cse->mexpr->data.diadic.left = expr3; + cse->mexpr->data.diadic.right = expr4; + + cse_update_usages(cse, cse->x1C); + extravars++; + + mexprsave = cse->mexpr; + if (mexpr == mexprsave) + mexpr = expr4; + + for (list = cselist; list; list = list->next) { + if (list->cse && !cse_issubcse(list->cse, cse)) { + if (list->cse->mexpr == mexprsave) + list->cse->mexpr = expr4; + if (list->cse->expr == mexprsave) + list->cse->expr = expr4; + if (list->expr == mexprsave) + list->expr = expr4; + } + } + } +} + +static COptCSE *cse_intconst(ENode *expr) { + COptCSE *cse = csenodes[EINTCONST]; + + for (; cse; cse = cse->next) { + if (expr->rtype == cse->expr->rtype) + if (CInt64_Equal(cse->expr->data.intval, expr->data.intval)) + return cse; + } + + cse = cse_new(expr); + cse->next = csenodes[EINTCONST]; + csenodes[EINTCONST] = cse; + return cse; +} + +static COptCSE *cse_floatconst(ENode *expr) { + COptCSE *cse = csenodes[EFLOATCONST]; + Float val = expr->data.floatval; + + for (; cse; cse = cse->next) { + if (CMach_CalcFloatDiadicBool(cse->expr->rtype, cse->expr->data.floatval, TK_LOGICAL_EQ, val)) + if (expr->rtype == cse->expr->rtype) + return cse; + } + + cse = cse_new(expr); + cse->next = csenodes[EFLOATCONST]; + csenodes[EFLOATCONST] = cse; + return cse; +} + +static COptCSE *cse_vectorconst(ENode *expr) { + COptCSE *cse = csenodes[EVECTOR128CONST]; + MWVector128 val = expr->data.vector128val; + + for (; cse; cse = cse->next) { + if (CMach_CalcVectorDiadicBool(cse->expr->rtype, &cse->expr->data.vector128val, TK_LOGICAL_EQ, &val)) + if (expr->rtype == cse->expr->rtype) + return cse; + } + + cse = cse_new(expr); + cse->next = csenodes[EVECTOR128CONST]; + csenodes[EVECTOR128CONST] = cse; + return cse; +} + +static COptCSE *cse_objref(ENode *expr) { + COptCSE *cse = csenodes[EOBJREF]; + Object *obj = expr->data.objref; + + for (; cse; cse = cse->next) { + if (cse->expr->data.objref == obj) + return cse; + } + + cse = cse_new(expr); + cse->next = csenodes[EOBJREF]; + csenodes[EOBJREF] = cse; + return cse; +} + +static COptCSE *cse_add_monadic_node(ENode *outer, COptCSE *innercse) { + COptCSE *cse; + + if (!innercse) + return NULL; + + for (cse = csenodes[outer->type]; cse; cse = cse->next) { + if (cse->left == innercse && cse->expr->rtype == outer->rtype) { + CError_ASSERT(524, cse->expr != outer); + cse->x1C++; + return cse; + } + } + + cse = cse_new(outer); + cse->next = csenodes[outer->type]; + csenodes[outer->type] = cse; + cse->left = innercse; + return cse; +} + +static COptCSE *cse_add_typecon_node(ENode *outer, COptCSE *innercse) { + COptCSE *cse; + + if (!innercse) + return NULL; + + for (cse = csenodes[outer->type]; cse; cse = cse->next) { + if (cse->left == innercse && cse->expr->rtype == outer->rtype) { + CError_ASSERT(552, cse->expr != outer); + cse->x1C++; + return cse; + } + } + + cse = cse_new(outer); + cse->next = csenodes[outer->type]; + csenodes[outer->type] = cse; + cse->left = innercse; + return cse; +} + +static COptCSE *cse_add_diadic_node(ENode *outer, COptCSE *leftcse, COptCSE *rightcse) { + COptCSE *cse; + + if (!leftcse || !rightcse) + return NULL; + + for (cse = csenodes[outer->type]; cse; cse = cse->next) { + if (cse->left == leftcse && cse->right == rightcse) { + CError_ASSERT(581, cse->expr != outer); + cse->x1C++; + return cse; + } + } + + cse = cse_new(outer); + cse->next = csenodes[outer->type]; + csenodes[outer->type] = cse; + cse->left = leftcse; + cse->right = rightcse; + return cse; +} + +static COptCSE *cse_add_commdiadic_node(ENode *outer, COptCSE *leftcse, COptCSE *rightcse) { + COptCSE *cse; + + if (!leftcse || !rightcse) + return NULL; + + for (cse = csenodes[outer->type]; cse; cse = cse->next) { + if ((cse->left == leftcse && cse->right == rightcse) || (cse->left == rightcse && cse->right == leftcse)) { + CError_ASSERT(612, cse->expr != outer); + cse->x1C++; + return cse; + } + } + + cse = cse_new(outer); + cse->next = csenodes[outer->type]; + csenodes[outer->type] = cse; + cse->left = leftcse; + cse->right = rightcse; + return cse; +} + +static void sfind_objref(ENode *expr) { + while (1) { + switch (expr->type) { + case ETYPCON: + expr = expr->data.monadic; + break; + case EOBJREF: + objrefnode = expr; + objrefnodes++; + return; + case EADD: + case ESUB: + sfind_objref(expr->data.diadic.left); + expr = expr->data.diadic.right; + break; + default: + return; + } + } +} + +static ENode *find_objref_node(ENode *expr) { + objrefnode = NULL; + objrefnodes = 0; + sfind_objref(expr); + if (objrefnodes == 1) + return objrefnode; + else + return NULL; +} + +static void cse_mem_modify(void) { + COptCSE *cse; + + for (cse = csenodes[EINDIRECT]; cse; cse = cse->next) { + if (ENODE_IS(cse->expr->data.monadic, EOBJREF)) { + Object *obj = cse->expr->data.monadic->data.objref; + CError_ASSERT(672, obj->datatype != DALIAS); + if (obj->datatype == DLOCAL && !obj->u.var.info->noregister) + continue; + } + + cse_inval(cse); + } +} + +static void cse_modify_expression(ENode *expr) { + if (!expr) { + short op; + + cse_remove(); + for (op = 0; op < MAXEXPR; op++) + csenodes[op] = NULL; + + cselist = NULL; + freeoheap(); + } else { + ENode *objnode; + Object *obj; + COptCSE *cse; + + cse_invals = 1; + if (ENODE_IS(expr, EINDIRECT) && (objnode = find_objref_node(expr->data.monadic))) { + do { + obj = objnode->data.objref; + cse_remove(); + for (cse = csenodes[EINDIRECT]; cse; cse = cse->next) { + if ((objnode = find_objref_node(cse->expr->data.monadic)) && obj == objnode->data.objref) + cse_inval(cse); + } + + objnode = find_objref_node(expr->data.monadic); + if (!objnode) { + cse_mem_modify(); + break; + } + } while (obj != objnode->data.objref); + } else { + cse_remove(); + cse_mem_modify(); + } + } +} + +static void cse_pascalcall(ENode *expr) { + ENodeList *list; + + for (list = expr->data.funccall.args; list; list = list->next) + cse_expression(list->node); + + if (ENODE_IS(expr, EFUNCCALLP)) + cse_expression(expr->data.funccall.funcref); + + cse_remove(); + cse_mem_modify(); +} + +static Boolean cse_pusharg(ENodeList *exprs, FuncArg *args) { + Boolean result; + + if (!exprs) + return 1; + + if (args && args != &elipsis && args != &oldstyle) + args = args->next; + if (exprs->next) + result = cse_pusharg(exprs->next, args); + + cse_expression(exprs->node); + return result; +} + +static void cse_ccall(ENode *expr) { + if (cse_pusharg(expr->data.funccall.args, expr->data.funccall.functype->args)) { + if (ENODE_IS(expr, EFUNCCALL)) + cse_expression(expr->data.funccall.funcref); + + cse_remove(); + cse_mem_modify(); + } else { + cse_modify_expression(NULL); + } +} + +static COptCSE *cse_expression(ENode *expr) { + ENode *save; + COptCSE *tmp; + ENodeType nt = expr->type; + + switch (nt) { + case EFUNCCALL: + cse_ccall(expr); + return NULL; + case EFUNCCALLP: + cse_pascalcall(expr); + return NULL; + case EPOSTINC: + case EPOSTDEC: + case EPREINC: + case EPREDEC: + save = mexpr; + mexpr = expr; + CError_ASSERT(816, ENODE_IS(expr->data.monadic, EINDIRECT)); + + cse_expression(expr->data.monadic->data.monadic); + cse_modify_expression(expr->data.monadic); + mexpr = save; + return NULL; + + case EINDIRECT: + case EMONMIN: + case EBINNOT: + case ELOGNOT: + case EFORCELOAD: + return cse_append(cse_add_monadic_node(expr, cse_expression(expr->data.monadic)), expr); + + case ETYPCON: + return cse_append(cse_add_typecon_node(expr, cse_expression(expr->data.monadic)), expr); + + case EMUL: + case EMULV: + case EADDV: + case EADD: + case EEQU: + case ENOTEQU: + case EAND: + case EXOR: + case EOR: + tmp = cse_expression(expr->data.diadic.left); + if (expr->type == nt) + return cse_append(cse_add_commdiadic_node(expr, tmp, cse_expression(expr->data.diadic.right)), expr); + else + return NULL; + + case EDIV: + case EMODULO: + case ESUBV: + case ESUB: + case ESHL: + case ESHR: + case ELESS: + case EGREATER: + case ELESSEQU: + case EGREATEREQU: + case EPMODULO: + case EROTL: + case EROTR: + case EBTST: + tmp = cse_expression(expr->data.diadic.left); + if (expr->type == nt) + return cse_append(cse_add_diadic_node(expr, tmp, cse_expression(expr->data.diadic.right)), expr); + else + return NULL; + + case EASS: + case EMULASS: + case EDIVASS: + case EMODASS: + case EADDASS: + case ESUBASS: + case ESHLASS: + case ESHRASS: + case EANDASS: + case EXORASS: + case EORASS: + CError_ASSERT(887, ENODE_IS(expr->data.diadic.left, EINDIRECT)); + save = mexpr; + mexpr = expr; + cse_expression(expr->data.diadic.right); + if (expr->type == nt) { + cse_expression(expr->data.diadic.left->data.monadic); + cse_modify_expression(expr->data.diadic.left); + mexpr = save; + return NULL; + } else { + cse_modify_expression(NULL); + return NULL; + } + + case ECOMMA: + cse_expression(expr->data.diadic.left); + save = mexpr; + mexpr = expr->data.diadic.right; + tmp = cse_expression(expr->data.diadic.right); + mexpr = save; + return tmp; + + case EINTCONST: + return cse_intconst(expr); + case EFLOATCONST: + return cse_floatconst(expr); + case EVECTOR128CONST: + return cse_vectorconst(expr); + case EOBJREF: + return cse_objref(expr); + + case EBITFIELD: + cse_modify_expression(NULL); + return NULL; + + case ECOND: + cse_expression(expr->data.cond.cond); + cse_modify_expression(NULL); + return NULL; + + case ENULLCHECK: + cse_expression(expr->data.nullcheck.nullcheckexpr); + cse_modify_expression(NULL); + return NULL; + + case ELAND: + case ELOR: + cse_expression(expr->data.diadic.left); + cse_modify_expression(NULL); + return NULL; + + case ESTRINGCONST: + case ELABEL: + return NULL; + + case EPRECOMP: + CError_FATAL(948); + + default: + CError_FATAL(951); + return NULL; + } +} + +static void cse_block(COptBlock *block) { + Statement *stmt; + COptBlock *check; + COptBlockList *scan; + COptBlock *best; + short i; + SInt32 counter; + UInt32 starttime; + + starttime = COS_GetTicks(); + counter = 0; + + while (1) { + cse_invals = 0; + currentblock = block; + block->x1E = 1; + + for (stmt = block->stmt, i = block->x1C; i > 0; stmt = stmt->next, i--) { + switch (stmt->type) { + case ST_EXPRESSION: + case ST_SWITCH: + case ST_IFGOTO: + case ST_IFNGOTO: + mexpr = stmt->expr; + cse_expression(mexpr); + break; + case ST_RETURN: + mexpr = stmt->expr; + if (mexpr) + cse_expression(mexpr); + break; + } + } + + i = 0; + for (scan = block->blocks2; scan; scan = scan->next) { + check = scan->block; + if (!check->x1E && check->blocks && !check->blocks->next && check->blocks->block == block) { + best = check; + i++; + } + } + + if (i != 1) + break; + + block = best; + if (COS_GetTicks() > (starttime + 60)) { + if (counter++ & 1) { + if (CWDisplayLines(cparamblkptr->context, lines)) + CError_UserBreak(); + } else { + if (CWDisplayLines(cparamblkptr->context, lines + 1)) + CError_UserBreak(); + } + starttime = COS_GetTicks(); + } + + if (cse_invals) + cse_cleanup(); + } + + cse_remove(); +} + +static void CSE(void) { + COptBlock *block; + + for (block = basicblocks->next; block; block = block->next) + block->x1E = 0; + + for (block = basicblocks->next; block; block = block->next) { + if (!block->x1E) { + short op; + + for (op = 0; op < MAXEXPR; op++) + csenodes[op] = NULL; + + cselist = NULL; + cse_found = 0; + cse_block(block); + freeoheap(); + } + } +} + +static short TestSetBit(short *set, short bit) { + return set[bit >> 4] & bitmasks[bit & 15]; +} + +static void SetSetBit(short *set, short bit) { + set[bit >> 4] |= bitmasks[bit & 15]; +} + +UInt32 RegAllocMask(short var) { + COptBlock *block; + UInt32 mask = 0; + + for (block = basicblocks; block; block = block->next) { + if (TestSetBit(block->set1, var) || TestSetBit(block->set2, var)) + mask |= block->allocmask; + } + + return mask; +} + +void MarkRegAllocMask(short var, short bit, Boolean flag) { + COptBlock *block; + UInt32 mask = 1 << bit; + + if (flag) { + for (block = basicblocks; block; block = block->next) { + if (TestSetBit(block->set1, var) || TestSetBit(block->set2, var)) + block->allocmask |= mask; + } + } else { + for (block = basicblocks; block; block = block->next) { + block->allocmask |= mask; + } + } +} + +static COptBlock *newblock(void) { + COptBlock *block; + short i; + short max; + + block = lalloc(sizeof(COptBlock) + (setbytes * 2)); + block->x1E = 0; + block->next = NULL; + block->blocks = NULL; + block->blocks2 = NULL; + block->allocmask = 0; + block->set1 = (short *) (((long) block) + sizeof(COptBlock)); + block->set2 = (short *) (((long) block) + setbytes + sizeof(COptBlock)); + + for (i = 0, max = setbytes / 2; i < max; i++) { + block->set1[i] = 0; + block->set2[i] = 0; + } + + return block; +} + +static void MarkFollow(COptBlock *block) { + COptBlockList *list; + +restart: + block->x1E = 1; + if ((list = block->blocks2)) { + while (1) { + if (!list->block->x1E) { + if (!list->next) { + block = list->block; + goto restart; + } + MarkFollow(list->block); + list = list->next; + } else { + list = list->next; + if (!list) + break; + } + } + } +} + +static Boolean CheckInit(short var) { + Boolean result; + COptBlock *block; + + result = 1; + for (block = basicblocks; block; block = block->next) { + if (!block->x1E && TestSetBit(block->set2, var)) + MarkFollow(block); + } + + for (block = basicblocks; block; block = block->next) { + if (!block->x1E) { + if (TestSetBit(block->set1, var)) + result = 0; + } else { + block->x1E = 0; + } + } + + return result; +} + +static void CheckVarInit(void) { + COptBlock *block; + VarInfo *vi; + ObjectList *list; + + for (block = basicblocks; block; block = block->next) + block->x1E = 0; + + for (list = locals; list; list = list->next) { + if (list->object->datatype == DLOCAL && !IsTempName(list->object->name) && !is_volatile_object(list->object)) { + vi = list->object->u.var.info; + if (vi->used && !CheckInit(vi->varnumber)) { + if (!IS_TYPE_CLASS(list->object->type) || !CClass_IsEmpty(TYPE_CLASS(list->object->type))) { + CError_SetErrorToken(&vi->deftoken); + CError_Warning(CErrorStr185, list->object->name->name); + } + } + } + } +} + +static void AddVar(Object *obj, Boolean whichSet) { + VarInfo *vi; + + if (obj->datatype == DLOCAL) { + vi = obj->u.var.info; + if (!whichSet) { + SetSetBit(currentblock->set1, vi->varnumber); + } else { + if (!TestSetBit(currentblock->set1, vi->varnumber)) + SetSetBit(currentblock->set2, vi->varnumber); + } + } +} + +static void CheckExpr(ENode *expr) { + ENodeList *list; + + while (1) { + switch (expr->type) { + case EINDIRECT: + if (ENODE_IS(expr->data.monadic, EOBJREF)) { + AddVar(expr->data.monadic->data.objref, 0); + return; + } + expr = expr->data.monadic; + break; + case EOBJREF: + AddVar(expr->data.objref, 1); + return; + case EFUNCCALL: + case EFUNCCALLP: + CheckExpr(expr->data.funccall.funcref); + for (list = expr->data.funccall.args; list; list = list->next) + CheckExpr(list->node); + return; + case ECOND: + CheckExpr(expr->data.cond.cond); + CheckExpr(expr->data.cond.expr1); + CheckExpr(expr->data.cond.expr2); + return; + case EASS: + if (ENODE_IS_INDIRECT_TO(expr->data.diadic.left, EOBJREF)) { + CheckExpr(expr->data.diadic.right); + AddVar(expr->data.diadic.left->data.monadic->data.objref, 1); + return; + } + case EMUL: + case EMULV: + case EDIV: + case EMODULO: + case EADDV: + case ESUBV: + case EADD: + case ESUB: + case ESHL: + case ESHR: + case ELESS: + case EGREATER: + case ELESSEQU: + case EGREATEREQU: + case EEQU: + case ENOTEQU: + case EAND: + case EXOR: + case EOR: + case ELAND: + case ELOR: + case EMULASS: + case EDIVASS: + case EMODASS: + case EADDASS: + case ESUBASS: + case ESHLASS: + case ESHRASS: + case EANDASS: + case EXORASS: + case EORASS: + case ECOMMA: + case EPMODULO: + case EROTL: + case EROTR: + case EBCLR: + case EBTST: + case EBSET: + CheckExpr(expr->data.diadic.left); + expr = expr->data.diadic.right; + break; + case EPOSTINC: + case EPOSTDEC: + case EPREINC: + case EPREDEC: + case EMONMIN: + case EBINNOT: + case ELOGNOT: + case EFORCELOAD: + case ETYPCON: + case EBITFIELD: + expr = expr->data.monadic; + break; + case ENULLCHECK: + CheckExpr(expr->data.nullcheck.nullcheckexpr); + expr = expr->data.nullcheck.condexpr; + break; + case EINTCONST: + case EFLOATCONST: + case ESTRINGCONST: + case EPRECOMP: + case ELABEL: + case EVECTOR128CONST: + return; + default: + CError_FATAL(1332); + } + } +} + +static short CheckPath(COptBlock *block, short var) { + COptBlockList *list; + + if (block->x1E) + return TestSetBit(block->set1, var); + + block->x1E = 1; + if (TestSetBit(block->set1, var)) + return -1; + if (TestSetBit(block->set2, var)) + return 0; + + for (list = block->blocks2; list; list = list->next) { + if (CheckPath(list->block, var)) { + SetSetBit(block->set1, var); + return -1; + } + } + + return 0; +} + +static void MarkPre(COptBlock *block, short var) { + COptBlockList *list; + +restart: + block->x1E = 1; + for (list = block->blocks; list; list = list->next) { + if (!list->block->x1E) { + if (!TestSetBit(list->block->set2, var)) { + SetSetBit(list->block->set1, var); + if (!list->next) { + block = list->block; + goto restart; + } + MarkPre(list->block, var); + } else { + list->block->x1E = 1; + } + } + } +} + +static void CheckVarUsage(void) { + short local; + COptBlock *block; + short counter; + + for (currentblock = basicblocks; currentblock; currentblock = currentblock->next) { + Statement *stmt = currentblock->stmt; + if (currentblock->x1C > 0 && stmt->type == ST_LABEL && (stmt->flags & StmtFlag_1)) { + short i; + for (i = 0; i < localcount; i++) + SetSetBit(currentblock->set2, i); + } + + for (counter = currentblock->x1C; counter > 0; counter--) { + if (stmt->type >= ST_EXPRESSION && stmt->type <= ST_GOTOEXPR && stmt->expr) + CheckExpr(stmt->expr); + stmt = stmt->next; + } + } + + for (local = 0; local < localcount; local++) { + for (block = basicblocks; block; block = block->next) { + if (!block->x1E && TestSetBit(block->set1, local)) + MarkPre(block, local); + } + for (block = basicblocks; block; block = block->next) { + block->x1E = 0; + } + } +} + +static void SplitCommaExpressions(void) { + COptBlock *block; + Statement *stmt; + ENode *expr; + Statement *stmtcopy; + short counter; + Boolean flag; + + block = basicblocks->next; + while (block) { + stmt = block->stmt; + counter = block->x1C; + flag = 1; + while (counter > 0) { + if (stmt->type >= ST_EXPRESSION && stmt->type <= ST_GOTOEXPR) { + if ((expr = stmt->expr) && ENODE_IS(expr, ECOMMA)) { + stmtcopy = lalloc(sizeof(Statement)); + *stmtcopy = *stmt; + stmt->next = stmtcopy; + stmt->type = ST_EXPRESSION; + stmt->expr = expr->data.diadic.left; + stmtcopy->expr = expr->data.diadic.right; + block->x1C++; + flag = 0; + break; + } + } + + stmt = stmt->next; + counter--; + } + + if (flag) + block = block->next; + } +} + +static void BasicBlockAnalyze(Statement *stmt) { + COptBlock *block; + ObjectList *objlist; + COptBlockList *scan; + COptBlockList *list; + CLabel *label; + COptBlock *iblock; + COptBlock *oblock; + SwitchCase *swcase; + + setbytes = 2 * ((localcount - 1) / 16) + 2; + if (copts.globaloptimizer) { + setbytes += 32; + extravars = 0; + } + + block = newblock(); + basicblocks = block; + block->stmt = NULL; + block->x1C = 0; + + if (stmt) { + list = lalloc(sizeof(COptBlockList)); + list->next = NULL; + block->blocks2 = list; + list->block = (COptBlock *) stmt; + } + + for (objlist = arguments; objlist; objlist = objlist->next) { + SetSetBit(block->set2, objlist->object->u.var.info->varnumber); + } + + while (stmt) { + int counter; + + block->next = newblock(); + block = block->next; + block->stmt = stmt; + counter = 1; + + innerLoop: + switch (stmt->type) { + case ST_ASM: + label = InlineAsm_GetReferencedLabel(stmt); + if (!label) + goto jumpahead; + list = lalloc(sizeof(COptBlockList)); + list->next = block->blocks2; + block->blocks2 = list; + list->block = (COptBlock *) label->stmt; + if (stmt->next) { + list = lalloc(sizeof(COptBlockList)); + list->next = block->blocks2; + block->blocks2 = list; + list->block = (COptBlock *) stmt->next; + } + stmt = stmt->next; + block->x1C = counter; + continue; + case ST_NOP: + case ST_LABEL: + case ST_ENTRY: + if (stmt->next && stmt->next->type != ST_LABEL) { + stmt = stmt->next; + counter++; + goto innerLoop; + } + break; + case ST_EXPRESSION: + case ST_BEGINCATCH: + case ST_ENDCATCH: + case ST_ENDCATCHDTOR: + jumpahead: + if (stmt->next && stmt->next->type == ST_GOTO) { + stmt = stmt->next; + counter++; + goto innerLoop; + } + break; + } + + switch (stmt->type) { + case ST_SWITCH: + label = ((SwitchInfo *) stmt->label)->defaultlabel; + if (label != cleanreturnlabel) { + list = lalloc(sizeof(COptBlockList)); + list->next = block->blocks2; + block->blocks2 = list; + list->block = (COptBlock *) label->stmt; + } + for (swcase = ((SwitchInfo *) stmt->label)->cases; swcase; swcase = swcase->next) { + label = swcase->label; + if (label != cleanreturnlabel) { + list = lalloc(sizeof(COptBlockList)); + list->next = block->blocks2; + block->blocks2 = list; + list->block = (COptBlock *) label->stmt; + } + } + break; + case ST_RETURN: + case ST_EXIT: + case ST_GOTOEXPR: + break; + case ST_GOTO: + case ST_IFGOTO: + case ST_IFNGOTO: + case ST_OVF: + label = stmt->label; + if (label != cleanreturnlabel) { + list = lalloc(sizeof(COptBlockList)); + list->next = block->blocks2; + block->blocks2 = list; + list->block = (COptBlock *) label->stmt; + } + if (stmt->type == ST_GOTO) + break; + default: + if (stmt->next) { + list = lalloc(sizeof(COptBlockList)); + list->next = block->blocks2; + block->blocks2 = list; + list->block = (COptBlock *) stmt->next; + } + break; + } + + stmt = stmt->next; + block->x1C = counter; + } + + for (oblock = basicblocks; oblock; oblock = oblock->next) { + for (scan = oblock->blocks2; scan; scan = scan->next) { + stmt = (Statement *) scan->block; + for (iblock = basicblocks->next; iblock; iblock = iblock->next) { + if (iblock->stmt == stmt) { + scan->block = iblock; + list = lalloc(sizeof(COptBlockList)); + list->next = iblock->blocks; + iblock->blocks = list; + list->block = oblock; + break; + } + } + + CError_ASSERT(1602, iblock); + } + } + + SplitCommaExpressions(); + CheckVarUsage(); +} + +static CLabel *finallabel(CLabel *label, Statement *stmt) { + Statement *scan; + + for (scan = label->stmt; scan; scan = scan->next) { + if (scan->type > ST_LABEL) { + if (scan == stmt) + return label; + if (scan->type == ST_GOTO) { + if (scan->label != label) + stmtchanged = 1; + return scan->label; + } + return label; + } + } + + return label; +} + +static void optimizegoto(Statement *stmt) { + Statement *scan; + + for (scan = stmt->next; scan; scan = scan->next) { + if (stmt->label->stmt == scan) { + stmt->type = ST_NOP; + stmtchanged = 1; + return; + } + if (scan->type > ST_LABEL) + break; + } + + stmt->label = finallabel(stmt->label, stmt); +} + +static void removeif(Statement *stmt, Boolean flag) { + if (((stmt->type == ST_IFGOTO) && flag) || ((stmt->type == ST_IFNGOTO) && !flag)) { + Statement *copy = lalloc(sizeof(Statement)); + *copy = *stmt; + copy->type = ST_GOTO; + stmt->next = copy; + } + stmt->type = ST_EXPRESSION; + stmtchanged = 1; +} + +static void optimizeif(Statement *stmt) { + Statement *scan; + Statement *scan2; + Boolean flag; + + if (iszero(stmt->expr)) { + removeif(stmt, 0); + return; + } + if (isnotzero(stmt->expr)) { + removeif(stmt, 1); + return; + } + + for (scan = stmt->next, flag = 0; scan; scan = scan->next) { + if (scan->type > ST_LABEL) { + if (scan->type == ST_GOTO) { + if (scan->label == stmt->label) { + stmt->type = ST_EXPRESSION; + stmtchanged = 1; + return; + } + + if (!flag) { + for (scan2 = scan->next; scan2; scan2 = scan2->next) { + if (scan2->type > ST_LABEL) + break; + if (stmt->label->stmt == scan2) { + stmt->label = scan->label; + scan->type = ST_NOP; + if (stmt->type == ST_IFGOTO) + stmt->type = ST_IFNGOTO; + else + stmt->type = ST_IFGOTO; + stmtchanged = 1; + stmt->label = finallabel(stmt->label, stmt); + return; + } + } + } + } else if (scan->type == ST_RETURN && !scan->expr && !static_for_inlines && !flag) { + for (scan2 = scan->next; scan2; scan2 = scan2->next) { + if (scan2->type > ST_LABEL) + break; + if (stmt->label->stmt == scan2) { + stmt->label = cleanreturnlabel; + needs_cleanup = 1; + scan->type = ST_NOP; + if (stmt->type == ST_IFGOTO) + stmt->type = ST_IFNGOTO; + else + stmt->type = ST_IFGOTO; + stmtchanged = 1; + return; + } + } + } + break; + } + + if (scan->type == ST_LABEL) + flag = 1; + + if (stmt->label->stmt == scan) { + stmt->type = ST_EXPRESSION; + stmtchanged = 1; + return; + } + } + + stmt->label = finallabel(stmt->label, stmt); +} + +static void optimizeswitch(Statement *stmt) { + SwitchInfo *info; + SwitchCase *swcase; + + info = (SwitchInfo *) stmt->label; + CError_ASSERT(1746, info && info->cases && info->defaultlabel); + + info->defaultlabel = finallabel(info->defaultlabel, stmt); + for (swcase = info->cases; swcase; swcase = swcase->next) + swcase->label = finallabel(swcase->label, stmt); + + if (ENODE_IS(stmt->expr, EINTCONST)) { + for (swcase = info->cases; swcase; swcase = swcase->next) { + if (CInt64_GreaterEqual(swcase->min, stmt->expr->data.intval) && CInt64_LessEqual(swcase->max, stmt->expr->data.intval)) + break; + } + + stmt->type = ST_GOTO; + stmt->label = swcase ? swcase->label : info->defaultlabel; + } +} + +static void removeunusedlabels(Statement *stmt) { + Statement *scan; + CLabel *label; + SwitchCase *swcase; + ExceptionAction *action; + + for (scan = stmt; scan; scan = scan->next) + scan->marked = 0; + + for (scan = stmt; scan; scan = scan->next) { + switch (scan->type) { + case ST_GOTO: + case ST_IFGOTO: + case ST_IFNGOTO: + case ST_OVF: + if (scan->label->stmt) + scan->label->stmt->marked = 1; + break; + case ST_SWITCH: + ((SwitchInfo *) scan->label)->defaultlabel->stmt->marked = 1; + for (swcase = ((SwitchInfo *) scan->label)->cases; swcase; swcase = swcase->next) + swcase->label->stmt->marked = 1; + break; + case ST_ASM: + if ((label = InlineAsm_GetReferencedLabel(scan))) + label->stmt->marked = 1; + if ((label = InlineAsm_GetReferencedLabel2(scan))) + label->stmt->marked = 1; + break; + case ST_BEGINLOOP: + ((LoopInfo *) scan->expr)->stmt->marked = 1; + break; + case ST_ENDLOOP: + if (scan->next->type == ST_GOTO && scan->next->next->type == ST_LABEL) + scan->next->next->marked = 1; + break; + default: + for (action = scan->dobjstack; action; action = action->prev) { + if (action->type == EAT_CATCHBLOCK) { + action->data.catch_block.catch_label->stmt->marked = 1; + action->data.catch_block.catch_label->stmt->flags = action->data.catch_block.catch_label->stmt->flags | StmtFlag_1; + } else if (action->type == EAT_SPECIFICATION) { + action->data.specification.unexp_label->stmt->marked = 1; + action->data.specification.unexp_label->stmt->flags = action->data.specification.unexp_label->stmt->flags | StmtFlag_1; + } + } + } + } + + for (scan = stmt; scan; scan = scan->next) { + if (scan->type == ST_LABEL && !scan->marked && !(scan->flags & StmtFlag_1)) { + scan->type = ST_NOP; + stmtchanged = 1; + } + } +} + +static void optimizebranches(Statement *stmt) { + removeunusedlabels(stmt); + while (stmt) { + switch (stmt->type) { + case ST_GOTO: + optimizegoto(stmt); + break; + case ST_IFGOTO: + case ST_IFNGOTO: + optimizeif(stmt); + break; + case ST_SWITCH: + optimizeswitch(stmt); + break; + } + stmt = stmt->next; + } +} + +void SetVarUsage(Object *obj, Boolean noregister) { + VarInfo *vi; + CError_ASSERT(1875, obj->datatype != DALIAS); + + if (obj->datatype == DLOCAL || obj->datatype == DNONLAZYPTR) { + vi = obj->u.var.info; + vi->used = 1; + if (!copts.globaloptimizer) { + if (copts.optimizesize) + vi->usage++; + else + vi->usage += curstmtvalue; + } + + if (noregister) + vi->noregister = 1; + } +} + +static void checkexpression(ENode *expr) { + ENodeList *list; + + while (1) { + switch (expr->type) { + case EOBJREF: + SetVarUsage(expr->data.objref, 1); + return; + case EINDIRECT: + if (ENODE_IS(expr->data.monadic, EOBJREF)) { + SetVarUsage(expr->data.monadic->data.objref, 0); + return; + } + expr = expr->data.monadic; + break; + case EFUNCCALL: + case EFUNCCALLP: + copt_isleaffunction = 0; + checkexpression(expr->data.funccall.funcref); + for (list = expr->data.funccall.args; list; list = list->next) + checkexpression(list->node); + return; + case ECOND: + case ECONDASS: + checkexpression(expr->data.cond.cond); + checkexpression(expr->data.cond.expr1); + checkexpression(expr->data.cond.expr2); + return; + case EMUL: + case EMULV: + case EDIV: + case EMODULO: + case EADDV: + case ESUBV: + case EADD: + case ESUB: + case ESHL: + case ESHR: + case ELESS: + case EGREATER: + case ELESSEQU: + case EGREATEREQU: + case EEQU: + case ENOTEQU: + case EAND: + case EXOR: + case EOR: + case ELAND: + case ELOR: + case EASS: + case EMULASS: + case EDIVASS: + case EMODASS: + case EADDASS: + case ESUBASS: + case ESHLASS: + case ESHRASS: + case EANDASS: + case EXORASS: + case EORASS: + case ECOMMA: + case EPMODULO: + case EROTL: + case EROTR: + case EBCLR: + case EBTST: + case EBSET: + checkexpression(expr->data.diadic.left); + expr = expr->data.diadic.right; + break; + case EPOSTINC: + case EPOSTDEC: + case EPREINC: + case EPREDEC: + case EMONMIN: + case EBINNOT: + case ELOGNOT: + case EFORCELOAD: + case ETYPCON: + case EBITFIELD: + expr = expr->data.monadic; + break; + case ENULLCHECK: + checkexpression(expr->data.nullcheck.nullcheckexpr); + expr = expr->data.nullcheck.condexpr; + break; + case EINTCONST: + case EFLOATCONST: + case EPRECOMP: + case ELABEL: + case EVECTOR128CONST: + return; + case ESTRINGCONST: + return; + default: + CError_FATAL(1998); + } + } +} + +static void checklocalusage(Statement *stmt) { + Statement *scan; + + for (scan = stmt; scan; scan = scan->next) { + if (scan->type >= ST_EXPRESSION && scan->type <= ST_GOTOEXPR && scan->expr) { + curstmtvalue = scan->value; + checkexpression(scan->expr); + } else if (scan->type == ST_ASM) { + curstmtvalue = scan->value; + InlineAsm_CheckLocalUsage(scan); + } + } +} + +static void colorcode(Statement *stmt) { + CLabel *label; + SwitchCase *swcase; + + while (stmt && !stmt->marked) { + stmt->marked = 1; + switch (stmt->type) { + case ST_GOTOEXPR: + return; + case ST_IFGOTO: + case ST_IFNGOTO: + case ST_OVF: + colorcode(stmt->label->stmt); + break; + case ST_GOTO: + case ST_EXIT: + stmt = stmt->label->stmt; + continue; + case ST_RETURN: + return; + case ST_SWITCH: + for (swcase = ((SwitchInfo *) stmt->label)->cases; swcase; swcase = swcase->next) + colorcode(swcase->label->stmt); + stmt = ((SwitchInfo *) stmt->label)->defaultlabel->stmt; + continue; + case ST_ASM: + if ((label = InlineAsm_GetReferencedLabel(stmt))) + colorcode(label->stmt); + if ((label = InlineAsm_GetReferencedLabel2(stmt))) + colorcode(label->stmt); + break; + case ST_ENDLOOP: + if (stmt->next && stmt->next->type == ST_GOTO) { + stmt = stmt->next; + stmt->marked = 1; + } + break; + case ST_NOP: + case ST_LABEL: + case ST_EXPRESSION: + case ST_ENTRY: + case ST_BEGINCATCH: + case ST_ENDCATCH: + case ST_ENDCATCHDTOR: + case ST_BEGINLOOP: + break; + default: + CError_FATAL(2096); + } + stmt = stmt->next; + } +} + +static void removeunusedcode(Statement *stmt) { + Statement *scan; + + for (scan = stmt; scan; scan = scan->next) + scan->marked = 0; + + colorcode(stmt); + for (scan = stmt; scan; scan = scan->next) { + if (!scan->marked && (scan->flags & StmtFlag_1)) + colorcode(scan); + } + + for (scan = stmt; scan; scan = scan->next) { + if (!scan->marked && scan->type != ST_NOP) { + scan->type = ST_NOP; + stmtchanged = 1; + } + } +} + +static void COpt_ReturnCheck(Object *obj, Statement *stmt) { + if ((copts.pedantic || copts.cplusplus) && obj && TYPE_FUNC(obj->type)->functype != &stvoid) { + while (stmt) { + if (!stmt->next && stmt->type != ST_GOTO && stmt->type != ST_RETURN) { + CError_Warning(CErrorStr184); + break; + } + + if (stmt->type == ST_RETURN && !stmt->expr && !(stmt->flags & StmtFlag_8)) { + CError_Warning(CErrorStr184); + break; + } + + stmt = stmt->next; + } + } +} + +static void COpt_Optimize(Object *obj, Statement *stmt) { + Statement **ptr; + + do { + stmtchanged = 0; + optimizebranches(stmt->next); + removeunusedcode(stmt->next); + } while (stmtchanged); + + ptr = &stmt->next; + while (*ptr) { + if ((*ptr)->type == ST_NOP) + *ptr = (*ptr)->next; + else + ptr = &(*ptr)->next; + } +} + +static void COpt_ELABELCallBack(ENode *expr) { + CError_ASSERT(2195, expr->data.label->stmt && expr->data.label->stmt->type == ST_LABEL); + expr->data.label->stmt->flags = expr->data.label->stmt->flags | StmtFlag_1; +} + +void COpt_SimpleOptimizer(Object *obj, Statement *stmt) { + Statement *scan; + + for (scan = stmt; scan; scan = scan->next) { + if ((scan->type >= ST_EXPRESSION && scan->type <= ST_GOTOEXPR) && scan->expr) + CExpr_SearchExprTree(scan->expr, COpt_ELABELCallBack, 1, ELABEL); + } + + static_for_inlines = 1; + cleanreturnlabel = NULL; + COpt_Optimize(obj, stmt); + COpt_ReturnCheck(obj, stmt); +} + +Statement *COpt_Optimizer(Object *obj, Statement *stmt) { + copt_isleaffunction = 1; + if (copts.globaloptimizer) + stmt = IRO_Optimizer(obj, stmt); + + static_for_inlines = 0; + COpt_Optimize(obj, stmt); + + if (obj && !(obj->qual & Q_INLINE)) + COpt_ReturnCheck(obj, stmt); + + checklocalusage(stmt->next); + return stmt; +} |