12187Smckusick /* Copyright (c) 1979 Regents of the University of California */ 22187Smckusick 3*10666Speter static char sccsid[] = "@(#)forop.c 1.13 02/01/83"; 42187Smckusick 52187Smckusick #include "whoami.h" 62187Smckusick #include "0.h" 72187Smckusick #include "opcode.h" 82187Smckusick #include "tree.h" 92187Smckusick #include "objfmt.h" 102187Smckusick #ifdef PC 112187Smckusick # include "pc.h" 122187Smckusick # include "pcops.h" 132187Smckusick #endif PC 143371Speter 152187Smckusick /* 162187Smckusick * forop for pc: 172187Smckusick * this evaluates the initial and termination expressions, 182187Smckusick * checks them to see if the loop executes at all, and then 192187Smckusick * does the assignment and the loop. 202187Smckusick * arg here looks like: 212187Smckusick * arg[0] T_FORU or T_FORD 222187Smckusick * [1] lineof "for" 232187Smckusick * [2] [0] T_ASGN 242187Smckusick * [1] lineof ":=" 252187Smckusick * [2] [0] T_VAR 262187Smckusick * [1] lineof id 272187Smckusick * [2] char * to id 282187Smckusick * [3] qualifications 292187Smckusick * [3] initial expression 302187Smckusick * [3] termination expression 312187Smckusick * [4] statement 322187Smckusick */ 332187Smckusick forop( arg ) 342187Smckusick int *arg; 352187Smckusick { 362187Smckusick int *lhs; 372187Smckusick struct nl *forvar; 382187Smckusick struct nl *fortype; 39*10666Speter #ifdef PC 40*10666Speter int forctype; /* p2type(fortype) */ 41*10666Speter #endif PC 42*10666Speter int forwidth; 432187Smckusick int *init; 442187Smckusick struct nl *inittype; 453836Speter struct nl *initnlp; /* initial value namelist entry */ 463371Speter char forflags; 472187Smckusick int *term; 482187Smckusick struct nl *termtype; 493836Speter struct nl *termnlp; /* termination value namelist entry */ 502187Smckusick int *stat; 512187Smckusick int goc; /* saved gocnt */ 522187Smckusick int again; /* label at the top of the loop */ 532187Smckusick int after; /* label after the end of the loop */ 545775Smckusic struct nl shadow_nl; /* saved namelist entry for loop var */ 552187Smckusick 562187Smckusick goc = gocnt; 572187Smckusick forvar = NIL; 582187Smckusick if ( arg == NIL ) { 592187Smckusick goto byebye; 602187Smckusick } 612187Smckusick if ( arg[2] == NIL ) { 622187Smckusick goto byebye; 632187Smckusick } 642187Smckusick line = arg[1]; 652187Smckusick putline(); 662187Smckusick lhs = ( (int *) arg[2] )[2]; 672187Smckusick init = ( (int *) arg[2] )[3]; 682187Smckusick term = arg[3]; 692187Smckusick stat = arg[4]; 703278Smckusic if (lhs == NIL) { 713278Smckusic nogood: 723584Speter if (forvar != NIL) { 733584Speter forvar->value[ NL_FORV ] = FORVAR; 743584Speter } 752187Smckusick rvalue( init , NIL , RREQ ); 762187Smckusick rvalue( term , NIL , RREQ ); 772187Smckusick statement( stat ); 782187Smckusick goto byebye; 792187Smckusick } 802187Smckusick /* 812187Smckusick * and this marks the variable as used!!! 822187Smckusick */ 832187Smckusick forvar = lookup( lhs[2] ); 842187Smckusick if ( forvar == NIL ) { 853278Smckusic goto nogood; 862187Smckusick } 875775Smckusic shadow_nl = *forvar; 883278Smckusic if ( lhs[3] != NIL ) { 893278Smckusic error("For variable %s must be unqualified", forvar->symbol); 903278Smckusic goto nogood; 913278Smckusic } 923278Smckusic if (forvar->class == WITHPTR) { 933278Smckusic error("For variable %s cannot be an element of a record", lhs[2]); 943278Smckusic goto nogood; 953278Smckusic } 963836Speter if ( opt('s') && 973836Speter ( ( bn != cbn ) || 983836Speter #ifdef OBJ 993836Speter ( whereis( bn , forvar->value[NL_OFFS] , 0 ) == PARAMVAR ) 1003836Speter #endif OBJ 1013836Speter #ifdef PC 1023836Speter ( whereis( bn , forvar->value[NL_OFFS] , forvar -> extra_flags ) 1033836Speter == PARAMVAR ) 1043836Speter #endif PC 1053836Speter ) ) { 1063278Smckusic standard(); 1073278Smckusic error("For variable %s must be declared in the block in which it is used", forvar->symbol); 1083278Smckusic } 1092187Smckusick /* 1102187Smckusick * find out the type of the loop variable 1112187Smckusick */ 1122187Smckusick codeoff(); 1132187Smckusick fortype = lvalue( lhs , MOD , RREQ ); 1142187Smckusick codeon(); 1152187Smckusick if ( fortype == NIL ) { 1163278Smckusic goto nogood; 1172187Smckusick } 1182187Smckusick if ( isnta( fortype , "bcis" ) ) { 1193278Smckusic error("For variable %s cannot be %ss", forvar->symbol, nameof( fortype ) ); 1203278Smckusic goto nogood; 1212187Smckusick } 1223584Speter if ( forvar->value[ NL_FORV ] & FORVAR ) { 1233584Speter error("Can't modify the for variable %s in the range of the loop", forvar->symbol); 1243584Speter forvar = NIL; 1253584Speter goto nogood; 1263584Speter } 1272187Smckusick /* 1282187Smckusick * allocate space for the initial and termination expressions 1293584Speter * the initial is tentatively placed in a register as it will 1303584Speter * shadow the for loop variable in the body of the loop. 1312187Smckusick */ 132*10666Speter forwidth = lwidth(fortype); 133*10666Speter initnlp = tmpalloc(forwidth, fortype, REGOK); 134*10666Speter termnlp = tmpalloc(forwidth, fortype, NOREG); 1352187Smckusick # ifdef PC 136*10666Speter forctype = p2type(fortype); 1372187Smckusick /* 1382187Smckusick * compute and save the initial expression 1392187Smckusick */ 1403836Speter putRV( 0 , cbn , initnlp -> value[ NL_OFFS ] , 141*10666Speter initnlp -> extra_flags , forctype ); 142*10666Speter if ( opt( 't' ) ) { 143*10666Speter precheck( fortype , "_RANG4" , "_RSNG4" ); 144*10666Speter } 1452187Smckusick # endif PC 1462187Smckusick # ifdef OBJ 1473836Speter put(2, O_LV | cbn<<8+INDX, initnlp -> value[ NL_OFFS ] ); 1482187Smckusick # endif OBJ 1492187Smckusick inittype = rvalue( init , fortype , RREQ ); 1502187Smckusick if ( incompat( inittype , fortype , init ) ) { 1512187Smckusick cerror("Type of initial expression clashed with index type in 'for' statement"); 1523584Speter if (forvar != NIL) { 1533584Speter forvar->value[ NL_FORV ] = FORVAR; 1543584Speter } 1552187Smckusick rvalue( term , NIL , RREQ ); 1562187Smckusick statement( stat ); 1572187Smckusick goto byebye; 1582187Smckusick } 1592187Smckusick # ifdef PC 160*10666Speter if ( opt( 't' ) ) { 161*10666Speter postcheck(fortype, inittype); 162*10666Speter } 163*10666Speter sconv(p2type(inittype), forctype); 164*10666Speter putop( P2ASSIGN , forctype ); 1652187Smckusick putdot( filename , line ); 1662187Smckusick /* 1672187Smckusick * compute and save the termination expression 1682187Smckusick */ 1693836Speter putRV( 0 , cbn , termnlp -> value[ NL_OFFS ] , 170*10666Speter termnlp -> extra_flags , forctype ); 171*10666Speter if ( opt( 't' ) ) { 172*10666Speter precheck( fortype , "_RANG4" , "_RSNG4" ); 173*10666Speter } 1742187Smckusick # endif PC 1752187Smckusick # ifdef OBJ 176*10666Speter rangechk(fortype, inittype); 177*10666Speter gen(O_AS2, O_AS2, forwidth, lwidth(inittype)); 1782187Smckusick /* 1792187Smckusick * compute and save the termination expression 1802187Smckusick */ 1813836Speter put(2, O_LV | cbn<<8+INDX, termnlp -> value[ NL_OFFS ] ); 1822187Smckusick # endif OBJ 1832187Smckusick termtype = rvalue( term , fortype , RREQ ); 1842187Smckusick if ( incompat( termtype , fortype , term ) ) { 1852187Smckusick cerror("Type of limit expression clashed with index type in 'for' statement"); 1863584Speter if (forvar != NIL) { 1873584Speter forvar->value[ NL_FORV ] = FORVAR; 1883584Speter } 1892187Smckusick statement( stat ); 1902187Smckusick goto byebye; 1912187Smckusick } 1922187Smckusick # ifdef PC 193*10666Speter if ( opt( 't' ) ) { 194*10666Speter postcheck(fortype, termtype); 195*10666Speter } 196*10666Speter sconv(p2type(termtype), forctype); 197*10666Speter putop( P2ASSIGN , forctype ); 1982187Smckusick putdot( filename , line ); 1992187Smckusick /* 2002187Smckusick * we can skip the loop altogether if !( init <= term ) 2012187Smckusick */ 2022187Smckusick after = getlab(); 2033836Speter putRV( 0 , cbn , initnlp -> value[ NL_OFFS ] , 204*10666Speter initnlp -> extra_flags , forctype ); 2053836Speter putRV( 0 , cbn , termnlp -> value[ NL_OFFS ] , 206*10666Speter termnlp -> extra_flags , forctype ); 207*10666Speter putop( ( arg[0] == T_FORU ? P2LE : P2GE ) , forctype ); 2082187Smckusick putleaf( P2ICON , after , 0 , P2INT , 0 ); 2092187Smckusick putop( P2CBRANCH , P2INT ); 2102187Smckusick putdot( filename , line ); 2112187Smckusick /* 2123278Smckusic * put down the label at the top of the loop 2133278Smckusic */ 2143278Smckusic again = getlab(); 2153278Smckusic putlab( again ); 2163278Smckusic /* 2172187Smckusick * okay, then we have to execute the body, but first, 2182187Smckusick * assign the initial expression to the for variable. 2192187Smckusick * see the note in asgnop1 about why this is an rvalue. 2202187Smckusick */ 2213371Speter lvalue( lhs , NOUSE , RREQ ); 2223836Speter putRV( 0 , cbn , initnlp -> value[ NL_OFFS ] , 223*10666Speter initnlp -> extra_flags , forctype ); 2243836Speter putop( P2ASSIGN , p2type( fortype ) ); 2252187Smckusick putdot( filename , line ); 2262187Smckusick # endif PC 2272187Smckusick # ifdef OBJ 228*10666Speter rangechk(fortype, termtype); 229*10666Speter gen(O_AS2, O_AS2, forwidth, lwidth(termtype)); 2302187Smckusick /* 2312187Smckusick * we can skip the loop altogether if !( init <= term ) 2322187Smckusick */ 233*10666Speter stackRV(initnlp); 234*10666Speter stackRV(termnlp); 235*10666Speter gen(NIL, arg[0] == T_FORU ? T_LE : T_GE, lwidth(nl+T4INT), 236*10666Speter lwidth(nl+T4INT)); 2372187Smckusick after = getlab(); 2382187Smckusick put(2, O_IF, after); 2392187Smckusick /* 2403278Smckusic * put down the label at the top of the loop 2413278Smckusic */ 2423278Smckusic again = getlab(); 2433278Smckusic putlab( again ); 2443278Smckusic /* 2452187Smckusick * okay, then we have to execute the body, but first, 2462187Smckusick * assign the initial expression to the for variable. 2472187Smckusick */ 2482187Smckusick lvalue( lhs , NOUSE , LREQ ); 249*10666Speter stackRV(initnlp); 250*10666Speter gen(O_AS2, O_AS2, forwidth, lwidth(nl+T4INT)); 2512187Smckusick # endif OBJ 2522187Smckusick /* 2533584Speter * shadowing the real for variable 2543584Speter * with the initail expression temporary: 2553584Speter * save the real for variable's offset, flags 2563584Speter * (including nl_block). 2573584Speter * replace them with the initial expression's offset, 2583584Speter * and mark it as being a for variable. 2593584Speter */ 2605871Smckusic shadow_nl.nl_flags = forvar -> nl_flags; 2615775Smckusic *forvar = *initnlp; 2625775Smckusic forvar -> symbol = shadow_nl.symbol; 2635775Smckusic forvar -> nl_next = shadow_nl.nl_next; 2643584Speter forvar -> value[ NL_FORV ] = FORVAR; 2653584Speter /* 2662187Smckusick * and don't forget ... 2672187Smckusick */ 2683278Smckusic putcnt(); 2693278Smckusic statement( stat ); 2702187Smckusick /* 2712187Smckusick * wasn't that fun? do we get to do it again? 2722187Smckusick * we don't do it again if ( !( forvar < limit ) ) 2732187Smckusick * pretend we were doing this at the top of the loop 2742187Smckusick */ 2752187Smckusick line = arg[ 1 ]; 2762187Smckusick # ifdef PC 2772187Smckusick if ( opt( 'p' ) ) { 2782187Smckusick if ( opt('t') ) { 2792187Smckusick putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 2802187Smckusick , "_LINO" ); 2812187Smckusick putop( P2UNARY P2CALL , P2INT ); 2822187Smckusick putdot( filename , line ); 2832187Smckusick } else { 2843836Speter putRV( STMTCOUNT , 0 , 0 , NGLOBAL , P2INT ); 2852187Smckusick putleaf( P2ICON , 1 , 0 , P2INT , 0 ); 2862187Smckusick putop( P2ASG P2PLUS , P2INT ); 2872187Smckusick putdot( filename , line ); 2882187Smckusick } 2892187Smckusick } 2903836Speter /*rvalue( lhs , NIL , RREQ );*/ 2913836Speter putRV( 0 , cbn , initnlp -> value[ NL_OFFS ] , 292*10666Speter initnlp -> extra_flags , forctype ); 2933836Speter putRV( 0 , cbn , termnlp -> value[ NL_OFFS ] , 294*10666Speter termnlp -> extra_flags , forctype ); 2953836Speter putop( ( arg[ 0 ] == T_FORU ? P2LT : P2GT ) , P2INT ); 2962187Smckusick putleaf( P2ICON , after , 0 , P2INT , 0 ); 2972187Smckusick putop( P2CBRANCH , P2INT ); 2982187Smckusick putdot( filename , line ); 2992187Smckusick /* 3002187Smckusick * okay, so we have to do it again, 3012187Smckusick * but first, increment the for variable. 3022187Smckusick * there it is again, an rvalue on the lhs of an assignment. 3032187Smckusick */ 3043836Speter /*lvalue( lhs , MOD , RREQ );*/ 3053836Speter putRV( 0 , cbn , initnlp -> value[ NL_OFFS ] , 306*10666Speter initnlp -> extra_flags , forctype ); 3072187Smckusick if ( opt( 't' ) ) { 3082187Smckusick precheck( fortype , "_RANG4" , "_RSNG4" ); 3092187Smckusick } 3103836Speter /*rvalue( lhs , NIL , RREQ );*/ 3113836Speter putRV( 0 , cbn , initnlp -> value[ NL_OFFS ] , 312*10666Speter initnlp -> extra_flags , forctype ); 313*10666Speter sconv(forctype, P2INT); 3143633Smckusic putleaf( P2ICON , 1 , 0 , P2INT , 0 ); 3153633Smckusic putop( ( arg[0] == T_FORU ? P2PLUS : P2MINUS ) , P2INT ); 3162187Smckusick if ( opt( 't' ) ) { 31710363Smckusick postcheck(fortype, nl+T4INT); 3182187Smckusick } 319*10666Speter sconv(P2INT, forctype); 320*10666Speter putop( P2ASSIGN , forctype ); 3212187Smckusick putdot( filename , line ); 3222187Smckusick /* 3232187Smckusick * and do it all again 3242187Smckusick */ 3252187Smckusick putjbr( again ); 3262187Smckusick /* 3272187Smckusick * and here we are 3282187Smckusick */ 3292187Smckusick putlab( after ); 3302187Smckusick # endif PC 3312187Smckusick # ifdef OBJ 3322187Smckusick /* 3332187Smckusick * okay, so we have to do it again. 3342187Smckusick * Luckily we have a magic opcode which increments the 3352187Smckusick * index variable, checks the limit falling through if 3362187Smckusick * it has been reached, else range checking the result 3372187Smckusick * updating the index variable, and returning to the top 3382187Smckusick * of the loop. 3392187Smckusick */ 3402649Speter putline(); 341*10666Speter stackRV(termnlp); 342*10666Speter put(2, O_LV | cbn<<8+INDX, initnlp -> value[ NL_OFFS ] ); 343*10666Speter if (forwidth <= 2) 344*10666Speter put(4, 345*10666Speter (arg[0] == T_FORU ? O_FOR1U : O_FOR1D) + (forwidth>>1), 346*10666Speter (int)fortype->range[0], (int)fortype->range[1], again); 3473083Smckusic else 3483083Smckusic put(4, (arg[0] == T_FORU ? O_FOR4U : O_FOR4D), 3493083Smckusic fortype->range[0], fortype->range[1], again); 3502187Smckusick /* 3512187Smckusick * and here we are 3522187Smckusick */ 3532187Smckusick patch( after ); 3542187Smckusick # endif OBJ 355*10666Speter /* and fall through */ 3562187Smckusick byebye: 3572187Smckusick noreach = 0; 3583584Speter if (forvar != NIL) { 3595871Smckusic shadow_nl.nl_flags |= forvar -> nl_flags & (NUSED|NMOD); 3605775Smckusic *forvar = shadow_nl; 3612187Smckusick } 3622187Smckusick if ( goc != gocnt ) { 3632187Smckusick putcnt(); 3642187Smckusick } 3652187Smckusick } 366