/* * Sort arglist so that register assignments ends up last. */ static int argsort(NODE *p) { NODE *q, *r; int rv = 0; if (p->n_op != CM) { if (p->n_op == ASSIGN && p->n_left->n_op == REG && coptype(p->n_right->n_op) != LTYPE) { q = tempnode(0, p->n_type, p->n_df, p->n_ap); r = ccopy(q); p->n_right = buildtree(COMOP, buildtree(ASSIGN, q, p->n_right), r); } return rv; } if (p->n_right->n_op == CM) { /* fixup for small structs in regs */ q = p->n_right->n_left; p->n_right->n_left = p->n_left; p->n_left = p->n_right; p->n_right = p->n_left->n_right; p->n_left->n_right = q; } if (p->n_right->n_op == ASSIGN && p->n_right->n_left->n_op == REG && coptype(p->n_right->n_right->n_op) != LTYPE) { /* move before everything to avoid reg trashing */ q = tempnode(0, p->n_right->n_type, p->n_right->n_df, p->n_right->n_ap); r = ccopy(q); p->n_right->n_right = buildtree(COMOP, buildtree(ASSIGN, q, p->n_right->n_right), r); } if (p->n_right->n_op == ASSIGN && p->n_right->n_left->n_op == REG) { if (p->n_left->n_op == CM && p->n_left->n_right->n_op == STASG) { q = p->n_left->n_right; p->n_left->n_right = p->n_right; p->n_right = q; rv = 1; } else if (p->n_left->n_op == STASG) { q = p->n_left; p->n_left = p->n_right; p->n_right = q; rv = 1; } } return rv | argsort(p->n_left); }
/* * See if there is a goto in the tree. * XXX this function is a hack for a flaw in handling of * compound expressions and inline functions and should not be * needed. */ static int hasgoto(NODE *p) { int o = coptype(p->n_op); if (o == LTYPE) return 0; if (p->n_op == GOTO) return 1; if (o == UTYPE) return hasgoto(p->n_left); if (hasgoto(p->n_left)) return 1; return hasgoto(p->n_right); }
/* 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); }
/* * local optimizations, most of which are probably * machine independent */ NODE * optim(NODE *p) { int o, ty; NODE *sp, *q; OFFSZ sz; int i; if (odebug) return(p); ty = coptype(p->n_op); if( ty == LTYPE ) return(p); if( ty == BITYPE ) p->n_right = optim(p->n_right); p->n_left = optim(p->n_left); /* collect constants */ again: o = p->n_op; switch(o){ case SCONV: if (concast(p->n_left, p->n_type)) { q = p->n_left; nfree(p); p = q; break; } /* FALLTHROUGH */ case PCONV: if (p->n_type != VOID) p = clocal(p); break; case FORTCALL: p->n_right = fortarg( p->n_right ); break; case ADDROF: if (LO(p) == TEMP) break; if( LO(p) != NAME ) cerror( "& error" ); if( !andable(p->n_left) && !statinit) break; LO(p) = ICON; setuleft: /* paint over the type of the left hand side with the type of the top */ p->n_left->n_type = p->n_type; p->n_left->n_df = p->n_df; p->n_left->n_ap = p->n_ap; q = p->n_left; nfree(p); p = q; break; case NOT: case UMINUS: case COMPL: if (LCON(p) && conval(p->n_left, o, p->n_left)) p = nfree(p); break; case UMUL: /* Do not discard ADDROF TEMP's */ if (LO(p) == ADDROF && LO(p->n_left) != TEMP) { q = p->n_left->n_left; nfree(p->n_left); nfree(p); p = q; break; } if( LO(p) != ICON ) break; LO(p) = NAME; goto setuleft; case RS: if (LCON(p) && RCON(p) && conval(p->n_left, o, p->n_right)) goto zapright; sz = tsize(p->n_type, p->n_df, p->n_ap); if (LO(p) == RS && RCON(p->n_left) && RCON(p) && (RV(p) + RV(p->n_left)) < sz) { /* two right-shift by constants */ RV(p) += RV(p->n_left); p->n_left = zapleft(p->n_left); } #if 0 else if (LO(p) == LS && RCON(p->n_left) && RCON(p)) { RV(p) -= RV(p->n_left); if (RV(p) < 0) o = p->n_op = LS, RV(p) = -RV(p); p->n_left = zapleft(p->n_left); } #endif if (RO(p) == ICON) { if (RV(p) < 0) { RV(p) = -RV(p); p->n_op = LS; goto again; } #ifdef notyet /* must check for side effects, --a >> 32; */ if (RV(p) >= tsize(p->n_type, p->n_df, p->n_sue) && ISUNSIGNED(p->n_type)) { /* ignore signed shifts */ /* too many shifts */ tfree(p->n_left); nfree(p->n_right); p->n_op = ICON; p->n_lval = 0; p->n_sp = NULL; } else #endif /* avoid larger shifts than type size */ if (RV(p) >= sz) { RV(p) = RV(p) % sz; werror("shift larger than type"); } if (RV(p) == 0) p = zapleft(p); } break; case LS: if (LCON(p) && RCON(p) && conval(p->n_left, o, p->n_right)) goto zapright; sz = tsize(p->n_type, p->n_df, p->n_ap); if (LO(p) == LS && RCON(p->n_left) && RCON(p)) { /* two left-shift by constants */ RV(p) += RV(p->n_left); p->n_left = zapleft(p->n_left); } #if 0 else if (LO(p) == RS && RCON(p->n_left) && RCON(p)) { RV(p) -= RV(p->n_left); p->n_left = zapleft(p->n_left); } #endif if (RO(p) == ICON) { if (RV(p) < 0) { RV(p) = -RV(p); p->n_op = RS; goto again; } #ifdef notyet /* must check for side effects */ if (RV(p) >= tsize(p->n_type, p->n_df, p->n_sue)) { /* too many shifts */ tfree(p->n_left); nfree(p->n_right); p->n_op = ICON; p->n_lval = 0; p->n_sp = NULL; } else #endif /* avoid larger shifts than type size */ if (RV(p) >= sz) { RV(p) = RV(p) % sz; werror("shift larger than type"); } if (RV(p) == 0) p = zapleft(p); } break; case MINUS: if (LCON(p) && RCON(p) && p->n_left->n_sp == p->n_right->n_sp) { /* link-time constants, but both are the same */ /* solve it now by forgetting the symbols */ p->n_left->n_sp = p->n_right->n_sp = NULL; } if( !nncon(p->n_right) ) break; RV(p) = -RV(p); o = p->n_op = PLUS; case MUL: /* * Check for u=(x-y)+z; where all vars are pointers to * the same struct. This has two advantages: * 1: avoid a mul+div * 2: even if not allowed, people may get surprised if this * calculation do not give correct result if using * unaligned structs. */ if (p->n_type == INTPTR && RCON(p) && LO(p) == DIV && RCON(p->n_left) && RV(p) == RV(p->n_left) && LO(p->n_left) == MINUS) { q = p->n_left->n_left; if (q->n_left->n_type == PTR+STRTY && q->n_right->n_type == PTR+STRTY && strmemb(q->n_left->n_ap) == strmemb(q->n_right->n_ap)) { p = zapleft(p); p = zapleft(p); } } /* FALLTHROUGH */ case PLUS: case AND: case OR: case ER: /* commutative ops; for now, just collect constants */ /* someday, do it right */ if( nncon(p->n_left) || ( LCON(p) && !RCON(p) ) ) SWAP( p->n_left, p->n_right ); /* make ops tower to the left, not the right */ if( RO(p) == o ){ NODE *t1, *t2, *t3; t1 = p->n_left; sp = p->n_right; t2 = sp->n_left; t3 = sp->n_right; /* now, put together again */ p->n_left = sp; sp->n_left = t1; sp->n_right = t2; sp->n_type = p->n_type; p->n_right = t3; } if(o == PLUS && LO(p) == MINUS && RCON(p) && RCON(p->n_left) && conval(p->n_right, MINUS, p->n_left->n_right)){ zapleft: q = p->n_left->n_left; nfree(p->n_left->n_right); nfree(p->n_left); p->n_left = q; } if( RCON(p) && LO(p)==o && RCON(p->n_left) && conval( p->n_right, o, p->n_left->n_right ) ){ goto zapleft; } else if( LCON(p) && RCON(p) && conval( p->n_left, o, p->n_right ) ){ zapright: nfree(p->n_right); q = makety(p->n_left, p->n_type, p->n_qual, p->n_df, p->n_ap); nfree(p); p = clocal(q); break; } /* change muls to shifts */ if( o == MUL && nncon(p->n_right) && (i=ispow2(RV(p)))>=0){ if( i == 0 ) { /* multiplication by 1 */ goto zapright; } o = p->n_op = LS; p->n_right->n_type = INT; p->n_right->n_df = NULL; RV(p) = i; } /* change +'s of negative consts back to - */ if( o==PLUS && nncon(p->n_right) && RV(p)<0 ){ RV(p) = -RV(p); o = p->n_op = MINUS; } /* remove ops with RHS 0 */ if ((o == PLUS || o == MINUS || o == OR || o == ER) && nncon(p->n_right) && RV(p) == 0) { goto zapright; } break; case DIV: if( nncon( p->n_right ) && p->n_right->n_lval == 1 ) goto zapright; if (LCON(p) && RCON(p) && conval(p->n_left, DIV, p->n_right)) goto zapright; if (RCON(p) && ISUNSIGNED(p->n_type) && (i=ispow2(RV(p))) > 0) { p->n_op = RS; RV(p) = i; q = p->n_right; if(tsize(q->n_type, q->n_df, q->n_ap) > SZINT) p->n_right = makety(q, INT, 0, 0, 0); break; } break; case MOD: if (RCON(p) && ISUNSIGNED(p->n_type) && ispow2(RV(p)) > 0) { p->n_op = AND; RV(p) = RV(p) -1; break; } break; case EQ: case NE: case LT: case LE: case GT: case GE: case ULT: case ULE: case UGT: case UGE: if( !LCON(p) ) break; /* exchange operands */ sp = p->n_left; p->n_left = p->n_right; p->n_right = sp; p->n_op = revrel[p->n_op - EQ ]; break; #ifdef notyet case ASSIGN: /* Simple test to avoid two branches */ if (RO(p) != NE) break; q = p->n_right; if (RCON(q) && RV(q) == 0 && LO(q) == AND && RCON(q->n_left) && (i = ispow2(RV(q->n_left))) && q->n_left->n_type == INT) { q->n_op = RS; RV(q) = i; } break; #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); }
/* 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; }