aboutsummaryrefslogtreecommitdiff
path: root/ssa.c
diff options
context:
space:
mode:
Diffstat (limited to 'ssa.c')
-rw-r--r--ssa.c2723
1 files changed, 2723 insertions, 0 deletions
diff --git a/ssa.c b/ssa.c
new file mode 100644
index 0000000..af1311f
--- /dev/null
+++ b/ssa.c
@@ -0,0 +1,2723 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include "ast.h"
+#include "ssa.h"
+#include "mips.h"
+#define NEW(type) ((type *)malloc(sizeof(type)))
+#define DBLINK(from, to) ((from)->next = (to))->prev = (from)
+
+static CGraph cfg, dtree;
+static CBlock_t blks[MAX_BLOCK];
+static COList_t raw_defs; /* defintion of all vars and tmps */
+static int bcnt; /* block counter */
+static int tcnt; /* temporary counter */
+
+static int quiet;
+static int gbbase;
+static CBlock_t entry;
+static COList_t defs; /* all defintions that have actual effects */
+
+/* for code generation */
+CFuncIR_t func_ir;
+
+COpr_t copr_create(void) {
+ COpr_t opr = NEW(COpr);
+ opr->type = NULL;
+ opr->cval = NULL;
+ opr->range = NULL;
+ opr->same = opr;
+ opr->dep = 0;
+ opr->mod = 0;
+ opr->par = opr;
+ return opr;
+}
+
+CInst_t cinst_create(void) {
+ CInst_t inst = NEW(CInst);
+ inst->dest = NULL;
+ inst->src1 = NULL;
+ inst->src2 = NULL;
+ inst->sysp = 0;
+ return inst;
+}
+
+CBlock_t cblock_create(int inc) {
+ CBlock_t cblk = NEW(CBlock);
+ CInst_t dum = cinst_create();
+ CPhi_t pdum = NEW(CPhi);
+ dum->prev = dum;
+ dum->next = dum;
+ pdum->prev = pdum;
+ pdum->next = pdum;
+ cblk->insts = dum;
+ cblk->phis = pdum;
+ cblk->next = NULL;
+ if (inc)
+ cblk->id = bcnt++;
+ cblk->ref = 0;
+ return cblk;
+}
+
+void cblock_append(CBlock_t cblk, CInst_t inst) {
+ CInst_t head = cblk->insts;
+ (inst->prev = head->prev)->next = inst;
+ (inst->next = head)->prev = inst;
+}
+
+void cblock_pushfront(CBlock_t cblk, CInst_t inst) {
+ CInst_t head = cblk->insts;
+ (inst->next = head->next)->prev = inst;
+ (inst->prev = head)->next = inst;
+}
+
+void cblock_pappend(CBlock_t cblk, CPhi_t phi) {
+ CPhi_t head = cblk->phis;
+ (phi->prev = head->prev)->next = phi;
+ (phi->next = head)->prev = phi;
+}
+
+void cblock_popback(CBlock_t cblk) {
+ CInst_t last = cblk->insts->prev;
+ last->next->prev = last->prev;
+ last->prev->next = last->next;
+}
+
+void cblock_popfront(CBlock_t cblk) {
+ CInst_t first = cblk->insts->next;
+ first->next->prev = first->prev;
+ first->prev->next = first->next;
+}
+
+CInst_t cblock_getback(CBlock_t cblk) {
+ CInst_t res = cblk->insts->prev;
+ return res != cblk->insts ? res : NULL;
+}
+
+int cblock_isempty(CBlock_t cblk) {
+ return cblk->insts->prev == cblk->insts;
+}
+
+CVar_t ctmp_create(void) {
+ static char buff[MAX_NAMELEN];
+ sprintf(buff, "t%d", tcnt++);
+ return cvar_create(strdup(buff), NULL, NULL);
+}
+
+void ctmp_destroy(CVar_t type) {
+ /* allocated dynamically */
+ free(type->name);
+ free(type);
+}
+
+void cfg_clear(void) {
+ int i;
+ for (i = 0; i < MAX_BLOCK; i++)
+ {
+ CEdge *p, *np;
+ for (p = cfg.head[i]; p; p = np)
+ {
+ np = p->next;
+ free(p);
+ }
+ cfg.head[i] = NULL;
+ for (p = cfg.rhead[i]; p; p = np)
+ {
+ np = p->next;
+ free(p);
+ }
+ cfg.rhead[i] = NULL;
+ }
+}
+
+void dtree_clear(void) {
+ int i;
+ CEdge *p, *np;
+ for (i = 0; i < MAX_BLOCK; dtree.head[i++] = NULL)
+ for (p = dtree.head[i]; p; p = np)
+ {
+ np = p->next;
+ free(p);
+ }
+}
+
+void cfg_add_edge(CBlock_t from, CBlock_t to) {
+ int fid = from->id, tid = to->id;
+#ifdef CIBIC_DEBUG
+ fprintf(stderr, "%d -> %d\n", from->id, to->id);
+#endif
+ CEdge *e = NEW(CEdge), *re = NEW(CEdge);
+ e->to = to;
+ e->next = cfg.head[fid];
+ cfg.head[fid] = e;
+
+ re->to = from;
+ re->next = cfg.rhead[tid];
+ cfg.rhead[tid] = re;
+}
+
+void dtree_add_edge(CBlock_t from, CBlock_t to) {
+#ifdef CIBIC_DEBUG
+ fprintf(stderr, "%d d-> %d\n", from->id, to->id);
+#endif
+ int id = from->id;
+ CEdge *e = NEW(CEdge);
+ e->to = to;
+ e->next = dtree.head[id];
+ dtree.head[id] = e;
+}
+
+void copr_print(FILE *f, COpr_t opr) {
+ switch (opr->kind)
+ {
+ case VAR:
+ fprintf(f, "%s_%d", opr->info.var->name, opr->sub);
+ break;
+ case TMP: fprintf(f, "%s", opr->info.var->name);
+ break;
+ case IMM: fprintf(f, "%d", opr->info.imm);
+ break;
+ case IMMS: fprintf(f, "\"%s\"", opr->info.cstr->str);
+ break;
+ case IMMF: fprintf(f, "%s", opr->info.str);
+ break;
+ }
+}
+
+void cinst_print(FILE *f, CInst_t inst) {
+ switch (inst->op)
+ {
+ case LOAD:
+ fprintf(f, "load ");
+ copr_print(f, inst->dest);
+ break;
+ case MOVE:
+ copr_print(f, inst->dest);
+ fprintf(f, " = ");
+ copr_print(f, inst->src1);
+ break;
+ case BEQ:
+ fprintf(f, "if (");
+ copr_print(f, inst->src1);
+ fprintf(f, " == ");
+ copr_print(f, inst->src2);
+ fprintf(f, ") goto _L");
+ copr_print(f, inst->dest);
+ break;
+ case BNE:
+ fprintf(f, "if (");
+ copr_print(f, inst->src1);
+ fprintf(f, " != ");
+ copr_print(f, inst->src2);
+ fprintf(f, ") goto _L");
+ copr_print(f, inst->dest);
+ break;
+ case GOTO:
+ fprintf(f, "goto _L");
+ copr_print(f, inst->dest);
+ break;
+ case ARR:
+ copr_print(f, inst->dest);
+ fprintf(f, " = ");
+ copr_print(f, inst->src1);
+ fprintf(f, "[");
+ copr_print(f, inst->src2);
+ fprintf(f, "]");
+ break;
+ case NEG:
+ copr_print(f, inst->dest);
+ fprintf(f, " = -");
+ copr_print(f, inst->src1);
+ break;
+ case WARR:
+ copr_print(f, inst->dest);
+ fprintf(f, "[");
+ copr_print(f, inst->src2);
+ fprintf(f, "] = ");
+ copr_print(f, inst->src1);
+ break;
+ case PUSH:
+ fprintf(f, "push ");
+ copr_print(f, inst->src1);
+ break;
+ case CALL:
+ copr_print(f, inst->dest);
+ fprintf(f, " = call ");
+ copr_print(f, inst->src1);
+ break;
+ case RET:
+ if (inst->src1)
+ {
+ fprintf(f, "return ");
+ copr_print(f, inst->src1);
+ }
+ else fprintf(f, "return");
+ break;
+ case ADDR:
+ copr_print(f, inst->dest);
+ fprintf(f, " = addr ");
+ copr_print(f, inst->src1);
+ break;
+ default:
+ {
+ const char *op;
+ switch (inst->op)
+ {
+ case MUL: op = "*"; break;
+ case DIV: op = "/"; break;
+ case MOD: op = "%"; break;
+ case ADD: op = "+"; break;
+ case SUB: op = "-"; break;
+ case SHL: op = "<<"; break;
+ case SHR: op = ">>"; break;
+ case AND: op = "&"; break;
+ case XOR: op = "^"; break;
+ case OR: op = "|"; break;
+ case LT: op = "<"; break;
+ case GT: op = ">"; break;
+ case LE: op = "<="; break;
+ case GE: op = ">="; break;
+ case EQ: op = "=="; break;
+ case NE: op = "!="; break;
+ case NOR: op = "nor"; break;
+ default: ;
+ }
+ copr_print(f, inst->dest);
+ fprintf(f, " = ");
+ copr_print(f, inst->src1);
+ fprintf(f, " %s ", op);
+ copr_print(f, inst->src2);
+ }
+ }
+ fprintf(f, "\n");
+}
+
+void cphi_print(CPhi_t phi, CBlock_t blk) {
+ int i;
+ fprintf(stderr, "%s_%d = phi", phi->dest->info.var->name,
+ phi->dest->sub);
+ for (i = 0; i < blk->pred; i++)
+ fprintf(stderr, " %s_%d", phi->oprs[i]->info.var->name,
+ phi->oprs[i]->sub);
+ fprintf(stderr, "\n");
+}
+
+void cblock_print(CBlock_t blk) {
+ fprintf(stderr, "_L%d:\n", blk->id + gbbase);
+ {
+ CPhi_t p, sp = blk->phis;
+ for (p = sp->next; p != sp; p = p->next)
+ {
+ fprintf(stderr, "\t");
+ cphi_print(p, blk);
+ }
+ }
+ {
+ CInst_t p, sp = blk->insts;
+ for (p = sp->next; p != sp; p = p->next)
+ {
+ fprintf(stderr, "%02d\t", p->id);
+ cinst_print(stderr, p);
+ }
+ }
+}
+void ssa_func_print(CBlock_t p) {
+ for (; p; p = p->next)
+ cblock_print(p);
+}
+void ssa_func(CType_t);
+void ssa_generate(int quiet) {
+ CTList_t f;
+ CFuncIR_t cf;
+ func_ir = NULL;
+ for (f = funcs; f; f = f->next)
+ {
+ cf = NEW(CFuncIR);
+ ssa_func(cf->func = f->type);
+ cf->gbbase = gbbase;
+ cf->defs = defs;
+ cf->entry = entry;
+ cf->next = func_ir;
+ func_ir = cf;
+ gbbase += bcnt;
+ bcnt = 0;
+ }
+ if (!quiet)
+ {
+ for (cf = func_ir; cf; cf = cf->next)
+ {
+ fprintf(stderr, "%s:\n", cf->func->name);
+ ssa_func_print(cf->entry);
+ }
+ }
+}
+
+#define POINTER_CONV(inst) \
+do { \
+ if (rt->type == CARR) \
+ { \
+ /* convert to pointer type */ \
+ CType_t a; \
+ a = ctype_create("", CPTR, p); \
+ a->rec.ref = rt->rec.arr.elem; \
+ (inst)->op = ADD; \
+ (inst)->dest->type = a; \
+ } \
+ else if (rt->type == CSTRUCT || rt->type == CUNION) \
+ (inst)->op = ADD; \
+ else (inst)->op = ARR; \
+} while (0)
+
+
+COpr_t ssa_exp_(CNode *p, CBlock_t *, CInst_t, CBlock_t);
+COpr_t ssa_postfix(CNode *p, CBlock_t *cur, CInst_t lval, CBlock_t succ) {
+ CNode *post = p->chd->next;
+ CType_t rt = p->ext.type;
+ CInst_t base = cinst_create();
+ switch (post->rec.subtype)
+ {
+ case POSTFIX_ARR:
+ {
+ CInst_t off = cinst_create();
+ off->dest = copr_create();
+ off->dest->kind = TMP;
+ off->dest->info.var = ctmp_create();
+ off->dest->type = post->chd->ext.type;
+ off->op = MUL;
+ off->src1 = ssa_exp_(post->chd, cur, NULL, succ);
+ off->src2 = copr_create();
+ off->src2->kind = IMM;
+ off->src2->info.imm = calc_size(rt);
+ cblock_append(*cur, off);
+
+ base->dest = copr_create();
+ base->dest->kind = TMP;
+ base->dest->info.var = ctmp_create();
+ base->dest->type = rt;
+ base->src1 = ssa_exp_(p->chd, cur, NULL, succ);
+ base->src2 = off->dest;
+ POINTER_CONV(base);
+ }
+ break;
+ case POSTFIX_DOT:
+ {
+ base->dest = copr_create();
+ base->dest->kind = TMP;
+ base->dest->info.var = ctmp_create();
+ base->dest->type = rt;
+ base->src1 = ssa_exp_(p->chd, cur, NULL, succ);
+ base->src2 = copr_create();
+ base->src2->kind = IMM;
+ base->src2->info.imm = p->ext.offset;
+ POINTER_CONV(base);
+ }
+ break;
+ case POSTFIX_PTR:
+ {
+ base->dest = copr_create();
+ base->dest->kind = TMP;
+ base->dest->info.var = ctmp_create();
+ base->dest->type = rt;
+ base->src1 = ssa_exp_(p->chd, cur, NULL, succ);
+ base->src2 = copr_create();
+ base->src2->kind = IMM;
+ base->src2->info.imm = p->ext.offset;
+ POINTER_CONV(base);
+ }
+ break;
+ case POSTFIX_CALL:
+ {
+ CNode *arg = post->chd->chd;
+ CInst h;
+ CInst_t t = &h, n;
+ base->op = CALL;
+ base->src1 = ssa_exp_(p->chd, cur, lval, succ);
+ base->dest = copr_create();
+ base->dest->kind = TMP;
+ base->dest->info.var = ctmp_create();
+ base->dest->type = rt;
+ for (; arg; arg = arg->next)
+ {
+ CInst_t pi = cinst_create();
+ pi->op = PUSH;
+ pi->src1 = ssa_exp_(arg, cur, lval, succ);
+ t->next = pi;
+ t = pi;
+ }
+ t->next = NULL;
+ for (t = h.next; t; t = n)
+ {
+ n = t->next;
+ cblock_append(*cur, t);
+ }
+ }
+ break;
+ default:
+ {
+ CInst_t tins = cinst_create();
+ ssa_exp_(p->chd, cur, tins, succ);
+ base->op = post->rec.subtype == OPT_INC ? ADD : SUB;
+ base->src2 = copr_create();
+ base->src2->kind = IMM;
+ base->src2->info.imm = 1;
+ base->src1 = ssa_exp_(p->chd, cur, NULL, succ);
+ if (tins->op == MOVE)
+ {
+ base->dest = tins->dest;
+ cblock_append(succ, base);
+ free(tins);
+ }
+ else
+ {
+ CInst_t tins2 = cinst_create();
+ base->dest = copr_create();
+ base->dest->kind = TMP;
+ base->dest->info.var = ctmp_create();
+ base->dest->type = rt;
+ tins->src1 = base->dest;
+ tins2->op = ARR;
+ tins2->src1 = tins->dest;
+ tins2->src2 = tins->src2;
+ tins2->dest = copr_create();
+ tins2->dest->kind = TMP;
+ tins2->dest->info.var = ctmp_create();
+ tins2->dest->type = rt;
+
+ cblock_append(succ, base);
+ cblock_append(succ, tins);
+ cblock_append(succ, tins2);
+ }
+ return base->src1;
+ }
+ break;
+ }
+
+ if (lval)
+ {
+ lval->op = WARR;
+ lval->dest = base->src1;
+ lval->src2 = base->src2;
+ lval->wtype = p->ext.type;
+ free(base);
+ return lval->dest;
+ }
+ cblock_append(*cur, base);
+ return base->dest;
+}
+
+CInst_t compress_branch(COpr_t r, CBlock_t blk, int rev) {
+ int flag = -1;
+ CInst_t b;
+ if (r->kind == TMP)
+ {
+ b = cblock_getback(blk);
+ if (b)
+ {
+ assert(r == b->dest);
+ if (b->op == EQ)
+ flag = 0;
+ else if (b->op == NE)
+ flag = 1;
+ }
+ }
+ if (flag != -1)
+ b->op = flag ? BNE : BEQ;
+ else
+ {
+ b = cinst_create();
+ b->op = BNE;
+ b->src1 = r;
+ b->src2 = copr_create();
+ b->src2->kind = IMM;
+ b->src2->info.imm = 0;
+ cblock_append(blk, b);
+ }
+ b->op ^= rev;
+ b->dest = copr_create();
+ b->dest->kind = IMM;
+ return b;
+}
+
+static CNode *opt_if = NULL;
+static CBlock_t opt_if_loop_exit = NULL;
+
+CBlock_t ssa_stmt(CNode *, CBlock_t, CBlock_t);
+#define IS_PTR(tt) ((tt) == CPTR || (tt) == CARR)
+COpr_t ssa_exp(CNode *, CBlock_t *, int);
+COpr_t ssa_exp_(CNode *p, CBlock_t *cur, CInst_t lval, CBlock_t succ) {/*{{{*/
+ COpr_t res;
+ CInst_t inst = cinst_create();
+ switch (p->type)
+ {
+ case NOP: ; break;
+ case ID:
+ res = copr_create();
+ res->kind = VAR;
+ res->info.var = p->ext.var;
+ res->type = p->ext.type;
+ {
+ CVar_t var = res->info.var;
+ CType_t type = var->type;
+ if (type->type == CPTR &&
+ type->rec.ref->type == CFUNC)
+ {
+ char *name = type->rec.ref->name;
+ if (*name != '\0')
+ {
+ res->kind = IMMF;
+ res->info.str = name;
+ }
+ }
+ }
+
+ if (lval)
+ {
+ lval->op = MOVE;
+ lval->dest = res;
+ }
+ break;
+ case STR:
+ res = copr_create();
+ res->kind = IMMS;
+ res->info.cstr = (CSList_t)(p->ext.const_val);
+ break;
+ default:
+ if (p->ext.is_const)
+ {
+ res = copr_create();
+ res->kind = IMM;
+ res->info.imm = p->ext.const_val;
+ }
+ else
+ {
+ int op = p->rec.subtype;
+ int rec = 1, auto_dest = 1;
+
+ if (op == ',')
+ {
+ ssa_exp(p->chd, cur, 1);
+ return ssa_exp_(p->chd->next, cur, NULL, succ);
+ }
+ else if (op == '=')
+ {
+ inst->src1 = ssa_exp_(p->chd->next, cur, NULL, succ);
+ ssa_exp_(p->chd, cur, inst, succ);
+ if (inst->op == MOVE)
+ {
+ CInst_t last = cblock_getback(*cur);
+ if (last && last->dest->kind == TMP
+ && last->dest == inst->src1)
+ {
+ free(last->dest);
+ last->dest = inst->dest;
+ free(inst);
+ return last->dest;
+ }
+ else
+ {
+ cblock_append(*cur, inst);
+ return inst->dest;
+ }
+ }
+ else
+ {
+ CInst_t tins = cinst_create();
+ cblock_append(*cur, inst);
+ tins->op = ARR;
+ tins->src1 = inst->dest; /* base */
+ tins->src2 = inst->src2; /* displacement */
+ tins->dest = copr_create();
+ tins->dest->kind = TMP;
+ tins->dest->info.var = ctmp_create();
+ tins->dest->type = p->ext.type;
+ cblock_append(*cur, tins);
+ return tins->dest;
+ }
+ }
+ else if (op == '*' && !p->chd->next)
+ {
+ if (lval)
+ {
+ lval->op = WARR;
+ lval->dest = ssa_exp_(p->chd, cur, NULL, succ);
+ lval->src2 = copr_create();
+ lval->src2->kind = IMM;
+ lval->src2->info.imm = 0;
+ lval->wtype = p->ext.type;
+ return lval->dest;
+ }
+ else
+ {
+ CType_t rt = p->ext.type;
+ inst->src1 = ssa_exp_(p->chd, cur, NULL, succ);
+ inst->src2 = copr_create();
+ inst->src2->kind = IMM;
+ inst->src2->info.imm = 0;
+ inst->dest = copr_create();
+ inst->dest->kind = TMP;
+ inst->dest->info.var = ctmp_create();
+ inst->dest->type = rt;
+ POINTER_CONV(inst);
+ cblock_append(*cur, inst);
+ return inst->dest;
+ }
+ }
+ else if (op == OPT_AND)
+ {
+ CBlock_t else_h = cblock_create(1), else_t = else_h,
+ one_h = cblock_create(1), one_t = one_h,
+ zero_h = cblock_create(1), zero_t = zero_h,
+ next_blk = cblock_create(1), sblk;
+ COpr_t r0, r1, ri;
+ CInst_t b, a0, a1;
+ CPhi_t m = NEW(CPhi);
+ CNode *t;
+ if (opt_if)
+ {
+ CNode *body1 = opt_if->chd->next, *body2 = body1->next;
+ one_t = ssa_stmt(body1, one_h, opt_if_loop_exit);
+ if (body2->type != NOP)
+ zero_t = ssa_stmt(body2, zero_h, opt_if_loop_exit);
+ opt_if = NULL;
+ }
+ else
+ {
+ /* constant opt */
+ a0 = cinst_create();
+ a0->op = MOVE;
+ a0->dest = copr_create();
+ a0->dest->kind = TMP;
+ a0->dest->info.var = ctmp_create();
+ a0->dest->type = p->ext.type; /* int */
+ a0->src1 = copr_create();
+ a0->src1->kind = IMM;
+ a0->src1->info.imm = 0;
+ cblock_append(zero_h, a0);
+
+ a1 = cinst_create();
+ a1->op = MOVE;
+ a1->dest = copr_create();
+ a1->dest->kind = TMP;
+ a1->dest->info.var = ctmp_create();
+ a1->dest->type = p->ext.type;
+ a1->src1 = copr_create();
+ a1->src1->kind = IMM;
+ a1->src1->info.imm = 1;
+ cblock_append(one_h, a1);
+
+ m->dest = copr_create();
+ m->dest->kind = TMP;
+ m->dest->info.var = ctmp_create();
+ m->dest->type = p->ext.type;
+ m->oprs = (COpr_t *)malloc(sizeof(COpr_t) * 2);
+ m->oprs[0] = a0->dest;
+ m->oprs[1] = a1->dest;
+ cblock_pappend(next_blk, m);
+ }
+
+ r1 = ssa_exp_(p->chd->next, &else_t, NULL, succ);
+ compress_branch(r1, else_t, 1)->dest->info.imm = zero_h->id + gbbase;
+ zero_h->ref = 1;
+
+ sblk = else_h;
+ for (t = p->chd; t->rec.subtype == OPT_AND; t = t->chd)
+ {
+ CBlock_t c_h = cblock_create(1), c_t = c_h;
+ ri = ssa_exp_(t->chd->next, &c_t, NULL, succ);
+ compress_branch(ri, c_t, 1)->dest->info.imm = zero_h->id + gbbase;
+ cfg_add_edge(c_t, zero_h); /* tail */
+ DBLINK(c_t, sblk);
+ cfg_add_edge(c_t, sblk); /* connect to header */
+ sblk = c_h;
+ }
+
+ r0 = ssa_exp_(t, cur, NULL, succ);
+ compress_branch(r0, *cur, 1)->dest->info.imm = zero_h->id + gbbase;
+ cfg_add_edge(*cur, zero_h);
+ DBLINK(*cur, sblk);
+ cfg_add_edge(*cur, sblk);
+
+ b = cinst_create();
+ b->op = GOTO;
+ b->dest = copr_create();
+ b->dest->kind = IMM;
+ b->dest->info.imm = next_blk->id + gbbase;
+ cblock_append(one_t, b);
+ next_blk->ref = 1;
+
+ DBLINK(else_t, one_h);
+ DBLINK(one_t, zero_h);
+ DBLINK(zero_t, next_blk);
+
+ cfg_add_edge(else_t, one_h);
+ cfg_add_edge(else_t, zero_h);
+ cfg_add_edge(one_t, next_blk);
+ cfg_add_edge(zero_t, next_blk);
+
+ *cur = next_blk;
+ return m->dest;
+ }
+ else if (op == OPT_OR)
+ {
+ CBlock_t else_h = cblock_create(1), else_t = else_h,
+ one_h = cblock_create(1), one_t = one_h,
+ zero_h = cblock_create(1), zero_t = zero_h,
+ next_blk = cblock_create(1), sblk;
+ COpr_t r0, r1, ri;
+ CInst_t b, a0, a1;
+ CPhi_t m = NEW(CPhi);
+ CNode *t;
+ if (opt_if)
+ {
+ CNode *body1 = opt_if->chd->next, *body2 = body1->next;
+ one_t = ssa_stmt(body1, one_h, opt_if_loop_exit);
+ if (body2->type != NOP)
+ zero_t = ssa_stmt(body2, zero_h, opt_if_loop_exit);
+ opt_if = NULL;
+ }
+ else
+ {
+ /* constant opt */
+ a0 = cinst_create();
+ a0->op = MOVE;
+ a0->dest = copr_create();
+ a0->dest->kind = TMP;
+ a0->dest->info.var = ctmp_create();
+ a0->dest->type = p->ext.type; /* int */
+ a0->src1 = copr_create();
+ a0->src1->kind = IMM;
+ a0->src1->info.imm = 0;
+ cblock_append(zero_h, a0);
+
+ a1 = cinst_create();
+ a1->op = MOVE;
+ a1->dest = copr_create();
+ a1->dest->kind = TMP;
+ a1->dest->info.var = ctmp_create();
+ a1->dest->type = p->ext.type;
+ a1->src1 = copr_create();
+ a1->src1->kind = IMM;
+ a1->src1->info.imm = 1;
+ cblock_append(one_h, a1);
+
+ m->dest = copr_create();
+ m->dest->kind = TMP;
+ m->dest->info.var = ctmp_create();
+ m->dest->type = p->ext.type;
+ m->oprs = (COpr_t *)malloc(sizeof(COpr_t) * 2);
+ m->oprs[0] = a1->dest;
+ m->oprs[1] = a0->dest;
+ cblock_pappend(next_blk, m);
+ }
+
+ r1 = ssa_exp_(p->chd->next, &else_t, NULL, succ);
+ compress_branch(r1, else_t, 0)->dest->info.imm = one_h->id + gbbase;
+ one_h->ref = 1;
+
+ sblk = else_h;
+ for (t = p->chd; t->rec.subtype == OPT_OR; t = t->chd)
+ {
+ CBlock_t c_h = cblock_create(1), c_t = c_h;
+ ri = ssa_exp_(t->chd->next, &c_t, NULL, succ);
+ compress_branch(ri, c_t, 0)->dest->info.imm = one_h->id + gbbase;
+ cfg_add_edge(c_t, one_h); /* tail */
+ DBLINK(c_t, sblk);
+ cfg_add_edge(c_t, sblk); /* connect to header */
+ sblk = c_h;
+ }
+
+ r0 = ssa_exp_(t, cur, NULL, succ);
+ compress_branch(r0, *cur, 0)->dest->info.imm = one_h->id + gbbase;
+ cfg_add_edge(*cur, one_h);
+ DBLINK(*cur, sblk);
+ cfg_add_edge(*cur, sblk);
+
+ b = cinst_create();
+ b->op = GOTO;
+ b->dest = copr_create();
+ b->dest->kind = IMM;
+ b->dest->info.imm = next_blk->id + gbbase;
+ cblock_append(zero_t, b);
+ next_blk->ref = 1;
+
+ DBLINK(else_t, zero_h);
+ DBLINK(zero_t, one_h);
+ DBLINK(one_t, next_blk);
+
+ cfg_add_edge(else_t, zero_h);
+ cfg_add_edge(else_t, one_h);
+ cfg_add_edge(zero_t, next_blk);
+ cfg_add_edge(one_t, next_blk);
+
+ *cur = next_blk;
+ return m->dest;
+ }
+ else if (op == '+' && IS_PTR(p->ext.type->type))
+ {
+ COpr_t lhs = ssa_exp_(p->chd, cur, lval, succ),
+ rhs = ssa_exp_(p->chd->next, cur, lval, succ);
+ CInst_t index = cinst_create();
+ CType_t et = p->chd->ext.type;
+ if (et->type == CPTR)
+ et = et->rec.ref;
+ else
+ et = et->rec.arr.elem;
+ index->op = MUL;
+ index->dest = copr_create();
+ index->dest->kind = TMP;
+ index->dest->info.var = ctmp_create();
+ index->dest->type = p->chd->next->ext.type;
+ index->src1 = rhs;
+ index->src2 = copr_create();
+ index->src2->kind = IMM;
+ index->src2->info.imm = calc_size(et);
+
+ inst->op = ADD;
+ inst->dest = copr_create();
+ inst->dest->kind = TMP;
+ inst->dest->info.var = ctmp_create();
+ inst->dest->type = p->ext.type;
+ inst->src1 = lhs;
+ inst->src2 = index->dest;
+ cblock_append(*cur, index);
+ cblock_append(*cur, inst);
+ return inst->dest;
+ }
+ else if (op == '-' && IS_PTR(p->chd->ext.type->type))
+ {
+ CType_t nt = p->chd->next->ext.type;
+ CType_t et = p->chd->ext.type;
+ COpr_t lhs = ssa_exp_(p->chd, cur, lval, succ),
+ rhs = ssa_exp_(p->chd->next, cur, lval, succ);
+ CInst_t diff = cinst_create();
+
+ if (et->type == CPTR)
+ et = et->rec.ref;
+ else
+ et = et->rec.arr.elem;
+
+ if (IS_PTR(nt->type))
+ {
+ diff->op = SUB;
+ diff->dest = copr_create();
+ diff->dest->kind = TMP;
+ diff->dest->info.var = ctmp_create();
+ diff->dest->type = p->ext.type;
+ diff->src1 = lhs;
+ diff->src2 = rhs;
+
+ inst->op = DIV;
+ inst->dest = copr_create();
+ inst->dest->kind = TMP;
+ inst->dest->info.var = ctmp_create();
+ inst->dest->type = p->ext.type;
+ inst->src1 = diff->dest;
+ inst->src2 = copr_create();
+ inst->src2->kind = IMM;
+ inst->src2->info.imm = calc_size(et);
+ }
+ else
+ {
+ diff->op = MUL;
+ diff->dest = copr_create();
+ diff->dest->kind = TMP;
+ diff->dest->info.var = ctmp_create();
+ diff->dest->type = p->chd->next->ext.type;
+ diff->src1 = rhs;
+ diff->src2 = copr_create();
+ diff->src2->kind = IMM;
+ diff->src2->info.imm = calc_size(et);
+
+ inst->op = SUB;
+ inst->dest = copr_create();
+ inst->dest->kind = TMP;
+ inst->dest->info.var = ctmp_create();
+ inst->dest->type = p->ext.type;
+ inst->src1 = lhs;
+ inst->src2 = diff->dest;
+ }
+ cblock_append(*cur, diff);
+ cblock_append(*cur, inst);
+ return inst->dest;
+ }
+ else if (op == '&' && !p->chd->next)
+ {
+ ssa_exp_(p->chd, cur, inst, succ);
+ if (inst->op == MOVE)
+ {
+ inst->op = ADDR;
+ inst->src1 = inst->dest;
+ }
+ else
+ {
+ inst->op = ADD;
+ inst->src1 = inst->dest;
+ }
+ inst->dest = copr_create();
+ inst->dest->kind = TMP;
+ inst->dest->info.var = ctmp_create();
+ inst->dest->type = p->ext.type;
+ cblock_append(*cur, inst);
+ return inst->dest;
+ }
+ else
+ {
+ int unary = 0;
+ inst->op = (unsigned)-1;
+ switch (op)
+ {
+ case ASS_MUL: inst->op = MUL; break;
+ case ASS_DIV: inst->op = DIV; break;
+ case ASS_MOD: inst->op = MOD; break;