static NODE * moveargs(NODE *p, int *regp) { NODE *r, **rp; int reg; if (p->n_op == CM) { p->n_left = moveargs(p->n_left, regp); r = p->n_right; rp = &p->n_right; } else { r = p; rp = &p; } reg = *regp; if (reg > R3 && r->n_op != STARG) { *rp = pusharg(r, regp); } else if (r->n_op == STARG) { *rp = movearg_struct(r, regp); } else if (DEUNSIGN(r->n_type) == LONGLONG) { *rp = movearg_64bit(r, regp); } else if (r->n_type == DOUBLE || r->n_type == LDOUBLE) { *rp = movearg_double(r, regp); } else if (r->n_type == FLOAT) { *rp = movearg_float(r, regp); } else { *rp = movearg_32bit(r, regp); } return straighten(p); }
/* * Called with a function call with arguments as argument. * This is done early in buildtree() and only done once. */ NODE * funcode(NODE *p) { int regnum = A0; NODE *l, *r, *t, *q; int ty; l = p->n_left; r = p->n_right; /* * if returning a structure, make the first argument * a hidden pointer to return structure. */ ty = DECREF(l->n_type); if (ty == STRTY+FTN || ty == UNIONTY+FTN) { ty = DECREF(l->n_type) - FTN; q = tempnode(0, ty, l->n_df, l->n_ap); q = buildtree(ADDROF, q, NIL); if (r->n_op != CM) { p->n_right = block(CM, q, r, INCREF(ty), l->n_df, l->n_ap); } else { for (t = r; t->n_left->n_op == CM; t = t->n_left) ; t->n_left = block(CM, q, t->n_left, INCREF(ty), l->n_df, l->n_ap); } } p->n_right = moveargs(p->n_right, ®num); return p; }
static NODE * moveargs(NODE *p, int *regp) { NODE *r, **rp; int lastreg; int reg; if (p->n_op == CM) { p->n_left = moveargs(p->n_left, regp); r = p->n_right; rp = &p->n_right; } else { r = p; rp = &p; } lastreg = A0 + nargregs - 1; reg = *regp; if (reg > lastreg && r->n_op != STARG) *rp = block(FUNARG, r, NIL, r->n_type, r->n_df, r->n_ap); else if (r->n_op == STARG) { *rp = movearg_struct(r, p, regp); } else if (DEUNSIGN(r->n_type) == LONGLONG) { *rp = movearg_64bit(r, regp); } else if (r->n_type == DOUBLE || r->n_type == LDOUBLE) { /* XXX bounce in and out of temporary to change to longlong */ NODE *t1 = tempnode(0, LONGLONG, 0, 0); int tmpnr = regno(t1); NODE *t2 = tempnode(tmpnr, r->n_type, r->n_df, r->n_ap); t1 = movearg_64bit(t1, regp); r = block(ASSIGN, t2, r, r->n_type, r->n_df, r->n_ap); if (p->n_op == CM) { p->n_left = buildtree(CM, p->n_left, t1); p->n_right = r; } else { p = buildtree(CM, t1, r); } } else if (r->n_type == FLOAT) { /* XXX bounce in and out of temporary to change to int */ NODE *t1 = tempnode(0, INT, 0, 0); int tmpnr = regno(t1); NODE *t2 = tempnode(tmpnr, r->n_type, r->n_df, r->n_ap); t1 = movearg_32bit(t1, regp); r = block(ASSIGN, t2, r, r->n_type, r->n_df, r->n_ap); if (p->n_op == CM) { p->n_left = buildtree(CM, p->n_left, t1); p->n_right = r; } else { p = buildtree(CM, t1, r); } } else { *rp = movearg_32bit(r, regp); } return p; }
/* * The first six 64-bit arguments are saved in the registers O0 to O5, * which become I0 to I5 after the "save" instruction moves the register * window. Arguments 7 and up must be saved on the stack to %sp+BIAS+176. * * For a pretty picture, see Figure 3-16 in the SPARC Compliance Def 2.4. */ static NODE * moveargs(NODE *p, int *regp, int *stacksize) { NODE *r, *q; if (p->n_op == CM) { p->n_left = moveargs(p->n_left, regp, stacksize); r = p->n_right; } else { r = p; } /* XXX more than six FP args can and should be passed in registers. */ if (*regp > 5 && r->n_op != STARG) { /* We are storing the stack offset in n_rval. */ r = block(FUNARG, r, NIL, r->n_type, r->n_df, r->n_ap); /* Make sure we are appropriately aligned. */ *stacksize = ALIGN(*stacksize, (tlen(r) - 1)); r->n_rval = *stacksize; *stacksize += tlen(r); } else if (r->n_op == STARG) cerror("op STARG in moveargs"); else { q = block(REG, NIL, NIL, r->n_type, r->n_df, r->n_ap); /* * The first six non-FP arguments go in the registers O0 - O5. * Float arguments are stored in %fp1, %fp3, ..., %fp29, %fp31. * Double arguments are stored in %fp0, %fp2, ..., %fp28, %fp30. * A non-fp argument still increments register, eg. * test(int a, int b, float b) * takes %o0, %o1, %fp5. */ if (q->n_type == FLOAT) q->n_rval = F0 + (*regp++ * 2) + 1; else if (q->n_type == DOUBLE) q->n_rval = D0 + *regp++; else if (q->n_type == LDOUBLE) cerror("long double support incomplete"); else q->n_rval = O0 + (*regp)++; r = buildtree(ASSIGN, q, r); } if (p->n_op == CM) { p->n_right = r; return p; } return r; }
NODE * funcode(NODE *p) { NODE *r, *l; int reg = 0, stacksize = 0; r = l = 0; p->n_right = moveargs(p->n_right, ®, &stacksize); /* * This is a particularly gross and inefficient way to handle * argument overflows. First, we calculate how much stack space * we need in moveargs(). Then we assign it by moving %sp, make * the function call, and then move %sp back. * * What we should be doing is getting the maximum of all the needed * stacksize values to the prologue and doing it all in the "save" * instruction. */ if (stacksize != 0) { stacksize = V9STEP(stacksize); /* 16-bit alignment. */ r = block(REG, NIL, NIL, INT, 0, 0); r->n_lval = 0; r->n_rval = SP; r = block(MINUS, r, bcon(stacksize), INT, 0, 0); l = block(REG, NIL, NIL, INT, 0, 0); l->n_lval = 0; l->n_rval = SP; r = buildtree(ASSIGN, l, r); p = buildtree(COMOP, r, p); r = block(REG, NIL, NIL, INT, 0, 0); r->n_lval = 0; r->n_rval = SP; r = block(PLUS, r, bcon(stacksize), INT, 0, 0); l = block(REG, NIL, NIL, INT, 0, 0); l->n_lval = 0; l->n_rval = SP; r = buildtree(ASSIGN, l, r); p = buildtree(COMOP, p, r); } return p; }
/* * Called with a function call with arguments as argument. * This is done early in buildtree() and only done once. */ NODE * funcode(NODE *p) { int reg = R0; if (p->n_type == STRTY+FTN || p->n_type == UNIONTY+FTN) { p = retstruct(p); reg = R1; } p->n_right = moveargs(p->n_right, ®); if (p->n_right == NULL) p->n_op += (UCALL - CALL); return p; }