#ifndef lint static char sccsid[] = "@(#)optim2.c 1.1 86/02/03 Copyr 1985 Sun Micro"; #endif /* * Copyright (c) 1985 by Sun Microsystems, Inc. */ #include "cpass2.h" /* * routines to detect and to deal with doubly-indexed OREGs. * Initially, these were all stolen from the vax code. */ base( p ) register NODE *p; { register int o = p->in.op; register v,maxoff; register NODE *lp,*rp; if ( BTYPE(p->in.type) == DOUBLE ) maxoff = 123; else maxoff = 127; if ( o==REG && isbreg( p->tn.rval )) return( p->tn.rval ); lp = p->in.left; rp = p->in.right; if ((o==PLUS || o==MINUS) && lp->in.op==REG && isbreg( lp->tn.rval ) && rp->in.op==ICON && rp->in.name[0] == '\0' && (use68020 || (v=rp->tn.lval) <= maxoff && v >= -128) ) return( lp->tn.rval ); return( -1 ); } offset( p, notused ) register NODE *p; int notused; { if ( p->in.op==REG ) { if ( p->in.type==INT || p->in.type==UNSIGNED || ISPTR(p->in.type) ) { return( p->tn.rval ); } if ( p->in.type==SHORT ) { /* * result is: short index flag + xreg */ return( (1<<8) + p->tn.rval ); } } if (use68020) { /* * test for scaled indexing */ int count; NODE *lp = p->in.left; NODE *rp = p->in.right; if ( p->in.op==LS && lp->in.op==REG && (lp->in.type==INT || lp->in.type==UNSIGNED || lp->in.type == SHORT ) && (rp->in.op==ICON && rp->in.name[0]=='\0') && (count = rp->tn.lval) >= 0 && count <= 3 ) { int scale = (1 << count); if ( p->in.type == SHORT ) { /* * result is: short index flag + scale factor + xreg */ return( (1<<8) + (scale<<4) + lp->tn.rval ); } /* * result is: scale factor + xreg */ return( (scale<<4) + lp->tn.rval ); } } return( -1 ); } makeor2( p, basenode, breg, scale_plus_xreg ) register NODE *p; /* node to be rewritten */ register NODE *basenode; /* base node (usually a ptr) */ int breg; /* base register */ int scale_plus_xreg; /* scale factor + index register */ { register NODE *t; /* from which tn.lval, tn.name are obtained */ register int i; NODE *f; register flags; int scale, xreg, shortx, ibit; ibit = 0; shortx= (scale_plus_xreg >> 8) & 1; scale = (scale_plus_xreg >> 4) & 017; xreg = scale_plus_xreg & 017; p->in.op = OREG; f = p->in.left; /* have to free this subtree later */ /* init base */ switch (basenode->in.op) { case ICON: case REG: case OREG: t = basenode; break; case MINUS: basenode->in.right->tn.lval = -basenode->in.right->tn.lval; case PLUS: t = basenode->in.right; break; case INCR: case ASG MINUS: t = basenode->in.left; break; case UNARY MUL: t = basenode->in.left->in.left; break; default: cerror("illegal makeor2"); } p->tn.lval = t->tn.lval; #ifndef FLEXNAMES for(i=0; i<NCHNAM; ++i) p->in.name[i] = t->in.name[i]; #else p->in.name = t->in.name; #endif /* * For 68020, R2UPK3 encodes the following data: * int shortx:1; short index * int ibit:1; memory indirect mode (unused) * int scale:4; scale factor (1,2,4,8) * For 68010, only the short index flag is encoded. */ R2PACKFLGS(flags,shortx,ibit,scale); p->tn.rval = R2PACK( breg, xreg, flags ); tfree(f); return; } /* * Multiply a value by a constant. * Multiplies are slow on the 68010, so do some shifting and * adding here. * For each 1-bit in the constant the value is shifted * by n where 2**n equals the bit. * The shifted value is then added into an accumulated value. * One tricky part is for runs of three or more consecutive * bits. For a number like 7, it is cheaper to calculate * (8 - 1), than it is (3 + 2 + 1) */ conmul(p, cookie) register NODE *p; { register const; /* The constant value */ register int curpos; /* Position of last one bit */ register int power; /* The bit being tested */ int run; /* Num of consecutive one bits */ int nbits; /* Num of bits since the last one bit */ int negconst; /* Is the constant <0 ? */ char * destreg; /* name of "AL" register */ char * helper; /* name of "A1" register */ int helperreg; TWORD ltype; char typechar; int t; /* * first determine how many instructions we will need to do * it in line. Cost estimator is: # single bits + 2* # of multi bit * runs. If this exceeds 5, then it is more compact to use a * multiply instruction or routine. */ const = p->in.right->tn.lval; if (const<0){ negconst = 1; const = - const; } else negconst = 0; run = const & (const>>1); /* each run shortened by one bit */ run = cntbits( run ^ (run>>1) ) + (run&1); /* 2*# multibit runs */ nbits = cntbits( const ^ (const>>1)) +(const&1); /* 2* #total runs*/ run += nbits; /* 2* estimator */ ltype = p->in.left->in.type; if ((ttype(ltype,TUCHAR|TCHAR|TUSHORT|TSHORT) && run>6) || (run > 10)){ /* old-fashioned way */ if (tshape( p->in.right, SSCON ) ){ if (negconst){ expand( p->in.left, INAREG|INTAREG, " negZB AL\nZv"); p->in.right->tn.lval = const; } if (ttype(ltype, TSHORT|TCHAR)){ expand( p, cookie, " muls #CR,AL\nZv"); } else if (ttype(ltype, TUSHORT|TUCHAR)){ expand( p, cookie, " mulu #CR,AL\n"); } else if (use68020) { if (ISUNSIGNED(p->in.type)) { expand( p, cookie, " mulul #CR,AL\n"); } else { expand( p, cookie, " mulsl #CR,AL\nZv"); } } else { expand( p, cookie, "\tmovl\tAL,A1\n\tswap\tA1\n\tmulu\t#CR,AL\n"); fputs( ttype(ltype, TULONG|TUNSIGNED|TUCHAR|TPOINT) ? "\tmulu" : "\tmuls", stdout); expand( p, cookie, "\t#CR,A1\n\tswap\tA1\n\tclrw\tA1\n\taddl\tA1,AL\nZv"); } } else if (use68020) { if (ISUNSIGNED(p->in.type)) { expand( p, cookie, " mulul #CR,AL\n"); } else { expand( p, cookie, " mulsl #CR,AL\nZv"); } } else { order( p->in.right, INTAREG ); order( p, INAREG|INTAREG ); } return; } typechar = (((t=p->in.type)==CHAR)||t==UCHAR) ? 'b' : (t==SHORT||t==USHORT) ? 'w' : 'l'; /* * if the result type is larger than the operand type, we must expand * the operand before doing the operation. */ switch( p->in.left->tn.type){ case UCHAR: case USHORT: if (typechar=='b' || typechar=='w') break; expand( p->in.left, INAREG|INTAREG, " andl #0xffff,AL\n"); break; case CHAR: case SHORT: if (typechar=='b' || typechar=='w') break; expand( p->in.left, INAREG|INTAREG, " extl AL\n"); break; } p->in.left->tn.type = t; nbits = ffs( const )-1; power = 0; helperreg = resc[0].tn.rval ; helper = rnames[ helperreg ]; destreg = rnames[ p->in.left->tn.rval]; if (negconst){ expand( p->in.left, INAREG|INTAREG, " negZB AL\nZv"); } if (nbits>0){ shiftreg( nbits, destreg, helperreg , 1, typechar, t); const >>= nbits; } if (const==1) return; /* * the first time is special (ask Ann Landers). If it is a run, * then we move, negate, shift add. Otherwise, we don't negate. */ run = ffs( ~const) -1; expand(p, cookie, " movZB AL,A1\n"); switch (run){ case 2: shiftreg( 1, helper, -1, 1, typechar, t); expand( p, cookie, "\taddZB\tA1,AL\nZv"); /* fall through */ case 1: curpos = 0; break; default: shiftreg( run, helper, -1, 1, typechar, t); expand( p->in.left, INAREG|INTAREG, " negZB AL\nZv"); expand( p, cookie, "\taddZB\tA1,AL\nZv"); curpos = 1; break; } for ( const >>= run; const >>= (power=ffs(const))-1; const >>= run){ run = ffs(~const)-1; switch(run) { case 1: shiftreg( power-curpos, helper, -1, 1, typechar, t); expand( p, cookie, "\taddZB\tA1,AL\nZv"); curpos = 0; break; case 2: shiftreg( power-curpos, helper, -1, 1, typechar, t); expand( p, cookie, "\taddZB\tA1,AL\nZv"); shiftreg( 1, helper, -1, 1, typechar, t); expand( p, cookie, "\taddZB\tA1,AL\nZv"); curpos = 0; break; default: shiftreg( power-curpos, helper, -1, 1, typechar, t); expand( p, cookie, "\tsubZB\tA1,AL\nZv"); shiftreg( run, helper, -1, 1, typechar, t); expand( p, cookie, "\taddZB\tA1,AL\nZv"); curpos = 1; break; } } } /* * divide a signed number by a constant. * divides are really slow on this machine, so we really want to avoid them. * the only interesting case is divide by power-of-two. Others, we really * have to do the division. */ void condiv( p, cookie ) register NODE *p; { char sizechar; register const; register TWORD ltype; int lab1f; char * lname = rnames[p->in.left->tn.rval]; const = p->in.right->tn.lval; ltype = p->in.left->tn.type; if (const & (const-1)){ /* too bad -- not a positive power of two */ switch (ltype){ case CHAR: print_str_str_nl( " extw ", lname ); /* fall through */ case SHORT: print_str_str_nl( " extl ", lname ); printf( " divs #%d,%s\n", const, lname); break; default: if (use68020) { printf( " divsl #%d,%s\n", const, lname); } else { order( p->in.right, INTAREG ); order( p, INTAREG ); } break; } return; } switch (ltype){ case CHAR: sizechar = 'b'; break; case SHORT: sizechar = 'w'; break; default: sizechar = 'l'; } lab1f = getlab(); printf(" tst%c %s\n jge L%d\n", sizechar, lname, lab1f); print_str((const >= 1 && const <= 8) ? " addq" : " add"); printf("%c #%d,%s\n", sizechar, const-1, lname ); deflab(lab1f); const = ffs(const)-1; /* like shiftreg(), but for right, arithmetic shifts */ while (const > 0){ if (const> 8){ printf(" asr%c #8,%s\n", sizechar, lname ); const -= 8; } else { printf(" asr%c #%d,%s\n", sizechar, const, lname ); const = 0; } } return; } /* * remainder a signed number by a constant. * remainders are really slow on this machine, so we really want to avoid them. * the only interesting case is powers-of-two. Others, we really * have to do the division. */ void conrem( p, cookie ) register NODE *p; { char sizechar, opchar; register const; register TWORD ltype; char * lname = rnames[p->in.left->tn.rval]; char * helper, u; int lab1f, lab2f; const = p->in.right->tn.lval; ltype = p->in.left->tn.type; if (const & (const-1)){ /* too bad -- not a positive power of two */ switch (ltype){ case CHAR: print_str_str_nl( " extw ", lname ); /* fall through */ case SHORT: print_str_str_nl( " extl ", lname ); printf( " divs #%d,%s\n", const, lname); print_str_str_nl( " swap ", lname ); break; case UCHAR: print_str_str_nl(" andl #0xff,", lname ); goto divu; case USHORT: print_str_str_nl(" andl #0xffff,", lname ); divu: printf(" divu #%d,%s\n", const, lname); print_str_str_nl(" swap ", lname); break; default: if (use68020) { helper = rnames[resc[0].tn.rval]; printf(" %s #%d,%s:%s\n", (ISUNSIGNED(ltype)? "divull" : "divsll"), const, helper, lname); printf(" movl %s,%s\n", helper, lname); } else { order( p->in.right, INTAREG ); order( p, INTAREG ); } break; } return; } helper = rnames[resc[0].tn.rval]; u = 0; switch (ltype){ case UCHAR: u = 1; /* fall through */ case CHAR: sizechar = 'b'; opchar = 'w'; break; case USHORT: u = 1; /* fall through */ case SHORT: sizechar = 'w'; opchar = 'w'; break; case UNSIGNED: u = 1; /* fall through */ default: sizechar = 'l'; opchar = 'l'; } if (!u){ lab1f = getlab(); lab2f = getlab(); } if (const<=128 && const >=-128){ printf(" moveq #%d,%s\n", const-1, helper); if (!u){ printf(" tst%c %s\n jge L%d\n neg%c %s\n", sizechar, lname, lab1f, sizechar, lname); printf(" and%c %s,%s\n neg%c %s\n jra L%d\n", opchar, helper, lname, opchar, lname, lab2f ); deflab( lab1f ); } printf(" and%c %s,%s\n", opchar, helper, lname); if (!u){ deflab(lab2f);} } else { if (!u){ printf(" mov%c %s,%s\n jge L%d\n neg%c %s\n", sizechar, lname, helper, lab1f, sizechar, lname); deflab(lab1f); } printf(" and%c #%d,%s\n", opchar, const-1, lname ); if (!u){ printf(" tst%c %s\n jge L%d\n neg%c %s\n", sizechar, helper, lab2f, opchar, lname ); deflab(lab2f); } } return; } optim2( p ) register NODE *p; { register NODE *q; register NODE *r; register long v; register op; int w; int lsize, rsize; NODE *rl, *rr, *qq; TWORD t; /* * reduction of strength on integer constant operands * this is a practical, fruitful area of peephole code optimization, * since there are so many easy things that can be done. * we also check for possible single-o OREGs in a place where * the oreg2() should but does not. */ op = p->in.op; switch (optype(op)) { case LTYPE: break; case UTYPE: optim2(p->in.left); break; case BITYPE: optim2(p->in.left); optim2(p->in.right); break; } switch (op){ case LS: case ASG LS: case RS: case ASG RS: /* if rhs is an extending SCONV, don't bother converting */ r = p->in.right; if (isconv(r, SHORT, USHORT) || isconv(r, CHAR, UCHAR)) { q = r->in.left; *r = *q; q->in.op = FREE; } /* one interesting case: <lhs> <op> 0 */ if (r->tn.op != ICON ) break; if (r->tn.lval == 0 && r->tn.name[0] == '\0' ){ promoteleft: t = p->in.type; q = p->in.left; *p = *q; /* paint over */ p->in.type = t; q->in.op = r->in.op = FREE; } /* could test for count of 1, too, but this is easier to do later on */ break; case UNARY MUL: /* in case this wasn't done earlier... */ if (p->in.left->in.op == ICON) { q = p->in.left; t = p->in.type; *p = *q; p->in.op = NAME; p->in.type = t; q->in.op = FREE; break; } /* * put potential double index OREG trees into a canonical * form: ( <base> + <offset> ) + <index> */ p = p->in.left; if (p->in.op != PLUS) break; q = p->in.left; r = p->in.right; if ( ISPTR(r->in.type) ) { /* * put the pointer on the left */ p->in.left = r; p->in.right = q; q = p->in.left; r = p->in.right; } if ( ISPTR(q->in.type) && (r->in.op == PLUS || r->in.op == MINUS) && !ISPTR(r->in.left->in.type) && r->in.right->in.op == ICON ) { /* * <ptr exp> + ( <int exp> [+-] ICON ) * rewrite as * (<ptr exp> [+-] ICON) + <int exp> */ p->in.right = r->in.left; r->in.left = q; p->in.left = r; r->in.type = q->in.type; break; } if (r->in.op == LS && ( (rr = r->in.right)->in.op == ICON ) && ( (rl = r->in.left)->in.op == PLUS || rl->in.op == MINUS ) && !ISPTR(rl->in.left->in.type) && rl->in.right->in.op == ICON ) { /* * <ptr exp> + ((<int exp> [+-] ICON) << ICON) * rewrite as * (<ptr exp> [+-] ICON*) + (<int exp> << ICON) */ r->in.left = rl->in.left; rl->in.left = q; p->in.left = rl; rl->in.type = q->in.type; rl->in.right->tn.lval <<= rr->tn.lval; break; } break; case PLUS: case ASG PLUS: case MINUS: case ASG MINUS: /* * one interesting cases: <lhs> <op> 0. * <address reg> + SCONV( <short> ) is a good one, too, * but is best done later on. */ if (((r=p->in.right)->tn.op == ICON && r->tn.lval == 0 && r->tn.name[0] == '\0' ) || (r->tn.op == FCON && r->fpn.dval == 0.0 )) { goto promoteleft; } break; case MUL: /* * put constants on the right */ if (p->in.left->in.op == ICON && p->in.right->in.op != ICON) { r = p->in.right; p->in.right = p->in.left; p->in.left = r; } /* fall through */ case ASG MUL: case DIV: case ASG DIV: case MOD: case ASG MOD: /* * two interesting case: <lhs> <op> 1 * and: small multiplies that can be handled by * the feeble instructions. */ if (((r=p->in.right)->tn.op == ICON && r->tn.lval == 1 && r->tn.name[0] == '\0') || (r->tn.op == FCON && r->fpn.dval == 1.0 )) { switch (op){ case MOD: case ASG MOD: /* * x%1 == 0 * BUT x might have side effects, so... * x%1 ==> (x,0) */ p->in.op = COMOP; if (r->tn.op==FCON) r->fpn.dval = 0.0; else r->tn.lval = 0; break; default: goto promoteleft; } break; } if (op == DIV || op == ASG DIV){ /* * a very particular case: a difference of two * pointers, divided by a power of two should * always give an integral result (this is * pointer subtraction, with the implied divide * by sizeof( *p ) ). So, we can change this * into a shift, if we ever see it. * AND... * a less peculiar case: unsigned divide by a power of 2. */ if ( (p->in.type == UNSIGNED && r->in.op ==ICON ) || ((p->in.type == INT || p->in.type == UNSIGNED) && r->in.op == ICON && (q = p->in.left)->in.op == MINUS && ISPTR(q->in.left->in.type) && ISPTR(q->in.right->in.type)) ){ if (cntbits( v=r->tn.lval )==1 && r->in.name[0]=='\0' ){ /* well, looks like we found one */ w = ffs( v ) - 1; p->in.op = op += RS - DIV; /* keep ASG if present */ r->tn.lval = w; break; } } } /* the other good case is multiply by a power of two, and thats already being handled in the front end */ /* * many multiplies * can be done directly in the hardware: * {SHORT, USHORT, CHAR, UCHAR} x * {SHORT, USHORT, CHAR, UCHAR, ICON} * * so can the corresponding divides. */ if (p->in.type != INT && p->in.type != UNSIGNED && !ISPTR(p->in.type)) break; q = p->in.left; if ( isconv(q, SHORT, USHORT ) ) lsize = 2; else if (isconv(q, CHAR, UCHAR )) lsize = 1; else if (q->in.type == SHORT) lsize = 0; else break; if ( isconv(r, SHORT, USHORT ) || special(r, SSCON) ) rsize = 2; else if (isconv(r, CHAR, UCHAR )) rsize = 1; else break; /* we've looked at both sides and it looks plausable */ /* rearrange lhs */ if (lsize == 1){ /* diddle SCONV, but leave it in place */ q->in.type = (q->in.left->tn.type==UCHAR)?USHORT:SHORT; } else if(lsize == 2){ p->in.left = q->in.left; q->in.op = FREE; } /* now rearrange rhs */ if (rsize == 1){ r->in.type = (r->in.left->tn.type==UCHAR)?USHORT:SHORT; } else if (r->tn.op == ICON){ r->tn.type = SHORT; } else { p->in.right = r->in.left; r->in.op = FREE; } /* * The result of the mul[us] instructions are ints * anyway, so leave the type of the MUL node alone. * But DIV must be acknowleged as short. */ if ( (op==DIV || op== ASG DIV || op==MOD || op==ASG MOD) && p->in.type != SHORT && p->in.type != USHORT){ w = (p->in.right->tn.type==SHORT && p->in.left->tn.type==SHORT) ? SHORT : USHORT; q = talloc(); *q = *p; p->in.op = SCONV; q->in.type = w; p->in.left = q; p->in.right = 0; } break; case SCONV: /* * conversions from float to double * in a coprocessor register are vacuous */ q = p->in.left; if (p->in.type == DOUBLE && q->in.type == FLOAT && q->in.op == REG && iscreg(q->tn.rval)) { TWORD t = p->in.type; *p = *q; p->in.type = t; q->in.op = FREE; return; } /* * John Gilmore memorial hack * * garbage-can case: * if this is a shorten of a simple calculation * whose (2) operands are no larger than the * result type, then we can do the operation more * cheaply, no? * The architypical case looks like: * (SCONV<short> (+<int> (SCONV<int> NAME<short> ) ICON )) * p^ q^ r^ */ if ( q->in.type!=INT && q->in.type!=UNSIGNED ) return; switch (q->in.op){ case PLUS: case MINUS: case MUL: case DIV: case MOD: case LS: case RS: case AND: case OR: case ER: break; default: return; } if ( p->in.type==SHORT || p->in.type==USHORT ){ w = 2; v = 0x7fff; }else if ( p->in.type==CHAR || p->in.type==UCHAR ){ w = 1; v = 0x7f; }else break; qq = q; r = q->in.right; q = q->in.left; if ( isconv(q, SHORT, USHORT ) ) lsize = 2; else if (isconv(q, CHAR, UCHAR )) lsize = 1; else if (q->in.op == ICON) if (q->tn.name[0] == '\0' && ((q->tn.lval | v)==v || (q->tn.lval|v)==-1)) lsize = 0; else break; else if (tlen(q) < sizeof(long)) lsize = -1; else break; if ( isconv(r, SHORT, USHORT ) ) rsize = 2; else if (isconv(r, CHAR, UCHAR )) rsize = 1; else if (r->in.op == ICON) if (r->tn.name[0] == '\0' && ((r->tn.lval | v)==v || (r->tn.lval|v)==-1)) rsize = 0; else break; else if (tlen(r) < sizeof(long)) rsize = -1; else break; if (lsize == -1) { NODE *t = talloc(); t->in.op = SCONV; t->in.type = qq->in.type; t->in.left = q; lsize = tlen(q); q = t; qq->in.left = q; } if (rsize == -1) { NODE *t = talloc(); t->in.op = SCONV; t->in.type = qq->in.type; t->in.left = r; rsize = tlen(r); r = t; qq->in.right = r; } if (rsize > w || lsize > w) { /* must preserve top SCONV, but weaken operation */ p = p->in.left; if (rsize >lsize){ p->in.type = r->in.left->in.type ; w = rsize; } else { p->in.type = q->in.left->in.type; w = lsize; } } else { /* clobber SCONV */ NODE * t = p->in.left; TWORD tt = p->in.type; *p = *t; /* paint over */ p->in.type = tt; /* except type */ t->in.op = FREE; /* give a node back */ } /* now weaken or elide child convs */ switch (lsize){ case 0: /* ICON -- diddle type */ q->in.type = p->in.type; break; case 1: /* char */ if (lsize <w){ /* retain SCONV but weaken */ q->in.type = p->in.type; break; } /* else fall through */ case 2: /* same size -- elide SCONV */ { NODE * t = q->in.left; *q = *t; t->in.op = FREE; } } switch (rsize){ case 0: /* ICON -- diddle type */ r->in.type = p->in.type; break; case 1: /* char */ if (rsize <w){ /* retain SCONV but weaken */ r->in.type = p->in.type; break; } /* else fall through */ case 2: /* same size -- elide SCONV */ { NODE * t = r->in.left; *r = *t; t->in.op = FREE; } } break; case CHK: /* * A CHK with constant bounds, of which the left-hand-side * is an SCONV that widens a shorter type can be converted * to an SCONV over a CHK. This lets us use weaker CHK * instructions. */ if (p->in.type != INT && p->in.type != UNSIGNED) break; q = p->in.left; if (!isconv(q, CHAR, UCHAR) && !isconv(q, SHORT, USHORT) )break; r = p->in.right; rr = r->in.right; rl = r->in.left; if (rr->in.op != ICON || rl->in.op != ICON) break; /* * make bounds smaller using the type of the * converted operand */ t = q->in.left->in.type; switch(t) { case CHAR: if (reduce_bounds(-128, 127, rl, rr)) goto delete_check; break; case UCHAR: if (reduce_bounds(0, 255, rl, rr)) goto delete_check; break; case SHORT: if (reduce_bounds(-32768, 32767, rl, rr)) goto delete_check; break; case USHORT: if (reduce_bounds(0, 65535, rl, rr)) goto delete_check; break; delete_check: *p = *q; q->in.op = FREE; tfree(r); return; } /* * weaken the conversion by * exchanging CHK and SCONV nodes */ *p = *q; /* p becomes SCONV node */ p->in.left = q; q->in.op = CHK; q->in.right = r; q->in.type = r->in.type = rl->tn.type = rr->tn.type = t; break; case INIT: /* * not an optimization, but prevents an * infinite loop later on in code generation... */ q = p->in.left; if (q->in.op != ICON && q->in.op != FCON) { uerror("Illegal initialization"); tfree(q); q = talloc(); q->in.type = p->in.type; if (ISFLOATING(p->in.type)) { q->in.op = FCON; q->fpn.dval = 0.0; } else { q->in.op = ICON; q->tn.name = ""; q->tn.lval = 0; } p->in.left = q; } break; case FORCE: /* * if the type of a FORCE op is {u}char or {u}short, * extend it into an INT. */ switch(p->in.type){ case CHAR: case UCHAR: case SHORT: case USHORT: q = talloc(); q->in.op = SCONV; q->in.type = INT; q->in.left = p->in.left; q->in.right = NULL; p->in.left = q; p->in.type = INT; break; } break; } /* switch */ } /* * reduce bounds of a range check using * the known bounds of the domain type */ int reduce_bounds(domain_min, domain_max, range_min, range_max) register CONSZ domain_min, domain_max; register NODE *range_min, *range_max; { /* do the domain and range intersect? */ if (domain_min > range_max->tn.lval || domain_max < range_min->tn.lval) { /* expression value is known to lie outside required range */ werror("expression value is out of range"); } /* range := intersection(range, domain) */ if (domain_min > range_min->tn.lval) range_min->tn.lval = domain_min; if (domain_max < range_max->tn.lval) range_max->tn.lval = domain_max; /* if domain is a subset of range, range check is unnecessary */ if (domain_min >= range_min->tn.lval && domain_max <= range_max->tn.lval) { return(1); } return(0); }