/* * Make a type signed, if possible. */ TWORD deunsign(TWORD t) { if (BTYPE(t) >= CHAR && BTYPE(t) <= ULONGLONG) t &= ~1; return t; }
/* * Check and cast arguments for builtins. */ static int acnt(NODE *a, int narg, TWORD *tp) { NODE *q; TWORD t; if (a == NIL) return narg; for (; a->n_op == CM; a = a->n_left, narg--) { if (tp == NULL) continue; q = a->n_right; t = tp[narg-1]; if (q->n_type == t) continue; a->n_right = ccast(q, t, 0, NULL, MKAP(BTYPE(t))); } /* Last arg is ugly to deal with */ if (narg == 1 && tp != NULL) { q = talloc(); *q = *a; q = ccast(q, tp[0], 0, NULL, MKAP(BTYPE(tp[0]))); *a = *q; nfree(q); } return narg != 1; }
/* * Make a type unsigned, if possible. */ TWORD enunsign(TWORD t) { if (BTYPE(t) >= CHAR && BTYPE(t) <= ULONGLONG) t |= 1; return t; }
/* * 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; }
/* * map types which are not defined on the local machine */ TWORD ctype(TWORD type) { switch (BTYPE(type)) { case SHORT: MODTYPE(type,INT); break; case USHORT: MODTYPE(type,UNSIGNED); break; case LONGLONG: MODTYPE(type,LONG); break; case ULONGLONG: MODTYPE(type,ULONG); break; case LDOUBLE: MODTYPE(type,DOUBLE); break; } return (type); }
void efcode(void) { TWORD t; NODE *p, *q; /* code for the end of a function */ if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN) return; t = PTR+BTYPE(cftnsp->stype); /* Create struct assignment */ q = tempnode(strtemp, t, 0, cftnsp->sap); q = buildtree(UMUL, q, NIL); p = block(REG, NIL, NIL, t, 0, cftnsp->sap); regno(p) = R0; p = buildtree(UMUL, p, NIL); p = buildtree(ASSIGN, q, p); ecomp(p); /* put hidden arg in r0 on return */ q = tempnode(strtemp, INT, 0, 0); p = block(REG, NIL, NIL, INT, 0, 0); regno(p) = R0; ecomp(buildtree(ASSIGN, p, q)); }
static int typch(int typ) { int c = BTYPE(typ); if (c == VOID) c = 0; return chmap[c]; }
/* * map types which are not defined on the local machine */ TWORD ctype(TWORD type) { switch (BTYPE(type)) { case LONG: MODTYPE(type,INT); break; case ULONG: MODTYPE(type,UNSIGNED); } return (type); }
static void cxxckproto(NODE *p, void *arg) { struct ckstr *cp = arg; if (cp->rv == -1) return; if (cp->al[0].type != p->n_type) goto fail; if (BTYPE(cp->al[0].type) > LDOUBLE) uerror("cxxckproto"); cp->al++; return; fail: cp->rv = -1; }
/* clocal() is called to do local transformations on * an expression tree preparitory to its being * written out in intermediate code. * * the major essential job is rewriting the * automatic variables and arguments in terms of * REG and OREG nodes * conversion ops which are not necessary are also clobbered here * in addition, any special features (such as rewriting * exclusive or) are easily handled here as well */ P1ND * clocal(P1ND *p) { struct attr *ap; register struct symtab *q; register P1ND *r, *l, *n, *s; register int o; register int m; #ifdef PCC_DEBUG if (xdebug) { printf("clocal: %p\n", p); p1fwalk(p, eprint, 0); } #endif switch( o = p->n_op ){ case NAME: if ((q = p->n_sp) == NULL) return p; /* Nothing to care about */ switch (q->sclass) { case PARAM: case AUTO: /* fake up a structure reference */ r = block(REG, NIL, NIL, PTR+STRTY, 0, 0); slval(r, 0); r->n_rval = FPREG; p = stref(block(STREF, r, p, 0, 0, 0)); break; case USTATIC: if (kflag == 0) break; /* FALLTHROUGH */ case STATIC: #ifdef TLS if (q->sflags & STLS) { p = tlsref(p); break; } #endif if (kflag == 0) { if (q->slevel == 0) break; } else if (kflag && !statinit && blevel > 0 && #ifdef GCC_COMPAT attr_find(q->sap, GCC_ATYP_WEAKREF)) { #else 0) { #endif /* extern call */ p = picext(p); } else if (blevel > 0 && !statinit) p = picstatic(p); break; case REGISTER: p->n_op = REG; slval(p, 0); p->n_rval = q->soffset; break; case EXTERN: case EXTDEF: #ifdef TLS if (q->sflags & STLS) { p = tlsref(p); break; } #endif #ifdef PECOFFABI if (q->sflags & SDLLINDIRECT) p = import(p); #endif #ifdef GCC_COMPAT if ((ap = attr_find(q->sap, GCC_ATYP_VISIBILITY)) != NULL && strcmp(ap->sarg(0), "hidden") == 0) printf(PRTPREF "\t.hidden %s\n", getsoname(q)); #endif if (kflag == 0) break; if (blevel > 0 && !statinit) p = picext(p); break; } break; case ADDROF: if (kflag == 0 || blevel == 0 || statinit) break; /* char arrays may end up here */ l = p->n_left; if (l->n_op != NAME || (l->n_type != ARY+CHAR && l->n_type != ARY+WCHAR_TYPE)) break; l = p; p = picstatic(p->n_left); p1nfree(l); if (p->n_op != UMUL) cerror("ADDROF error"); l = p; p = p->n_left; p1nfree(l); break; case UCALL: if (kflag == 0) break; l = block(REG, NIL, NIL, INT, 0, 0); l->n_rval = EBX; p->n_right = buildtree(ASSIGN, l, tempnode(gotnr, INT, 0, 0)); p->n_op -= (UCALL-CALL); break; case USTCALL: #if defined(os_openbsd) ap = strattr(p->n_left->n_ap); if (ap->amsize == SZCHAR || ap->amsize == SZSHORT || ap->amsize == SZINT || ap->amsize == SZLONGLONG) #else if (attr_find(p->n_left->n_ap, ATTR_COMPLEX) && (ap = strattr(p->n_left->n_ap)) && ap->amsize == SZLONGLONG) #endif { /* float complex */ /* fake one arg to make pass2 happy */ p->n_right = block(FUNARG, bcon(0), NIL, INT, 0, 0); p->n_op -= (UCALL-CALL); break; } /* Add hidden arg0 */ r = block(REG, NIL, NIL, INCREF(VOID), 0, 0); regno(r) = EBP; #ifdef GCC_COMPAT if ((ap = attr_find(p->n_ap, GCC_ATYP_REGPARM)) != NULL && ap->iarg(0) > 0) { l = block(REG, NIL, NIL, INCREF(VOID), 0, 0); regno(l) = EAX; p->n_right = buildtree(ASSIGN, l, r); } else #endif p->n_right = block(FUNARG, r, NIL, INCREF(VOID), 0, 0); p->n_op -= (UCALL-CALL); if (kflag == 0) break; l = block(REG, NIL, NIL, INT, 0, 0); regno(l) = EBX; r = buildtree(ASSIGN, l, tempnode(gotnr, INT, 0, 0)); p->n_right = block(CM, r, p->n_right, INT, 0, 0); break; /* FALLTHROUGH */ #if defined(MACHOABI) case CALL: case STCALL: if (p->n_type == VOID) break; r = tempnode(0, p->n_type, p->n_df, p->n_ap); l = tcopy(r); p = buildtree(COMOP, buildtree(ASSIGN, r, p), l); #endif break; #ifdef notyet /* XXX breaks sometimes */ case CBRANCH: l = p->n_left; /* * Remove unnecessary conversion ops. */ if (!clogop(l->n_op) || l->n_left->n_op != SCONV) break; if (coptype(l->n_op) != BITYPE) break; if (l->n_right->n_op != ICON) break; r = l->n_left->n_left; if (r->n_type >= FLOAT) break; if (toolarge(r->n_type, l->n_right->n_lval)) break; l->n_right->n_type = r->n_type; if (l->n_op >= ULE && l->n_op <= UGT) l->n_op -= (UGT-ULE); p->n_left = buildtree(l->n_op, r, l->n_right); p1nfree(l->n_left); p1nfree(l); break; #endif case PCONV: l = p->n_left; /* Make int type before pointer */ if (l->n_type < INT || l->n_type == LONGLONG || l->n_type == ULONGLONG || l->n_type == BOOL) { /* float etc? */ p->n_left = block(SCONV, l, NIL, UNSIGNED, 0, 0); } break; case SCONV: if (p->n_left->n_op == COMOP) break; /* may propagate wrong type later */ l = p->n_left; if (p->n_type == l->n_type) { p1nfree(p); return l; } if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 && tsize(p->n_type, p->n_df, p->n_ap) == tsize(l->n_type, l->n_df, l->n_ap)) { if (p->n_type != FLOAT && p->n_type != DOUBLE && l->n_type != FLOAT && l->n_type != DOUBLE && l->n_type != LDOUBLE && p->n_type != LDOUBLE) { if (l->n_op == NAME || l->n_op == UMUL || l->n_op == TEMP) { l->n_type = p->n_type; p1nfree(p); return l; } } } if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == INT && coptype(l->n_op) == BITYPE && l->n_op != COMOP && l->n_op != QUEST && l->n_op != ASSIGN) { l->n_type = p->n_type; p1nfree(p); return l; } o = l->n_op; m = p->n_type; if (o == ICON) { /* * Can only end up here if o is an address, * and in that case the only compile-time conversion * possible is to int. */ if ((TMASK & l->n_type) == 0 && l->n_sp == NULL) cerror("SCONV ICON"); if (l->n_sp == 0) { p->n_type = UNSIGNED; concast(l, m); } else if (m != INT && m != UNSIGNED) break; l->n_type = m; l->n_ap = 0; p1nfree(p); return l; } else if (l->n_op == FCON) cerror("SCONV FCON"); if ((p->n_type == CHAR || p->n_type == UCHAR || p->n_type == SHORT || p->n_type == USHORT) && (l->n_type == FLOAT || l->n_type == DOUBLE || l->n_type == LDOUBLE)) { p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_ap); p->n_left->n_type = INT; return p; } break; case MOD: case DIV: if (o == DIV && p->n_type != CHAR && p->n_type != SHORT) break; if (o == MOD && p->n_type != CHAR && p->n_type != SHORT) break; /* make it an int division by inserting conversions */ p->n_left = makety(p->n_left, INT, 0, 0, 0); p->n_right = makety(p->n_right, INT, 0, 0, 0); o = p->n_type; p->n_type = INT; p = makety(p, o, 0, 0, 0); break; case FORCE: /* put return value in return reg */ p->n_op = ASSIGN; p->n_right = p->n_left; p->n_left = block(REG, NIL, NIL, p->n_type, 0, 0); p->n_left->n_rval = p->n_left->n_type == BOOL ? RETREG(CHAR) : RETREG(p->n_type); break; case LS: case RS: /* shift count must be in a char */ if (p->n_right->n_type == CHAR || p->n_right->n_type == UCHAR) break; p->n_right = block(SCONV, p->n_right, NIL, CHAR, 0, 0); break; /* If not using pcc struct return */ case STASG: r = p->n_right; if (r->n_op != STCALL && r->n_op != USTCALL) break; m = tsize(BTYPE(r->n_type), r->n_df, r->n_ap); if (m == SZCHAR) m = CHAR; else if (m == SZSHORT) m = SHORT; else if (m == SZINT) m = INT; else if (m == SZLONGLONG) m = LONGLONG; else break; #if !defined(os_openbsd) if (attr_find(r->n_ap, ATTR_COMPLEX) == 0) break; /* float _Complex always in regs */ #endif l = buildtree(ADDROF, p->n_left, NIL); p1nfree(p); r->n_op -= (STCALL-CALL); r->n_type = m; /* r = long, l = &struct */ n = tempnode(0, m, r->n_df, r->n_ap); r = buildtree(ASSIGN, p1tcopy(n), r); s = tempnode(0, l->n_type, l->n_df, l->n_ap); l = buildtree(ASSIGN, p1tcopy(s), l); p = buildtree(COMOP, r, l); l = buildtree(CAST, block(NAME, NIL, NIL, m|PTR, 0, 0), p1tcopy(s)); r = l->n_right; p1nfree(l->n_left); p1nfree(l); r = buildtree(ASSIGN, buildtree(UMUL, r, NIL), n); p = buildtree(COMOP, p, r); p = buildtree(COMOP, p, s); break; }
/* * 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); }
/* * does the type t match tword */ int ttype(TWORD t, int tword) { if (tword & TANY) return(1); #ifdef PCC_DEBUG if (t2debug) printf("ttype(0x%x, 0x%x)\n", t, tword); #endif if (ISPTR(t) && ISFTN(DECREF(t)) && (tword & TFTN)) { /* For funny function pointers */ return 1; } if (ISPTR(t) && (tword&TPTRTO)) { do { t = DECREF(t); } while (ISARY(t)); /* arrays that are left are usually only * in structure references... */ return (ttype(t, tword&(~TPTRTO))); } if (t != BTYPE(t)) return (tword & TPOINT); /* TPOINT means not simple! */ if (tword & TPTRTO) return(0); switch (t) { case CHAR: return( tword & TCHAR ); case SHORT: return( tword & TSHORT ); case STRTY: case UNIONTY: return( tword & TSTRUCT ); case INT: return( tword & TINT ); case UNSIGNED: return( tword & TUNSIGNED ); case USHORT: return( tword & TUSHORT ); case UCHAR: return( tword & TUCHAR ); case ULONG: return( tword & TULONG ); case LONG: return( tword & TLONG ); case LONGLONG: return( tword & TLONGLONG ); case ULONGLONG: return( tword & TULONGLONG ); case FLOAT: return( tword & TFLOAT ); case DOUBLE: return( tword & TDOUBLE ); case LDOUBLE: return( tword & TLDOUBLE ); } return(0); }
/* * Fixup types when modes given in defid(). */ void gcc_modefix(NODE *p) { struct attr *ap; #ifdef TARGET_TIMODE struct attr *a2; #endif struct symtab *sp; char *s; int i, u; if ((ap = attr_find(p->n_ap, GCC_ATYP_MODE)) == NULL) return; u = ISUNSIGNED(BTYPE(p->n_type)); if ((i = amatch(ap->aa[0].sarg, mods, ATSZ)) == 0) { werror("unknown mode arg %s", ap->aa[0].sarg); return; } i = mods[i].typ; if (i >= 1 && i <= MAXTYPES) { MODTYPE(p->n_type, ctype(i)); if (u) p->n_type = ENUNSIGN(p->n_type); } else switch (i) { #ifdef TARGET_TIMODE case 800: if (BTYPE(p->n_type) == STRTY) break; MODTYPE(p->n_type, tisp->stype); p->n_df = tisp->sdf; p->n_ap = tisp->sap; if (ap->iarg(1) == u) break; /* must add a new mode struct to avoid overwriting */ a2 = attr_new(GCC_ATYP_MODE, 3); a2->sarg(0) = ap->sarg(0); a2->iarg(1) = u; p->n_ap = attr_add(p->n_ap, a2); break; #endif case FCOMPLEX: case COMPLEX: case LCOMPLEX: /* Destination should have been converted to a struct already */ if (BTYPE(p->n_type) != STRTY) uerror("gcc_modefix: complex not STRTY"); i -= (FCOMPLEX-FLOAT); ap = strattr(p->n_ap); sp = ap->amlist; if (sp->stype == (unsigned)i) return; /* Already correct type */ /* we must change to another struct */ s = i == FLOAT ? "0f" : i == DOUBLE ? "0d" : i == LDOUBLE ? "0l" : 0; sp = lookup(addname(s), 0); for (ap = sp->sap; ap != NULL; ap = ap->next) p->n_ap = attr_add(p->n_ap, attr_dup(ap)); break; default: cerror("gcc_modefix"); } }