12187Smckusick /* Copyright (c) 1979 Regents of the University of California */ 22187Smckusick 3*5871Smckusic static char sccsid[] = "@(#)forop.c 1.11 02/16/82"; 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; 413836Speter struct nl *initnlp; /* initial value namelist entry */ 423371Speter char forflags; 432187Smckusick int *term; 442187Smckusick struct nl *termtype; 453836Speter 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 */ 505775Smckusic struct nl shadow_nl; /* saved namelist entry for loop var */ 512187Smckusick 522187Smckusick goc = gocnt; 532187Smckusick forvar = NIL; 542187Smckusick if ( arg == NIL ) { 552187Smckusick goto byebye; 562187Smckusick } 572187Smckusick if ( arg[2] == NIL ) { 582187Smckusick goto byebye; 592187Smckusick } 602187Smckusick line = arg[1]; 612187Smckusick putline(); 622187Smckusick lhs = ( (int *) arg[2] )[2]; 632187Smckusick init = ( (int *) arg[2] )[3]; 642187Smckusick term = arg[3]; 652187Smckusick stat = arg[4]; 663278Smckusic if (lhs == NIL) { 673278Smckusic nogood: 683584Speter if (forvar != NIL) { 693584Speter forvar->value[ NL_FORV ] = FORVAR; 703584Speter } 712187Smckusick rvalue( init , NIL , RREQ ); 722187Smckusick rvalue( term , NIL , RREQ ); 732187Smckusick statement( stat ); 742187Smckusick goto byebye; 752187Smckusick } 762187Smckusick /* 772187Smckusick * and this marks the variable as used!!! 782187Smckusick */ 792187Smckusick forvar = lookup( lhs[2] ); 802187Smckusick if ( forvar == NIL ) { 813278Smckusic goto nogood; 822187Smckusick } 835775Smckusic shadow_nl = *forvar; 843278Smckusic if ( lhs[3] != NIL ) { 853278Smckusic error("For variable %s must be unqualified", forvar->symbol); 863278Smckusic goto nogood; 873278Smckusic } 883278Smckusic if (forvar->class == WITHPTR) { 893278Smckusic error("For variable %s cannot be an element of a record", lhs[2]); 903278Smckusic goto nogood; 913278Smckusic } 923836Speter if ( opt('s') && 933836Speter ( ( bn != cbn ) || 943836Speter #ifdef OBJ 953836Speter ( whereis( bn , forvar->value[NL_OFFS] , 0 ) == PARAMVAR ) 963836Speter #endif OBJ 973836Speter #ifdef PC 983836Speter ( whereis( bn , forvar->value[NL_OFFS] , forvar -> extra_flags ) 993836Speter == PARAMVAR ) 1003836Speter #endif PC 1013836Speter ) ) { 1023278Smckusic standard(); 1033278Smckusic error("For variable %s must be declared in the block in which it is used", forvar->symbol); 1043278Smckusic } 1052187Smckusick /* 1062187Smckusick * find out the type of the loop variable 1072187Smckusick */ 1082187Smckusick codeoff(); 1092187Smckusick fortype = lvalue( lhs , MOD , RREQ ); 1102187Smckusick codeon(); 1112187Smckusick if ( fortype == NIL ) { 1123278Smckusic goto nogood; 1132187Smckusick } 1142187Smckusick if ( isnta( fortype , "bcis" ) ) { 1153278Smckusic error("For variable %s cannot be %ss", forvar->symbol, nameof( fortype ) ); 1163278Smckusic goto nogood; 1172187Smckusick } 1183584Speter if ( forvar->value[ NL_FORV ] & FORVAR ) { 1193584Speter error("Can't modify the for variable %s in the range of the loop", forvar->symbol); 1203584Speter forvar = NIL; 1213584Speter goto nogood; 1223584Speter } 1232187Smckusick /* 1242187Smckusick * allocate space for the initial and termination expressions 1253584Speter * the initial is tentatively placed in a register as it will 1263584Speter * shadow the for loop variable in the body of the loop. 1272187Smckusick */ 1283836Speter initnlp = tmpalloc(sizeof(long), nl+T4INT, REGOK); 1293836Speter termnlp = tmpalloc(sizeof(long), nl+T4INT, NOREG); 1302187Smckusick # ifdef PC 1312187Smckusick /* 1322187Smckusick * compute and save the initial expression 1332187Smckusick */ 1343836Speter putRV( 0 , cbn , initnlp -> value[ NL_OFFS ] , 1353836Speter initnlp -> extra_flags , P2INT ); 1362187Smckusick # endif PC 1372187Smckusick # ifdef OBJ 1383836Speter put(2, O_LV | cbn<<8+INDX, initnlp -> value[ NL_OFFS ] ); 1392187Smckusick # endif OBJ 1402187Smckusick inittype = rvalue( init , fortype , RREQ ); 1412187Smckusick if ( incompat( inittype , fortype , init ) ) { 1422187Smckusick cerror("Type of initial expression clashed with index type in 'for' statement"); 1433584Speter if (forvar != NIL) { 1443584Speter forvar->value[ NL_FORV ] = FORVAR; 1453584Speter } 1462187Smckusick rvalue( term , NIL , RREQ ); 1472187Smckusick statement( stat ); 1482187Smckusick goto byebye; 1492187Smckusick } 1502187Smckusick # ifdef PC 1513836Speter putop( P2ASSIGN , P2INT ); 1522187Smckusick putdot( filename , line ); 1532187Smckusick /* 1542187Smckusick * compute and save the termination expression 1552187Smckusick */ 1563836Speter putRV( 0 , cbn , termnlp -> value[ NL_OFFS ] , 1573836Speter termnlp -> extra_flags , P2INT ); 1582187Smckusick # endif PC 1592187Smckusick # ifdef OBJ 1603083Smckusic gen(O_AS2, O_AS2, sizeof(long), width(inittype)); 1612187Smckusick /* 1622187Smckusick * compute and save the termination expression 1632187Smckusick */ 1643836Speter put(2, O_LV | cbn<<8+INDX, termnlp -> value[ NL_OFFS ] ); 1652187Smckusick # endif OBJ 1662187Smckusick termtype = rvalue( term , fortype , RREQ ); 1672187Smckusick if ( incompat( termtype , fortype , term ) ) { 1682187Smckusick cerror("Type of limit expression clashed with index type in 'for' statement"); 1693584Speter if (forvar != NIL) { 1703584Speter forvar->value[ NL_FORV ] = FORVAR; 1713584Speter } 1722187Smckusick statement( stat ); 1732187Smckusick goto byebye; 1742187Smckusick } 1752187Smckusick # ifdef PC 1763836Speter putop( P2ASSIGN , P2INT ); 1772187Smckusick putdot( filename , line ); 1782187Smckusick /* 1792187Smckusick * we can skip the loop altogether if !( init <= term ) 1802187Smckusick */ 1812187Smckusick after = getlab(); 1823836Speter putRV( 0 , cbn , initnlp -> value[ NL_OFFS ] , 1833836Speter initnlp -> extra_flags , P2INT ); 1843836Speter putRV( 0 , cbn , termnlp -> value[ NL_OFFS ] , 1853836Speter termnlp -> extra_flags , P2INT ); 1863836Speter putop( ( arg[0] == T_FORU ? P2LE : P2GE ) , P2INT ); 1872187Smckusick putleaf( P2ICON , after , 0 , P2INT , 0 ); 1882187Smckusick putop( P2CBRANCH , P2INT ); 1892187Smckusick putdot( filename , line ); 1902187Smckusick /* 1913278Smckusic * put down the label at the top of the loop 1923278Smckusic */ 1933278Smckusic again = getlab(); 1943278Smckusic putlab( again ); 1953278Smckusic /* 1962187Smckusick * okay, then we have to execute the body, but first, 1972187Smckusick * assign the initial expression to the for variable. 1982187Smckusick * see the note in asgnop1 about why this is an rvalue. 1992187Smckusick */ 2003371Speter lvalue( lhs , NOUSE , RREQ ); 2012187Smckusick if ( opt( 't' ) ) { 2022187Smckusick precheck( fortype , "_RANG4" , "_RSNG4" ); 2032187Smckusick } 2043836Speter putRV( 0 , cbn , initnlp -> value[ NL_OFFS ] , 2053836Speter initnlp -> extra_flags , P2INT ); 2062187Smckusick if ( opt( 't' ) ) { 2072187Smckusick postcheck( fortype ); 2082187Smckusick } 2093836Speter putop( P2ASSIGN , p2type( fortype ) ); 2102187Smckusick putdot( filename , line ); 2112187Smckusick # endif PC 2122187Smckusick # ifdef OBJ 2133083Smckusic gen(O_AS2, O_AS2, sizeof(long), width(termtype)); 2142187Smckusick /* 2152187Smckusick * we can skip the loop altogether if !( init <= term ) 2162187Smckusick */ 2173836Speter put(2, O_RV4 | cbn<<8+INDX, initnlp -> value[ NL_OFFS ] ); 2183836Speter put(2, O_RV4 | cbn<<8+INDX, termnlp -> value[ NL_OFFS ] ); 2192187Smckusick gen(NIL, arg[0] == T_FORU ? T_LE : T_GE, sizeof(long), 2202187Smckusick sizeof(long)); 2212187Smckusick after = getlab(); 2222187Smckusick put(2, O_IF, after); 2232187Smckusick /* 2243278Smckusic * put down the label at the top of the loop 2253278Smckusic */ 2263278Smckusic again = getlab(); 2273278Smckusic putlab( again ); 2283278Smckusic /* 2292187Smckusick * okay, then we have to execute the body, but first, 2302187Smckusick * assign the initial expression to the for variable. 2312187Smckusick */ 2322187Smckusick lvalue( lhs , NOUSE , LREQ ); 2333836Speter put(2, O_RV4 | cbn<<8+INDX, initnlp -> value[ NL_OFFS ] ); 2342187Smckusick rangechk(fortype, nl+T4INT); 2353083Smckusic gen(O_AS2, O_AS2, width(fortype), sizeof(long)); 2362187Smckusick # endif OBJ 2372187Smckusick /* 2383584Speter * shadowing the real for variable 2393584Speter * with the initail expression temporary: 2403584Speter * save the real for variable's offset, flags 2413584Speter * (including nl_block). 2423584Speter * replace them with the initial expression's offset, 2433584Speter * and mark it as being a for variable. 2443584Speter */ 245*5871Smckusic shadow_nl.nl_flags = forvar -> nl_flags; 2465775Smckusic *forvar = *initnlp; 2475775Smckusic forvar -> symbol = shadow_nl.symbol; 2485775Smckusic forvar -> nl_next = shadow_nl.nl_next; 249*5871Smckusic forvar -> type = shadow_nl.type; 2503584Speter forvar -> value[ NL_FORV ] = FORVAR; 2513584Speter /* 2522187Smckusick * and don't forget ... 2532187Smckusick */ 2543278Smckusic putcnt(); 2553278Smckusic statement( stat ); 2562187Smckusick /* 2572187Smckusick * wasn't that fun? do we get to do it again? 2582187Smckusick * we don't do it again if ( !( forvar < limit ) ) 2592187Smckusick * pretend we were doing this at the top of the loop 2602187Smckusick */ 2612187Smckusick line = arg[ 1 ]; 2622187Smckusick # ifdef PC 2632187Smckusick if ( opt( 'p' ) ) { 2642187Smckusick if ( opt('t') ) { 2652187Smckusick putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 2662187Smckusick , "_LINO" ); 2672187Smckusick putop( P2UNARY P2CALL , P2INT ); 2682187Smckusick putdot( filename , line ); 2692187Smckusick } else { 2703836Speter putRV( STMTCOUNT , 0 , 0 , NGLOBAL , P2INT ); 2712187Smckusick putleaf( P2ICON , 1 , 0 , P2INT , 0 ); 2722187Smckusick putop( P2ASG P2PLUS , P2INT ); 2732187Smckusick putdot( filename , line ); 2742187Smckusick } 2752187Smckusick } 2763836Speter /*rvalue( lhs , NIL , RREQ );*/ 2773836Speter putRV( 0 , cbn , initnlp -> value[ NL_OFFS ] , 2783836Speter initnlp -> extra_flags , P2INT ); 2793836Speter putRV( 0 , cbn , termnlp -> value[ NL_OFFS ] , 2803836Speter termnlp -> extra_flags , P2INT ); 2813836Speter putop( ( arg[ 0 ] == T_FORU ? P2LT : P2GT ) , P2INT ); 2822187Smckusick putleaf( P2ICON , after , 0 , P2INT , 0 ); 2832187Smckusick putop( P2CBRANCH , P2INT ); 2842187Smckusick putdot( filename , line ); 2852187Smckusick /* 2862187Smckusick * okay, so we have to do it again, 2872187Smckusick * but first, increment the for variable. 2882187Smckusick * there it is again, an rvalue on the lhs of an assignment. 2892187Smckusick */ 2903836Speter /*lvalue( lhs , MOD , RREQ );*/ 2913836Speter putRV( 0 , cbn , initnlp -> value[ NL_OFFS ] , 2923836Speter initnlp -> extra_flags , P2INT ); 2932187Smckusick if ( opt( 't' ) ) { 2942187Smckusick precheck( fortype , "_RANG4" , "_RSNG4" ); 2952187Smckusick } 2963836Speter /*rvalue( lhs , NIL , RREQ );*/ 2973836Speter putRV( 0 , cbn , initnlp -> value[ NL_OFFS ] , 2983836Speter initnlp -> extra_flags , P2INT ); 2993633Smckusic putleaf( P2ICON , 1 , 0 , P2INT , 0 ); 3003633Smckusic putop( ( arg[0] == T_FORU ? P2PLUS : P2MINUS ) , P2INT ); 3012187Smckusick if ( opt( 't' ) ) { 3022187Smckusick postcheck( fortype ); 3032187Smckusick } 3043836Speter putop( P2ASSIGN , P2INT ); 3052187Smckusick putdot( filename , line ); 3062187Smckusick /* 3072187Smckusick * and do it all again 3082187Smckusick */ 3092187Smckusick putjbr( again ); 3102187Smckusick /* 3112187Smckusick * and here we are 3122187Smckusick */ 3132187Smckusick putlab( after ); 3142187Smckusick # endif PC 3152187Smckusick # ifdef OBJ 3162187Smckusick /* 3172187Smckusick * okay, so we have to do it again. 3182187Smckusick * Luckily we have a magic opcode which increments the 3192187Smckusick * index variable, checks the limit falling through if 3202187Smckusick * it has been reached, else range checking the result 3212187Smckusick * updating the index variable, and returning to the top 3222187Smckusick * of the loop. 3232187Smckusick */ 3242649Speter putline(); 3253836Speter put(2, O_RV4 | cbn<<8+INDX, termnlp -> value[ NL_OFFS ] ); 3262187Smckusick lvalue(lhs, MOD, LREQ); 3273083Smckusic if (width(fortype) <= 2) 3283083Smckusic put(4, (arg[0] == T_FORU ? O_FOR1U : O_FOR1D) + 3293083Smckusic (width(fortype)>>1), (int)fortype->range[0], 3303083Smckusic (int)fortype->range[1], again); 3313083Smckusic else 3323083Smckusic put(4, (arg[0] == T_FORU ? O_FOR4U : O_FOR4D), 3333083Smckusic fortype->range[0], fortype->range[1], again); 3342187Smckusick /* 3352187Smckusick * and here we are 3362187Smckusick */ 3372187Smckusick patch( after ); 3382187Smckusick # endif OBJ 3392187Smckusick byebye: 3402187Smckusick noreach = 0; 3413584Speter if (forvar != NIL) { 342*5871Smckusic shadow_nl.nl_flags |= forvar -> nl_flags & (NUSED|NMOD); 3435775Smckusic *forvar = shadow_nl; 3442187Smckusick } 3452187Smckusick if ( goc != gocnt ) { 3462187Smckusick putcnt(); 3472187Smckusick } 3482187Smckusick } 349