#include "gc.h" static int resvreg[nelem(reg)]; void ginit(void) { int i; Type *t; thechar = '6'; thestring = "amd64"; exregoffset = REGEXT; exfregoffset = FREGEXT; listinit(); nstring = 0; mnstring = 0; nrathole = 0; pc = 0; breakpc = -1; continpc = -1; cases = C; firstp = P; lastp = P; tfield = types[TINT]; typeword = typechlvp; typeswitch = typechlv; typecmplx = typesu; /* TO DO */ memmove(typechlpv, typechlp, sizeof(typechlpv)); typechlpv[TVLONG] = 1; typechlpv[TUVLONG] = 1; zprog.link = P; zprog.as = AGOK; zprog.from.type = D_NONE; zprog.from.index = D_NONE; zprog.from.scale = 0; zprog.to = zprog.from; lregnode.op = OREGISTER; lregnode.class = CEXREG; lregnode.reg = REGTMP; lregnode.complex = 0; lregnode.addable = 11; lregnode.type = types[TLONG]; qregnode = lregnode; qregnode.type = types[TVLONG]; constnode.op = OCONST; constnode.class = CXXX; constnode.complex = 0; constnode.addable = 20; constnode.type = types[TLONG]; vconstnode = constnode; vconstnode.type = types[TVLONG]; fconstnode.op = OCONST; fconstnode.class = CXXX; fconstnode.complex = 0; fconstnode.addable = 20; fconstnode.type = types[TDOUBLE]; nodsafe = new(ONAME, Z, Z); nodsafe->sym = slookup(".safe"); nodsafe->type = types[TINT]; nodsafe->etype = types[TINT]->etype; nodsafe->class = CAUTO; complex(nodsafe); t = typ(TARRAY, types[TCHAR]); symrathole = slookup(".rathole"); symrathole->class = CGLOBL; symrathole->type = t; nodrat = new(ONAME, Z, Z); nodrat->sym = symrathole; nodrat->type = types[TIND]; nodrat->etype = TVOID; nodrat->class = CGLOBL; complex(nodrat); nodrat->type = t; nodret = new(ONAME, Z, Z); nodret->sym = slookup(".ret"); nodret->type = types[TIND]; nodret->etype = TIND; nodret->class = CPARAM; nodret = new(OIND, nodret, Z); complex(nodret); if(0) com64init(); memset(reg, 0, sizeof(reg)); for(i=0; i= D_AX && i <= D_R15 && i != D_SP) reg[i] = 0; if(i >= D_X0 && i <= D_X7) reg[i] = 0; } /* keep two external registers */ reg[REGEXT] = 1; reg[REGEXT-1] = 1; memmove(resvreg, reg, sizeof(resvreg)); } void gclean(void) { int i; Sym *s; reg[D_SP]--; for(i=D_AX; i<=D_R15; i++) if(reg[i] && !resvreg[i]) diag(Z, "reg %R left allocated", i); for(i=D_X0; i<=D_X7; i++) if(reg[i] && !resvreg[i]) diag(Z, "reg %R left allocated", i); while(mnstring) outstring("", 1L); symstring->type->width = nstring; symrathole->type->width = nrathole; for(i=0; ilink) { if(s->type == T) continue; if(s->type->width == 0) continue; if(s->class != CGLOBL && s->class != CSTATIC) continue; if(s->type == types[TENUM]) continue; gpseudo(AGLOBL, s, nodconst(s->type->width)); } nextpc(); p->as = AEND; outcode(); } void nextpc(void) { p = alloc(sizeof(*p)); *p = zprog; p->lineno = nearln; pc++; if(firstp == P) { firstp = p; lastp = p; return; } lastp->link = p; lastp = p; } void gargs(Node *n, Node *tn1, Node *tn2) { long regs; Node fnxargs[20], *fnxp; regs = cursafe; fnxp = fnxargs; garg1(n, tn1, tn2, 0, &fnxp); /* compile fns to temps */ curarg = 0; fnxp = fnxargs; garg1(n, tn1, tn2, 1, &fnxp); /* compile normal args and temps */ cursafe = regs; } int nareg(void) { int i, n; n = 0; for(i=D_AX; i<=D_R15; i++) if(reg[i] == 0 && !resvreg[i]) n++; return n; } void garg1(Node *n, Node *tn1, Node *tn2, int f, Node **fnxp) { Node nod; if(n == Z) return; if(n->op == OLIST) { garg1(n->left, tn1, tn2, f, fnxp); garg1(n->right, tn1, tn2, f, fnxp); return; } if(f == 0) { if(n->complex >= FNX) { regsalloc(*fnxp, n); nod = znode; nod.op = OAS; nod.left = *fnxp; nod.right = n; nod.type = n->type; cgen(&nod, Z); (*fnxp)++; } return; } if(typesu[n->type->etype]) { regaalloc(tn2, n); if(n->complex >= FNX) { sugen(*fnxp, tn2, n->type->width); (*fnxp)++; } else sugen(n, tn2, n->type->width); return; } if(REGARG && curarg == 0 && typechlpv[n->type->etype]) { regaalloc1(tn1, n); if(n->complex >= FNX) { cgen(*fnxp, tn1); (*fnxp)++; } else cgen(n, tn1); return; } if(vconst(n) == 0) { regaalloc(tn2, n); gmove(n, tn2); return; } regalloc(tn1, n, Z); if(n->complex >= FNX) { cgen(*fnxp, tn1); (*fnxp)++; } else cgen(n, tn1); regaalloc(tn2, n); gmove(tn1, tn2); regfree(tn1); } Node* nodgconst(vlong v, Type *t) { if(!typev[t->etype]) return nodconst((long)v); vconstnode.vconst = v; return &vconstnode; } Node* nodconst(long v) { constnode.vconst = v; return &constnode; } Node* nodfconst(double d) { fconstnode.fconst = d; return &fconstnode; } int isreg(Node *n, int r) { if(n->op == OREGISTER) if(n->reg == r) return 1; return 0; } int nodreg(Node *n, Node *nn, int r) { int et; *n = qregnode; n->reg = r; if(nn != Z){ et = nn->type->etype; if(!typefd[et] && nn->type->width <= SZ_LONG && 0) n->type = typeu[et]? types[TUINT]: types[TINT]; else n->type = nn->type; //print("nodreg %s [%s]\n", tnames[et], tnames[n->type->etype]); n->lineno = nn->lineno; } if(reg[r] == 0) return 0; if(nn != Z) { if(nn->op == OREGISTER) if(nn->reg == r) return 0; } return 1; } void regret(Node *n, Node *nn) { int r; r = REGRET; if(typefd[nn->type->etype]) r = FREGRET; nodreg(n, nn, r); reg[r]++; } void regalloc(Node *n, Node *tn, Node *o) { int i; switch(tn->type->etype) { case TCHAR: case TUCHAR: case TSHORT: case TUSHORT: case TINT: case TUINT: case TLONG: case TULONG: case TVLONG: case TUVLONG: case TIND: if(o != Z && o->op == OREGISTER) { i = o->reg; if(i >= D_AX && i <= D_R15) goto out; } for(i=D_AX; i<=D_R15; i++) if(reg[i] == 0 && !resvreg[i]) goto out; diag(tn, "out of fixed registers"); goto err; case TFLOAT: case TDOUBLE: if(o != Z && o->op == OREGISTER) { i = o->reg; if(i >= D_X0 && i <= D_X7) goto out; } for(i=D_X0; i<=D_X7; i++) if(reg[i] == 0 && !resvreg[i]) goto out; diag(tn, "out of float registers"); goto out; } diag(tn, "unknown type in regalloc: %T", tn->type); err: i = 0; out: if(i) reg[i]++; nodreg(n, tn, i); } void regialloc(Node *n, Node *tn, Node *o) { Node nod; nod = *tn; nod.type = types[TIND]; regalloc(n, &nod, o); } void regfree(Node *n) { int i; i = 0; if(n->op != OREGISTER && n->op != OINDREG) goto err; i = n->reg; if(i < 0 || i >= sizeof(reg)) goto err; if(reg[i] <= 0) goto err; reg[i]--; return; err: diag(n, "error in regfree: %R", i); } void regsalloc(Node *n, Node *nn) { cursafe = align(cursafe, nn->type, Aaut3); maxargsafe = maxround(maxargsafe, cursafe+curarg); *n = *nodsafe; n->xoffset = -(stkoff + cursafe); n->type = nn->type; n->etype = nn->type->etype; n->lineno = nn->lineno; } void regaalloc1(Node *n, Node *nn) { nodreg(n, nn, REGARG); reg[REGARG]++; curarg = align(curarg, nn->type, Aarg1); curarg = align(curarg, nn->type, Aarg2); maxargsafe = maxround(maxargsafe, cursafe+curarg); } void regaalloc(Node *n, Node *nn) { curarg = align(curarg, nn->type, Aarg1); *n = *nn; n->op = OINDREG; n->reg = REGSP; n->xoffset = curarg; n->complex = 0; n->addable = 20; curarg = align(curarg, nn->type, Aarg2); maxargsafe = maxround(maxargsafe, cursafe+curarg); } void regind(Node *n, Node *nn) { if(n->op != OREGISTER) { diag(n, "regind not OREGISTER"); return; } n->op = OINDREG; n->type = nn->type; } void naddr(Node *n, Adr *a) { long v; a->type = D_NONE; if(n == Z) return; switch(n->op) { default: bad: diag(n, "bad in naddr: %O %D", n->op, a); break; case OREGISTER: a->type = n->reg; a->sym = S; break; case OIND: naddr(n->left, a); if(a->type >= D_AX && a->type <= D_R15) a->type += D_INDIR; else if(a->type == D_CONST) a->type = D_NONE+D_INDIR; else if(a->type == D_ADDR) { a->type = a->index; a->index = D_NONE; } else goto bad; break; case OINDEX: a->type = idx.ptr; if(n->left->op == OADDR || n->left->op == OCONST) naddr(n->left, a); if(a->type >= D_AX && a->type <= D_R15) a->type += D_INDIR; else if(a->type == D_CONST) a->type = D_NONE+D_INDIR; else if(a->type == D_ADDR) { a->type = a->index; a->index = D_NONE; } else goto bad; a->index = idx.reg; a->scale = n->scale; a->offset += n->xoffset; break; case OINDREG: a->type = n->reg+D_INDIR; a->sym = S; a->offset = n->xoffset; break; case ONAME: a->etype = n->etype; a->type = D_STATIC; a->sym = n->sym; a->offset = n->xoffset; if(n->class == CSTATIC) break; if(n->class == CEXTERN || n->class == CGLOBL) { a->type = D_EXTERN; break; } if(n->class == CAUTO) { a->type = D_AUTO; break; } if(n->class == CPARAM) { a->type = D_PARAM; break; } goto bad; case OCONST: if(typefd[n->type->etype]) { a->type = D_FCONST; a->dval = n->fconst; break; } a->sym = S; a->type = D_CONST; if(typev[n->type->etype] || n->type->etype == TIND) a->offset = n->vconst; else a->offset = convvtox(n->vconst, typeu[n->type->etype]? TULONG: TLONG); break; case OADDR: naddr(n->left, a); if(a->type >= D_INDIR) { a->type -= D_INDIR; break; } if(a->type == D_EXTERN || a->type == D_STATIC || a->type == D_AUTO || a->type == D_PARAM) if(a->index == D_NONE) { a->index = a->type; a->type = D_ADDR; break; } goto bad; case OADD: if(n->right->op == OCONST) { v = n->right->vconst; naddr(n->left, a); } else if(n->left->op == OCONST) { v = n->left->vconst; naddr(n->right, a); } else goto bad; a->offset += v; break; } } void gcmp(int op, Node *n, vlong val) { Node *cn, nod; cn = nodgconst(val, n->type); if(!immconst(cn)){ regalloc(&nod, n, Z); gmove(cn, &nod); gopcode(op, n->type, n, &nod); regfree(&nod); }else gopcode(op, n->type, n, cn); } #define CASE(a,b) ((a<<8)|(b<<0)) void gmove(Node *f, Node *t) { int ft, tt, t64, a; Node nod, nod1, nod2, nod3; Prog *p1, *p2; ft = f->type->etype; tt = t->type->etype; t64 = tt == TVLONG || tt == TUVLONG || tt == TIND; if(debug['M']) print("gop: %O %O[%s],%O[%s]\n", OAS, f->op, tnames[ft], t->op, tnames[tt]); if(typefd[ft] && f->op == OCONST) { /* TO DO: pick up special constants, possibly preloaded */ if(f->fconst == 0.0){ regalloc(&nod, t, t); gins(AXORPD, &nod, &nod); gmove(&nod, t); regfree(&nod); return; } } /* * load */ if(f->op == ONAME || f->op == OINDREG || f->op == OIND || f->op == OINDEX) switch(ft) { case TCHAR: a = AMOVBLSX; if(t64) a = AMOVBQSX; goto ld; case TUCHAR: a = AMOVBLZX; if(t64) a = AMOVBQZX; goto ld; case TSHORT: a = AMOVWLSX; if(t64) a = AMOVWQSX; goto ld; case TUSHORT: a = AMOVWLZX; if(t64) a = AMOVWQZX; goto ld; case TINT: case TLONG: if(typefd[tt]) { regalloc(&nod, t, t); if(tt == TDOUBLE) a = ACVTSL2SD; else a = ACVTSL2SS; gins(a, f, &nod); gmove(&nod, t); regfree(&nod); return; } a = AMOVL; if(t64) a = AMOVLQSX; goto ld; case TUINT: case TULONG: a = AMOVL; if(t64) a = AMOVLQZX; /* could probably use plain MOVL */ goto ld; case TVLONG: if(typefd[tt]) { regalloc(&nod, t, t); if(tt == TDOUBLE) a = ACVTSQ2SD; else a = ACVTSQ2SS; gins(a, f, &nod); gmove(&nod, t); regfree(&nod); return; } case TUVLONG: case TIND: a = AMOVQ; ld: regalloc(&nod, f, t); gins(a, f, &nod); gmove(&nod, t); regfree(&nod); return; case TFLOAT: a = AMOVSS; goto ld; case TDOUBLE: a = AMOVSD; goto ld; } /* * store */ if(t->op == ONAME || t->op == OINDREG || t->op == OIND || t->op == OINDEX) switch(tt) { case TCHAR: case TUCHAR: a = AMOVB; goto st; case TSHORT: case TUSHORT: a = AMOVW; goto st; case TINT: case TUINT: case TLONG: case TULONG: a = AMOVL; goto st; case TVLONG: case TUVLONG: case TIND: a = AMOVQ; goto st; st: if(f->op == OCONST) { gins(a, f, t); return; } fst: regalloc(&nod, t, f); gmove(f, &nod); gins(a, &nod, t); regfree(&nod); return; case TFLOAT: a = AMOVSS; goto fst; case TDOUBLE: a = AMOVSD; goto fst; } /* * convert */ switch(CASE(ft,tt)) { default: /* * integer to integer ******** a = AGOK; break; case CASE( TCHAR, TCHAR): case CASE( TUCHAR, TCHAR): case CASE( TSHORT, TCHAR): case CASE( TUSHORT,TCHAR): case CASE( TINT, TCHAR): case CASE( TUINT, TCHAR): case CASE( TLONG, TCHAR): case CASE( TULONG, TCHAR): case CASE( TCHAR, TUCHAR): case CASE( TUCHAR, TUCHAR): case CASE( TSHORT, TUCHAR): case CASE( TUSHORT,TUCHAR): case CASE( TINT, TUCHAR): case CASE( TUINT, TUCHAR): case CASE( TLONG, TUCHAR): case CASE( TULONG, TUCHAR): case CASE( TSHORT, TSHORT): case CASE( TUSHORT,TSHORT): case CASE( TINT, TSHORT): case CASE( TUINT, TSHORT): case CASE( TLONG, TSHORT): case CASE( TULONG, TSHORT): case CASE( TSHORT, TUSHORT): case CASE( TUSHORT,TUSHORT): case CASE( TINT, TUSHORT): case CASE( TUINT, TUSHORT): case CASE( TLONG, TUSHORT): case CASE( TULONG, TUSHORT): case CASE( TINT, TINT): case CASE( TUINT, TINT): case CASE( TLONG, TINT): case CASE( TULONG, TINT):: case CASE( TINT, TUINT): case CASE( TUINT, TUINT): case CASE( TLONG, TUINT): case CASE( TULONG, TUINT): *****/ a = AMOVL; break; case CASE( TINT, TIND): case CASE( TINT, TVLONG): case CASE( TINT, TUVLONG): case CASE( TLONG, TIND): case CASE( TLONG, TVLONG): case CASE( TLONG, TUVLONG): a = AMOVLQSX; if(f->op == OCONST) { f->vconst &= (uvlong)0xffffffffU; if(f->vconst & 0x80000000) f->vconst |= (vlong)0xffffffff << 32; a = AMOVQ; } break; case CASE( TUINT, TIND): case CASE( TUINT, TVLONG): case CASE( TUINT, TUVLONG): case CASE( TULONG, TVLONG): case CASE( TULONG, TUVLONG): case CASE( TULONG, TIND): a = AMOVLQZX; if(f->op == OCONST) { f->vconst &= (uvlong)0xffffffffU; a = AMOVQ; } break; case CASE( TIND, TCHAR): case CASE( TIND, TUCHAR): case CASE( TIND, TSHORT): case CASE( TIND, TUSHORT): case CASE( TIND, TINT): case CASE( TIND, TUINT): case CASE( TIND, TLONG): case CASE( TIND, TULONG): case CASE( TVLONG, TCHAR): case CASE( TVLONG, TUCHAR): case CASE( TVLONG, TSHORT): case CASE( TVLONG, TUSHORT): case CASE( TVLONG, TINT): case CASE( TVLONG, TUINT): case CASE( TVLONG, TLONG): case CASE( TVLONG, TULONG): case CASE( TUVLONG, TCHAR): case CASE( TUVLONG, TUCHAR): case CASE( TUVLONG, TSHORT): case CASE( TUVLONG, TUSHORT): case CASE( TUVLONG, TINT): case CASE( TUVLONG, TUINT): case CASE( TUVLONG, TLONG): case CASE( TUVLONG, TULONG): a = AMOVQL; if(f->op == OCONST) { f->vconst &= 0xffffffffU; a = AMOVL; } break; case CASE( TIND, TIND): case CASE( TIND, TVLONG): case CASE( TIND, TUVLONG): case CASE( TVLONG, TIND): case CASE( TVLONG, TVLONG): case CASE( TVLONG, TUVLONG): case CASE( TUVLONG, TIND): case CASE( TUVLONG, TVLONG): case CASE( TUVLONG, TUVLONG): a = AMOVQ; break; case CASE( TSHORT, TINT): case CASE( TSHORT, TUINT): case CASE( TSHORT, TLONG): case CASE( TSHORT, TULONG): a = AMOVWLSX; if(f->op == OCONST) { f->vconst &= 0xffff; if(f->vconst & 0x8000) f->vconst |= 0xffff0000; a = AMOVL; } break; case CASE( TSHORT, TVLONG): case CASE( TSHORT, TUVLONG): case CASE( TSHORT, TIND): a = AMOVWQSX; if(f->op == OCONST) { f->vconst &= 0xffff; if(f->vconst & 0x8000){ f->vconst |= 0xffff0000; f->vconst |= (vlong)~0 << 32; } a = AMOVL; } break; case CASE( TUSHORT,TINT): case CASE( TUSHORT,TUINT): case CASE( TUSHORT,TLONG): case CASE( TUSHORT,TULONG): a = AMOVWLZX; if(f->op == OCONST) { f->vconst &= 0xffff; a = AMOVL; } break; case CASE( TUSHORT,TVLONG): case CASE( TUSHORT,TUVLONG): case CASE( TUSHORT,TIND): a = AMOVWQZX; if(f->op == OCONST) { f->vconst &= 0xffff; a = AMOVL; /* MOVL also zero-extends to 64 bits */ } break; case CASE( TCHAR, TSHORT): case CASE( TCHAR, TUSHORT): case CASE( TCHAR, TINT): case CASE( TCHAR, TUINT): case CASE( TCHAR, TLONG): case CASE( TCHAR, TULONG): a = AMOVBLSX; if(f->op == OCONST) { f->vconst &= 0xff; if(f->vconst & 0x80) f->vconst |= 0xffffff00; a = AMOVL; } break; case CASE( TCHAR, TVLONG): case CASE( TCHAR, TUVLONG): case CASE( TCHAR, TIND): a = AMOVBQSX; if(f->op == OCONST) { f->vconst &= 0xff; if(f->vconst & 0x80){ f->vconst |= 0xffffff00; f->vconst |= (vlong)~0 << 32; } a = AMOVQ; } break; case CASE( TUCHAR, TSHORT): case CASE( TUCHAR, TUSHORT): case CASE( TUCHAR, TINT): case CASE( TUCHAR, TUINT): case CASE( TUCHAR, TLONG): case CASE( TUCHAR, TULONG): a = AMOVBLZX; if(f->op == OCONST) { f->vconst &= 0xff; a = AMOVL; } break; case CASE( TUCHAR, TVLONG): case CASE( TUCHAR, TUVLONG): case CASE( TUCHAR, TIND): a = AMOVBQZX; if(f->op == OCONST) { f->vconst &= 0xff; a = AMOVL; /* zero-extends to 64-bits */ } break; /* * float to fix */ case CASE( TFLOAT, TCHAR): case CASE( TFLOAT, TUCHAR): case CASE( TFLOAT, TSHORT): case CASE( TFLOAT, TUSHORT): case CASE( TFLOAT, TINT): case CASE( TFLOAT, TUINT): case CASE( TFLOAT, TLONG): case CASE( TFLOAT, TULONG): case CASE( TFLOAT, TVLONG): case CASE( TFLOAT, TUVLONG): case CASE( TFLOAT, TIND): case CASE( TDOUBLE,TCHAR): case CASE( TDOUBLE,TUCHAR): case CASE( TDOUBLE,TSHORT): case CASE( TDOUBLE,TUSHORT): case CASE( TDOUBLE,TINT): case CASE( TDOUBLE,TUINT): case CASE( TDOUBLE,TLONG): case CASE( TDOUBLE,TULONG): case CASE( TDOUBLE,TVLONG): case CASE( TDOUBLE,TUVLONG): case CASE( TDOUBLE,TIND): regalloc(&nod, t, Z); if(ewidth[tt] == SZ_VLONG || typeu[tt] && ewidth[tt] == SZ_INT){ if(ft == TFLOAT) a = ACVTTSS2SQ; else a = ACVTTSD2SQ; }else{ if(ft == TFLOAT) a = ACVTTSS2SL; else a = ACVTTSD2SL; } gins(a, f, &nod); gmove(&nod, t); regfree(&nod); return; /* * ulong to float */ case CASE( TUVLONG, TDOUBLE): case CASE( TUVLONG, TFLOAT): a = ACVTSQ2SS; if(tt == TDOUBLE) a = ACVTSQ2SD; regalloc(&nod, f, f); gmove(f, &nod); regalloc(&nod1, t, t); gins(ACMPQ, &nod, nodconst(0)); gins(AJLT, Z, Z); p1 = p; gins(a, &nod, &nod1); gins(AJMP, Z, Z); p2 = p; patch(p1, pc); regalloc(&nod2, f, Z); regalloc(&nod3, f, Z); gmove(&nod, &nod2); gins(ASHRQ, nodconst(1), &nod2); gmove(&nod, &nod3); gins(AANDL, nodconst(1), &nod3); gins(AORQ, &nod3, &nod2); gins(a, &nod2, &nod1); gins(tt == TDOUBLE? AADDSD: AADDSS, &nod1, &nod1); regfree(&nod2); regfree(&nod3); patch(p2, pc); regfree(&nod); regfree(&nod1); return; case CASE( TULONG, TDOUBLE): case CASE( TUINT, TDOUBLE): case CASE( TULONG, TFLOAT): case CASE( TUINT, TFLOAT): a = ACVTSQ2SS; if(tt == TDOUBLE) a = ACVTSQ2SD; regalloc(&nod, f, f); gins(AMOVLQZX, f, &nod); regalloc(&nod1, t, t); gins(a, &nod, &nod1); gmove(&nod1, t); regfree(&nod); regfree(&nod1); return; /* * fix to float */ case CASE( TCHAR, TFLOAT): case CASE( TUCHAR, TFLOAT): case CASE( TSHORT, TFLOAT): case CASE( TUSHORT,TFLOAT): case CASE( TINT, TFLOAT): case CASE( TLONG, TFLOAT): case CASE( TVLONG, TFLOAT): case CASE( TIND, TFLOAT): case CASE( TCHAR, TDOUBLE): case CASE( TUCHAR, TDOUBLE): case CASE( TSHORT, TDOUBLE): case CASE( TUSHORT,TDOUBLE): case CASE( TINT, TDOUBLE): case CASE( TLONG, TDOUBLE): case CASE( TVLONG, TDOUBLE): case CASE( TIND, TDOUBLE): regalloc(&nod, t, t); if(ewidth[ft] == SZ_VLONG){ if(tt == TFLOAT) a = ACVTSQ2SS; else a = ACVTSQ2SD; }else{ if(tt == TFLOAT) a = ACVTSL2SS; else a = ACVTSL2SD; } gins(a, f, &nod); gmove(&nod, t); regfree(&nod); return; /* * float to float */ case CASE( TFLOAT, TFLOAT): a = AMOVSS; break; case CASE( TDOUBLE,TFLOAT): a = ACVTSD2SS; break; case CASE( TFLOAT, TDOUBLE): a = ACVTSS2SD; break; case CASE( TDOUBLE,TDOUBLE): a = AMOVSD; break; } if(a == AMOVQ || a == AMOVSD || a == AMOVSS || a == AMOVL && ewidth[ft] == ewidth[tt]) /* TO DO: check AMOVL */ if(samaddr(f, t)) return; gins(a, f, t); } void doindex(Node *n) { Node nod, nod1; long v; if(debug['Y']) prtree(n, "index"); if(n->left->complex >= FNX) print("botch in doindex\n"); regalloc(&nod, &qregnode, Z); v = constnode.vconst; cgen(n->right, &nod); idx.ptr = D_NONE; if(n->left->op == OCONST) idx.ptr = D_CONST; else if(n->left->op == OREGISTER) idx.ptr = n->left->reg; else if(n->left->op != OADDR) { reg[D_BP]++; // cant be used as a base regalloc(&nod1, &qregnode, Z); cgen(n->left, &nod1); idx.ptr = nod1.reg; regfree(&nod1); reg[D_BP]--; } idx.reg = nod.reg; regfree(&nod); constnode.vconst = v; } void gins(int a, Node *f, Node *t) { if(f != Z && f->op == OINDEX) doindex(f); if(t != Z && t->op == OINDEX) doindex(t); nextpc(); p->as = a; if(f != Z) naddr(f, &p->from); if(t != Z) naddr(t, &p->to); if(debug['g']) print("%P\n", p); } void gopcode(int o, Type *ty, Node *f, Node *t) { int a, et; et = TLONG; if(ty != T) et = ty->etype; if(debug['M']) { if(f != Z && f->type != T) print("gop: %O %O[%s],", o, f->op, tnames[et]); else print("gop: %O Z,", o); if(t != Z && t->type != T) print("%O[%s]\n", t->op, tnames[t->type->etype]); else print("Z\n"); } a = AGOK; switch(o) { case OCOM: a = ANOTL; if(et == TCHAR || et == TUCHAR) a = ANOTB; if(et == TSHORT || et == TUSHORT) a = ANOTW; if(et == TVLONG || et == TUVLONG || et == TIND) a = ANOTQ; break; case ONEG: a = ANEGL; if(et == TCHAR || et == TUCHAR) a = ANEGB; if(et == TSHORT || et == TUSHORT) a = ANEGW; if(et == TVLONG || et == TUVLONG || et == TIND) a = ANEGQ; break; case OADDR: a = ALEAQ; break; case OASADD: case OADD: a = AADDL; if(et == TCHAR || et == TUCHAR) a = AADDB; if(et == TSHORT || et == TUSHORT) a = AADDW; if(et == TVLONG || et == TUVLONG || et == TIND) a = AADDQ; if(et == TFLOAT) a = AADDSS; if(et == TDOUBLE) a = AADDSD; break; case OASSUB: case OSUB: a = ASUBL; if(et == TCHAR || et == TUCHAR) a = ASUBB; if(et == TSHORT || et == TUSHORT) a = ASUBW; if(et == TVLONG || et == TUVLONG || et == TIND) a = ASUBQ; if(et == TFLOAT) a = ASUBSS; if(et == TDOUBLE) a = ASUBSD; break; case OASOR: case OOR: a = AORL; if(et == TCHAR || et == TUCHAR) a = AORB; if(et == TSHORT || et == TUSHORT) a = AORW; if(et == TVLONG || et == TUVLONG || et == TIND) a = AORQ; break; case OASAND: case OAND: a = AANDL; if(et == TCHAR || et == TUCHAR) a = AANDB; if(et == TSHORT || et == TUSHORT) a = AANDW; if(et == TVLONG || et == TUVLONG || et == TIND) a = AANDQ; break; case OASXOR: case OXOR: a = AXORL; if(et == TCHAR || et == TUCHAR) a = AXORB; if(et == TSHORT || et == TUSHORT) a = AXORW; if(et == TVLONG || et == TUVLONG || et == TIND) a = AXORQ; break; case OASLSHR: case OLSHR: a = ASHRL; if(et == TCHAR || et == TUCHAR) a = ASHRB; if(et == TSHORT || et == TUSHORT) a = ASHRW; if(et == TVLONG || et == TUVLONG || et == TIND) a = ASHRQ; break; case OASASHR: case OASHR: a = ASARL; if(et == TCHAR || et == TUCHAR) a = ASARB; if(et == TSHORT || et == TUSHORT) a = ASARW; if(et == TVLONG || et == TUVLONG || et == TIND) a = ASARQ; break; case OASASHL: case OASHL: a = ASALL; if(et == TCHAR || et == TUCHAR) a = ASALB; if(et == TSHORT || et == TUSHORT) a = ASALW; if(et == TVLONG || et == TUVLONG || et == TIND) a = ASALQ; break; case OROL: a = AROLL; if(et == TCHAR || et == TUCHAR) a = AROLB; if(et == TSHORT || et == TUSHORT) a = AROLW; if(et == TVLONG || et == TUVLONG || et == TIND) a = AROLQ; break; case OFUNC: a = ACALL; break; case OASMUL: case OMUL: if(f->op == OREGISTER && t != Z && isreg(t, D_AX) && reg[D_DX] == 0) t = Z; a = AIMULL; if(et == TVLONG || et == TUVLONG || et == TIND) a = AIMULQ; if(et == TFLOAT) a = AMULSS; if(et == TDOUBLE) a = AMULSD; break; case OASMOD: case OMOD: case OASDIV: case ODIV: a = AIDIVL; if(et == TVLONG || et == TUVLONG || et == TIND) a = AIDIVQ; if(et == TFLOAT) a = ADIVSS; if(et == TDOUBLE) a = ADIVSD; break; case OASLMUL: case OLMUL: a = AMULL; if(et == TVLONG || et == TUVLONG || et == TIND) a = AMULQ; break; case OASLMOD: case OLMOD: case OASLDIV: case OLDIV: a = ADIVL; if(et == TVLONG || et == TUVLONG || et == TIND) a = ADIVQ; break; case OEQ: case ONE: case OLT: case OLE: case OGE: case OGT: case OLO: case OLS: case OHS: case OHI: a = ACMPL; if(et == TCHAR || et == TUCHAR) a = ACMPB; if(et == TSHORT || et == TUSHORT) a = ACMPW; if(et == TVLONG || et == TUVLONG || et == TIND) a = ACMPQ; if(et == TFLOAT) a = AUCOMISS; if(et == TDOUBLE) a = AUCOMISD; gins(a, f, t); switch(o) { case OEQ: a = AJEQ; break; case ONE: a = AJNE; break; case OLT: a = AJLT; break; case OLE: a = AJLE; break; case OGE: a = AJGE; break; case OGT: a = AJGT; break; case OLO: a = AJCS; break; case OLS: a = AJLS; break; case OHS: a = AJCC; break; case OHI: a = AJHI; break; } gins(a, Z, Z); return; } if(a == AGOK) diag(Z, "bad in gopcode %O", o); gins(a, f, t); } int samaddr(Node *f, Node *t) { return f->op == OREGISTER && t->op == OREGISTER && f->reg == t->reg; } void gbranch(int o) { int a; a = AGOK; switch(o) { case ORETURN: a = ARET; break; case OGOTO: a = AJMP; break; } nextpc(); if(a == AGOK) { diag(Z, "bad in gbranch %O", o); nextpc(); } p->as = a; } void patch(Prog *op, long pc) { op->to.offset = pc; op->to.type = D_BRANCH; } void gpseudo(int a, Sym *s, Node *n) { nextpc(); p->as = a; p->from.type = D_EXTERN; p->from.sym = s; p->from.scale = (profileflg ? 0 : NOPROF); if(s->class == CSTATIC) p->from.type = D_STATIC; naddr(n, &p->to); if(a == ADATA || a == AGLOBL) pc--; } int sconst(Node *n) { long v; if(n->op == OCONST && !typefd[n->type->etype]) { v = n->vconst; if(v >= -32766L && v < 32766L) return 1; } return 0; } long exreg(Type *t) { long o; if(typechlpv[t->etype]) { if(exregoffset <= REGEXT-4) return 0; o = exregoffset; exregoffset--; return o; } return 0; } schar ewidth[NTYPE] = { -1, /*[TXXX]*/ SZ_CHAR, /*[TCHAR]*/ SZ_CHAR, /*[TUCHAR]*/ SZ_SHORT, /*[TSHORT]*/ SZ_SHORT, /*[TUSHORT]*/ SZ_INT, /*[TINT]*/ SZ_INT, /*[TUINT]*/ SZ_LONG, /*[TLONG]*/ SZ_LONG, /*[TULONG]*/ SZ_VLONG, /*[TVLONG]*/ SZ_VLONG, /*[TUVLONG]*/ SZ_FLOAT, /*[TFLOAT]*/ SZ_DOUBLE, /*[TDOUBLE]*/ SZ_IND, /*[TIND]*/ 0, /*[TFUNC]*/ -1, /*[TARRAY]*/ 0, /*[TVOID]*/ -1, /*[TSTRUCT]*/ -1, /*[TUNION]*/ SZ_INT, /*[TENUM]*/ }; long ncast[NTYPE] = { 0, /*[TXXX]*/ BCHAR|BUCHAR, /*[TCHAR]*/ BCHAR|BUCHAR, /*[TUCHAR]*/ BSHORT|BUSHORT, /*[TSHORT]*/ BSHORT|BUSHORT, /*[TUSHORT]*/ BINT|BUINT|BLONG|BULONG, /*[TINT]*/ BINT|BUINT|BLONG|BULONG, /*[TUINT]*/ BINT|BUINT|BLONG|BULONG, /*[TLONG]*/ BINT|BUINT|BLONG|BULONG, /*[TULONG]*/ BVLONG|BUVLONG|BIND, /*[TVLONG]*/ BVLONG|BUVLONG|BIND, /*[TUVLONG]*/ BFLOAT, /*[TFLOAT]*/ BDOUBLE, /*[TDOUBLE]*/ BVLONG|BUVLONG|BIND, /*[TIND]*/ 0, /*[TFUNC]*/ 0, /*[TARRAY]*/ 0, /*[TVOID]*/ BSTRUCT, /*[TSTRUCT]*/ BUNION, /*[TUNION]*/ 0, /*[TENUM]*/ };