void swit2(C1 *q, int nc, int32 def, Node *n) { C1 *r; int i; Prog *sp; if(nc < 5) { for(i=0; i<nc; i++) { if(debug['W']) print("case = %.8ux\n", q->val); gopcode(OEQ, n->type, n, nodconst(q->val)); patch(p, q->label); q++; } gbranch(OGOTO); patch(p, def); return; } i = nc / 2; r = q+i; if(debug['W']) print("case > %.8ux\n", r->val); gopcode(OGT, n->type, n, nodconst(r->val)); sp = p; gbranch(OGOTO); p->as = AJEQ; patch(p, r->label); swit2(q, i, def, n); if(debug['W']) print("case < %.8ux\n", r->val); patch(sp, pc); swit2(r+1, nc-i-1, def, n); }
void swit1(C1 *q, int nc, int32_t def, Node *n) { C1 *r; int i; Prog *sp; if(nc < 5) { for(i=0; i<nc; i++) { if(debug['K']) print("case = %.8llux\n", q->val); gcmp(OEQ, n, q->val); patch(p, q->label); q++; } gbranch(OGOTO); patch(p, def); return; } i = nc / 2; r = q+i; if(debug['K']) print("case > %.8llux\n", r->val); gcmp(OGT, n, r->val); sp = p; gbranch(OGOTO); p->as = AJEQ; patch(p, r->label); swit1(q, i, def, n); if(debug['K']) print("case < %.8llux\n", r->val); patch(sp, pc); swit1(r+1, nc-i-1, def, n); }
/* else binary */ void swit1(C1 *q, int nc, long def, int g, Node *n) { C1 *r; int i; long v; Prog *sp1, *sp2; /* note that g and g+1 are not allocated */ if(nc <= N1) goto linear; /* * divide and conquer */ i = nc / 2; r = q+i; v = r->val; /* compare median */ if(v >= -128 && v < 128) { gopcode(OAS, n->type, D_CONST, nodconst(v), g+1, n); gopcode(OEQ, n->type, g, n, g+1, n); } else gopcode(OEQ, n->type, g, n, D_CONST, nodconst(v)); gbranch(OLT); sp1 = p; gbranch(OGT); sp2 = p; gbranch(OGOTO); patch(p, r->label); patch(sp1, pc); swit1(q, i, def, g, n); patch(sp2, pc); swit1(r+1, nc-i-1, def, g, n); return; linear: for(i=0; i<nc; i++) { v = q->val; if(v >= -128 && v < 128) { gopcode(OAS, n->type, D_CONST, nodconst(v), g+1, n); gopcode(OEQ, n->type, g+1, n, g, n); } else gopcode(OEQ, n->type, g, n, D_CONST, nodconst(v)); gbranch(OEQ); patch(p, q->label); q++; } gbranch(OGOTO); patch(p, def); }
void galign(int n, int v) { int b; b = gbranch(CodeAlign); branch[b].param = n; branch[b].target = v; }
void codgen(Node *n, Node *nn) { Prog *sp; argoff = 0; inargs = 0; for(;; nn = nn->left) { if(nn == Z) { diag(Z, "cant find function name"); return; } if(nn->op == ONAME) break; } nearln = nn->lineno; gpseudo(ATEXT, nn->sym, D_CONST, stkoff); sp = p; retok = 0; gen(n); if(!retok) if(thisfn->link->etype != TVOID) warn(Z, "no return at end of function: %s", nn->sym->name); noretval(3); gbranch(ORETURN); if(!debug['N'] || debug['R'] || debug['P']) regopt(sp); }
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(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]; n = b; }
void swit1(C1 *q, int nc, long def, Node *n) { C1 *r; int i; Prog *sp; if(nc < 5) { for(i=0; i<nc; i++) { if(debug['W']) print("case = %.8lux\n", q->val); gopcode(OEQ, nodconst(q->val), n, Z); patch(p, q->label); q++; } gbranch(OGOTO); patch(p, def); return; } i = nc / 2; r = q+i; if(debug['W']) print("case > %.8lux\n", r->val); gopcode(OGT, nodconst(r->val), n, Z); sp = p; gopcode(OEQ, nodconst(r->val), n, Z); /* just gen the B.EQ */ patch(p, r->label); swit1(q, i, def, n); if(debug['W']) print("case < %.8lux\n", r->val); patch(sp, pc); swit1(r+1, nc-i-1, def, n); }
void codgen(Node *n, Node *nn) { Prog *sp; Node *n1, nod, nod1; cursafe = 0; curarg = 0; maxargsafe = 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; sp->reg |= ALLTHUMBS; /* denotes thumb code */ /* * isolate first argument */ if(REGARG >= 0) { if(typesuv[thisfn->link->etype]) { nod1 = *nodret->left; nodreg(&nod, &nod1, REGARG); gopcode(OAS, &nod, Z, &nod1); } else if(firstarg && typechlp[firstargtype->etype]) { nod1 = *nodret->left; nod1.sym = firstarg; nod1.type = firstargtype; nod1.xoffset = align(0, firstargtype, Aarg1); nod1.etype = firstargtype->etype; nodreg(&nod, &nod1, REGARG); gopcode(OAS, &nod, Z, &nod1); } } retok = 0; gen(n); if(!retok) if(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); sp->to.offset += maxargsafe; }
int gjmp(int l, int c) { int b; b = gbranch(CodeJump); branch[b].target = l; branch[b].param = c; return b; }
// Output relocation void greloc(Sym *sym, int c, int rel) { int b; if (sym && !sym->c) put_extern_sym(sym, NULL, 0, 0); b = gbranch(CodeReloc); if (sym) branch[b].target = sym->c; branch[b].param = rel; gen_le32(c); }
// Generate function epilog void gfunc_epilog(void) { // Mark end of code gbranch(CodeEnd); // Output code for function gcode(); // Clear code buffer clear_code_buf(); }
void swit2(C1 *q, int nc, long def, Node *n, Node *tn) { C1 *r; int i; Prog *sp; if(nc < 5) { for(i=0; i<nc; i++) { if(sval(q->val)) { gopcode(OEQ, n, Z, nodconst(q->val)); } else { gopcode(OSUB, nodconst(q->val), n, tn); gopcode(OEQ, tn, Z, nodconst(0)); } patch(p, q->label); q++; } gbranch(OGOTO); patch(p, def); return; } i = nc / 2; r = q+i; if(sval(r->val)) { gopcode(OGT, n, Z, nodconst(r->val)); sp = p; } else { gopcode(OSUB, nodconst(r->val), n, tn); gopcode(OGT, tn, Z, nodconst(0)); sp = p; } gbranch(OGOTO); p->as = ABEQ; patch(p, r->label); swit2(q, i, def, n, tn); patch(sp, pc); swit2(r+1, nc-i-1, def, n, tn); }
void lcgen(Node *n, Node *nn) { Prog *p1; Node nod; if(debug['g']) { prtree(nn, "lcgen lhs"); prtree(n, "lcgen"); } if(n == Z || n->type == T) return; if(nn == Z) { nn = &nod; regalloc(&nod, n, Z); } switch(n->op) { default: if(n->addable < INDEXED) { diag(n, "unknown op in lcgen: %O", n->op); break; } nod = *n; nod.op = OADDR; nod.left = n; nod.right = Z; nod.type = types[TIND]; gopcode(OAS, &nod, Z, nn); break; case OCOMMA: cgen(n->left, n->left); lcgen(n->right, nn); break; case OIND: cgen(n->left, nn); break; case OCOND: bcgen(n->left, 1); p1 = p; lcgen(n->right->left, nn); gbranch(OGOTO); patch(p1, pc); p1 = p; lcgen(n->right->right, nn); patch(p1, pc); break; } }
void bcomplex(Node *n) { complex(n); if(n->type != T) if(tcompat(n, T, n->type, tnot)) n->type = T; if(n->type != T) { bool64(n); doinc(n, PRE); boolgen(n, 1, D_NONE, Z, n); } else gbranch(OGOTO); }
void paste_code_buffer(CodeBuffer *cb) { int i; int ind_ofs = ind; int br_ofs = br; for (i = 0; i < cb->ind; ++i) g(cb->code[i]); for (i = 0; i < cb->br; ++i) { Branch *b = branch + gbranch(cb->branch[i].type); *b = cb->branch[i]; b->ind += ind_ofs; if (b->type == CodeJump) b->target += br_ofs; } free(cb->code); free(cb->branch); }
int bcomplex(Node *n, Node *c) { complex(n); if(n->type != T) if(tcompat(n, T, n->type, tnot)) n->type = T; if(n->type != T) { if(c != Z && n->op == OCONST && deadheads(c)) return 1; bool64(n); boolgen(n, 1, Z); } else gbranch(OGOTO); return 0; }
void codgen(Node *n, Node *nn) { Prog *sp; Node *n1, nod, nod1; cursafe = 0; curarg = 0; maxargsafe = 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; p = gtext(n1->sym, stkoff); sp = p; /* * isolate first argument */ if(REGARG >= 0) { if(typesuv[thisfn->link->etype]) { nod1 = *nodret->left; nodreg(&nod, &nod1, REGARG); gmove(&nod, &nod1); } else if(firstarg && typechlp[firstargtype->etype]) { nod1 = *nodret->left; nod1.sym = firstarg; nod1.type = firstargtype; nod1.xoffset = align(0, firstargtype, Aarg1, nil); nod1.etype = firstargtype->etype; nodreg(&nod, &nod1, REGARG); gmove(&nod, &nod1); } } retok = 0; canreach = 1; warnreach = 1; gen(n); if(canreach && thisfn->link->etype != TVOID) diag(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') /* [sic] */ maxargsafe = xround(maxargsafe, 8); sp->to.offset += maxargsafe; }
void doswit(Node *n) { Case *c; C1 *q, *iq, *iqh, *iql; long def, nc, i, j, isv, nh; Prog *hsb; Node *vr[2]; int dup; def = 0; nc = 0; isv = 0; for(c = cases; c->link != C; c = c->link) { if(c->def) { if(def) diag(n, "more than one default in switch"); def = c->label; continue; } isv |= c->isv; nc++; } if(typev[n->type->etype]) isv = 1; else if(isv){ warn(n, "32-bit switch expression with 64-bit case constant"); isv = 0; } iq = alloc(nc*sizeof(C1)); q = iq; for(c = cases; c->link != C; c = c->link) { if(c->def) continue; if(c->isv && !isv) continue; /* can never match */ q->label = c->label; if(isv) q->val = c->val; else q->val = (long)c->val; /* cast ensures correct value for 32-bit switch on 64-bit architecture */ q++; } qsort(iq, nc, sizeof(C1), swcmp); if(debug['K']) for(i=0; i<nc; i++) print("case %2ld: = %.8llux\n", i, (vlong)iq[i].val); dup = 0; for(i=0; i<nc-1; i++) if(iq[i].val == iq[i+1].val) { diag(n, "duplicate cases in switch %lld", (vlong)iq[i].val); dup = 1; } if(dup) return; if(def == 0) { def = breakpc; nbreak++; } if(!isv || ewidth[TIND] > ewidth[TLONG] || n->op == OREGISTER) { swit1(iq, nc, def, n); return; } /* * 64-bit case on 32-bit machine: * switch on high-order words, and * in each of those, switch on low-order words */ if(n->op != OREGPAIR) fatal(n, "internal: expected register pair"); if(thechar == '8'){ /* TO DO: need an enquiry function */ vr[0] = n->left; /* low */ vr[1] = n->right; /* high */ }else{ vr[0] = n->right; vr[1] = n->left; } vr[0]->type = types[TLONG]; vr[1]->type = types[TLONG]; gbranch(OGOTO); hsb = p; iqh = alloc(nc*sizeof(C1)); iql = alloc(nc*sizeof(C1)); nh = 0; for(i=0; i<nc;){ iqh[nh].val = iq[i].val >> 32; q = iql; /* iq is sorted, so equal top halves are adjacent */ for(j = i; j < nc; j++){ if((iq[j].val>>32) != iqh[nh].val) break; q->val = (long)iq[j].val; q->label = iq[j].label; q++; } qsort(iql, q-iql, sizeof(C1), swcmp); if(0){for(int k=0; k<(q-iql); k++)print("nh=%ld k=%d h=%#llux l=%#llux lab=%ld\n", nh, k, (vlong)iqh[nh].val, (vlong)iql[k].val, iql[k].label);} iqh[nh].label = pc; nh++; swit1(iql, q-iql, def, vr[0]); i = j; } patch(hsb, pc); if(0){for(int k=0; k<nh; k++)print("k*=%d h=%#llux lab=%ld\n", k, (vlong)iqh[k].val, iqh[k].label);} swit1(iqh, nh, def, vr[1]); }
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; 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 gline(int linenum) { int b; b = gbranch(CodeLine); branch[b].target = linenum; }
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; } }
void cgen(Node *n, Node *nn) { Node *l, *r, *t; Prog *p1; Node nod, nod1, nod2, nod3, nod4; int o, hardleft; int32 v, curs; vlong c; if(debug['g']) { prtree(nn, "cgen lhs"); prtree(n, "cgen"); } if(n == Z || n->type == T) return; if(typesu[n->type->etype]) { sugen(n, nn, n->type->width); return; } l = n->left; r = n->right; o = n->op; if(n->op == OEXREG || (nn != Z && nn->op == OEXREG)) { gmove(n, nn); return; } if(n->addable >= INDEXED) { if(nn == Z) { switch(o) { default: nullwarn(Z, Z); break; case OINDEX: nullwarn(l, r); break; } return; } gmove(n, nn); return; } curs = cursafe; if(l->complex >= FNX) if(r != Z && r->complex >= FNX) switch(o) { default: if(cond(o) && typesu[l->type->etype]) break; regret(&nod, r); cgen(r, &nod); regsalloc(&nod1, r); gmove(&nod, &nod1); regfree(&nod); nod = *n; nod.right = &nod1; cgen(&nod, nn); return; case OFUNC: case OCOMMA: case OANDAND: case OOROR: case OCOND: case ODOT: break; } hardleft = l->addable < INDEXED || l->complex >= FNX; switch(o) { default: diag(n, "unknown op in cgen: %O", o); break; case ONEG: case OCOM: if(nn == Z) { nullwarn(l, Z); break; } regalloc(&nod, l, nn); cgen(l, &nod); gopcode(o, n->type, Z, &nod); gmove(&nod, nn); regfree(&nod); break; case OAS: if(l->op == OBIT) goto bitas; if(!hardleft) { if(nn != Z || r->addable < INDEXED || hardconst(r)) { if(r->complex >= FNX && nn == Z) regret(&nod, r); else regalloc(&nod, r, nn); cgen(r, &nod); gmove(&nod, l); if(nn != Z) gmove(&nod, nn); regfree(&nod); } else gmove(r, l); break; } if(l->complex >= r->complex) { if(l->op == OINDEX && immconst(r)) { gmove(r, l); break; } reglcgen(&nod1, l, Z); if(r->addable >= INDEXED && !hardconst(r)) { gmove(r, &nod1); if(nn != Z) gmove(r, nn); regfree(&nod1); break; } regalloc(&nod, r, nn); cgen(r, &nod); } else { regalloc(&nod, r, nn); cgen(r, &nod); reglcgen(&nod1, l, Z); } gmove(&nod, &nod1); regfree(&nod); regfree(&nod1); break; bitas: n = l->left; regalloc(&nod, r, nn); if(l->complex >= r->complex) { reglcgen(&nod1, n, Z); cgen(r, &nod); } else { cgen(r, &nod); reglcgen(&nod1, n, Z); } regalloc(&nod2, n, Z); gmove(&nod1, &nod2); bitstore(l, &nod, &nod1, &nod2, nn); break; case OBIT: if(nn == Z) { nullwarn(l, Z); break; } bitload(n, &nod, Z, Z, nn); gmove(&nod, nn); regfree(&nod); break; case OLSHR: case OASHL: case OASHR: if(nn == Z) { nullwarn(l, r); break; } if(r->op == OCONST) { if(r->vconst == 0) { cgen(l, nn); break; } regalloc(&nod, l, nn); cgen(l, &nod); if(o == OASHL && r->vconst == 1) gopcode(OADD, n->type, &nod, &nod); else gopcode(o, n->type, r, &nod); gmove(&nod, nn); regfree(&nod); break; } /* * get nod to be D_CX */ if(nodreg(&nod, nn, D_CX)) { regsalloc(&nod1, n); gmove(&nod, &nod1); cgen(n, &nod); /* probably a bug */ gmove(&nod, nn); gmove(&nod1, &nod); break; } reg[D_CX]++; if(nn->op == OREGISTER && nn->reg == D_CX) regalloc(&nod1, l, Z); else regalloc(&nod1, l, nn); if(r->complex >= l->complex) { cgen(r, &nod); cgen(l, &nod1); } else { cgen(l, &nod1); cgen(r, &nod); } gopcode(o, n->type, &nod, &nod1); gmove(&nod1, nn); regfree(&nod); regfree(&nod1); break; case OADD: case OSUB: case OOR: case OXOR: case OAND: if(nn == Z) { nullwarn(l, r); break; } if(typefd[n->type->etype]) goto fop; if(r->op == OCONST) { if(r->vconst == 0 && o != OAND) { cgen(l, nn); break; } } if(n->op == OADD && l->op == OASHL && l->right->op == OCONST && (r->op != OCONST || r->vconst < -128 || r->vconst > 127)) { c = l->right->vconst; if(c > 0 && c <= 3) { if(l->left->complex >= r->complex) { regalloc(&nod, l->left, nn); cgen(l->left, &nod); if(r->addable < INDEXED) { regalloc(&nod1, r, Z); cgen(r, &nod1); genmuladd(&nod, &nod, 1 << c, &nod1); regfree(&nod1); } else genmuladd(&nod, &nod, 1 << c, r); } else { regalloc(&nod, r, nn); cgen(r, &nod); regalloc(&nod1, l->left, Z); cgen(l->left, &nod1); genmuladd(&nod, &nod1, 1 << c, &nod); regfree(&nod1); } gmove(&nod, nn); regfree(&nod); break; } } if(r->addable >= INDEXED && !hardconst(r)) { regalloc(&nod, l, nn); cgen(l, &nod); gopcode(o, n->type, r, &nod); gmove(&nod, nn); regfree(&nod); break; } if(l->complex >= r->complex) { regalloc(&nod, l, nn); cgen(l, &nod); regalloc(&nod1, r, Z); cgen(r, &nod1); gopcode(o, n->type, &nod1, &nod); } else { regalloc(&nod1, r, nn); cgen(r, &nod1); regalloc(&nod, l, Z); cgen(l, &nod); gopcode(o, n->type, &nod1, &nod); } gmove(&nod, nn); regfree(&nod); regfree(&nod1); break; case OLMOD: case OMOD: case OLMUL: case OLDIV: case OMUL: case ODIV: if(nn == Z) { nullwarn(l, r); break; } if(typefd[n->type->etype]) goto fop; if(r->op == OCONST && typechl[n->type->etype]) { /* TO DO */ SET(v); switch(o) { case ODIV: case OMOD: c = r->vconst; if(c < 0) c = -c; v = xlog2(c); if(v < 0) break; /* fall thru */ case OMUL: case OLMUL: regalloc(&nod, l, nn); cgen(l, &nod); switch(o) { case OMUL: case OLMUL: mulgen(n->type, r, &nod); break; case ODIV: sdiv2(r->vconst, v, l, &nod); break; case OMOD: smod2(r->vconst, v, l, &nod); break; } gmove(&nod, nn); regfree(&nod); goto done; case OLDIV: c = r->vconst; if((c & 0x80000000) == 0) break; regalloc(&nod1, l, Z); cgen(l, &nod1); regalloc(&nod, l, nn); zeroregm(&nod); gins(ACMPL, &nod1, nodconst(c)); gins(ASBBL, nodconst(-1), &nod); regfree(&nod1); gmove(&nod, nn); regfree(&nod); goto done; } } if(o == OMUL) { if(l->addable >= INDEXED) { t = l; l = r; r = t; } /* should favour AX */ regalloc(&nod, l, nn); cgen(l, &nod); if(r->addable < INDEXED || hardconst(r)) { regalloc(&nod1, r, Z); cgen(r, &nod1); gopcode(OMUL, n->type, &nod1, &nod); regfree(&nod1); }else gopcode(OMUL, n->type, r, &nod); /* addressible */ gmove(&nod, nn); regfree(&nod); break; } /* * get nod to be D_AX * get nod1 to be D_DX */ if(nodreg(&nod, nn, D_AX)) { regsalloc(&nod2, n); gmove(&nod, &nod2); v = reg[D_AX]; reg[D_AX] = 0; if(isreg(l, D_AX)) { nod3 = *n; nod3.left = &nod2; cgen(&nod3, nn); } else if(isreg(r, D_AX)) { nod3 = *n; nod3.right = &nod2; cgen(&nod3, nn); } else cgen(n, nn); gmove(&nod2, &nod); reg[D_AX] = v; break; } if(nodreg(&nod1, nn, D_DX)) { regsalloc(&nod2, n); gmove(&nod1, &nod2); v = reg[D_DX]; reg[D_DX] = 0; if(isreg(l, D_DX)) { nod3 = *n; nod3.left = &nod2; cgen(&nod3, nn); } else if(isreg(r, D_DX)) { nod3 = *n; nod3.right = &nod2; cgen(&nod3, nn); } else cgen(n, nn); gmove(&nod2, &nod1); reg[D_DX] = v; break; } reg[D_AX]++; if(r->op == OCONST && (o == ODIV || o == OLDIV) && immconst(r) && typechl[r->type->etype]) { reg[D_DX]++; if(l->addable < INDEXED) { regalloc(&nod2, l, Z); cgen(l, &nod2); l = &nod2; } if(o == ODIV) sdivgen(l, r, &nod, &nod1); else udivgen(l, r, &nod, &nod1); gmove(&nod1, nn); if(l == &nod2) regfree(l); goto freeaxdx; } if(l->complex >= r->complex) { cgen(l, &nod); reg[D_DX]++; if(o == ODIV || o == OMOD) gins(typechl[l->type->etype]? ACDQ: ACQO, Z, Z); if(o == OLDIV || o == OLMOD) zeroregm(&nod1); if(r->addable < INDEXED || r->op == OCONST) { regsalloc(&nod3, r); cgen(r, &nod3); gopcode(o, n->type, &nod3, Z); } else gopcode(o, n->type, r, Z); } else { regsalloc(&nod3, r); cgen(r, &nod3); cgen(l, &nod); reg[D_DX]++; if(o == ODIV || o == OMOD) gins(typechl[l->type->etype]? ACDQ: ACQO, Z, Z); if(o == OLDIV || o == OLMOD) zeroregm(&nod1); gopcode(o, n->type, &nod3, Z); } if(o == OMOD || o == OLMOD) gmove(&nod1, nn); else gmove(&nod, nn); freeaxdx: regfree(&nod); regfree(&nod1); break; case OASLSHR: case OASASHL: case OASASHR: if(r->op == OCONST) goto asand; if(l->op == OBIT) goto asbitop; if(typefd[n->type->etype]) goto asand; /* can this happen? */ /* * get nod to be D_CX */ if(nodreg(&nod, nn, D_CX)) { regsalloc(&nod1, n); gmove(&nod, &nod1); cgen(n, &nod); if(nn != Z) gmove(&nod, nn); gmove(&nod1, &nod); break; } reg[D_CX]++; if(r->complex >= l->complex) { cgen(r, &nod); if(hardleft) reglcgen(&nod1, l, Z); else nod1 = *l; } else { if(hardleft) reglcgen(&nod1, l, Z); else nod1 = *l; cgen(r, &nod); } gopcode(o, l->type, &nod, &nod1); regfree(&nod); if(nn != Z) gmove(&nod1, nn); if(hardleft) regfree(&nod1); break; case OASAND: case OASADD: case OASSUB: case OASXOR: case OASOR: asand: if(l->op == OBIT) goto asbitop; if(typefd[l->type->etype] || typefd[r->type->etype]) goto asfop; if(l->complex >= r->complex) { if(hardleft) reglcgen(&nod, l, Z); else nod = *l; if(!immconst(r)) { regalloc(&nod1, r, nn); cgen(r, &nod1); gopcode(o, l->type, &nod1, &nod); regfree(&nod1); } else gopcode(o, l->type, r, &nod); } else { regalloc(&nod1, r, nn); cgen(r, &nod1); if(hardleft) reglcgen(&nod, l, Z); else nod = *l; gopcode(o, l->type, &nod1, &nod); regfree(&nod1); } if(nn != Z) gmove(&nod, nn); if(hardleft) regfree(&nod); break; asfop: if(l->complex >= r->complex) { if(hardleft) reglcgen(&nod, l, Z); else nod = *l; if(r->addable < INDEXED){ regalloc(&nod1, r, nn); cgen(r, &nod1); }else nod1 = *r; regalloc(&nod2, r, Z); gmove(&nod, &nod2); gopcode(o, r->type, &nod1, &nod2); gmove(&nod2, &nod); regfree(&nod2); if(r->addable < INDEXED) regfree(&nod1); } else { regalloc(&nod1, r, nn); cgen(r, &nod1); if(hardleft) reglcgen(&nod, l, Z); else nod = *l; if(o != OASMUL && o != OASADD) { regalloc(&nod2, r, Z); gmove(&nod, &nod2); gopcode(o, r->type, &nod1, &nod2); regfree(&nod1); gmove(&nod2, &nod); regfree(&nod2); } else { gopcode(o, r->type, &nod, &nod1); gmove(&nod1, &nod); regfree(&nod1); } } if(nn != Z) gmove(&nod, nn); if(hardleft) regfree(&nod); break; case OASLMUL: case OASLDIV: case OASLMOD: case OASMUL: case OASDIV: case OASMOD: if(l->op == OBIT) goto asbitop; if(typefd[n->type->etype] || typefd[r->type->etype]) goto asfop; if(r->op == OCONST && typechl[n->type->etype]) { SET(v); switch(o) { case OASDIV: case OASMOD: c = r->vconst; if(c < 0) c = -c; v = xlog2(c); if(v < 0) break; /* fall thru */ case OASMUL: case OASLMUL: if(hardleft) reglcgen(&nod2, l, Z); else nod2 = *l; regalloc(&nod, l, nn); cgen(&nod2, &nod); switch(o) { case OASMUL: case OASLMUL: mulgen(n->type, r, &nod); break; case OASDIV: sdiv2(r->vconst, v, l, &nod); break; case OASMOD: smod2(r->vconst, v, l, &nod); break; } havev: gmove(&nod, &nod2); if(nn != Z) gmove(&nod, nn); if(hardleft) regfree(&nod2); regfree(&nod); goto done; case OASLDIV: c = r->vconst; if((c & 0x80000000) == 0) break; if(hardleft) reglcgen(&nod2, l, Z); else nod2 = *l; regalloc(&nod1, l, nn); cgen(&nod2, &nod1); regalloc(&nod, l, nn); zeroregm(&nod); gins(ACMPL, &nod1, nodconst(c)); gins(ASBBL, nodconst(-1), &nod); regfree(&nod1); goto havev; } } if(o == OASMUL) { /* should favour AX */ regalloc(&nod, l, nn); if(r->complex >= FNX) { regalloc(&nod1, r, Z); cgen(r, &nod1); r = &nod1; } if(hardleft) reglcgen(&nod2, l, Z); else nod2 = *l; cgen(&nod2, &nod); if(r->addable < INDEXED || hardconst(r)) { if(r->complex < FNX) { regalloc(&nod1, r, Z); cgen(r, &nod1); } gopcode(OASMUL, n->type, &nod1, &nod); regfree(&nod1); } else gopcode(OASMUL, n->type, r, &nod); if(r == &nod1) regfree(r); gmove(&nod, &nod2); if(nn != Z) gmove(&nod, nn); regfree(&nod); if(hardleft) regfree(&nod2); break; } /* * get nod to be D_AX * get nod1 to be D_DX */ if(nodreg(&nod, nn, D_AX)) { regsalloc(&nod2, n); gmove(&nod, &nod2); v = reg[D_AX]; reg[D_AX] = 0; if(isreg(l, D_AX)) { nod3 = *n; nod3.left = &nod2; cgen(&nod3, nn); } else if(isreg(r, D_AX)) { nod3 = *n; nod3.right = &nod2; cgen(&nod3, nn); } else cgen(n, nn); gmove(&nod2, &nod); reg[D_AX] = v; break; } if(nodreg(&nod1, nn, D_DX)) { regsalloc(&nod2, n); gmove(&nod1, &nod2); v = reg[D_DX]; reg[D_DX] = 0; if(isreg(l, D_DX)) { nod3 = *n; nod3.left = &nod2; cgen(&nod3, nn); } else if(isreg(r, D_DX)) { nod3 = *n; nod3.right = &nod2; cgen(&nod3, nn); } else cgen(n, nn); gmove(&nod2, &nod1); reg[D_DX] = v; break; } reg[D_AX]++; reg[D_DX]++; if(l->complex >= r->complex) { if(hardleft) reglcgen(&nod2, l, Z); else nod2 = *l; cgen(&nod2, &nod); if(r->op == OCONST && typechl[r->type->etype]) { switch(o) { case OASDIV: sdivgen(&nod2, r, &nod, &nod1); goto divdone; case OASLDIV: udivgen(&nod2, r, &nod, &nod1); divdone: gmove(&nod1, &nod2); if(nn != Z) gmove(&nod1, nn); goto freelxaxdx; } } if(o == OASDIV || o == OASMOD) gins(typechl[l->type->etype]? ACDQ: ACQO, Z, Z); if(o == OASLDIV || o == OASLMOD) zeroregm(&nod1); if(r->addable < INDEXED || r->op == OCONST || !typeil[r->type->etype]) { regalloc(&nod3, r, Z); cgen(r, &nod3); gopcode(o, l->type, &nod3, Z); regfree(&nod3); } else gopcode(o, n->type, r, Z); } else { regalloc(&nod3, r, Z); cgen(r, &nod3); if(hardleft) reglcgen(&nod2, l, Z); else nod2 = *l; cgen(&nod2, &nod); if(o == OASDIV || o == OASMOD) gins(typechl[l->type->etype]? ACDQ: ACQO, Z, Z); if(o == OASLDIV || o == OASLMOD) zeroregm(&nod1); gopcode(o, l->type, &nod3, Z); regfree(&nod3); } if(o == OASMOD || o == OASLMOD) { gmove(&nod1, &nod2); if(nn != Z) gmove(&nod1, nn); } else { gmove(&nod, &nod2); if(nn != Z) gmove(&nod, nn); } freelxaxdx: if(hardleft) regfree(&nod2); regfree(&nod); regfree(&nod1); break; fop: if(l->complex >= r->complex) { regalloc(&nod, l, nn); cgen(l, &nod); if(r->addable < INDEXED) { regalloc(&nod1, r, Z); cgen(r, &nod1); gopcode(o, n->type, &nod1, &nod); regfree(&nod1); } else gopcode(o, n->type, r, &nod); } else { /* TO DO: could do better with r->addable >= INDEXED */ regalloc(&nod1, r, Z); cgen(r, &nod1); regalloc(&nod, l, nn); cgen(l, &nod); gopcode(o, n->type, &nod1, &nod); regfree(&nod1); } gmove(&nod, nn); regfree(&nod); break; asbitop: regalloc(&nod4, n, nn); if(l->complex >= r->complex) { bitload(l, &nod, &nod1, &nod2, &nod4); regalloc(&nod3, r, Z); cgen(r, &nod3); } else { regalloc(&nod3, r, Z); cgen(r, &nod3); bitload(l, &nod, &nod1, &nod2, &nod4); } gmove(&nod, &nod4); { /* TO DO: check floating point source */ Node onod; /* incredible grot ... */ onod = nod3; onod.op = o; onod.complex = 2; onod.addable = 0; onod.type = tfield; onod.left = &nod4; onod.right = &nod3; cgen(&onod, Z); } regfree(&nod3); gmove(&nod4, &nod); regfree(&nod4); bitstore(l, &nod, &nod1, &nod2, nn); break; case OADDR: if(nn == Z) { nullwarn(l, Z); break; } lcgen(l, nn); break; case OFUNC: if(l->complex >= FNX) { if(l->op != OIND) diag(n, "bad function call"); regret(&nod, l->left); cgen(l->left, &nod); regsalloc(&nod1, l->left); gmove(&nod, &nod1); regfree(&nod); nod = *n; nod.left = &nod2; nod2 = *l; nod2.left = &nod1; nod2.complex = 1; cgen(&nod, nn); return; } o = 0; if(REGARG >= 0) o = reg[REGARG]; gargs(r, &nod, &nod1); if(l->addable < INDEXED) { reglcgen(&nod, l, nn); nod.op = OREGISTER; gopcode(OFUNC, n->type, Z, &nod); regfree(&nod); } else gopcode(OFUNC, n->type, Z, l); if(REGARG >= 0) if(o != reg[REGARG]) reg[REGARG]--; if(nn != Z) { regret(&nod, n); gmove(&nod, nn); regfree(&nod); } break; case OIND: if(nn == Z) { nullwarn(l, Z); break; } regialloc(&nod, n, nn); r = l; while(r->op == OADD) r = r->right; if(sconst(r)) { v = r->vconst; r->vconst = 0; cgen(l, &nod); nod.xoffset += v; r->vconst = v; } else cgen(l, &nod); regind(&nod, n); gmove(&nod, nn); regfree(&nod); break; case OEQ: case ONE: case OLE: case OLT: case OGE: case OGT: case OLO: case OLS: case OHI: case OHS: if(nn == Z) { nullwarn(l, r); break; } boolgen(n, 1, nn); break; case OANDAND: case OOROR: boolgen(n, 1, nn); if(nn == Z) patch(p, pc); break; case ONOT: if(nn == Z) { nullwarn(l, Z); break; } boolgen(n, 1, nn); break; case OCOMMA: cgen(l, Z); cgen(r, nn); break; case OCAST: if(nn == Z) { nullwarn(l, Z); break; } /* * convert from types l->n->nn */ if(nocast(l->type, n->type) && nocast(n->type, nn->type)) { /* both null, gen l->nn */ cgen(l, nn); break; } if(ewidth[n->type->etype] < ewidth[l->type->etype]){ if(l->type->etype == TIND && typechlp[n->type->etype]) warn(n, "conversion of pointer to shorter integer"); }else if(0){ if(nocast(n->type, nn->type) || castup(n->type, nn->type)){ if(typefd[l->type->etype] != typefd[nn->type->etype]) regalloc(&nod, l, nn); else regalloc(&nod, nn, nn); cgen(l, &nod); gmove(&nod, nn); regfree(&nod); break; } } regalloc(&nod, l, nn); cgen(l, &nod); regalloc(&nod1, n, &nod); gmove(&nod, &nod1); gmove(&nod1, nn); regfree(&nod1); regfree(&nod); break; case ODOT: sugen(l, nodrat, l->type->width); if(nn == Z) break; warn(n, "non-interruptable temporary"); nod = *nodrat; if(!r || r->op != OCONST) { diag(n, "DOT and no offset"); break; } nod.xoffset += (int32)r->vconst; nod.type = n->type; cgen(&nod, nn); break; case OCOND: bcgen(l, 1); p1 = p; cgen(r->left, nn); gbranch(OGOTO); patch(p1, pc); p1 = p; cgen(r->right, nn); patch(p1, pc); break; case OPOSTINC: case OPOSTDEC: v = 1; if(l->type->etype == TIND) v = l->type->link->width; if(o == OPOSTDEC) v = -v; if(l->op == OBIT) goto bitinc; if(nn == Z) goto pre; if(hardleft) reglcgen(&nod, l, Z); else nod = *l; gmove(&nod, nn); if(typefd[n->type->etype]) { regalloc(&nod1, l, Z); gmove(&nod, &nod1); if(v < 0) gopcode(OSUB, n->type, nodfconst(-v), &nod1); else gopcode(OADD, n->type, nodfconst(v), &nod1); gmove(&nod1, &nod); regfree(&nod1); } else gopcode(OADD, n->type, nodconst(v), &nod); if(hardleft) regfree(&nod); break; case OPREINC: case OPREDEC: v = 1; if(l->type->etype == TIND) v = l->type->link->width; if(o == OPREDEC) v = -v; if(l->op == OBIT) goto bitinc; pre: if(hardleft) reglcgen(&nod, l, Z); else nod = *l; if(typefd[n->type->etype]) { regalloc(&nod1, l, Z); gmove(&nod, &nod1); if(v < 0) gopcode(OSUB, n->type, nodfconst(-v), &nod1); else gopcode(OADD, n->type, nodfconst(v), &nod1); gmove(&nod1, &nod); regfree(&nod1); } else gopcode(OADD, n->type, nodconst(v), &nod); if(nn != Z) gmove(&nod, nn); if(hardleft) regfree(&nod); break; bitinc: if(nn != Z && (o == OPOSTINC || o == OPOSTDEC)) { bitload(l, &nod, &nod1, &nod2, Z); gmove(&nod, nn); gopcode(OADD, tfield, nodconst(v), &nod); bitstore(l, &nod, &nod1, &nod2, Z); break; } bitload(l, &nod, &nod1, &nod2, nn); gopcode(OADD, tfield, nodconst(v), &nod); bitstore(l, &nod, &nod1, &nod2, nn); break; } done: cursafe = curs; }
void swit2(C1 *q, int nc, int32 def, Node *n) { C1 *r; int i; int32 v; Prog *sp; if(nc >= 3) { i = (q+nc-1)->val - (q+0)->val; if(i > 0 && i < nc*2) goto direct; } if(nc < 5) { for(i=0; i<nc; i++) { if(debug['W']) print("case = %.8ux\n", q->val); gopcode(OEQ, nodconst(q->val), n, Z); patch(p, q->label); q++; } gbranch(OGOTO); patch(p, def); return; } i = nc / 2; r = q+i; if(debug['W']) print("case > %.8ux\n", r->val); gopcode(OGT, nodconst(r->val), n, Z); sp = p; gopcode(OEQ, nodconst(r->val), n, Z); /* just gen the B.EQ */ patch(p, r->label); swit2(q, i, def, n); if(debug['W']) print("case < %.8ux\n", r->val); patch(sp, pc); swit2(r+1, nc-i-1, def, n); return; direct: v = q->val; if(v != 0) gopcode(OSUB, nodconst(v), Z, n); gopcode(OCASE, nodconst((q+nc-1)->val - v), n, Z); patch(p, def); for(i=0; i<nc; i++) { if(debug['W']) print("case = %.8ux\n", q->val); while(q->val != v) { nextpc(); p->as = ABCASE; patch(p, def); v++; } nextpc(); p->as = ABCASE; patch(p, q->label); q++; v++; } gbranch(OGOTO); /* so that regopt() won't be confused */ patch(p, def); }
void gstart(void) { gbranch(CodeStart); }
// Generate function prolog of type 't' void gfunc_prolog(CType *func_type) { int addr, align, size, func_call, fastcall_nb_regs; int param_index, param_addr; uint8_t *fastcall_regs_ptr; Sym *sym; CType *type; #ifdef DEBUG_BRANCH printf("compile %s\n", func_name); #endif reset_code_buf(); gbranch(CodeStart); sym = func_type->ref; func_naked = FUNC_NAKED(sym->r); func_call = FUNC_CALL(sym->r); addr = 8; loc = 0; regs_used = 0; if (func_call >= FUNC_FASTCALL1 && func_call <= FUNC_FASTCALL3) { fastcall_nb_regs = func_call - FUNC_FASTCALL1 + 1; fastcall_regs_ptr = fastcall_regs; } else if (func_call == FUNC_FASTCALLW) { fastcall_nb_regs = 2; fastcall_regs_ptr = fastcallw_regs; } else { fastcall_nb_regs = 0; fastcall_regs_ptr = NULL; } param_index = 0; // If the function returns a structure, then add an implicit pointer parameter func_vt = sym->type; if ((func_vt.t & VT_BTYPE) == VT_STRUCT) { // TODO: fastcall case? func_vc = addr; addr += 4; param_index++; } // Define parameters while ((sym = sym->next) != NULL) { type = &sym->type; size = type_size(type, &align); size = (size + 3) & ~3; if (param_index < fastcall_nb_regs) { // Save FASTCALL register if (!func_naked) { loc -= 4; o(0x89); // movl gen_modrm(fastcall_regs_ptr[param_index], VT_LOCAL, NULL, loc); param_addr = loc; } } else { param_addr = addr; addr += size; } sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | VT_LVAL, param_addr); param_index++; } // pascal type call? func_ret_sub = 0; if (func_call == FUNC_STDCALL) func_ret_sub = addr - 8; func_noargs = (addr == 8); }
void gend(void) { gbranch(CodeEnd); }
void cgen(Node *n, Node *nn) { Node *l, *r; Prog *p1; Node nod, nod1, nod2, nod3, nod4; int o; long v, curs; if(debug['g']) { prtree(nn, "cgen lhs"); prtree(n, "cgen"); } if(n == Z || n->type == T) return; if(typesuv[n->type->etype]) { sugen(n, nn, n->type->width); return; } l = n->left; r = n->right; o = n->op; if(n->addable >= INDEXED) { if(nn == Z) { switch(o) { default: nullwarn(Z, Z); break; case OINDEX: nullwarn(l, r); break; } return; } gmove(n, nn); return; } curs = cursafe; if(n->complex >= FNX) if(l->complex >= FNX) if(r != Z && r->complex >= FNX) switch(o) { default: regret(&nod, r); cgen(r, &nod); regsalloc(&nod1, r); gopcode(OAS, &nod, Z, &nod1); regfree(&nod); nod = *n; nod.right = &nod1; cgen(&nod, nn); return; case OFUNC: case OCOMMA: case OANDAND: case OOROR: case OCOND: case ODOT: break; } switch(o) { default: diag(n, "unknown op in cgen: %O", o); break; case OAS: if(l->op == OBIT) goto bitas; if(l->addable >= INDEXED && l->complex < FNX) { if(nn != Z || r->addable < INDEXED) { if(r->complex >= FNX && nn == Z) regret(&nod, r); else regalloc(&nod, r, nn); cgen(r, &nod); gmove(&nod, l); if(nn != Z) gmove(&nod, nn); regfree(&nod); } else gmove(r, l); break; } if(l->complex >= r->complex) { reglcgen(&nod1, l, Z); if(r->addable >= INDEXED) { gmove(r, &nod1); if(nn != Z) gmove(r, nn); regfree(&nod1); break; } regalloc(&nod, r, nn); cgen(r, &nod); } else { regalloc(&nod, r, nn); cgen(r, &nod); reglcgen(&nod1, l, Z); } gmove(&nod, &nod1); regfree(&nod); regfree(&nod1); break; bitas: n = l->left; regalloc(&nod, r, nn); if(l->complex >= r->complex) { reglcgen(&nod1, n, Z); cgen(r, &nod); } else { cgen(r, &nod); reglcgen(&nod1, n, Z); } regalloc(&nod2, n, Z); gopcode(OAS, &nod1, Z, &nod2); bitstore(l, &nod, &nod1, &nod2, nn); break; case OBIT: if(nn == Z) { nullwarn(l, Z); break; } bitload(n, &nod, Z, Z, nn); gopcode(OAS, &nod, Z, nn); regfree(&nod); break; case OADD: case OSUB: case OAND: case OOR: case OXOR: case OLSHR: case OASHL: case OASHR: /* * immediate operands */ if(nn != Z) if(r->op == OCONST) if(!typefd[n->type->etype]) { cgen(l, nn); if(r->vconst == 0) if(o != OAND) break; if(nn != Z) gopcode(o, r, Z, nn); break; } case OLMUL: case OLDIV: case OLMOD: case OMUL: case ODIV: case OMOD: if(nn == Z) { nullwarn(l, r); break; } if(o == OMUL || o == OLMUL) { if(mulcon(n, nn)) break; } if(l->complex >= r->complex) { regalloc(&nod, l, nn); cgen(l, &nod); regalloc(&nod1, r, Z); cgen(r, &nod1); gopcode(o, &nod1, Z, &nod); } else { regalloc(&nod, r, nn); cgen(r, &nod); regalloc(&nod1, l, Z); cgen(l, &nod1); gopcode(o, &nod, &nod1, &nod); } gopcode(OAS, &nod, Z, nn); regfree(&nod); regfree(&nod1); break; case OASLSHR: case OASASHL: case OASASHR: case OASAND: case OASADD: case OASSUB: case OASXOR: case OASOR: if(l->op == OBIT) goto asbitop; if(r->op == OCONST) if(!typefd[r->type->etype]) if(!typefd[n->type->etype]) { if(l->addable < INDEXED) reglcgen(&nod2, l, Z); else nod2 = *l; regalloc(&nod, r, nn); gopcode(OAS, &nod2, Z, &nod); gopcode(o, r, Z, &nod); gopcode(OAS, &nod, Z, &nod2); regfree(&nod); if(l->addable < INDEXED) regfree(&nod2); break; } case OASLMUL: case OASLDIV: case OASLMOD: case OASMUL: case OASDIV: case OASMOD: if(l->op == OBIT) goto asbitop; if(l->complex >= r->complex) { if(l->addable < INDEXED) reglcgen(&nod2, l, Z); else nod2 = *l; regalloc(&nod1, r, Z); cgen(r, &nod1); } else { regalloc(&nod1, r, Z); cgen(r, &nod1); if(l->addable < INDEXED) reglcgen(&nod2, l, Z); else nod2 = *l; } regalloc(&nod, n, nn); gmove(&nod2, &nod); gopcode(o, &nod1, Z, &nod); gmove(&nod, &nod2); if(nn != Z) gopcode(OAS, &nod, Z, nn); regfree(&nod); regfree(&nod1); if(l->addable < INDEXED) regfree(&nod2); break; asbitop: regalloc(&nod4, n, nn); if(l->complex >= r->complex) { bitload(l, &nod, &nod1, &nod2, &nod4); regalloc(&nod3, r, Z); cgen(r, &nod3); } else { regalloc(&nod3, r, Z); cgen(r, &nod3); bitload(l, &nod, &nod1, &nod2, &nod4); } gmove(&nod, &nod4); gopcode(o, &nod3, Z, &nod4); regfree(&nod3); gmove(&nod4, &nod); regfree(&nod4); bitstore(l, &nod, &nod1, &nod2, nn); break; case OADDR: if(nn == Z) { nullwarn(l, Z); break; } lcgen(l, nn); break; case OFUNC: if(l->complex >= FNX) { if(l->op != OIND) diag(n, "bad function call"); regret(&nod, l->left); cgen(l->left, &nod); regsalloc(&nod1, l->left); gopcode(OAS, &nod, Z, &nod1); regfree(&nod); nod = *n; nod.left = &nod2; nod2 = *l; nod2.left = &nod1; nod2.complex = 1; cgen(&nod, nn); return; } o = reg[REGARG]; gargs(r, &nod, &nod1); if(l->addable < INDEXED) { reglcgen(&nod, l, Z); gopcode(OFUNC, Z, Z, &nod); regfree(&nod); } else gopcode(OFUNC, Z, Z, l); if(REGARG) if(o != reg[REGARG]) reg[REGARG]--; if(nn != Z) { regret(&nod, n); gopcode(OAS, &nod, Z, nn); regfree(&nod); } break; case OIND: if(nn == Z) { nullwarn(l, Z); break; } regialloc(&nod, n, nn); r = l; while(r->op == OADD) r = r->right; if(sconst(r)) { v = r->vconst; r->vconst = 0; cgen(l, &nod); nod.xoffset += v; r->vconst = v; } else cgen(l, &nod); regind(&nod, n); gopcode(OAS, &nod, Z, nn); regfree(&nod); break; case OEQ: case ONE: case OLE: case OLT: case OGE: case OGT: case OLO: case OLS: case OHI: case OHS: if(nn == Z) { nullwarn(l, r); break; } boolgen(n, 1, nn); break; case OANDAND: case OOROR: boolgen(n, 1, nn); if(nn == Z) patch(p, pc); break; case ONOT: if(nn == Z) { nullwarn(l, Z); break; } boolgen(n, 1, nn); break; case OCOMMA: cgen(l, Z); cgen(r, nn); break; case OCAST: if(nn == Z) { nullwarn(l, Z); break; } /* * convert from types l->n->nn */ if(nocast(l->type, n->type)) { if(nocast(n->type, nn->type)) { cgen(l, nn); break; } } regalloc(&nod, l, nn); cgen(l, &nod); regalloc(&nod1, n, &nod); gopcode(OAS, &nod, Z, &nod1); gopcode(OAS, &nod1, Z, nn); regfree(&nod1); regfree(&nod); break; case ODOT: sugen(l, nodrat, l->type->width); if(nn != Z) { warn(n, "non-interruptable temporary"); nod = *nodrat; if(!r || r->op != OCONST) { diag(n, "DOT and no offset"); break; } nod.xoffset += (long)r->vconst; nod.type = n->type; cgen(&nod, nn); } break; case OCOND: bcgen(l, 1); p1 = p; cgen(r->left, nn); gbranch(OGOTO); patch(p1, pc); p1 = p; cgen(r->right, nn); patch(p1, pc); break; case OPOSTINC: case OPOSTDEC: v = 1; if(l->type->etype == TIND) v = l->type->link->width; if(o == OPOSTDEC) v = -v; if(l->op == OBIT) goto bitinc; if(nn == Z) goto pre; if(l->addable < INDEXED) reglcgen(&nod2, l, Z); else nod2 = *l; regalloc(&nod, l, nn); gopcode(OAS, &nod2, Z, &nod); regalloc(&nod1, l, Z); if(typefd[l->type->etype]) { regalloc(&nod3, l, Z); if(v < 0) { gopcode(OAS, nodfconst(-v), Z, &nod3); gopcode(OSUB, &nod3, &nod, &nod1); } else { gopcode(OAS, nodfconst(v), Z, &nod3); gopcode(OADD, &nod3, &nod, &nod1); } regfree(&nod3); } else gopcode(OADD, nodconst(v), &nod, &nod1); gopcode(OAS, &nod1, Z, &nod2); regfree(&nod); regfree(&nod1); if(l->addable < INDEXED) regfree(&nod2); break; case OPREINC: case OPREDEC: v = 1; if(l->type->etype == TIND) v = l->type->link->width; if(o == OPREDEC) v = -v; if(l->op == OBIT) goto bitinc; pre: if(l->addable < INDEXED) reglcgen(&nod2, l, Z); else nod2 = *l; regalloc(&nod, l, nn); gopcode(OAS, &nod2, Z, &nod); if(typefd[l->type->etype]) { regalloc(&nod3, l, Z); if(v < 0) { gopcode(OAS, nodfconst(-v), Z, &nod3); gopcode(OSUB, &nod3, Z, &nod); } else { gopcode(OAS, nodfconst(v), Z, &nod3); gopcode(OADD, &nod3, Z, &nod); } regfree(&nod3); } else gopcode(OADD, nodconst(v), Z, &nod); gopcode(OAS, &nod, Z, &nod2); if(nn && l->op == ONAME) /* in x=++i, emit USED(i) */ gins(ANOP, l, Z); regfree(&nod); if(l->addable < INDEXED) regfree(&nod2); break; bitinc: if(nn != Z && (o == OPOSTINC || o == OPOSTDEC)) { bitload(l, &nod, &nod1, &nod2, Z); gopcode(OAS, &nod, Z, nn); gopcode(OADD, nodconst(v), Z, &nod); bitstore(l, &nod, &nod1, &nod2, Z); break; } bitload(l, &nod, &nod1, &nod2, nn); gopcode(OADD, nodconst(v), Z, &nod); bitstore(l, &nod, &nod1, &nod2, nn); break; } cursafe = curs; }
/* else binary */ void swit1(C1 *q, int nc, long def, int g, Node *n) { C1 *r, *s; int i, l, m, y; long v, range; Prog *sp1, *sp2; /* note that g and g+1 are not allocated */ if(nc <= N1) goto linear; y = 23*nc/100 + 5; /* number of cases needed to make */ if(y < N2) /* direct switch worthwile */ y = N2; /* try to do better than n**2 here */ for(m=nc; m>=y; m--) { /* m is number of cases */ s = q+nc; r = s-m; for(l=nc-m; l>=0; l--) { /* l is base of contig cases */ s--; range = s->val - r->val; if(range > 0 && range <= N3*m) goto direct; r--; } } /* * divide and conquer */ i = nc / 2; r = q+i; v = r->val; /* compare median */ if(v >= -128 && v < 128) { gopcode(OAS, n->type, D_CONST, nodconst(v), g+1, n); gopcode(OEQ, n->type, g, n, g+1, n); } else gopcode(OEQ, n->type, g, n, D_CONST, nodconst(v)); gbranch(OLT); sp1 = p; gbranch(OGT); sp2 = p; gbranch(OGOTO); patch(p, r->label); patch(sp1, pc); swit1(q, i, def, g, n); patch(sp2, pc); swit1(r+1, nc-i-1, def, g, n); return; direct: /* compare low bound */ v = r->val; if(v >= -128 && v < 128) { gopcode(OAS, n->type, D_CONST, nodconst(v), g+1, n); gopcode(OEQ, n->type, g, n, g+1, n); } else gopcode(OEQ, n->type, g, n, D_CONST, nodconst(v)); gbranch(OLT); sp1 = p; /* compare high bound */ v = s->val; if(v >= -128 && v < 128) { gopcode(OAS, n->type, D_CONST, nodconst(v), g+1, n); gopcode(OEQ, n->type, g, n, g+1, n); } else gopcode(OEQ, n->type, g, n, D_CONST, nodconst(v)); gbranch(OGT); sp2 = p; /* switch */ v = r->val; gpseudo(AMOVW, symstatic, D_R0, 0L); p->from.offset = nstatic - v*2; p->from.index = g|I_INDEX1; p->from.scale = 5; nextpc(); p->as = ACASEW; /* table */ for(i=0; i<=range; i++) { gbranch(OCASE); if(v == r->val) { patch(p, r->label); r++; } else patch(p, def); p->from.type = D_STATIC; p->from.sym = symstatic; p->from.offset = nstatic; nstatic += types[TSHORT]->width; v++; } gbranch(OGOTO); patch(p, def); if(r != s+1) print("smelly direct switch\n"); if(l > 0) { patch(sp1, pc); swit1(q, l, def, g, n); } else patch(sp1, def); m += l; if(m < nc) { patch(sp2, pc); swit1(q+m, nc-m, def, g, n); } else patch(sp2, def); return; linear: for(i=0; i<nc; i++) { v = q->val; if(v >= -128 && v < 128) { gopcode(OAS, n->type, D_CONST, nodconst(v), g+1, n); gopcode(OEQ, n->type, g+1, n, g, n); } else gopcode(OEQ, n->type, g, n, D_CONST, nodconst(v)); gbranch(OEQ); patch(p, q->label); q++; } gbranch(OGOTO); patch(p, def); }
int glabel(void) { return gbranch(CodeLabel); }