/* * code for the end of a function * deals with struct return here * The return value is in (or pointed to by) RETREG. */ void efcode(void) { struct symtab *sp; extern int gotnr; TWORD t; NODE *p, *r, *l; int typ, ssz, rno; gotnr = 0; /* new number for next fun */ sp = cftnsp; t = DECREF(sp->stype); if (t != STRTY && t != UNIONTY) return; /* XXX should have one routine for this */ ngpr = nsse = 0; if ((typ = argtyp(t, sp->sdf, sp->sap)) == STRREG || typ == STRCPX) { /* Cast to long pointer and move to the registers */ /* XXX can overrun struct size */ /* XXX check carefully for SSE members */ if ((ssz = tsize(t, sp->sdf, sp->sap)) > SZLONG*2) cerror("efcode1"); if (typ == STRCPX) { t = DOUBLE; rno = XMM0; } else { t = LONG; rno = RAX; } if (ssz > SZLONG) { p = block(REG, NIL, NIL, INCREF(t), 0, 0); regno(p) = RAX; p = buildtree(UMUL, buildtree(PLUS, p, bcon(1)), NIL); ecomp(movtoreg(p, rno+1)); } p = block(REG, NIL, NIL, INCREF(t), 0, 0); regno(p) = RAX; p = buildtree(UMUL, p, NIL); ecomp(movtoreg(p, rno)); } else if (typ == STRMEM) { r = block(REG, NIL, NIL, INCREF(t), sp->sdf, sp->sap); regno(r) = RAX; r = buildtree(UMUL, r, NIL); l = tempnode(stroffset, INCREF(t), sp->sdf, sp->sap); l = buildtree(UMUL, l, NIL); ecomp(buildtree(ASSIGN, l, r)); l = block(REG, NIL, NIL, LONG, 0, 0); regno(l) = RAX; r = tempnode(stroffset, LONG, 0, 0); ecomp(buildtree(ASSIGN, l, r)); } else cerror("efcode"); }
/* * Do the "hard work" in assigning correct destination for arguments. * Also convert arguments < INT to inte (default argument promotions). * XXX - should be dome elsewhere. */ static NODE * argput(NODE *p) { NODE *q; TWORD ty; int typ, r, ssz; if (p->n_op == CM) { p->n_left = argput(p->n_left); p->n_right = argput(p->n_right); return p; } /* first arg may be struct return pointer */ /* XXX - check if varargs; setup al */ switch (typ = argtyp(p->n_type, p->n_df, p->n_ap)) { case INTEGER: case SSE: if (typ == SSE) r = XMM0 + nsse++; else r = argregsi[ngpr++]; if (p->n_type < INT || p->n_type == BOOL) p = cast(p, INT, 0); p = movtoreg(p, r); break; case X87: r = nrsp; nrsp += SZLDOUBLE; p = movtomem(p, r, STKREG); break; case SSEMEM: r = nrsp; nrsp += SZDOUBLE; p = movtomem(p, r, STKREG); break; case INTMEM: r = nrsp; nrsp += SZLONG; p = movtomem(p, r, STKREG); break; case STRCPX: case STRREG: /* Struct in registers */ /* Cast to long pointer and move to the registers */ /* XXX can overrun struct size */ /* XXX check carefully for SSE members */ ssz = tsize(p->n_type, p->n_df, p->n_ap); if (typ == STRCPX) { ty = DOUBLE; r = XMM0 + nsse++; } else { ty = LONG; r = argregsi[ngpr++]; } if (ssz <= SZLONG) { q = cast(p->n_left, INCREF(ty), 0); nfree(p); q = buildtree(UMUL, q, NIL); p = movtoreg(q, r); } else if (ssz <= SZLONG*2) { NODE *ql, *qr; qr = cast(ccopy(p->n_left), INCREF(ty), 0); qr = movtoreg(buildtree(UMUL, qr, NIL), r); ql = cast(p->n_left, INCREF(ty), 0); ql = buildtree(UMUL, buildtree(PLUS, ql, bcon(1)), NIL); r = (typ == STRCPX ? XMM0 + nsse++ : argregsi[ngpr++]); ql = movtoreg(ql, r); nfree(p); p = buildtree(CM, ql, qr); } else cerror("STRREG"); break; case STRMEM: { struct symtab s; NODE *l, *t; q = buildtree(UMUL, p->n_left, NIL); s.stype = p->n_type; s.squal = 0; s.sdf = p->n_df; s.sap = p->n_ap; s.soffset = nrsp; s.sclass = AUTO; nrsp += tsize(p->n_type, p->n_df, p->n_ap); l = block(REG, NIL, NIL, PTR+STRTY, 0, 0); l->n_lval = 0; regno(l) = STKREG; t = block(NAME, NIL, NIL, p->n_type, p->n_df, p->n_ap); t->n_sp = &s; t = stref(block(STREF, l, t, 0, 0, 0)); t = (buildtree(ASSIGN, t, q)); nfree(p); p = t->n_left; nfree(t); break; } default: cerror("argument %d", typ); } return p; }
/* * code for the beginning of a function; a is an array of * indices in symtab for the arguments; n is the number */ void bfcode(struct symtab **s, int cnt) { union arglist *al; struct symtab *sp; NODE *p, *r; TWORD t; int i, rno, typ; /* recalculate the arg offset and create TEMP moves */ /* Always do this for reg, even if not optimizing, to free arg regs */ nsse = ngpr = 0; nrsp = ARGINIT; if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) { sp = cftnsp; if (argtyp(DECREF(sp->stype), sp->sdf, sp->sap) == STRMEM) { r = block(REG, NIL, NIL, LONG, 0, MKAP(LONG)); regno(r) = argregsi[ngpr++]; p = tempnode(0, r->n_type, r->n_df, r->n_ap); stroffset = regno(p); ecomp(buildtree(ASSIGN, p, r)); } } for (i = 0; i < cnt; i++) { sp = s[i]; if (sp == NULL) continue; /* XXX when happens this? */ switch (typ = argtyp(sp->stype, sp->sdf, sp->sap)) { case INTEGER: case SSE: if (typ == SSE) rno = XMM0 + nsse++; else rno = argregsi[ngpr++]; r = block(REG, NIL, NIL, sp->stype, sp->sdf, sp->sap); regno(r) = rno; p = tempnode(0, sp->stype, sp->sdf, sp->sap); sp->soffset = regno(p); sp->sflags |= STNODE; ecomp(buildtree(ASSIGN, p, r)); break; case SSEMEM: sp->soffset = nrsp; nrsp += SZDOUBLE; if (xtemps) { p = tempnode(0, sp->stype, sp->sdf, sp->sap); p = buildtree(ASSIGN, p, nametree(sp)); sp->soffset = regno(p->n_left); sp->sflags |= STNODE; ecomp(p); } break; case INTMEM: sp->soffset = nrsp; nrsp += SZLONG; if (xtemps) { p = tempnode(0, sp->stype, sp->sdf, sp->sap); p = buildtree(ASSIGN, p, nametree(sp)); sp->soffset = regno(p->n_left); sp->sflags |= STNODE; ecomp(p); } break; case STRMEM: /* Struct in memory */ sp->soffset = nrsp; nrsp += tsize(sp->stype, sp->sdf, sp->sap); break; case X87: /* long double args */ sp->soffset = nrsp; nrsp += SZLDOUBLE; break; case STRCPX: case STRREG: /* Struct in register */ /* Allocate space on stack for the struct */ /* For simplicity always fetch two longwords */ autooff += (2*SZLONG); if (typ == STRCPX) { t = DOUBLE; rno = XMM0 + nsse++; } else { t = LONG; rno = argregsi[ngpr++]; } r = block(REG, NIL, NIL, t, 0, MKAP(t)); regno(r) = rno; ecomp(movtomem(r, -autooff, FPREG)); if (tsize(sp->stype, sp->sdf, sp->sap) > SZLONG) { r = block(REG, NIL, NIL, t, 0, MKAP(t)); regno(r) = (typ == STRCPX ? XMM0 + nsse++ : argregsi[ngpr++]); ecomp(movtomem(r, -autooff+SZLONG, FPREG)); } sp->soffset = -autooff; break; default: cerror("bfcode: %d", typ); } } /* Check if there are varargs */ if (cftnsp->sdf == NULL || cftnsp->sdf->dfun == NULL) return; /* no prototype */ al = cftnsp->sdf->dfun; for (; al->type != TELLIPSIS; al++) { t = al->type; if (t == TNULL) return; if (BTYPE(t) == STRTY || BTYPE(t) == UNIONTY) al++; for (; t > BTMASK; t = DECREF(t)) if (ISARY(t) || ISFTN(t)) al++; } /* fix stack offset */ SETOFF(autooff, ALMAX); /* Save reg arguments in the reg save area */ p = NIL; for (i = ngpr; i < 6; i++) { r = block(REG, NIL, NIL, LONG, 0, MKAP(LONG)); regno(r) = argregsi[i]; r = movtomem(r, -RSALONGOFF(i)-autooff, FPREG); p = (p == NIL ? r : block(COMOP, p, r, INT, 0, MKAP(INT))); } for (i = nsse; i < 8; i++) { r = block(REG, NIL, NIL, DOUBLE, 0, MKAP(DOUBLE)); regno(r) = i + XMM0; r = movtomem(r, -RSADBLOFF(i)-autooff, FPREG); p = (p == NIL ? r : block(COMOP, p, r, INT, 0, MKAP(INT))); } autooff += RSASZ; rsaoff = autooff; thissse = nsse; thisgpr = ngpr; thisrsp = nrsp; ecomp(p); }