1#include <assert.h>2#include <stdlib.h>3#include <string.h>45#include <scc/scc.h>67#include "cc2.h"89struct cfg {10 int nr;11 Block *entryb, *exitb;12 Block *cur;13 Block *blocks;14};1516static struct cfg cfg;17static int modjmp;1819static Node *20jtarget(Node *np)21{22 return np->u.sym->u.stmt;23}2425static Block *26jtargetbb(Node *np)27{28 return jtarget(np)->bb;29}3031#ifndef NDEBUG32#include <stdio.h>3334static void35prbb(Block *bb)36{37 Swtch *swt;38 Block *casebb;39 Node **cases, **bp;4041 if (!bb || bb->printed)42 return;4344 assert(bb->id != -1);45 bb->printed = 1;46 if (bb->btrue) {47 fprintf(stderr,48 "\t%d -> %d [label=\"true\"]\n",49 bb->id, bb->btrue->id);50 }51 if (bb->bfalse) {52 fprintf(stderr,53 "\t%d -> %d [label=\"false\"]\n",54 bb->id, bb->bfalse->id);55 }56 prbb(bb->btrue);57 prbb(bb->bfalse);5859 swt = bb->swtch;60 if (!swt)61 return;62 cases = swt->cases;6364 for (bp = cases; bp < &cases[swt->nr]; ++bp) {65 casebb = jtargetbb(*bp);66 fprintf(stderr,67 "\t%d -> %d [label=\"case %lld\"]\n",68 bb->id,69 casebb->id,70 (*bp)->left->u.i);71 prbb(casebb);72 }7374 casebb = jtargetbb(swtchdefault(swt));75 fprintf(stderr,76 "\t%d -> %d [label=\"default\"]\n",77 bb->id,78 casebb->id);79 prbb(casebb);80}8182static void83prcfg(char *msg)84{85 Block *bb;86 Node *np;8788 fprintf(stderr, "{digraph %s_%d {\n", msg, curfun->id);8990 for (bb = cfg.blocks; bb < &cfg.blocks[cfg.nr]; ++bb) {91 if (bb->id == -1)92 continue;93 bb->printed = 0;9495 fprintf(stderr, "\t%d [shape=box;label=\"", bb->id);96 for (np = bb->entryp; np; np = np->next) {97 prtree(np);98 putc('\n', stderr);99 if (np == bb->exitp)100 break;101 }102 fputs("\"]\n", stderr);103 }104105 prbb(cfg.entryb);106 fputs("}}\n", stderr);107}108#endif109110static Block *111newbb(Node *np)112{113 Block *bb;114115 bb = &cfg.blocks[cfg.nr];116 bb->entryp = np;117 bb->exitp = NULL;118 bb->swtch = NULL;119 bb->btrue = bb->bfalse = NULL;120 bb->id = cfg.nr++;121 bb->visited = 0;122 cfg.cur = bb;123124 return bb;125}126127static Node *128mkcfg(Node *np)129{130 if ((np->flags & (BBENTRY|BBEXIT)) == 0)131 return np;132133 if (np->flags & BBENTRY)134 cfg.cur = np->bb;135136 if (np->flags & BBEXIT) {137 cfg.cur->exitp = np;138 cfg.cur->btrue = np->next->bb;139 }140141 switch (np->op) {142 case OBFUN:143 cfg.entryb = cfg.cur;144 break;145 case OEFUN:146 cfg.exitb = cfg.cur;147 break;148 case ORET:149 cfg.cur->btrue = laststmt->bb;150 break;151 case OBSWITCH:152 cfg.cur->swtch = np->u.swtch;153 cfg.cur->btrue = NULL;154 break;155 case OBRANCH:156 cfg.cur->bfalse = np->next->bb;157 case OJMP:158 cfg.cur->btrue = jtargetbb(np);159 break;160 }161162 return np;163}164165static Node *166mkbb(Node *np)167{168 if (np->flags & BBENTRY)169 newbb(np);170 np->bb = cfg.cur;171172 return np;173}174175static void176newentry(Node *np)177{178 if (np->flags & BBENTRY)179 return;180181 np->flags |= BBENTRY;182 if (np->prev)183 np->prev->flags |= BBEXIT;184 cfg.nr++;185 DBG("new entry point %d", cfg.nr);186}187188static Node *189markbb(Node *np)190{191 Swtch *swt;192 Node **cases, **bp;193194 switch (np->op) {195 case OBFUN:196 newentry(np);197 break;198 case ORET:199 newentry(laststmt);200 newentry(np->next);201 break;202 case OBSWITCH:203 np->flags |= BBEXIT;204 swt = np->u.swtch;205 cases = swt->cases;206 for (bp = cases; bp < &cases[swt->nr]; ++bp)207 newentry(jtarget((*bp)));208 newentry(jtarget(swtchdefault(swt)));209 break;210 case OBRANCH:211 case OJMP:212 newentry(jtarget(np));213 newentry(np->next);214 break;215 }216 return np;217}218219static void220visit(Block *bb)221{222 Swtch *swt;223 Node **cases, **bp, *p;224225 if (!bb || bb->visited)226 return;227 bb->visited = 1;228 visit(bb->btrue);229 visit(bb->bfalse);230231 swt = bb->swtch;232 if (!swt)233 return;234 cases = swt->cases;235236 for (bp = swt->cases; bp < &cases[swt->nr]; ++bp)237 visit(jtargetbb(*bp));238 visit(jtargetbb(swtchdefault(swt)));239}240241static void242trimcfg(void)243{244 Block *bb, *prev, *next;245246 visit(cfg.entryb);247 for (bb = cfg.blocks; bb < &cfg.blocks[cfg.nr]; ++bb) {248 if (bb->visited)249 continue;250 delrange(bb->entryp, bb->exitp);251 bb->id = -1;252 }253 PRCFG("trimmed_cfg");254}255256static void257buildcfg(void)258{259 int nr;260261 apply(markbb);262 PRTREE("bb_mark");263264 cfg.blocks = xcalloc(cfg.nr, sizeof(Block));265 nr = cfg.nr;266 cfg.nr = 0;267 apply(mkbb);268 assert(cfg.nr == nr);269270 PRTREE("bb_mk");271 apply(mkcfg);272 PRCFG("cfg");273}274275static int276negop(int op)277{278 switch (op) {279 case OEQ: return ONE;280 case ONE: return OEQ;281 case OLT: return OGE;282 case OGE: return OLT;283 case OLE: return OGT;284 case OGT: return OLE;285 default: abort();286 }287 return op;288}289290static Node *291skipnop(Node *np, Node *target)292{293 for ( ; np->op == ONOP && np != target; np = np->next)294 ;295 return np;296}297298static Node *299optjmps_helper(Node *np)300{301 Symbol *label;302 Node *p, *stmt, *next;303304 switch (np->op) {305 case ONOP:306 if (np->label->refcnt == 0) {307 modjmp = 1;308 return NULL;309 }310 break;311 case OBRANCH:312 branch:313 label = np->u.sym;314 stmt = label->u.stmt;315 next = np->next;316317 /* avoid branch over jump */318 if (next->op == OJMP && next->next->label == label &&319 (!next->label || next->label->refcnt == 0)) {320 Node *left = np->left;321 np->u.sym = next->u.sym;322 label->refcnt--;323 left->op = negop(left->op);324 delstmt(next);325 modjmp = 1;326 goto branch;327 }328 goto chain_jumps;329 case OJMP:330 label = np->u.sym;331 stmt = label->u.stmt;332333 /* avoid jump over a set of NOPs */334 p = skipnop(np->next, stmt);335 if (p == stmt) {336 label->refcnt--;337 modjmp = 1;338 return NULL;339 }340341 chain_jumps:342 /* avoid chain of jumps to jumps */343 p = skipnop(stmt, NULL);344 if (p != np && p->op == OJMP) {345 label->refcnt--;346 label = p->u.sym;347 stmt = label->u.stmt;348 np->u.sym = label;349 modjmp = 1;350 goto chain_jumps;351 }352 }353354 return np;355}356357static void358optjmps(void)359{360 do {361 modjmp = 0;362 apply(optjmps_helper);363 PRTREE("after_modjmp");364 } while (modjmp == 1);365}366367void368gencfg(void)369{370 optjmps();371 DBG("new cfg");372 buildcfg();373 trimcfg();374375 PRTREE("after_gencfg");376}377378void379cleancfg(void)380{381 free(cfg.blocks);382 memset(&cfg, 0, sizeof(cfg));383}