123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587 |
- #include "gc.h"
- void
- codgen(Node *n, Node *nn)
- {
- Prog *sp;
- Node *n1, nod, nod1;
- cursafe = 0;
- curarg = 0;
- maxargsafe = 0;
- hasdoubled = 0;
- /*
- * isolate name
- */
- for(n1 = nn;; n1 = n1->left) {
- if(n1 == Z) {
- diag(nn, "cant find function name");
- return;
- }
- if(n1->op == ONAME)
- break;
- }
- nearln = nn->lineno;
- gpseudo(ATEXT, n1->sym, nodconst(stkoff));
- sp = p;
- if(typecmplx[thisfn->link->etype]) {
- if(nodret == nil) {
- nodret = new(ONAME, Z, Z);
- nodret->sym = slookup(".ret");
- nodret->class = CPARAM;
- nodret->type = types[TIND];
- nodret->etype = TIND;
- nodret = new(OIND, nodret, Z);
- }
- n1 = nodret->left;
- if(n1->type == T || n1->type->link != thisfn->link) {
- n1->type = typ(TIND, thisfn->link);
- n1->etype = n1->type->etype;
- nodret = new(OIND, n1, Z);
- complex(nodret);
- }
- }
- /*
- * isolate first argument
- */
- if(REGARG >= 0) {
- if(typecmplx[thisfn->link->etype]) {
- nod1 = *nodret->left;
- nodreg(&nod, &nod1, REGARG);
- gmove(&nod, &nod1);
- } else
- if(firstarg && typeword[firstargtype->etype]) {
- nod1 = znode;
- nod1.op = ONAME;
- nod1.sym = firstarg;
- nod1.type = firstargtype;
- nod1.class = CPARAM;
- nod1.xoffset = align(0, firstargtype, Aarg1);
- nod1.etype = firstargtype->etype;
- xcom(&nod1);
- nodreg(&nod, &nod1, REGARG);
- gmove(&nod, &nod1);
- }
- }
- canreach = 1;
- warnreach = 1;
- gen(n);
- if(canreach && thisfn->link->etype != TVOID)
- warn(Z, "no return at end of function: %s", n1->sym->name);
- noretval(3);
- gbranch(ORETURN);
- if(!debug['N'] || debug['R'] || debug['P'])
- regopt(sp);
-
- if(thechar=='6' || thechar=='7' || thechar=='9' || hasdoubled) /* [sic] */
- maxargsafe = round(maxargsafe, 8);
- sp->to.offset += maxargsafe;
- }
- void
- supgen(Node *n)
- {
- int owarn;
- long spc;
- Prog *sp;
- if(n == Z)
- return;
- suppress++;
- owarn = warnreach;
- warnreach = 0;
- spc = pc;
- sp = lastp;
- gen(n);
- lastp = sp;
- pc = spc;
- sp->link = nil;
- suppress--;
- warnreach = owarn;
- }
- Node*
- uncomma(Node *n)
- {
- while(n != Z && n->op == OCOMMA) {
- cgen(n->left, Z);
- n = n->right;
- }
- return n;
- }
- void
- gen(Node *n)
- {
- Node *l, nod, rn;
- Prog *sp, *spc, *spb;
- Case *cn;
- long sbc, scc;
- int snbreak, sncontin;
- int f, o, oldreach;
- loop:
- if(n == Z)
- return;
- nearln = n->lineno;
- o = n->op;
- if(debug['G'])
- if(o != OLIST)
- print("%L %O\n", nearln, o);
- if(!canreach) {
- switch(o) {
- case OLABEL:
- case OCASE:
- case OLIST:
- case OCOMMA:
- case OBREAK:
- case OFOR:
- case OWHILE:
- case ODWHILE:
- /* all handled specially - see switch body below */
- break;
- default:
- if(warnreach) {
- warn(n, "unreachable code %O", o);
- warnreach = 0;
- }
- }
- }
- switch(o) {
- default:
- complex(n);
- cgen(n, Z);
- break;
- case OLIST:
- case OCOMMA:
- gen(n->left);
- rloop:
- n = n->right;
- goto loop;
- case ORETURN:
- canreach = 0;
- warnreach = !suppress;
- complex(n);
- if(n->type == T)
- break;
- l = uncomma(n->left);
- if(l == Z) {
- noretval(3);
- gbranch(ORETURN);
- break;
- }
- if(typecmplx[n->type->etype]) {
- nod = znode;
- nod.op = OAS;
- nod.left = nodret;
- nod.right = l;
- nod.type = n->type;
- nod.complex = l->complex;
- cgen(&nod, Z);
- noretval(3);
- gbranch(ORETURN);
- break;
- }
- if(newvlongcode && !typefd[n->type->etype]){
- regret(&rn, n);
- regfree(&rn);
- nod = znode;
- nod.op = OAS;
- nod.left = &rn;
- nod.right = l;
- nod.type = n->type;
- nod.complex = l->complex;
- cgen(&nod, Z);
- noretval(2);
- gbranch(ORETURN);
- break;
- }
- regret(&nod, n);
- cgen(l, &nod);
- regfree(&nod);
- if(typefd[n->type->etype])
- noretval(1);
- else
- noretval(2);
- gbranch(ORETURN);
- break;
- case OLABEL:
- canreach = 1;
- l = n->left;
- if(l) {
- l->pc = pc;
- if(l->label)
- patch(l->label, pc);
- }
- gbranch(OGOTO); /* prevent self reference in reg */
- patch(p, pc);
- goto rloop;
- case OGOTO:
- canreach = 0;
- warnreach = !suppress;
- n = n->left;
- if(n == Z)
- return;
- if(n->complex == 0) {
- diag(Z, "label undefined: %s", n->sym->name);
- return;
- }
- if(suppress)
- return;
- gbranch(OGOTO);
- if(n->pc) {
- patch(p, n->pc);
- return;
- }
- if(n->label)
- patch(n->label, pc-1);
- n->label = p;
- return;
- case OCASE:
- canreach = 1;
- l = n->left;
- if(cases == C)
- diag(n, "case/default outside a switch");
- if(l == Z) {
- casf();
- cases->val = 0;
- cases->def = 1;
- cases->label = pc;
- cases->isv = 0;
- goto rloop;
- }
- complex(l);
- if(l->type == T)
- goto rloop;
- if(l->op == OCONST)
- if(typeword[l->type->etype] && l->type->etype != TIND) {
- casf();
- cases->val = l->vconst;
- cases->def = 0;
- cases->label = pc;
- cases->isv = typev[l->type->etype];
- goto rloop;
- }
- diag(n, "case expression must be integer constant");
- goto rloop;
- case OSWITCH:
- l = n->left;
- complex(l);
- if(l->type == T)
- break;
- if(!typeword[l->type->etype] || l->type->etype == TIND) {
- diag(n, "switch expression must be integer");
- break;
- }
- gbranch(OGOTO); /* entry */
- sp = p;
- cn = cases;
- cases = C;
- casf();
- sbc = breakpc;
- breakpc = pc;
- snbreak = nbreak;
- nbreak = 0;
- gbranch(OGOTO);
- spb = p;
- gen(n->right); /* body */
- if(canreach){
- gbranch(OGOTO);
- patch(p, breakpc);
- nbreak++;
- }
- patch(sp, pc);
- regalloc(&nod, l, Z);
- /* always signed */
- if(typev[l->type->etype])
- nod.type = types[TVLONG];
- else
- nod.type = types[TLONG];
- cgen(l, &nod);
- doswit(&nod);
- regfree(&nod);
- patch(spb, pc);
- cases = cn;
- breakpc = sbc;
- canreach = nbreak!=0;
- if(canreach == 0)
- warnreach = !suppress;
- nbreak = snbreak;
- break;
- case OWHILE:
- case ODWHILE:
- l = n->left;
- gbranch(OGOTO); /* entry */
- sp = p;
- scc = continpc;
- continpc = pc;
- gbranch(OGOTO);
- spc = p;
- sbc = breakpc;
- breakpc = pc;
- snbreak = nbreak;
- nbreak = 0;
- gbranch(OGOTO);
- spb = p;
- patch(spc, pc);
- if(n->op == OWHILE)
- patch(sp, pc);
- bcomplex(l, Z); /* test */
- patch(p, breakpc);
- if(l->op != OCONST || vconst(l) == 0)
- nbreak++;
- if(n->op == ODWHILE)
- patch(sp, pc);
- gen(n->right); /* body */
- gbranch(OGOTO);
- patch(p, continpc);
- patch(spb, pc);
- continpc = scc;
- breakpc = sbc;
- canreach = nbreak!=0;
- if(canreach == 0)
- warnreach = !suppress;
- nbreak = snbreak;
- break;
- case OFOR:
- l = n->left;
- if(!canreach && l->right->left && warnreach) {
- warn(n, "unreachable code FOR");
- warnreach = 0;
- }
- gen(l->right->left); /* init */
- gbranch(OGOTO); /* entry */
- sp = p;
- /*
- * if there are no incoming labels in the
- * body and the top's not reachable, warn
- */
- if(!canreach && warnreach && deadheads(n)) {
- warn(n, "unreachable code %O", o);
- warnreach = 0;
- }
- scc = continpc;
- continpc = pc;
- gbranch(OGOTO);
- spc = p;
- sbc = breakpc;
- breakpc = pc;
- snbreak = nbreak;
- nbreak = 0;
- sncontin = ncontin;
- ncontin = 0;
- gbranch(OGOTO);
- spb = p;
- patch(spc, pc);
- gen(l->right->right); /* inc */
- patch(sp, pc);
- if(l->left != Z) { /* test */
- bcomplex(l->left, Z);
- patch(p, breakpc);
- if(l->left->op != OCONST || vconst(l->left) == 0)
- nbreak++;
- }
- canreach = 1;
- gen(n->right); /* body */
- if(canreach){
- gbranch(OGOTO);
- patch(p, continpc);
- ncontin++;
- }
- if(!ncontin && l->right->right && warnreach) {
- warn(l->right->right, "unreachable FOR inc");
- warnreach = 0;
- }
- patch(spb, pc);
- continpc = scc;
- breakpc = sbc;
- canreach = nbreak!=0;
- if(canreach == 0)
- warnreach = !suppress;
- nbreak = snbreak;
- ncontin = sncontin;
- break;
- case OCONTINUE:
- if(continpc < 0) {
- diag(n, "continue not in a loop");
- break;
- }
- gbranch(OGOTO);
- patch(p, continpc);
- ncontin++;
- canreach = 0;
- warnreach = !suppress;
- break;
- case OBREAK:
- if(breakpc < 0) {
- diag(n, "break not in a loop");
- break;
- }
- /*
- * Don't complain about unreachable break statements.
- * There are breaks hidden in yacc's output and some people
- * write return; break; in their switch statements out of habit.
- * However, don't confuse the analysis by inserting an
- * unreachable reference to breakpc either.
- */
- if(!canreach)
- break;
- gbranch(OGOTO);
- patch(p, breakpc);
- nbreak++;
- canreach = 0;
- warnreach = !suppress;
- break;
- case OIF:
- l = n->left;
- if(bcomplex(l, n->right)) {
- if(typefd[l->type->etype])
- f = !l->fconst;
- else
- f = !l->vconst;
- if(debug['c'])
- print("%L const if %s\n", nearln, f ? "false" : "true");
- if(f) {
- canreach = 1;
- supgen(n->right->left);
- oldreach = canreach;
- canreach = 1;
- gen(n->right->right);
- /*
- * treat constant ifs as regular ifs for
- * reachability warnings.
- */
- if(!canreach && oldreach && debug['w'] < 2)
- warnreach = 0;
- }
- else {
- canreach = 1;
- gen(n->right->left);
- oldreach = canreach;
- canreach = 1;
- supgen(n->right->right);
- /*
- * treat constant ifs as regular ifs for
- * reachability warnings.
- */
- if(!oldreach && canreach && debug['w'] < 2)
- warnreach = 0;
- canreach = oldreach;
- }
- }
- else {
- sp = p;
- canreach = 1;
- if(n->right->left != Z)
- gen(n->right->left);
- oldreach = canreach;
- canreach = 1;
- if(n->right->right != Z) {
- gbranch(OGOTO);
- patch(sp, pc);
- sp = p;
- gen(n->right->right);
- }
- patch(sp, pc);
- canreach = canreach || oldreach;
- if(canreach == 0)
- warnreach = !suppress;
- }
- break;
- case OSET:
- case OUSED:
- usedset(n->left, o);
- break;
- }
- }
- void
- usedset(Node *n, int o)
- {
- if(n->op == OLIST) {
- usedset(n->left, o);
- usedset(n->right, o);
- return;
- }
- complex(n);
- switch(n->op) {
- case OADDR: /* volatile */
- gins(ANOP, n, Z);
- break;
- case ONAME:
- if(o == OSET)
- gins(ANOP, Z, n);
- else
- gins(ANOP, n, Z);
- break;
- }
- }
- int
- bcomplex(Node *n, Node *c)
- {
- Node *b, nod;
- complex(n);
- if(n->type != T)
- if(tcompat(n, T, n->type, tnot))
- n->type = T;
- if(n->type == T) {
- gbranch(OGOTO);
- return 0;
- }
- if(c != Z && n->op == OCONST && deadheads(c))
- return 1;
- if(newvlongcode && typev[n->type->etype] && machcap(Z)) {
- b = &nod;
- b->op = ONE;
- b->left = n;
- b->right = new(0, Z, Z);
- *b->right = *nodconst(0);
- b->right->type = n->type;
- b->type = types[TLONG];
- cgen(b, Z);
- return 0;
- }
- bool64(n);
- boolgen(n, 1, Z);
- return 0;
- }
|