-/*
- * If the arguments to the cond branch are constants, eval and
- * return BRANCH_NOT_TAKEN for not taken, BRANCH_TAKEN for taken,
- * BRANCH_UNDEF otherwise.
- * If this code is changed to handle also non-const values, make sure
- * side effects are handled in optimize_branches() in mini.c, by
- * inserting pop instructions.
- */
-int
-mono_eval_cond_branch (MonoInst *ins)
-{
- MonoInst *left, *right;
- /* FIXME: handle also 64 bit ints */
- left = ins->inst_left->inst_left;
- if (left->opcode != OP_ICONST && left->opcode != OP_PCONST)
- return BRANCH_UNDEF;
- right = ins->inst_left->inst_right;
- if (right->opcode != OP_ICONST && right->opcode != OP_PCONST)
- return BRANCH_UNDEF;
- switch (ins->opcode) {
- case CEE_BEQ:
- if (left->inst_c0 == right->inst_c0)
- return BRANCH_TAKEN;
- return BRANCH_NOT_TAKEN;
- case CEE_BGE:
- if (left->inst_c0 >= right->inst_c0)
- return BRANCH_TAKEN;
- return BRANCH_NOT_TAKEN;
- case CEE_BGT:
- if (left->inst_c0 > right->inst_c0)
- return BRANCH_TAKEN;
- return BRANCH_NOT_TAKEN;
- case CEE_BLE:
- if (left->inst_c0 <= right->inst_c0)
- return BRANCH_TAKEN;
- return BRANCH_NOT_TAKEN;
- case CEE_BLT:
- if (left->inst_c0 < right->inst_c0)
- return BRANCH_TAKEN;
- return BRANCH_NOT_TAKEN;
- case CEE_BNE_UN:
- if ((gsize)left->inst_c0 != (gsize)right->inst_c0)
- return BRANCH_TAKEN;
- return BRANCH_NOT_TAKEN;
- case CEE_BGE_UN:
- if ((gsize)left->inst_c0 >= (gsize)right->inst_c0)
- return BRANCH_TAKEN;
- return BRANCH_NOT_TAKEN;
- case CEE_BGT_UN:
- if ((gsize)left->inst_c0 > (gsize)right->inst_c0)
- return BRANCH_TAKEN;
- return BRANCH_NOT_TAKEN;
- case CEE_BLE_UN:
- if ((gsize)left->inst_c0 <= (gsize)right->inst_c0)
- return BRANCH_TAKEN;
- return BRANCH_NOT_TAKEN;
- case CEE_BLT_UN:
- if ((gsize)left->inst_c0 < (gsize)right->inst_c0)
- return BRANCH_TAKEN;
- return BRANCH_NOT_TAKEN;
+ switch (next->opcode) {
+ case OP_CEQ:
+ case OP_ICEQ:
+ case OP_CGT:
+ case OP_ICGT:
+ case OP_CGT_UN:
+ case OP_ICGT_UN:
+ case OP_CLT:
+ case OP_ICLT:
+ case OP_CLT_UN:
+ case OP_ICLT_UN:
+ switch (next->opcode) {
+ FOLD_BINOPCXX (OP_CEQ,==,gint32);
+ FOLD_BINOPCXX (OP_ICEQ,==,gint32);
+ FOLD_BINOPCXX (OP_CGT,>,gint32);
+ FOLD_BINOPCXX (OP_ICGT,>,gint32);
+ FOLD_BINOPCXX (OP_CGT_UN,>,guint32);
+ FOLD_BINOPCXX (OP_ICGT_UN,>,guint32);
+ FOLD_BINOPCXX (OP_CLT,<,gint32);
+ FOLD_BINOPCXX (OP_ICLT,<,gint32);
+ FOLD_BINOPCXX (OP_CLT_UN,<,guint32);
+ FOLD_BINOPCXX (OP_ICLT_UN,<,guint32);
+ }
+
+ if (overwrite) {
+ NULLIFY_INS (ins);
+ next->opcode = OP_ICONST;
+ next->inst_c0 = res;
+ MONO_INST_NULLIFY_SREGS (next);
+ } else {
+ ALLOC_DEST (cfg, dest, ins);
+ dest->opcode = OP_ICONST;
+ dest->inst_c0 = res;
+ }
+ break;
+ case OP_IBEQ:
+ case OP_IBNE_UN:
+ case OP_IBGT:
+ case OP_IBGT_UN:
+ case OP_IBGE:
+ case OP_IBGE_UN:
+ case OP_IBLT:
+ case OP_IBLT_UN:
+ case OP_IBLE:
+ case OP_IBLE_UN:
+ switch (next->opcode) {
+ FOLD_BINOPCXX (OP_IBEQ,==,gint32);
+ FOLD_BINOPCXX (OP_IBNE_UN,!=,guint32);
+ FOLD_BINOPCXX (OP_IBGT,>,gint32);
+ FOLD_BINOPCXX (OP_IBGT_UN,>,guint32);
+ FOLD_BINOPCXX (OP_IBGE,>=,gint32);
+ FOLD_BINOPCXX (OP_IBGE_UN,>=,guint32);
+ FOLD_BINOPCXX (OP_IBLT,<,gint32);
+ FOLD_BINOPCXX (OP_IBLT_UN,<,guint32);
+ FOLD_BINOPCXX (OP_IBLE,<=,gint32);
+ FOLD_BINOPCXX (OP_IBLE_UN,<=,guint32);
+ }
+
+ if (overwrite) {
+ /*
+ * Can't nullify OP_COMPARE here since the decompose long branch
+ * opcodes depend on it being executed. Also, the branch might not
+ * be eliminated after all if loop opts is disabled, for example.
+ */
+ if (res)
+ next->flags |= MONO_INST_CFOLD_TAKEN;
+ else
+ next->flags |= MONO_INST_CFOLD_NOT_TAKEN;
+ } else {
+ ALLOC_DEST (cfg, dest, ins);
+ dest->opcode = OP_ICONST;
+ dest->inst_c0 = res;
+ }
+ break;
+ case OP_NOP:
+ case OP_BR:
+ /* This happens when a conditional branch is eliminated */
+ if (next->next == NULL) {
+ /* Last ins */
+ if (overwrite)
+ NULLIFY_INS (ins);
+ }
+ break;
+ default:
+ return NULL;
+ }
+ }
+ break;