summaryrefslogtreecommitdiff
path: root/compiler_and_linker/FrontEnd/Common/COptimizer.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/Common/COptimizer.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/Common/COptimizer.c')
-rw-r--r--compiler_and_linker/FrontEnd/Common/COptimizer.c1831
1 files changed, 1831 insertions, 0 deletions
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;
+}