12187Smckusick /* Copyright (c) 1979 Regents of the University of California */ 22187Smckusick 3*3836Speter static char sccsid[] = "@(#)forop.c 1.9 06/01/81"; 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; 392187Smckusick int *init; 402187Smckusick struct nl *inittype; 41*3836Speter struct nl *initnlp; /* initial value namelist entry */ 423371Speter char forflags; 432187Smckusick int *term; 442187Smckusick struct nl *termtype; 45*3836Speter struct nl *termnlp; /* termination value namelist entry */ 462187Smckusick int *stat; 472187Smckusick int goc; /* saved gocnt */ 482187Smckusick int again; /* label at the top of the loop */ 492187Smckusick int after; /* label after the end of the loop */ 503584Speter bool shadowed; /* shadowing for var in temporary? */ 513584Speter long s_offset; /* saved offset of real for variable */ 523584Speter long s_flags; /* saved flags of real for variable */ 533584Speter long s_forv; /* saved NL_FORV of the for variable */ 54*3836Speter # ifdef PC 55*3836Speter char s_extra_flags; /* saved extra_flags of the for var */ 56*3836Speter # endif PC 572187Smckusick 582187Smckusick goc = gocnt; 592187Smckusick forvar = NIL; 603584Speter shadowed = FALSE; 612187Smckusick if ( arg == NIL ) { 622187Smckusick goto byebye; 632187Smckusick } 642187Smckusick if ( arg[2] == NIL ) { 652187Smckusick goto byebye; 662187Smckusick } 672187Smckusick line = arg[1]; 682187Smckusick putline(); 692187Smckusick lhs = ( (int *) arg[2] )[2]; 702187Smckusick init = ( (int *) arg[2] )[3]; 712187Smckusick term = arg[3]; 722187Smckusick stat = arg[4]; 733278Smckusic if (lhs == NIL) { 743278Smckusic nogood: 753584Speter if (forvar != NIL) { 763584Speter forvar->value[ NL_FORV ] = FORVAR; 773584Speter } 782187Smckusick rvalue( init , NIL , RREQ ); 792187Smckusick rvalue( term , NIL , RREQ ); 802187Smckusick statement( stat ); 812187Smckusick goto byebye; 822187Smckusick } 832187Smckusick /* 842187Smckusick * and this marks the variable as used!!! 852187Smckusick */ 862187Smckusick forvar = lookup( lhs[2] ); 872187Smckusick if ( forvar == NIL ) { 883278Smckusic goto nogood; 892187Smckusick } 903584Speter s_forv = forvar -> value[ NL_FORV ]; 913278Smckusic if ( lhs[3] != NIL ) { 923278Smckusic error("For variable %s must be unqualified", forvar->symbol); 933278Smckusic goto nogood; 943278Smckusic } 953278Smckusic if (forvar->class == WITHPTR) { 963278Smckusic error("For variable %s cannot be an element of a record", lhs[2]); 973278Smckusic goto nogood; 983278Smckusic } 99*3836Speter if ( opt('s') && 100*3836Speter ( ( bn != cbn ) || 101*3836Speter #ifdef OBJ 102*3836Speter ( whereis( bn , forvar->value[NL_OFFS] , 0 ) == PARAMVAR ) 103*3836Speter #endif OBJ 104*3836Speter #ifdef PC 105*3836Speter ( whereis( bn , forvar->value[NL_OFFS] , forvar -> extra_flags ) 106*3836Speter == PARAMVAR ) 107*3836Speter #endif PC 108*3836Speter ) ) { 1093278Smckusic standard(); 1103278Smckusic error("For variable %s must be declared in the block in which it is used", forvar->symbol); 1113278Smckusic } 1122187Smckusick /* 1132187Smckusick * find out the type of the loop variable 1142187Smckusick */ 1152187Smckusick codeoff(); 1162187Smckusick fortype = lvalue( lhs , MOD , RREQ ); 1172187Smckusick codeon(); 1182187Smckusick if ( fortype == NIL ) { 1193278Smckusic goto nogood; 1202187Smckusick } 1212187Smckusick if ( isnta( fortype , "bcis" ) ) { 1223278Smckusic error("For variable %s cannot be %ss", forvar->symbol, nameof( fortype ) ); 1233278Smckusic goto nogood; 1242187Smckusick } 1253584Speter if ( forvar->value[ NL_FORV ] & FORVAR ) { 1263584Speter error("Can't modify the for variable %s in the range of the loop", forvar->symbol); 1273584Speter forvar = NIL; 1283584Speter goto nogood; 1293584Speter } 1302187Smckusick /* 1312187Smckusick * allocate space for the initial and termination expressions 1323584Speter * the initial is tentatively placed in a register as it will 1333584Speter * shadow the for loop variable in the body of the loop. 1342187Smckusick */ 135*3836Speter initnlp = tmpalloc(sizeof(long), nl+T4INT, REGOK); 136*3836Speter termnlp = tmpalloc(sizeof(long), nl+T4INT, NOREG); 1372187Smckusick # ifdef PC 1382187Smckusick /* 1392187Smckusick * compute and save the initial expression 1402187Smckusick */ 141*3836Speter putRV( 0 , cbn , initnlp -> value[ NL_OFFS ] , 142*3836Speter initnlp -> extra_flags , P2INT ); 1432187Smckusick # endif PC 1442187Smckusick # ifdef OBJ 145*3836Speter put(2, O_LV | cbn<<8+INDX, initnlp -> value[ NL_OFFS ] ); 1462187Smckusick # endif OBJ 1472187Smckusick inittype = rvalue( init , fortype , RREQ ); 1482187Smckusick if ( incompat( inittype , fortype , init ) ) { 1492187Smckusick cerror("Type of initial expression clashed with index type in 'for' statement"); 1503584Speter if (forvar != NIL) { 1513584Speter forvar->value[ NL_FORV ] = FORVAR; 1523584Speter } 1532187Smckusick rvalue( term , NIL , RREQ ); 1542187Smckusick statement( stat ); 1552187Smckusick goto byebye; 1562187Smckusick } 1572187Smckusick # ifdef PC 158*3836Speter putop( P2ASSIGN , P2INT ); 1592187Smckusick putdot( filename , line ); 1602187Smckusick /* 1612187Smckusick * compute and save the termination expression 1622187Smckusick */ 163*3836Speter putRV( 0 , cbn , termnlp -> value[ NL_OFFS ] , 164*3836Speter termnlp -> extra_flags , P2INT ); 1652187Smckusick # endif PC 1662187Smckusick # ifdef OBJ 1673083Smckusic gen(O_AS2, O_AS2, sizeof(long), width(inittype)); 1682187Smckusick /* 1692187Smckusick * compute and save the termination expression 1702187Smckusick */ 171*3836Speter put(2, O_LV | cbn<<8+INDX, termnlp -> value[ NL_OFFS ] ); 1722187Smckusick # endif OBJ 1732187Smckusick termtype = rvalue( term , fortype , RREQ ); 1742187Smckusick if ( incompat( termtype , fortype , term ) ) { 1752187Smckusick cerror("Type of limit expression clashed with index type in 'for' statement"); 1763584Speter if (forvar != NIL) { 1773584Speter forvar->value[ NL_FORV ] = FORVAR; 1783584Speter } 1792187Smckusick statement( stat ); 1802187Smckusick goto byebye; 1812187Smckusick } 1822187Smckusick # ifdef PC 183*3836Speter putop( P2ASSIGN , P2INT ); 1842187Smckusick putdot( filename , line ); 1852187Smckusick /* 1862187Smckusick * we can skip the loop altogether if !( init <= term ) 1872187Smckusick */ 1882187Smckusick after = getlab(); 189*3836Speter putRV( 0 , cbn , initnlp -> value[ NL_OFFS ] , 190*3836Speter initnlp -> extra_flags , P2INT ); 191*3836Speter putRV( 0 , cbn , termnlp -> value[ NL_OFFS ] , 192*3836Speter termnlp -> extra_flags , P2INT ); 193*3836Speter putop( ( arg[0] == T_FORU ? P2LE : P2GE ) , P2INT ); 1942187Smckusick putleaf( P2ICON , after , 0 , P2INT , 0 ); 1952187Smckusick putop( P2CBRANCH , P2INT ); 1962187Smckusick putdot( filename , line ); 1972187Smckusick /* 1983278Smckusic * put down the label at the top of the loop 1993278Smckusic */ 2003278Smckusic again = getlab(); 2013278Smckusic putlab( again ); 2023278Smckusic /* 2032187Smckusick * okay, then we have to execute the body, but first, 2042187Smckusick * assign the initial expression to the for variable. 2052187Smckusick * see the note in asgnop1 about why this is an rvalue. 2062187Smckusick */ 2073371Speter lvalue( lhs , NOUSE , RREQ ); 2082187Smckusick if ( opt( 't' ) ) { 2092187Smckusick precheck( fortype , "_RANG4" , "_RSNG4" ); 2102187Smckusick } 211*3836Speter putRV( 0 , cbn , initnlp -> value[ NL_OFFS ] , 212*3836Speter initnlp -> extra_flags , P2INT ); 2132187Smckusick if ( opt( 't' ) ) { 2142187Smckusick postcheck( fortype ); 2152187Smckusick } 216*3836Speter putop( P2ASSIGN , p2type( fortype ) ); 2172187Smckusick putdot( filename , line ); 2182187Smckusick # endif PC 2192187Smckusick # ifdef OBJ 2203083Smckusic gen(O_AS2, O_AS2, sizeof(long), width(termtype)); 2212187Smckusick /* 2222187Smckusick * we can skip the loop altogether if !( init <= term ) 2232187Smckusick */ 224*3836Speter put(2, O_RV4 | cbn<<8+INDX, initnlp -> value[ NL_OFFS ] ); 225*3836Speter put(2, O_RV4 | cbn<<8+INDX, termnlp -> value[ NL_OFFS ] ); 2262187Smckusick gen(NIL, arg[0] == T_FORU ? T_LE : T_GE, sizeof(long), 2272187Smckusick sizeof(long)); 2282187Smckusick after = getlab(); 2292187Smckusick put(2, O_IF, after); 2302187Smckusick /* 2313278Smckusic * put down the label at the top of the loop 2323278Smckusic */ 2333278Smckusic again = getlab(); 2343278Smckusic putlab( again ); 2353278Smckusic /* 2362187Smckusick * okay, then we have to execute the body, but first, 2372187Smckusick * assign the initial expression to the for variable. 2382187Smckusick */ 2392187Smckusick lvalue( lhs , NOUSE , LREQ ); 240*3836Speter put(2, O_RV4 | cbn<<8+INDX, initnlp -> value[ NL_OFFS ] ); 2412187Smckusick rangechk(fortype, nl+T4INT); 2423083Smckusic gen(O_AS2, O_AS2, width(fortype), sizeof(long)); 2432187Smckusick # endif OBJ 2442187Smckusick /* 2453584Speter * shadowing the real for variable 2463584Speter * with the initail expression temporary: 2473584Speter * save the real for variable's offset, flags 2483584Speter * (including nl_block). 2493584Speter * replace them with the initial expression's offset, 2503584Speter * and mark it as being a for variable. 2513584Speter */ 2523584Speter shadowed = TRUE; 2533584Speter s_offset = forvar -> value[ NL_OFFS ]; 2543584Speter s_flags = forvar -> nl_flags; 255*3836Speter forvar -> value[ NL_OFFS ] = initnlp -> value[ NL_OFFS ]; 2563584Speter forvar -> nl_flags = cbn; 2573584Speter forvar -> value[ NL_FORV ] = FORVAR; 258*3836Speter # ifdef PC 259*3836Speter s_extra_flags = forvar -> extra_flags; 260*3836Speter forvar -> extra_flags = initnlp -> extra_flags; 261*3836Speter # endif PC 2623584Speter /* 2632187Smckusick * and don't forget ... 2642187Smckusick */ 2653278Smckusic putcnt(); 2663278Smckusic statement( stat ); 2672187Smckusick /* 2682187Smckusick * wasn't that fun? do we get to do it again? 2692187Smckusick * we don't do it again if ( !( forvar < limit ) ) 2702187Smckusick * pretend we were doing this at the top of the loop 2712187Smckusick */ 2722187Smckusick line = arg[ 1 ]; 2732187Smckusick # ifdef PC 2742187Smckusick if ( opt( 'p' ) ) { 2752187Smckusick if ( opt('t') ) { 2762187Smckusick putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 2772187Smckusick , "_LINO" ); 2782187Smckusick putop( P2UNARY P2CALL , P2INT ); 2792187Smckusick putdot( filename , line ); 2802187Smckusick } else { 281*3836Speter putRV( STMTCOUNT , 0 , 0 , NGLOBAL , P2INT ); 2822187Smckusick putleaf( P2ICON , 1 , 0 , P2INT , 0 ); 2832187Smckusick putop( P2ASG P2PLUS , P2INT ); 2842187Smckusick putdot( filename , line ); 2852187Smckusick } 2862187Smckusick } 287*3836Speter /*rvalue( lhs , NIL , RREQ );*/ 288*3836Speter putRV( 0 , cbn , initnlp -> value[ NL_OFFS ] , 289*3836Speter initnlp -> extra_flags , P2INT ); 290*3836Speter putRV( 0 , cbn , termnlp -> value[ NL_OFFS ] , 291*3836Speter termnlp -> extra_flags , P2INT ); 292*3836Speter putop( ( arg[ 0 ] == T_FORU ? P2LT : P2GT ) , P2INT ); 2932187Smckusick putleaf( P2ICON , after , 0 , P2INT , 0 ); 2942187Smckusick putop( P2CBRANCH , P2INT ); 2952187Smckusick putdot( filename , line ); 2962187Smckusick /* 2972187Smckusick * okay, so we have to do it again, 2982187Smckusick * but first, increment the for variable. 2992187Smckusick * there it is again, an rvalue on the lhs of an assignment. 3002187Smckusick */ 301*3836Speter /*lvalue( lhs , MOD , RREQ );*/ 302*3836Speter putRV( 0 , cbn , initnlp -> value[ NL_OFFS ] , 303*3836Speter initnlp -> extra_flags , P2INT ); 3042187Smckusick if ( opt( 't' ) ) { 3052187Smckusick precheck( fortype , "_RANG4" , "_RSNG4" ); 3062187Smckusick } 307*3836Speter /*rvalue( lhs , NIL , RREQ );*/ 308*3836Speter putRV( 0 , cbn , initnlp -> value[ NL_OFFS ] , 309*3836Speter initnlp -> extra_flags , P2INT ); 3103633Smckusic putleaf( P2ICON , 1 , 0 , P2INT , 0 ); 3113633Smckusic putop( ( arg[0] == T_FORU ? P2PLUS : P2MINUS ) , P2INT ); 3122187Smckusick if ( opt( 't' ) ) { 3132187Smckusick postcheck( fortype ); 3142187Smckusick } 315*3836Speter putop( P2ASSIGN , P2INT ); 3162187Smckusick putdot( filename , line ); 3172187Smckusick /* 3182187Smckusick * and do it all again 3192187Smckusick */ 3202187Smckusick putjbr( again ); 3212187Smckusick /* 3222187Smckusick * and here we are 3232187Smckusick */ 3242187Smckusick putlab( after ); 3252187Smckusick # endif PC 3262187Smckusick # ifdef OBJ 3272187Smckusick /* 3282187Smckusick * okay, so we have to do it again. 3292187Smckusick * Luckily we have a magic opcode which increments the 3302187Smckusick * index variable, checks the limit falling through if 3312187Smckusick * it has been reached, else range checking the result 3322187Smckusick * updating the index variable, and returning to the top 3332187Smckusick * of the loop. 3342187Smckusick */ 3352649Speter putline(); 336*3836Speter put(2, O_RV4 | cbn<<8+INDX, termnlp -> value[ NL_OFFS ] ); 3372187Smckusick lvalue(lhs, MOD, LREQ); 3383083Smckusic if (width(fortype) <= 2) 3393083Smckusic put(4, (arg[0] == T_FORU ? O_FOR1U : O_FOR1D) + 3403083Smckusic (width(fortype)>>1), (int)fortype->range[0], 3413083Smckusic (int)fortype->range[1], again); 3423083Smckusic else 3433083Smckusic put(4, (arg[0] == T_FORU ? O_FOR4U : O_FOR4D), 3443083Smckusic fortype->range[0], fortype->range[1], again); 3452187Smckusick /* 3462187Smckusick * and here we are 3472187Smckusick */ 3482187Smckusick patch( after ); 3492187Smckusick # endif OBJ 3502187Smckusick byebye: 3512187Smckusick noreach = 0; 3523584Speter if (forvar != NIL) { 3533584Speter forvar -> value[ NL_FORV ] = s_forv; 3542187Smckusick } 3553584Speter if ( shadowed ) { 3563584Speter forvar -> value[ NL_OFFS ] = s_offset; 3573584Speter forvar -> nl_flags = s_flags; 358*3836Speter # ifdef PC 359*3836Speter forvar -> extra_flags = s_extra_flags; 360*3836Speter # endif PC 3613584Speter } 3622187Smckusick if ( goc != gocnt ) { 3632187Smckusick putcnt(); 3642187Smckusick } 3652187Smckusick } 366