void gen(Node *n) { Node *l; Prog *sp, *spc, *spb; Case *cn; long sbc, scc; int snbreak; int g, o; loop: if(n == Z) return; nearln = n->lineno; o = n->op; if(debug['G']) if(o != OLIST) print("%L %O\n", nearln, o); retok = 0; switch(o) { default: complex(n); doinc(n, PRE); cgen(n, D_NONE, n); doinc(n, POST); break; case OLIST: gen(n->left); rloop: n = n->right; goto loop; case ORETURN: retok = 1; complex(n); if(n->type == T) break; l = n->left; if(l == Z) { noretval(3); gbranch(ORETURN); break; } doinc(l, PRE); if(typesuv[n->type->etype]) { sugen(l, D_TREE, nodret, n->type->width); doinc(l, POST); noretval(3); gbranch(ORETURN); break; } g = regalloc(n->type, regret(n->type)); cgen(l, g, n); doinc(l, POST); if(typefd[n->type->etype]) noretval(1); else noretval(2); gbranch(ORETURN); regfree(g); break; case OLABEL: l = n->left; if(l) { l->xoffset = pc; if(l->label) patch(l->label, pc); } gbranch(OGOTO); /* prevent self reference in reg */ patch(p, pc); goto rloop; case OGOTO: retok = 1; n = n->left; if(n == Z) return; if(n->complex == 0) { diag(Z, "label undefined: %s", n->sym->name); return; } gbranch(OGOTO); if(n->xoffset) { patch(p, n->xoffset); return; } if(n->label) patch(n->label, pc-1); n->label = p; return; case OCASE: 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; setsp();; goto rloop; } complex(l); if(l->type == T) goto rloop; if(l->op == OCONST) if(typechl[l->type->etype]) { casf(); cases->val = l->vconst; cases->def = 0; cases->label = pc; setsp(); goto rloop; } diag(n, "case expression must be integer constant"); goto rloop; case OSWITCH: l = n->left; complex(l); doinc(l, PRE); if(l->type == T) break; if(!typechl[l->type->etype]) { diag(n, "switch expression must be integer"); break; } g = regalloc(types[TLONG], D_NONE); n->type = types[TLONG]; cgen(l, g, n); regfree(g); doinc(l, POST); setsp(); 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); gbranch(OGOTO); patch(p, breakpc); nbreak++; patch(sp, pc); doswit(g, l); patch(spb, pc); cases = cn; breakpc = sbc; nbreak = snbreak; setsp(); 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); /* 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; if(nbreak == 0) retok = 1; nbreak = snbreak; break; case OFOR: l = n->left; gen(l->right->left); /* init */ 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); gen(l->right->right); /* inc */ patch(sp, pc); if(l->left != Z) { /* test */ bcomplex(l->left); patch(p, breakpc); if(l->left->op != OCONST || vconst(l->left) == 0) nbreak++; } gen(n->right); /* body */ gbranch(OGOTO); patch(p, continpc); patch(spb, pc); continpc = scc; breakpc = sbc; if(nbreak == 0) retok = 1; nbreak = snbreak; break; case OCONTINUE: if(continpc < 0) { diag(n, "continue not in a loop"); break; } gbranch(OGOTO); patch(p, continpc); break; case OBREAK: if(breakpc < 0) { diag(n, "break not in a loop"); break; } gbranch(OGOTO); patch(p, breakpc); nbreak++; break; case OIF: l = n->left; bcomplex(l); sp = p; if(n->right->left != Z) gen(n->right->left); if(n->right->right != Z) { gbranch(OGOTO); patch(sp, pc); sp = p; gen(n->right->right); } patch(sp, pc); break; case OSET: case OUSED: usedset(n->left, o); break; } }
void gen(Node *n) { Node *l, nod; 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 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: gen(n->left); rloop: n = n->right; goto loop; case ORETURN: canreach = 0; warnreach = !suppress; complex(n); if(n->type == T) break; l = n->left; if(l == Z) { noretval(3); gbranch(ORETURN); break; } if(typecmplx[n->type->etype]) { sugen(l, nodret, n->type->width); noretval(3); 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) { newcase(); 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) { newcase(); 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(!typechlvp[l->type->etype] || l->type->etype == TIND) { diag(n, "switch expression must be integer"); break; } gbranch(OGOTO); /* entry */ sp = p; cn = cases; cases = C; newcase(); 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); doswit(l); 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: case OPREFETCH: usedset(n->left, o); break; } }
void gen(Node *n) { Node *l, nod; Prog *sp, *spc, *spb; Case *cn; long sbc, scc; int o, f; loop: if(n == Z) return; nearln = n->lineno; o = n->op; if(debug['G']) if(o != OLIST) print("%L %O\n", nearln, o); retok = 0; switch(o) { default: complex(n); cgen(n, Z); break; case OLIST: gen(n->left); rloop: n = n->right; goto loop; case ORETURN: retok = 1; complex(n); if(n->type == T) break; l = n->left; if(l == Z) { noretval(3); gbranch(ORETURN); break; } if(typesuv[n->type->etype]) { sugen(l, nodret, n->type->width); noretval(3); 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: 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: retok = 1; 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: 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; goto rloop; } complex(l); if(l->type == T) goto rloop; if(l->op == OCONST) if(typechl[l->type->etype]) { casf(); cases->val = l->vconst; cases->def = 0; cases->label = pc; 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(!typechl[l->type->etype]) { diag(n, "switch expression must be integer"); break; } gbranch(OGOTO); /* entry */ sp = p; cn = cases; cases = C; casf(); sbc = breakpc; breakpc = pc; gbranch(OGOTO); spb = p; gen(n->right); gbranch(OGOTO); patch(p, breakpc); patch(sp, pc); regalloc(&nod, l, Z); nod.type = types[TLONG]; cgen(l, &nod); doswit(&nod); regfree(&nod); patch(spb, pc); cases = cn; breakpc = sbc; 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; gbranch(OGOTO); spb = p; patch(spc, pc); if(n->op == OWHILE) patch(sp, pc); bcomplex(l, Z); /* test */ patch(p, breakpc); if(n->op == ODWHILE) patch(sp, pc); gen(n->right); /* body */ gbranch(OGOTO); patch(p, continpc); patch(spb, pc); continpc = scc; breakpc = sbc; break; case OFOR: l = n->left; gen(l->right->left); /* init */ gbranch(OGOTO); /* entry */ sp = p; scc = continpc; continpc = pc; gbranch(OGOTO); spc = p; sbc = breakpc; breakpc = pc; 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); } gen(n->right); /* body */ gbranch(OGOTO); patch(p, continpc); patch(spb, pc); continpc = scc; breakpc = sbc; break; case OCONTINUE: if(continpc < 0) { diag(n, "continue not in a loop"); break; } gbranch(OGOTO); patch(p, continpc); break; case OBREAK: if(breakpc < 0) { diag(n, "break not in a loop"); break; } gbranch(OGOTO); patch(p, breakpc); 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) { supgen(n->right->left); gen(n->right->right); } else { gen(n->right->left); supgen(n->right->right); } } else { sp = p; if(n->right->left != Z) gen(n->right->left); if(n->right->right != Z) { gbranch(OGOTO); patch(sp, pc); sp = p; gen(n->right->right); } patch(sp, pc); } break; case OSET: case OUSED: usedset(n->left, o); break; } }