/* * http://gcc.gnu.org/onlinedocs/gccint/Integer-library-routines.html#Integer-library-routines */ static void emulop(NODE *p) { char *ch = NULL; if (p->n_op == LS && DEUNSIGN(p->n_type) == LONGLONG) ch = "ashldi3"; else if (p->n_op == LS && (DEUNSIGN(p->n_type) == LONG || DEUNSIGN(p->n_type) == INT)) ch = "ashlsi3"; else if (p->n_op == RS && p->n_type == ULONGLONG) ch = "lshrdi3"; else if (p->n_op == RS && (p->n_type == ULONG || p->n_type == INT)) ch = "lshrsi3"; else if (p->n_op == RS && p->n_type == LONGLONG) ch = "ashrdi3"; else if (p->n_op == RS && (p->n_type == LONG || p->n_type == INT)) ch = "ashrsi3"; else if (p->n_op == DIV && p->n_type == LONGLONG) ch = "divdi3"; else if (p->n_op == DIV && (p->n_type == LONG || p->n_type == INT)) ch = "divsi3"; else if (p->n_op == DIV && p->n_type == ULONGLONG) ch = "udivdi3"; else if (p->n_op == DIV && (p->n_type == ULONG || p->n_type == UNSIGNED)) ch = "udivsi3"; else if (p->n_op == MOD && p->n_type == LONGLONG) ch = "moddi3"; else if (p->n_op == MOD && (p->n_type == LONG || p->n_type == INT)) ch = "modsi3"; else if (p->n_op == MOD && p->n_type == ULONGLONG) ch = "umoddi3"; else if (p->n_op == MOD && (p->n_type == ULONG || p->n_type == UNSIGNED)) ch = "umodsi3"; else if (p->n_op == MUL && p->n_type == LONGLONG) ch = "muldi3"; else if (p->n_op == MUL && (p->n_type == LONG || p->n_type == INT)) ch = "mulsi3"; else if (p->n_op == UMINUS && p->n_type == LONGLONG) ch = "negdi2"; else if (p->n_op == UMINUS && p->n_type == LONG) ch = "negsi2"; else ch = 0, comperr("ZE"); printf("\tsubu %s,%s,16\n", rnames[SP], rnames[SP]); printf("\tjal __%s\t# emulated operation\n", exname(ch)); printf("\tnop\n"); printf("\taddiu %s,%s,16\n", rnames[SP], rnames[SP]); }
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); }
static int argsiz(NODE *p) { TWORD t; int size = 0; int sz = 0; if (p->n_op == CM) { size = argsiz(p->n_left); p = p->n_right; } t = p->n_type; if (t < LONGLONG || t > BTMASK) sz = 4; else if (DEUNSIGN(t) == LONGLONG) sz = 8; else if (t == DOUBLE || t == LDOUBLE) sz = 8; else if (t == FLOAT) sz = 4; else if (t == STRTY || t == UNIONTY) sz = p->n_stsize; if (p->n_type == STRTY || p->n_type == UNIONTY) { return (size + sz); } /* alignment */ if (sz == 8 && (size & 7) != 0) sz += 4; // printf("size=%d, sz=%d -> %d\n", size, sz, size + sz); return (size + sz); }
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; }
NODE * mips_builtin_va_arg(NODE *f, NODE *a, TWORD t) { NODE *p, *q, *r; int sz, tmpnr; /* check num args and type */ if (a == NULL || a->n_op != CM || a->n_left->n_op == CM || !ISPTR(a->n_left->n_type) || a->n_right->n_op != TYPE) goto bad; r = a->n_right; /* get type size */ sz = tsize(r->n_type, r->n_df, r->n_ap) / SZCHAR; if (sz < SZINT/SZCHAR) { werror("%s%s promoted to int when passed through ...", r->n_type & 1 ? "unsigned " : "", DEUNSIGN(r->n_type) == SHORT ? "short" : "char"); sz = SZINT/SZCHAR; } /* alignment */ p = tcopy(a->n_left); if (sz > SZINT/SZCHAR && r->n_type != UNIONTY && r->n_type != STRTY) { p = buildtree(PLUS, p, bcon(7)); p = block(AND, p, bcon(-8), p->n_type, p->n_df, p->n_ap); } /* create a copy to a temp node */ q = tempnode(0, p->n_type, p->n_df, p->n_ap); tmpnr = regno(q); p = buildtree(ASSIGN, q, p); q = tempnode(tmpnr, p->n_type, p->n_df,p->n_ap); q = buildtree(PLUS, q, bcon(sz)); q = buildtree(ASSIGN, a->n_left, q); q = buildtree(COMOP, p, q); nfree(a->n_right); nfree(a); nfree(f); p = tempnode(tmpnr, INCREF(r->n_type), r->n_df, r->n_ap); p = buildtree(UMUL, p, NIL); p = buildtree(COMOP, q, p); return p; bad: uerror("bad argument to __builtin_va_arg"); return bcon(0); }
/* * If we're big endian, then all OREG loads of a type * larger than the destination, must have the * offset changed to point to the correct bytes in memory. */ static void offchg(NODE *p, void *arg) { NODE *l; if (p->n_op != SCONV) return; l = p->n_left; if (l->n_op != OREG) return; switch (l->n_type) { case SHORT: case USHORT: if (DEUNSIGN(p->n_type) == CHAR) l->n_lval += 1; break; case LONG: case ULONG: case INT: case UNSIGNED: if (DEUNSIGN(p->n_type) == CHAR) l->n_lval += 3; else if (DEUNSIGN(p->n_type) == SHORT) l->n_lval += 2; break; case LONGLONG: case ULONGLONG: if (DEUNSIGN(p->n_type) == CHAR) l->n_lval += 7; else if (DEUNSIGN(p->n_type) == SHORT) l->n_lval += 6; else if (DEUNSIGN(p->n_type) == INT || DEUNSIGN(p->n_type) == LONG) l->n_lval += 4; break; default: comperr("offchg: unknown type"); break; } }
/* * If we're big endian, then all OREG loads of a type * larger than the destination, must have the * offset changed to point to the correct bytes in memory. */ static void offchg(NODE *p, void *arg) { NODE *l; if (p->n_op != SCONV) return; l = p->n_left; if (l->n_op != OREG) return; switch (l->n_type) { case SHORT: case USHORT: if (DEUNSIGN(p->n_type) == CHAR) setlval(l, getlval(l) + 1); break; case LONG: case ULONG: case INT: case UNSIGNED: if (DEUNSIGN(p->n_type) == CHAR) setlval(l, getlval(l + 3)); else if (DEUNSIGN(p->n_type) == SHORT) setlval(l, getlval(l + 2)); break; case LONGLONG: case ULONGLONG: if (DEUNSIGN(p->n_type) == CHAR) setlval(l, getlval(l + 7)); else if (DEUNSIGN(p->n_type) == SHORT) setlval(l, getlval(l + 6)); else if (DEUNSIGN(p->n_type) == INT || DEUNSIGN(p->n_type) == LONG) setlval(l, getlval(l + 4)); break; default: comperr("offchg: unknown type"); break; } }
/* 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 */ NODE * clocal(NODE *p) { register struct symtab *q; register NODE *r, *l; register int o; register int m; TWORD t; #ifdef PCC_DEBUG if (xdebug) { printf("clocal: %p\n", p); fwalk(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 break; case REGISTER: p->n_op = REG; slval(p, 0); p->n_rval = q->soffset; break; case EXTERN: case EXTDEF: if (q->sflags & STLS) { p = tlsref(p); break; } if (kflag == 0 || statinit) break; if (blevel > 0) p = picext(p); break; } break; case UCALL: case USTCALL: /* For now, always clear eax */ l = block(REG, NIL, NIL, INT, 0, 0); regno(l) = RAX; p->n_right = clocal(buildtree(ASSIGN, l, bcon(0))); p->n_op -= (UCALL-CALL); break; case SCONV: /* Special-case shifts */ if (p->n_type == LONG && (l = p->n_left)->n_op == LS && l->n_type == INT && l->n_right->n_op == ICON) { p->n_left = l->n_left; p = buildtree(LS, p, l->n_right); nfree(l); break; } l = p->n_left; /* Float conversions may need extra casts */ if (p->n_type == FLOAT || p->n_type == DOUBLE || p->n_type == LDOUBLE) { if (l->n_type < INT || l->n_type == BOOL) { p->n_left = block(SCONV, l, NIL, ISUNSIGNED(l->n_type) ? UNSIGNED : INT, l->n_df, l->n_ap); break; } } if (p->n_type == l->n_type) { nfree(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; nfree(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; nfree(p); return l; } o = l->n_op; m = p->n_type; if (o == ICON) { CONSZ val = glval(l); /* if named constant and pointer, allow cast to long/ulong */ if (!nncon(l) && (l->n_type & TMASK) && (m == LONG || m == ULONG)) { l->n_type = m; l->n_ap = 0; return nfree(p); } if (ISPTR(l->n_type) && !nncon(l)) break; /* cannot convert named pointers */ if (!ISPTR(m)) /* Pointers don't need to be conv'd */ switch (m) { case BOOL: val = nncon(l) ? (val != 0) : 1; slval(l, val); l->n_sp = NULL; break; case CHAR: slval(l, (char)val); break; case UCHAR: slval(l, val & 0377); break; case SHORT: slval(l, (short)val); break; case USHORT: slval(l, val & 0177777); break; case UNSIGNED: slval(l, val & 0xffffffff); break; case INT: slval(l, (int)val); break; case LONG: case LONGLONG: slval(l, (long long)val); break; case ULONG: case ULONGLONG: slval(l, val); break; case VOID: break; case LDOUBLE: case DOUBLE: case FLOAT: l->n_op = FCON; l->n_dcon = fltallo(); FCAST(l->n_dcon)->fp = val; break; default: cerror("unknown type %d", m); } l->n_type = m; l->n_ap = NULL; nfree(p); return l; } else if (l->n_op == FCON) { CONSZ lv; if (p->n_type == BOOL) lv = !FLOAT_ISZERO(FCAST(l->n_dcon)); else { FLOAT_FP2INT(lv, FCAST(l->n_dcon), m); } slval(l, lv); l->n_sp = NULL; l->n_op = ICON; l->n_type = m; l->n_ap = NULL; nfree(p); return clocal(l); } 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); p = makety(p, p->n_type, 0, 0, 0); p->n_left->n_type = INT; 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); t = p->n_type; if (ISITY(t)) t = t - (FIMAG-FLOAT); p->n_left->n_rval = p->n_left->n_type == BOOL ? RETREG(CHAR) : RETREG(t); 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 = makety(p->n_right, CHAR, 0, 0, 0); break; } #ifdef PCC_DEBUG if (xdebug) { printf("clocal end: %p\n", p); fwalk(p, eprint, 0); } #endif return(p); }
NODE * clocal(NODE *p) { struct symtab *q; NODE *r, *l; TWORD t; int o; #ifdef PCC_DEBUG if (xdebug) { printf("clocal\n"); fwalk(p, eprint, 0); } #endif switch( o = p->n_op ){ case NAME: /* handle variables */ if ((q = p->n_sp) == NULL) return p; /* Nothing to care about */ switch (q->sclass) { case PARAM: case AUTO: if (0 && q->soffset < MAXZP * SZINT && q->sclass != PARAM) { p->n_lval = -(q->soffset/SZCHAR) + ZPOFF*2; p->n_sp = NULL; } else { /* fake up a structure reference */ r = block(REG, NIL, NIL, PTR+STRTY, 0, 0); r->n_lval = 0; r->n_rval = FPREG; p = stref(block(STREF, r, p, 0, 0, 0)); } break; default: break; } break; case PMCONV: case PVCONV: if( p->n_right->n_op != ICON ) cerror( "bad conversion", 0); nfree(p); p = (buildtree(o==PMCONV?MUL:DIV, p->n_left, p->n_right)); break; case PCONV: t = p->n_type; if (t == INCREF(CHAR) || t == INCREF(UCHAR) || t == INCREF(BOOL) || t == INCREF(VOID)) break; l = p->n_left; t = l->n_type; if (t == INCREF(CHAR) || t == INCREF(UCHAR) || t == INCREF(BOOL) || t == INCREF(VOID)) break; if (p->n_type <= UCHAR || l->n_type <= UCHAR) break; /* must do runtime ptr conv */ /* if conversion to another pointer type, just remove */ if (p->n_type > BTMASK && l->n_type > BTMASK) goto delp; if (l->n_op == ICON && l->n_sp == NULL) goto delp; break; delp: l->n_type = p->n_type; l->n_qual = p->n_qual; l->n_df = p->n_df; l->n_ap = p->n_ap; p = nfree(p); break; } #ifdef PCC_DEBUG if (xdebug) { printf("clocal end\n"); fwalk(p, eprint, 0); } #endif #if 0 register struct symtab *q; register NODE *r, *l; register int o; register int m; TWORD t; //printf("in:\n"); //fwalk(p, eprint, 0); 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); r->n_lval = 0; r->n_rval = FPREG; p = stref(block(STREF, r, p, 0, 0, 0)); break; case STATIC: if (q->slevel == 0) break; p->n_lval = 0; p->n_sp = q; break; case REGISTER: p->n_op = REG; p->n_lval = 0; p->n_rval = q->soffset; break; } break; case STCALL: case CALL: /* 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->n_op != FUNARG) r->n_right = block(FUNARG, r->n_right, NIL, r->n_right->n_type, r->n_right->n_df, r->n_right->n_sue); } if (r->n_op != STARG && r->n_op != FUNARG) { l = talloc(); *l = *r; r->n_op = FUNARG; r->n_left = l; r->n_type = l->n_type; } break; case CBRANCH: l = p->n_left; /* * Remove unnecessary conversion ops. */ if (clogop(l->n_op) && l->n_left->n_op == SCONV) { if (coptype(l->n_op) != BITYPE) break; if (l->n_right->n_op == ICON) { r = l->n_left->n_left; if (r->n_type >= FLOAT && r->n_type <= LDOUBLE) break; /* Type must be correct */ t = r->n_type; nfree(l->n_left); l->n_left = r; l->n_type = t; l->n_right->n_type = t; } } break; case PCONV: /* Remove redundant PCONV's. Be careful */ l = p->n_left; if (l->n_op == ICON) { l->n_lval = (unsigned)l->n_lval; goto delp; } if (l->n_type < INT || l->n_type == LONGLONG || l->n_type == ULONGLONG) { /* float etc? */ p->n_left = block(SCONV, l, NIL, UNSIGNED, 0, 0); break; } /* if left is SCONV, cannot remove */ if (l->n_op == SCONV) break; /* if conversion to another pointer type, just remove */ if (p->n_type > BTMASK && l->n_type > BTMASK) goto delp; break; delp: l->n_type = p->n_type; l->n_qual = p->n_qual; l->n_df = p->n_df; l->n_sue = p->n_sue; nfree(p); p = l; break; case SCONV: l = p->n_left; if (p->n_type == l->n_type) { nfree(p); return l; } if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 && btdims[p->n_type].suesize == btdims[l->n_type].suesize) { 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; nfree(p); return l; } } } if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == INT && coptype(l->n_op) == BITYPE) { l->n_type = p->n_type; nfree(p); return l; } o = l->n_op; m = p->n_type; if (o == ICON) { CONSZ val = l->n_lval; if (!ISPTR(m)) /* Pointers don't need to be conv'd */ switch (m) { case CHAR: l->n_lval = (char)val; break; case UCHAR: l->n_lval = val & 0377; break; case SHORT: l->n_lval = (short)val; break; case USHORT: l->n_lval = val & 0177777; break; case ULONG: case UNSIGNED: l->n_lval = val & 0xffffffff; break; case LONG: case INT: l->n_lval = (int)val; break; case LONGLONG: l->n_lval = (long long)val; break; case ULONGLONG: l->n_lval = val; break; case VOID: break; case LDOUBLE: case DOUBLE: case FLOAT: l->n_op = FCON; l->n_dcon = val; break; default: cerror("unknown type %d", m); } l->n_type = m; l->n_sue = 0; nfree(p); return l; } if (DEUNSIGN(p->n_type) == SHORT && DEUNSIGN(l->n_type) == SHORT) { nfree(p); p = l; } 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_sue); 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 = block(SCONV, p->n_left, NIL, INT, 0, 0); p->n_right = block(SCONV, p->n_right, NIL, INT, 0, 0); p = block(SCONV, p, NIL, p->n_type, 0, 0); p->n_left->n_type = INT; break; case PMCONV: case PVCONV: if( p->n_right->n_op != ICON ) cerror( "bad conversion", 0); nfree(p); return(buildtree(o==PMCONV?MUL:DIV, p->n_left, p->n_right)); 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 = RETREG(p->n_type); break; case LS: case RS: /* shift count must be in a char * unless longlong, where it must be int */ if (p->n_right->n_op == ICON) break; /* do not do anything */ if (p->n_type == LONGLONG || p->n_type == ULONGLONG) { if (p->n_right->n_type != INT) p->n_right = block(SCONV, p->n_right, NIL, INT, 0, 0); break; } 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; } //printf("ut:\n"); //fwalk(p, eprint, 0); #endif return(p); }
/* * print out a constant node * mat be associated with a label */ int ninval(CONSZ off, int fsz, NODE *p) { union { float f; double d; int i[2]; } u; struct symtab *q; TWORD t; #ifndef USE_GAS int i, j; #endif t = p->n_type; if (t > BTMASK) p->n_type = t = INT; /* pointer */ if (p->n_op == ICON && p->n_sp != NULL && DEUNSIGN(t) != INT) uerror("element not constant"); switch (t) { case LONGLONG: case ULONGLONG: #ifdef USE_GAS printf("\t.dword %lld\n", (long long)p->n_lval); #else i = p->n_lval >> 32; j = p->n_lval & 0xffffffff; p->n_type = INT; if (bigendian) { p->n_lval = j; ninval(off, 32, p); p->n_lval = i; ninval(off+32, 32, p); } else { p->n_lval = i; ninval(off, 32, p); p->n_lval = j; ninval(off+32, 32, p); } #endif break; case INT: case UNSIGNED: printf("\t.word " CONFMT, (CONSZ)p->n_lval); if ((q = p->n_sp) != NULL) { if ((q->sclass == STATIC && q->slevel > 0)) { printf("+" LABFMT, q->soffset); } else printf("+%s", q->soname ? q->soname : exname(q->sname)); } printf("\n"); break; case SHORT: case USHORT: astypnames[SHORT] = astypnames[USHORT] = "\t.half"; return 0; case LDOUBLE: case DOUBLE: u.d = (double)p->n_dcon; if (bigendian) { printf("\t.word\t%d\n", u.i[0]); printf("\t.word\t%d\n", u.i[1]); } else { printf("\t.word\t%d\n", u.i[1]); printf("\t.word\t%d\n", u.i[0]); } break; case FLOAT: u.f = (float)p->n_dcon; printf("\t.word\t0x%x\n", u.i[0]); break; default: return 0; } return 1; }
/* this is called to do local transformations on * an expression tree preparitory to its being * written out in intermediate code. */ NODE * clocal(NODE *p) { struct symtab *q; NODE *r, *l; int o; int m; TWORD ty; int tmpnr, isptrvoid = 0; #ifdef PCC_DEBUG if (xdebug) { printf("clocal in: %p\n", p); fwalk(p, eprint, 0); } #endif switch (o = p->n_op) { case UCALL: case CALL: case STCALL: case USTCALL: if (p->n_type == VOID) break; /* * if the function returns void*, ecode() invokes * delvoid() to convert it to uchar*. * We just let this happen on the ASSIGN to the temp, * and cast the pointer back to void* on access * from the temp. */ if (p->n_type == PTR+VOID) isptrvoid = 1; r = tempnode(0, p->n_type, p->n_df, p->n_ap); tmpnr = regno(r); r = block(ASSIGN, r, p, p->n_type, p->n_df, p->n_ap); p = tempnode(tmpnr, r->n_type, r->n_df, r->n_ap); if (isptrvoid) { p = block(PCONV, p, NIL, PTR+VOID, p->n_df, 0); } p = buildtree(COMOP, r, p); break; 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); r->n_lval = 0; r->n_rval = FP; p = stref(block(STREF, r, p, 0, 0, 0)); break; case STATIC: if (q->slevel == 0) break; p->n_lval = 0; p->n_sp = q; break; case REGISTER: p->n_op = REG; p->n_lval = 0; p->n_rval = q->soffset; break; } break; case FUNARG: /* Args smaller than int are given as int */ if (p->n_type != CHAR && p->n_type != UCHAR && p->n_type != SHORT && p->n_type != USHORT) break; p->n_left = block(SCONV, p->n_left, NIL, INT, 0, 0); p->n_type = INT; p->n_ap = 0; p->n_rval = SZINT; break; case CBRANCH: l = p->n_left; /* * Remove unnecessary conversion ops. */ if (clogop(l->n_op) && l->n_left->n_op == SCONV) { if (coptype(l->n_op) != BITYPE) break; if (l->n_right->n_op == ICON) { r = l->n_left->n_left; if (r->n_type >= FLOAT && r->n_type <= LDOUBLE) break; /* Type must be correct */ ty = r->n_type; nfree(l->n_left); l->n_left = r; l->n_type = ty; l->n_right->n_type = ty; } #if 0 else if (l->n_right->n_op == SCONV && l->n_left->n_type == l->n_right->n_type) { r = l->n_left->n_left; nfree(l->n_left); l->n_left = r; r = l->n_right->n_left; nfree(l->n_right); l->n_right = r; } #endif } break; case PCONV: /* Remove redundant PCONV's. Be careful */ l = p->n_left; if (l->n_op == ICON) { l->n_lval = (unsigned)l->n_lval; goto delp; } if (l->n_type < INT || DEUNSIGN(l->n_type) == LONGLONG) { /* float etc? */ p->n_left = block(SCONV, l, NIL, UNSIGNED, 0, 0); break; } /* if left is SCONV, cannot remove */ if (l->n_op == SCONV) break; /* avoid ADDROF TEMP */ if (l->n_op == ADDROF && l->n_left->n_op == TEMP) break; /* if conversion to another pointer type, just remove */ if (p->n_type > BTMASK && l->n_type > BTMASK) goto delp; break; delp: l->n_type = p->n_type; l->n_qual = p->n_qual; l->n_df = p->n_df; l->n_ap = p->n_ap; nfree(p); p = l; break; case SCONV: l = p->n_left; if (p->n_type == l->n_type) { nfree(p); p = l; break; } 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; nfree(p); p = l; break; } } } if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == INT && coptype(l->n_op) == BITYPE) { l->n_type = p->n_type; nfree(p); p = l; } if (DEUNSIGN(p->n_type) == SHORT && DEUNSIGN(l->n_type) == SHORT) { nfree(p); p = l; } /* convert float/double to int before to (u)char/(u)short */ if ((DEUNSIGN(p->n_type) == CHAR || DEUNSIGN(p->n_type) == SHORT) && (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; break; } /* convert (u)char/(u)short to int before float/double */ if ((p->n_type == FLOAT || p->n_type == DOUBLE || p->n_type == LDOUBLE) && (DEUNSIGN(l->n_type) == CHAR || DEUNSIGN(l->n_type) == SHORT)) { p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_ap); p->n_left->n_type = INT; break; } o = l->n_op; m = p->n_type; if (o == ICON) { CONSZ val = l->n_lval; if (!ISPTR(m)) /* Pointers don't need to be conv'd */ switch (m) { case BOOL: l->n_lval = l->n_lval != 0; break; case CHAR: l->n_lval = (char)val; break; case UCHAR: l->n_lval = val & 0377; break; case SHORT: l->n_lval = (short)val; break; case USHORT: l->n_lval = val & 0177777; break; case ULONG: case UNSIGNED: l->n_lval = val & 0xffffffff; break; case LONG: case INT: l->n_lval = (int)val; break; case LONGLONG: l->n_lval = (long long)val; break; case ULONGLONG: l->n_lval = val; break; case VOID: break; case LDOUBLE: case DOUBLE: case FLOAT: l->n_op = FCON; l->n_dcon = val; break; default: cerror("unknown type %d", m); } l->n_type = m; nfree(p); p = l; } else if (o == FCON) { l->n_lval = l->n_dcon; l->n_sp = NULL; l->n_op = ICON; l->n_type = m; l->n_ap = 0; nfree(p); p = clocal(l); } 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 = block(SCONV, p->n_left, NIL, INT, 0, 0); p->n_right = block(SCONV, p->n_right, NIL, INT, 0, 0); p = block(SCONV, p, NIL, p->n_type, 0, 0); p->n_left->n_type = INT; 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 = RETREG(p->n_type); break; } #ifdef PCC_DEBUG if (xdebug) { printf("clocal out: %p\n", p); fwalk(p, eprint, 0); } #endif return(p); }
/* 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 **sp, int cnt) { union arglist *usym; int lastreg = A0 + nargregs - 1; int saveallargs = 0; int i, reg; /* * Detect if this function has ellipses and save all * argument register onto stack. */ usym = cftnsp->sdf->dfun; while (usym && usym->type != TNULL) { if (usym->type == TELLIPSIS) { saveallargs = 1; break; } ++usym; } reg = A0; /* assign hidden return structure to temporary */ if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) { param_retptr(); ++reg; } /* recalculate the arg offset and create TEMP moves */ for (i = 0; i < cnt; i++) { if ((reg > lastreg) && !xtemps) break; else if (reg > lastreg) putintemp(sp[i]); else if (sp[i]->stype == STRTY || sp[i]->stype == UNIONTY) param_struct(sp[i], ®); else if (DEUNSIGN(sp[i]->stype) == LONGLONG) param_64bit(sp[i], ®, xtemps && !saveallargs); else if (sp[i]->stype == DOUBLE || sp[i]->stype == LDOUBLE) param_double(sp[i], ®, xtemps && !saveallargs); else if (sp[i]->stype == FLOAT) param_float(sp[i], ®, xtemps && !saveallargs); else param_32bit(sp[i], ®, xtemps && !saveallargs); } /* if saveallargs, save the rest of the args onto the stack */ if (!saveallargs) return; while (reg <= lastreg) { NODE *p, *q; int off = ARGINIT/SZINT + (reg - A0); q = block(REG, NIL, NIL, INT, 0, 0); q->n_rval = reg++; p = block(REG, NIL, NIL, INT, 0, 0); p->n_rval = FP; p = block(PLUS, p, bcon(4*off), INT, 0, 0); p = block(UMUL, p, NIL, INT, 0, 0); p = buildtree(ASSIGN, p, q); ecomp(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; } }
/* * Beginning-of-function code: * * 'sp' is an array of indices in symtab for the arguments * 'cnt' is the number of arguments */ void bfcode(struct symtab **sp, int cnt) { union arglist *usym; int saveallargs = 0; int i, argofs = 0; /* * Detect if this function has ellipses and save all * argument registers onto stack. */ usym = cftnsp->sdf->dfun; while (usym && usym->type != TNULL) { if (usym->type == TELLIPSIS) { saveallargs = 1; break; } ++usym; } /* if returning a structure, move the hidden argument into a TEMP */ if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) { param_retstruct(); ++argofs; } /* recalculate the arg offset and create TEMP moves */ for (i = 0; i < cnt; i++) { if (sp[i] == NULL) continue; if ((argofs >= NARGREGS) && !xtemps) break; if (argofs > NARGREGS) { putintemp(sp[i]); } else if (sp[i]->stype == STRTY || sp[i]->stype == UNIONTY) { param_struct(sp[i], &argofs); } else if (DEUNSIGN(sp[i]->stype) == LONGLONG) { param_64bit(sp[i], &argofs, xtemps && !saveallargs); } else if (sp[i]->stype == DOUBLE || sp[i]->stype == LDOUBLE) { if (features(FEATURE_HARDFLOAT)) param_double(sp[i], &argofs, xtemps && !saveallargs); else param_64bit(sp[i], &argofs, xtemps && !saveallargs); } else if (sp[i]->stype == FLOAT) { if (features(FEATURE_HARDFLOAT)) param_float(sp[i], &argofs, xtemps && !saveallargs); else param_32bit(sp[i], &argofs, xtemps && !saveallargs); } else { param_32bit(sp[i], &argofs, xtemps && !saveallargs); } } /* if saveallargs, save the rest of the args onto the stack */ while (saveallargs && argofs < NARGREGS) { NODE *p, *q; int off = ARGINIT/SZINT + argofs; q = block(REG, NIL, NIL, INT, 0, 0); regno(q) = R0 + argofs++; p = block(REG, NIL, NIL, INT, 0, 0); regno(p) = FPREG; p = block(PLUS, p, bcon(4*off), INT, 0, 0); p = block(UMUL, p, NIL, INT, 0, 0); p = buildtree(ASSIGN, p, q); ecomp(p); } }
NODE * clocal(NODE *p) { /* this 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 */ struct symtab *q; NODE *l, *r; int o; TWORD ml; 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); r->n_lval = 0; r->n_rval = FPREG; p = stref(block(STREF, r, p, 0, 0, 0)); break; case STATIC: if (q->slevel == 0) break; p->n_lval = 0; p->n_sp = q; break; case REGISTER: p->n_op = REG; p->n_lval = 0; p->n_rval = q->soffset; break; } break; case PCONV: ml = p->n_left->n_type; l = p->n_left; if ((ml == CHAR || ml == UCHAR) && l->n_op != ICON) break; l->n_type = p->n_type; l->n_qual = p->n_qual; l->n_df = p->n_df; l->n_sue = p->n_sue; nfree(p); p = l; break; case SCONV: l = p->n_left; if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == INT) { nfree(p); return l; } if (l->n_op == ICON) { CONSZ val = l->n_lval; switch (p->n_type) { case CHAR: l->n_lval = (char)val; break; case UCHAR: l->n_lval = val & 0377; break; case SHORT: case INT: l->n_lval = (short)val; break; case USHORT: case UNSIGNED: l->n_lval = val & 0177777; break; case ULONG: case ULONGLONG: l->n_lval = val & 0xffffffff; break; case LONG: case LONGLONG: l->n_lval = (int)val; break; case VOID: break; case LDOUBLE: case DOUBLE: case FLOAT: l->n_op = FCON; l->n_dcon = val; break; default: cerror("unknown type %d", p->n_type); } l->n_type = p->n_type; nfree(p); return l; } break; } return(p); }
/* * code for the beginning of a function; a is an array of * indices in symtab for the arguments; n is the number * On m16k, space is allocated on stack for register arguments, * arguments are moved to the stack and symtab is updated accordingly. */ void bfcode(struct symtab **a, int n) { struct symtab *s; int i, r0l, r0h, a0, r2, sz, hasch, stk; int argoff = ARGINIT; if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) { /* Function returns struct, adjust arg offset */ for (i = 0; i < n; i++) a[i]->soffset += SZPOINT(INT); } /* first check if there are 1-byte parameters */ for (hasch = i = 0; i < n && i < 6; i++) if (DEUNSIGN(a[i]->stype) == CHAR) hasch = 1; stk = r0l = r0h = a0 = r2 = 0; for (i = 0; i < n; i++) { s = a[i]; sz = tsize(s->stype, s->sdf, s->ssue); if (ISPTR(s->stype) && ISFTN(DECREF(s->stype))) sz = SZLONG; /* function pointers are always 32 */ if (stk == 0) switch (sz) { case SZCHAR: if (r0l) { if (r0h) break; argmove(s, 1); r0h = 1; } else { argmove(s, 0); r0l = 1; } continue; case SZINT: if (s->stype > BTMASK) { /* is a pointer */ if (a0) { if (r0l || hasch) { if (r2) break; argmove(s, R2); r2 = 1; } else { argmove(s, R0); r0l = r0h = 1; } } else { argmove(s, A0); a0 = 1; } } else if (r0l || hasch) { if (r2) { if (a0) break; argmove(s, A0); a0 = 1; } else { argmove(s, R2); r2 = 1; } } else { argmove(s, R0); r0l = r0h = 1; } continue; case SZLONG: if (r0l||r0h||r2) break; argmove(s, R0); r0l = r0h = r2 = 1; continue; default: break; } stk = 1; s->soffset = argoff; argoff += sz; } }
void zzzcode(NODE *p, int c) { NODE *l, *r; TWORD t; int m; char *ch; switch (c) { case 'N': /* logical ops, turned into 0-1 */ /* use register given by register 1 */ cbgen( 0, m=getlab2()); deflab( p->n_label ); printf( " clrl %s\n", rnames[getlr( p, '1' )->n_rval] ); deflab( m ); return; case 'A': /* Assign a constant directly to a memory position */ printf("\t"); if (p->n_type < LONG || ISPTR(p->n_type)) casg(p); else casg64(p); printf("\n"); break; case 'B': /* long long compare */ twollcomp(p); break; case 'C': /* num words pushed on arg stack */ printf("$%d", p->n_qual); break; case 'D': /* INCR and DECR */ zzzcode(p->n_left, 'A'); printf("\n "); #if 0 case 'E': /* INCR and DECR, FOREFF */ if (p->n_right->n_lval == 1) { printf("%s", (p->n_op == INCR ? "inc" : "dec") ); prtype(p->n_left); printf(" "); adrput(stdout, p->n_left); return; } printf("%s", (p->n_op == INCR ? "add" : "sub") ); prtype(p->n_left); printf("2 "); adrput(stdout, p->n_right); printf(","); adrput(p->n_left); return; #endif case 'F': /* register type of right operand */ { register NODE *n; register int ty; n = getlr( p, 'R' ); ty = n->n_type; if (x2debug) printf("->%d<-", ty); if ( ty==DOUBLE) printf("d"); else if ( ty==FLOAT ) printf("f"); else printf("l"); return; } case 'G': /* emit conversion instructions */ sconv(p); break; case 'J': /* jump or ret? */ { struct interpass *ip = DLIST_PREV((struct interpass *)p2env.epp, qelem); if (ip->type != IP_DEFLAB || ip->ip_lbl != getlr(p, 'L')->n_lval) expand(p, FOREFF, "jbr LL"); else printf("ret"); } break; case 'L': /* type of left operand */ case 'R': /* type of right operand */ { register NODE *n; n = getlr ( p, c); if (x2debug) printf("->%d<-", n->n_type); prtype(n); return; } case 'O': /* print out emulated ops */ expand(p, FOREFF, "\tmovq AR,-(%sp)\n"); expand(p, FOREFF, "\tmovq AL,-(%sp)\n"); if (p->n_op == DIV && p->n_type == ULONGLONG) ch = "udiv"; else if (p->n_op == DIV) ch = "div"; else if (p->n_op == MOD && p->n_type == ULONGLONG) ch = "umod"; else if (p->n_op == MOD) ch = "mod"; else if (p->n_op == MUL) ch = "mul"; else ch = 0, comperr("ZO %d", p->n_op); printf("\tcalls $4,__%sdi3\n", ch); break; case 'Z': /* complement mask for bit instr */ printf("$%Ld", ~p->n_right->n_lval); return; case 'U': /* 32 - n, for unsigned right shifts */ t = DEUNSIGN(p->n_left->n_type); m = t == CHAR ? 8 : t == SHORT ? 16 : 32; printf("$" CONFMT, m - p->n_right->n_lval); return; case 'T': /* rounded structure length for arguments */ { int size; size = p->n_stsize; SETOFF( size, 4); printf("$%d", size); return; } case 'S': /* structure assignment */ { register int size; size = p->n_stsize; l = r = NULL; /* XXX gcc */ if( p->n_op == STASG ){ l = p->n_left; r = p->n_right; } else if( p->n_op == STARG ){ /* store an arg into a temporary */ printf("\tsubl2 $%d,%%sp\n", size < 4 ? 4 : size); l = mklnode(OREG, 0, SP, INT); r = p->n_left; } else cerror( "STASG bad" ); if( r->n_op == ICON ) r->n_op = NAME; else if( r->n_op == REG ) r->n_op = OREG; else if( r->n_op != OREG ) cerror( "STASG-r" ); if (size != 0) { if( size <= 0 || size > 65535 ) cerror("structure size <0=0 or >65535"); switch(size) { case 1: printf(" movb "); break; case 2: printf(" movw "); break; case 4: printf(" movl "); break; case 8: printf(" movq "); break; default: printf(" movc3 $%d,", size); break; } adrput(stdout, r); printf(","); adrput(stdout, l); printf("\n"); } if( r->n_op == NAME ) r->n_op = ICON; else if( r->n_op == OREG ) r->n_op = REG; if (p->n_op == STARG) tfree(l); } break; default: comperr("illegal zzzcode '%c'", c); } }