/* setup a float param on the stack * used by bfcode() */ static void param_float(struct symtab *sym, int *argofsp, int dotemps) { NODE *p, *q, *t; int tmpnr; /* * we have to dump the float from the general register * into a temp, since the register allocator doesn't like * floats to be in CLASSA. This may not work for -xtemps. */ t = tempnode(0, INT, 0, 0); tmpnr = regno(t); q = block(REG, NIL, NIL, INT, 0, 0); q->n_rval = R0 + (*argofsp)++; p = buildtree(ASSIGN, t, q); ecomp(p); if (dotemps) { sym->soffset = tmpnr; sym->sflags |= STNODE; } else { q = tempnode(tmpnr, sym->stype, sym->sdf, sym->sap); p = nametree(sym); p = buildtree(ASSIGN, p, q); ecomp(p); } }
void bfcode(struct symtab **sp, int cnt) { int i, off; NODE *p, *q; struct symtab *sym; /* Process the first six arguments. */ for (i=0; i < cnt && i < 6; i++) { sym = sp[i]; q = block(REG, NIL, NIL, sym->stype, sym->sdf, sym->sap); q->n_rval = RETREG_PRE(sym->stype) + i; p = tempnode(0, sym->stype, sym->sdf, sym->sap); sym->soffset = regno(p); sym->sflags |= STNODE; p = buildtree(ASSIGN, p, q); ecomp(p); } /* Process the remaining arguments. */ for (off = V9RESERVE; i < cnt; i++) { sym = sp[i]; p = tempnode(0, sym->stype, sym->sdf, sym->sap); off = ALIGN(off, (tlen(p) - 1)); sym->soffset = off * SZCHAR; off += tlen(p); p = buildtree(ASSIGN, p, nametree(sym)); sym->soffset = regno(p->n_left); sym->sflags |= STNODE; ecomp(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 **sp, int cnt) { struct symtab *sp2; NODE *n; int i; if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) { /* Function returns struct, adjust arg offset */ for (i = 0; i < cnt; i++) sp[i]->soffset += SZPOINT(INT); } if (xtemps == 0) return; /* put arguments in temporaries */ for (i = 0; i < cnt; i++) { if (sp[i]->stype == STRTY || sp[i]->stype == UNIONTY || cisreg(sp[i]->stype) == 0) continue; sp2 = sp[i]; n = tempnode(0, sp[i]->stype, sp[i]->sdf, sp[i]->sap); n = buildtree(ASSIGN, n, nametree(sp2)); sp[i]->soffset = regno(n->n_left); sp[i]->sflags |= STNODE; ecomp(n); } }
/* * code for the beginning of a function; a is an array of * indices in stab for the arguments; n is the number */ void bfcode(struct symtab **sp, int cnt) { NODE *p, *q; int i, n; if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) { uerror("no struct return yet"); } /* recalculate the arg offset and create TEMP moves */ for (n = 1, i = 0; i < cnt; i++) { if (n < 8) { p = tempnode(0, sp[i]->stype, sp[i]->sdf, sp[i]->ssue); q = block(REG, NIL, NIL, sp[i]->stype, sp[i]->sdf, sp[i]->ssue); q->n_rval = n; p = buildtree(ASSIGN, p, q); sp[i]->soffset = regno(p->n_left); sp[i]->sflags |= STNODE; ecomp(p); } else { sp[i]->soffset += SZINT * n; if (xtemps) { /* put stack args in temps if optimizing */ p = tempnode(0, sp[i]->stype, sp[i]->sdf, sp[i]->ssue); p = buildtree(ASSIGN, p, nametree(sp[i])); sp[i]->soffset = regno(p->n_left); sp[i]->sflags |= STNODE; ecomp(p); } } n += szty(sp[i]->stype); } }
static P1ND * tlsnonpic(P1ND *p) { P1ND *q, *r; struct symtab *sp, *sp2; int ext = p->n_sp->sclass; char *name; name = getsoname(p->n_sp); sp = picsymtab("", name, ext == EXTERN ? "@INDNTPOFF" : "@NTPOFF"); q = xbcon(0, sp, INT); if (ext == EXTERN) q = block(UMUL, q, NIL, PTR|VOID, 0, 0); sp2 = lookup("%gs:0", 0); sp2->stype = EXTERN|INT; r = nametree(sp2); q = buildtree(PLUS, q, r); q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap); q->n_sp = p->n_sp; /* for init */ p1nfree(p); return q; }
void bfcode(struct symtab **sp, int n) { struct symtab *sp2; NODE *p, *q; int i; if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) { /* Move return address into temporary */ p = tempnode(0, INT, 0, 0); strtemp = regno(p); q = block(REG, 0, 0, INT, 0, 0); regno(q) = R1; ecomp(buildtree(ASSIGN, p, q)); } if (xtemps == 0) return; /* put arguments in temporaries */ for (i = 0; i < n; i++) { if (sp[i]->stype == STRTY || sp[i]->stype == UNIONTY || cisreg(sp[i]->stype) == 0) continue; if (cqual(sp[i]->stype, sp[i]->squal) & VOL) continue; sp2 = sp[i]; p = tempnode(0, sp[i]->stype, sp[i]->sdf, sp[i]->sap); p = buildtree(ASSIGN, p, nametree(sp2)); sp[i]->soffset = regno(p->n_left); sp[i]->sflags |= STNODE; ecomp(p); } }
/* Put a symbol in a temporary * used by bfcode() and its helpers */ static void putintemp(struct symtab *sym) { NODE *p; p = tempnode(0, sym->stype, sym->sdf, sym->sap); p = buildtree(ASSIGN, p, nametree(sym)); sym->soffset = regno(p->n_left); sym->sflags |= STNODE; ecomp(p); }
/* * Check if we may have to do a cast to/from TI. */ NODE * gcc_eval_ticast(int op, NODE *p1, NODE *p2) { struct attr *a1, *a2; int t; a2 = NULL; /* XXX flow analysis */ if ((a1 = isti(p1)) == NULL && (a2 = isti(p2)) == NULL) return NIL; if (op == RETURN) p1 = p1tcopy(p1); if (a1 == NULL) { if (a2 == NULL) cerror("gcc_eval_ticast error"); switch (p1->n_type) { case LDOUBLE: p2 = doacall(floatuntixfsp, nametree(floatuntixfsp), p2); tfree(p1); break; case ULONG: case LONG: p2 = cast(structref(p2, DOT, loti), p1->n_type, 0); tfree(p1); break; case VOID: return NIL; default: uerror("gcc_eval_ticast: %d", p1->n_type); } return p2; } /* p2 can be anything, but we must cast it to p1 */ t = a1->iarg(1); if (p2->n_type == STRTY && (a2 = attr_find(p2->n_ap, GCC_ATYP_MODE)) && strcmp(a2->sarg(0), TISTR) == 0) { /* Already TI, just add extra mode bits */ a2 = attr_new(GCC_ATYP_MODE, 3); a2->sarg(0) = TISTR; a2->iarg(1) = t; p2->n_ap = attr_add(p2->n_ap, a2); } else { p2 = ticast(p2, t); } tfree(p1); return p2; }
/* * helper for bfcode() to put register arguments on stack. */ static void argmove(struct symtab *s, int regno) { NODE *p, *r; s->sclass = AUTO; s->soffset = NOOFFSET; oalloc(s, &autooff); p = nametree(s); r = bcon(0); r->n_op = REG; r->n_rval = regno; r->n_type = p->n_type; r->n_sue = p->n_sue; r->n_df = p->n_df; ecode(buildtree(ASSIGN, p, r)); }
void bfcode(struct symtab **sp, int n) { struct symtab *sp2; NODE *p, *q; int i, argbase, sz; if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) { /* Move return address into temporary */ p = tempnode(0, INT, 0, 0); strtemp = regno(p); q = block(REG, 0, 0, INT, 0, 0); regno(q) = R1; ecomp(buildtree(ASSIGN, p, q)); } /* correct arg alignment XXX should be done somewhere else */ argbase = ARGINIT; for (i = 0; i < n; i++) { sp2 = sp[i]; sz = tsize(sp2->stype, sp2->sdf, sp2->sap); SETOFF(sz, SZINT); sp2->soffset = argbase; argbase += sz; } if (xtemps == 0) return; /* put arguments in temporaries */ for (i = 0; i < n; i++) { if (sp[i]->stype == STRTY || sp[i]->stype == UNIONTY || cisreg(sp[i]->stype) == 0) continue; if (cqual(sp[i]->stype, sp[i]->squal) & VOL) continue; sp2 = sp[i]; p = tempnode(0, sp[i]->stype, sp[i]->sdf, sp[i]->sap); p = buildtree(ASSIGN, p, nametree(sp2)); sp[i]->soffset = regno(p->n_left); sp[i]->sflags |= STNODE; ecomp(p); } }
/* setup a 32-bit param on the stack * used by bfcode() */ static void param_32bit(struct symtab *sym, int *argofsp, int dotemps) { NODE *p, *q; q = block(REG, NIL, NIL, sym->stype, sym->sdf, sym->sap); regno(q) = R0 + (*argofsp)++; if (dotemps) { p = tempnode(0, sym->stype, sym->sdf, sym->sap); sym->soffset = regno(p); sym->sflags |= STNODE; } else { p = nametree(sym); } p = buildtree(ASSIGN, p, q); ecomp(p); }
/* * XXX This is a hack. We cannot have (l)doubles in more than one * register class. So we bounce them in and out of temps to * move them in and out of the right registers. */ static void param_double(struct symtab *sym, int *regp, int dotemps) { int reg = *regp; NODE *p, *q, *t; int navail; int tmpnr; /* alignment */ ++reg; reg &= ~1; navail = nargregs - (reg - A0); if (navail < 2) { /* would have appeared half in registers/half * on the stack, but alignment ensures it * appears on the stack */ if (dotemps) putintemp(sym); *regp = reg; return; } t = tempnode(0, LONGLONG, 0, 0); tmpnr = regno(t); q = block(REG, NIL, NIL, LONGLONG, 0, 0); q->n_rval = A0A1 + (reg - A0); p = buildtree(ASSIGN, t, q); ecomp(p); if (dotemps) { sym->soffset = tmpnr; sym->sflags |= STNODE; } else { q = tempnode(tmpnr, sym->stype, sym->sdf, sym->sap); p = nametree(sym); p = buildtree(ASSIGN, p, q); ecomp(p); } *regp = reg + 2; }
/* * Watch out for references to static members. */ NODE * cxxstructref(NODE *p, int f, char *n) { struct symtab *sp = strmemb(p->n_ap); if (sp == NULL) cerror("ref to unknown struct"); sp = sfind(n, sp); while (sp != NULL) { if (ISFTN(sp->stype) == 0) { if (sp->sclass == STATIC || sp->sclass == USTATIC) { tfree(p); return nametree(sp); } break; } sp = sfind(n, sp->snext); } return structref(p, f, n); }
/* * Create a reference for a TLS variable. */ static P1ND * tlspic(P1ND *p) { P1ND *q, *r; struct symtab *sp, *sp2; char *name; /* * creates: * leal var@TLSGD(%ebx),%eax * call ___tls_get_addr@PLT */ /* calc address of var@TLSGD */ q = tempnode(gotnr, PTR|VOID, 0, 0); name = getsoname(p->n_sp); sp = picsymtab("", name, "@TLSGD"); r = xbcon(0, sp, INT); q = buildtree(PLUS, q, r); /* assign to %eax */ r = block(REG, NIL, NIL, PTR|VOID, 0, 0); r->n_rval = EAX; q = buildtree(ASSIGN, r, q); /* call ___tls_get_addr */ sp2 = lookup("___tls_get_addr@PLT", 0); sp2->stype = EXTERN|INT|FTN; r = nametree(sp2); r = buildtree(ADDROF, r, NIL); r = block(UCALL, r, NIL, INT, 0, 0); /* fusion both parts together */ q = buildtree(COMOP, q, r); q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap); q->n_sp = p->n_sp; /* for init */ p1nfree(p); return q; }
/* * Generate a call tree to function named n. */ static NODE * callftn(char *n, ...) { struct symtab *sp = getsymtab(n, 0); NODE *p, *a, *b; va_list ap; sp->stype = (FTN|VOID) | (PTR << TSHIFT); va_start(ap, n); a = va_arg(ap, NODE *); if (a != NULL) { do { b = va_arg(ap, NODE *); if (b != NULL) a = buildtree(CM, a, b); } while (b != NULL); } p = doacall(sp, nametree(sp), a, 0); va_end(ap); return p; }
/* * XXX This is a hack. We cannot have floats in more than one * register class. So we bounce them in and out of temps to * move them in and out of the right registers. */ static void param_float(struct symtab *sym, int *regp, int dotemps) { NODE *p, *q, *t; int tmpnr; t = tempnode(0, INT, 0, 0); tmpnr = regno(t); q = block(REG, NIL, NIL, INT, 0, 0); q->n_rval = (*regp)++; p = buildtree(ASSIGN, t, q); ecomp(p); if (dotemps) { sym->soffset = tmpnr; sym->sflags |= STNODE; } else { q = tempnode(tmpnr, sym->stype, sym->sdf, sym->sap); p = nametree(sym); p = buildtree(ASSIGN, p, q); ecomp(p); } }
/* * Search for correct matching function in a struct depending on * argument list a. Return a call node for this function. * Do not touch neither f nor a. * return a name tree suitable for a function call. * We know here that f is a struct reference. */ NODE * cxxmatchftn(NODE *f, NODE *a) { struct attr *ap; struct symtab *sp; char *n = (char *)f->n_right->n_sp; f = f->n_left; if ((ap = attr_find(f->n_ap, ATTR_STRUCT)) == NULL) { uerror("undefined class"); sp = getsymtab(n, 0); } else sp = ap->amlist; sp = sfind(n, sp); while (sp != NULL) { if (ISFTN(sp->stype) && cxxptreecmp(sp, a) == 0) break; sp = sfind(n, sp->snext); } if (sp == NULL) uerror("undefined class member"); return nametree(sp); }
/* * Apply a unary op on a TI value. */ NODE * gcc_eval_tiuni(int op, NODE *p1) { struct attr *a1; NODE *p; if ((a1 = isti(p1)) == NULL) return NULL; switch (op) { case UMINUS: p = ticast(bcon(0), 0); p = buildtree(CM, p, p1); p = doacall(subvti3sp, nametree(subvti3sp), p); break; case UMUL: p = NULL; default: uerror("unsupported unary TI mode op %d", op); p = NULL; } return p; }
/* * Evaluate 128-bit operands. */ NODE * gcc_eval_timode(int op, NODE *p1, NODE *p2) { struct attr *a1, *a2; struct symtab *sp; NODE *p; int isu = 0, gotti, isaop; if (op == CM) return buildtree(op, p1, p2); a1 = isti(p1); a2 = isti(p2); if (a1 == NULL && a2 == NULL) return NULL; if (op == ASSIGN) return timodeassign(p1, p2); gotti = (a1 != NULL); gotti += (a2 != NULL); if (gotti == 0) return NULL; if (a1 != NULL) isu = a1->iarg(1); if (a2 != NULL && !isu) isu = a2->iarg(1); if (a1 == NULL) { p1 = ticast(p1, isu); a1 = attr_find(p1->n_ap, GCC_ATYP_MODE); } if (a2 == NULL && (cdope(op) & SHFFLG) == 0) { p2 = ticast(p2, isu); a2 = attr_find(p2->n_ap, GCC_ATYP_MODE); } switch (op) { case GT: case GE: case LT: case LE: case EQ: case NE: /* change to call */ sp = isu ? ucmpti2sp : cmpti2sp; p = doacall(sp, nametree(sp), buildtree(CM, p1, p2)); p = buildtree(op, p, bcon(1)); break; case AND: case ER: case OR: if (!ISPTR(p1->n_type)) p1 = buildtree(ADDROF, p1, NIL); if (!ISPTR(p2->n_type)) p2 = buildtree(ADDROF, p2, NIL); p = gcc_andorer(op, p1, p2); break; case LSEQ: case RSEQ: case LS: case RS: sp = op == LS || op == LSEQ ? ashldi3sp : isu ? lshrdi3sp : ashrdi3sp; p2 = cast(p2, INT, 0); /* XXX p1 ccopy may have side effects */ p = doacall(sp, nametree(sp), buildtree(CM, ccopy(p1), p2)); if (op == LSEQ || op == RSEQ) { p = buildtree(ASSIGN, p1, p); } else tfree(p1); break; case PLUSEQ: case MINUSEQ: case MULEQ: case DIVEQ: case MODEQ: case PLUS: case MINUS: case MUL: case DIV: case MOD: isaop = (cdope(op)&ASGOPFLG); if (isaop) op = UNASG op; sp = op == PLUS ? addvti3sp : op == MINUS ? subvti3sp : op == MUL ? mulvti3sp : op == DIV ? (isu ? udivti3sp : divti3sp) : op == MOD ? (isu ? umodti3sp : modti3sp) : 0; /* XXX p1 ccopy may have side effects */ p = doacall(sp, nametree(sp), buildtree(CM, ccopy(p1), p2)); if (isaop) p = buildtree(ASSIGN, p1, p); else tfree(p1); break; default: uerror("unsupported TImode op %d", op); p = bcon(0); } 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); }
/* setup a 64-bit parameter (double/ldouble/longlong) * used by bfcode() */ static void param_64bit(struct symtab *sym, int *argofsp, int dotemps) { int argofs = *argofsp; NODE *p, *q; int navail; #if ALLONGLONG == 64 /* alignment */ ++argofs; argofs &= ~1; *argofsp = argofs; #endif navail = NARGREGS - argofs; if (navail < 2) { /* half in and half out of the registers */ if (features(FEATURE_BIGENDIAN)) { cerror("param_64bit"); p = q = NULL; } else { q = block(REG, NIL, NIL, INT, 0, 0); regno(q) = R0 + argofs; if (dotemps) { q = block(SCONV, q, NIL, ULONGLONG, 0, 0); p = nametree(sym); p->n_type = ULONGLONG; p->n_df = 0; p->n_ap = NULL; p = block(LS, p, bcon(32), ULONGLONG, 0, 0); q = block(PLUS, p, q, ULONGLONG, 0, 0); p = tempnode(0, ULONGLONG, 0, 0); sym->soffset = regno(p); sym->sflags |= STNODE; } else { p = nametree(sym); regno(p) = sym->soffset; p->n_type = INT; p->n_df = 0; p->n_ap = NULL; } } p = buildtree(ASSIGN, p, q); ecomp(p); *argofsp = argofs + 2; return; } q = block(REG, NIL, NIL, sym->stype, sym->sdf, sym->sap); regno(q) = R0R1 + argofs; if (dotemps) { p = tempnode(0, sym->stype, sym->sdf, sym->sap); sym->soffset = regno(p); sym->sflags |= STNODE; } else { p = nametree(sym); } p = buildtree(ASSIGN, p, q); ecomp(p); *argofsp = argofs + 2; }