/* * Called with a function call with arguments as argument. * This is done early in buildtree() and only done once. * Returns p. */ NODE * funcode(NODE *p) { NODE *l, *r; TWORD t; int i; nsse = ngpr = nrsp = 0; /* Check if hidden arg needed */ /* If so, add it in pass2 */ if ((l = p->n_left)->n_type == INCREF(FTN)+STRTY || l->n_type == INCREF(FTN)+UNIONTY) { int ssz = tsize(BTYPE(l->n_type), l->n_df, l->n_ap); if (ssz > 2*SZLONG) ngpr++; } /* Convert just regs to assign insn's */ p->n_right = argput(p->n_right); /* Must sort arglist so that STASG ends up first */ /* This avoids registers being clobbered */ while (argsort(p->n_right)) ; /* Check if there are varargs */ if (nsse || l->n_df == NULL || l->n_df->dfun == NULL) { ; /* Need RAX */ } else { union arglist *al = l->n_df->dfun; for (; al->type != TELLIPSIS; al++) { if ((t = al->type) == TNULL) return p; /* No need */ if (ISSOU(BTYPE(t))) al++; for (i = 0; t > BTMASK; t = DECREF(t)) if (ISARY(t) || ISFTN(t)) i++; if (i) al++; } } /* Always emit number of SSE regs used */ l = movtoreg(bcon(nsse), RAX); if (p->n_right->n_op != CM) { p->n_right = block(CM, l, p->n_right, INT, 0, 0); } else { for (r = p->n_right; r->n_left->n_op == CM; r = r->n_left) ; r->n_left = block(CM, l, r->n_left, INT, 0, 0); } return p; }
/* * Fixup struct/unions depending on attributes. */ void gcc_tcattrfix(NODE *p) { struct symtab *sp; struct attr *ap; int sz, coff, csz, al, oal, mxal; if (!ISSOU(p->n_type)) /* only for structs or unions */ return; if ((ap = attr_find(p->n_ap, GCC_ATYP_PACKED)) == NULL) return; /* nothing to fix */ al = ap->iarg(0); mxal = 0; /* Must repack struct */ coff = csz = 0; for (sp = strmemb(ap); sp; sp = sp->snext) { oal = talign(sp->stype, sp->sap); if (oal > al) oal = al; if (mxal < oal) mxal = oal; if (sp->sclass & FIELD) sz = sp->sclass&FLDSIZ; else sz = (int)tsize(sp->stype, sp->sdf, sp->sap); sp->soffset = upoff(sz, oal, &coff); if (coff > csz) csz = coff; if (p->n_type == UNIONTY) coff = 0; } if (mxal < ALCHAR) mxal = ALCHAR; /* for bitfields */ SETOFF(csz, mxal); /* Roundup to whatever */ ap = attr_find(p->n_ap, ATTR_STRUCT); ap->amsize = csz; ap = attr_find(p->n_ap, ATTR_ALIGNED); ap->iarg(0) = mxal; }
NODE * amd64_builtin_va_arg(NODE *f, NODE *a, TWORD t) { NODE *ap, *r, *dp; ap = a->n_left; dp = a->n_right; if (dp->n_type <= ULONGLONG || ISPTR(dp->n_type) || dp->n_type == FLOAT || dp->n_type == DOUBLE) { /* type might be in general register */ if (dp->n_type == FLOAT || dp->n_type == DOUBLE) { f->n_sp = lookup(fpnext, SNORMAL); varneeds |= NEED_FPNEXT; } else { f->n_sp = lookup(gpnext, SNORMAL); varneeds |= NEED_GPNEXT; } f->n_type = f->n_sp->stype = INCREF(dp->n_type) + (FTN-PTR); f->n_ap = dp->n_ap; f->n_df = /* dp->n_df */ NULL; f = clocal(f); r = buildtree(CALL, f, ccopy(ap)); } else if (ISSOU(dp->n_type) || dp->n_type == LDOUBLE) { /* put a reference directly to the stack */ int sz = tsize(dp->n_type, dp->n_df, dp->n_ap); int al = talign(dp->n_type, dp->n_ap); if (al < ALLONG) al = ALLONG; if (sz <= SZLONG*2 && al == ALLONG) { if (sz <= SZLONG) { f->n_sp = lookup(_1regref, SNORMAL); varneeds |= NEED_1REGREF; } else { f->n_sp = lookup(_2regref, SNORMAL); varneeds |= NEED_2REGREF; } f->n_type = f->n_sp->stype; f = clocal(f); r = buildtree(CALL, f, ccopy(ap)); r = ccast(r, INCREF(dp->n_type), 0, dp->n_df, dp->n_ap); r = buildtree(UMUL, r, NIL); } else { f->n_sp = lookup(memref, SNORMAL); varneeds |= NEED_MEMREF; f->n_type = f->n_sp->stype; f = clocal(f); SETOFF(sz, al); r = buildtree(CALL, f, buildtree(CM, ccopy(ap), bcon(sz/SZCHAR))); r = ccast(r, INCREF(dp->n_type), 0, dp->n_df, dp->n_ap); r = buildtree(UMUL, r, NIL); } } else { uerror("amd64_builtin_va_arg not supported type"); goto bad; } tfree(a); return r; bad: uerror("bad argument to __builtin_va_arg"); return bcon(0); }
/* * Called with a function call with arguments as argument. * This is done early in buildtree() and only done once. * Returns p. */ NODE * funcode(NODE *p) { extern int gotnr; #ifdef GCC_COMPAT struct attr *ap; #endif NODE *r, *l; TWORD t = DECREF(DECREF(p->n_left->n_type)); int stcall; stcall = ISSOU(t); /* * We may have to prepend: * - Hidden arg0 for struct return (in reg or on stack). * - ebx in case of PIC code. */ /* Fix function call arguments. On x86, just add funarg */ for (r = p->n_right; r->n_op == CM; r = r->n_left) { if (r->n_right->n_op != STARG) { r->n_right = intprom(r->n_right); r->n_right = block(FUNARG, r->n_right, NIL, r->n_right->n_type, r->n_right->n_df, r->n_right->n_ap); } } if (r->n_op != STARG) { l = talloc(); *l = *r; r->n_op = FUNARG; r->n_left = l; r->n_left = intprom(r->n_left); r->n_type = r->n_left->n_type; } if (stcall) { /* Prepend a placeholder for struct address. */ /* Use BP, can never show up under normal circumstances */ l = talloc(); *l = *r; r->n_op = CM; r->n_right = l; r->n_type = INT; l = block(REG, 0, 0, INCREF(VOID), 0, 0); regno(l) = BP; l = block(FUNARG, l, 0, INCREF(VOID), 0, 0); r->n_left = l; } #ifdef GCC_COMPAT if ((ap = attr_find(p->n_left->n_ap, GCC_ATYP_REGPARM))) rparg = ap->iarg(0); else #endif rparg = 0; regcvt = 0; if (rparg) listf(p->n_right, addreg); return p; }
/* * code for the beginning of a function; a is an array of * indices in symtab for the arguments; n is the number * * Classifying args on i386; not simple: * - Args may be on stack or in registers (regparm) * - There may be a hidden first arg, unless OpenBSD struct return. * - Regparm syntax is not well documented. * - There may be stdcall functions, where the called function pops stack * - ...probably more */ void bfcode(struct symtab **sp, int cnt) { extern int argstacksize; #ifdef GCC_COMPAT struct attr *ap; #endif struct symtab *sp2; extern int gotnr; NODE *n, *p; int i, regparmarg; int argbase, nrarg, sz; argbase = ARGINIT; nrarg = regparmarg = 0; #ifdef GCC_COMPAT if (attr_find(cftnsp->sap, GCC_ATYP_STDCALL) != NULL) cftnsp->sflags |= SSTDCALL; if ((ap = attr_find(cftnsp->sap, GCC_ATYP_REGPARM))) regparmarg = ap->iarg(0); #endif /* Function returns struct, create return arg node */ if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) { { if (regparmarg) { n = block(REG, 0, 0, INT, 0, 0); regno(n) = regpregs[nrarg++]; } else { n = block(OREG, 0, 0, INT, 0, 0); n->n_lval = argbase/SZCHAR; argbase += SZINT; regno(n) = FPREG; } p = tempnode(0, INT, 0, 0); structrettemp = regno(p); p = buildtree(ASSIGN, p, n); ecomp(p); } } /* * Find where all params are so that they end up at the right place. * At the same time recalculate their arg offset on stack. * We also get the "pop size" for stdcall. */ for (i = 0; i < cnt; i++) { sp2 = sp[i]; sz = tsize(sp2->stype, sp2->sdf, sp2->sap); SETOFF(sz, SZINT); if (cisreg(sp2->stype) == 0 || ((regparmarg - nrarg) * SZINT < sz)) { /* not in reg */ sp2->soffset = argbase; argbase += sz; nrarg = regparmarg; /* no more in reg either */ } else { /* in reg */ sp2->soffset = nrarg; nrarg += sz/SZINT; sp2->sclass = REGISTER; } } /* * Now (argbase - ARGINIT) is used space on stack. * Move (if necessary) the args to something new. */ for (i = 0; i < cnt; i++) { int reg, j; sp2 = sp[i]; if (ISSOU(sp2->stype) && sp2->sclass == REGISTER) { /* must move to stack */ sz = tsize(sp2->stype, sp2->sdf, sp2->sap); SETOFF(sz, SZINT); SETOFF(autooff, SZINT); reg = sp2->soffset; sp2->sclass = AUTO; sp2->soffset = NOOFFSET; oalloc(sp2, &autooff); for (j = 0; j < sz/SZCHAR; j += 4) { p = block(OREG, 0, 0, INT, 0, 0); p->n_lval = sp2->soffset/SZCHAR + j; regno(p) = FPREG; n = block(REG, 0, 0, INT, 0, 0); regno(n) = regpregs[reg++]; p = block(ASSIGN, p, n, INT, 0, 0); ecomp(p); } } else if (cisreg(sp2->stype) && !ISSOU(sp2->stype) && ((cqual(sp2->stype, sp2->squal) & VOL) == 0)) { /* just put rest in temps */ if (sp2->sclass == REGISTER) { n = block(REG, 0, 0, sp2->stype, sp2->sdf, sp2->sap); if (ISLONGLONG(sp2->stype)|| sp2->stype == LONG || sp2->stype == ULONG) regno(n) = longregs[sp2->soffset]; else if (DEUNSIGN(sp2->stype) == CHAR || sp2->stype == BOOL) regno(n) = charregs[sp2->soffset]; else regno(n) = regpregs[sp2->soffset]; } else { n = block(OREG, 0, 0, sp2->stype, sp2->sdf, sp2->sap); n->n_lval = sp2->soffset/SZCHAR; regno(n) = FPREG; } p = tempnode(0, sp2->stype, sp2->sdf, sp2->sap); sp2->soffset = regno(p); sp2->sflags |= STNODE; n = buildtree(ASSIGN, p, n); ecomp(n); } } argstacksize = 0; if (cftnsp->sflags & SSTDCALL) { argstacksize = (argbase - ARGINIT)/SZCHAR; } }
/* * 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, 0); 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, 0); regno(r) = rno; ecomp(movtomem(r, -autooff, FPREG)); if (tsize(sp->stype, sp->sdf, sp->sap) > SZLONG) { r = block(REG, NIL, NIL, t, 0, 0); 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 (ISSOU(BTYPE(t))) al++; for (i = 0; t > BTMASK; t = DECREF(t)) if (ISARY(t) || ISFTN(t)) i++; if (i) 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, 0); regno(r) = argregsi[i]; r = movtomem(r, -RSALONGOFF(i)-autooff, FPREG); p = (p == NIL ? r : block(COMOP, p, r, INT, 0, 0)); } for (i = nsse; i < 8; i++) { r = block(REG, NIL, NIL, DOUBLE, 0, 0); regno(r) = i + XMM0; r = movtomem(r, -RSADBLOFF(i)-autooff, FPREG); p = (p == NIL ? r : block(COMOP, p, r, INT, 0, 0)); } autooff += RSASZ; rsaoff = autooff; thissse = nsse; thisgpr = ngpr; thisrsp = nrsp; ecomp(p); }