12187Smckusick /* Copyright (c) 1979 Regents of the University of California */ 22187Smckusick 3*10363Smckusick static char sccsid[] = "@(#)forop.c 1.12 01/17/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; 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 151*10363Smckusick sconv(p2type(inittype), P2INT); 1523836Speter putop( P2ASSIGN , P2INT ); 1532187Smckusick putdot( filename , line ); 1542187Smckusick /* 1552187Smckusick * compute and save the termination expression 1562187Smckusick */ 1573836Speter putRV( 0 , cbn , termnlp -> value[ NL_OFFS ] , 1583836Speter termnlp -> extra_flags , P2INT ); 1592187Smckusick # endif PC 1602187Smckusick # ifdef OBJ 1613083Smckusic gen(O_AS2, O_AS2, sizeof(long), width(inittype)); 1622187Smckusick /* 1632187Smckusick * compute and save the termination expression 1642187Smckusick */ 1653836Speter put(2, O_LV | cbn<<8+INDX, termnlp -> value[ NL_OFFS ] ); 1662187Smckusick # endif OBJ 1672187Smckusick termtype = rvalue( term , fortype , RREQ ); 1682187Smckusick if ( incompat( termtype , fortype , term ) ) { 1692187Smckusick cerror("Type of limit expression clashed with index type in 'for' statement"); 1703584Speter if (forvar != NIL) { 1713584Speter forvar->value[ NL_FORV ] = FORVAR; 1723584Speter } 1732187Smckusick statement( stat ); 1742187Smckusick goto byebye; 1752187Smckusick } 1762187Smckusick # ifdef PC 177*10363Smckusick sconv(p2type(termtype), P2INT); 1783836Speter putop( P2ASSIGN , P2INT ); 1792187Smckusick putdot( filename , line ); 1802187Smckusick /* 1812187Smckusick * we can skip the loop altogether if !( init <= term ) 1822187Smckusick */ 1832187Smckusick after = getlab(); 1843836Speter putRV( 0 , cbn , initnlp -> value[ NL_OFFS ] , 1853836Speter initnlp -> extra_flags , P2INT ); 1863836Speter putRV( 0 , cbn , termnlp -> value[ NL_OFFS ] , 1873836Speter termnlp -> extra_flags , P2INT ); 1883836Speter putop( ( arg[0] == T_FORU ? P2LE : P2GE ) , P2INT ); 1892187Smckusick putleaf( P2ICON , after , 0 , P2INT , 0 ); 1902187Smckusick putop( P2CBRANCH , P2INT ); 1912187Smckusick putdot( filename , line ); 1922187Smckusick /* 1933278Smckusic * put down the label at the top of the loop 1943278Smckusic */ 1953278Smckusic again = getlab(); 1963278Smckusic putlab( again ); 1973278Smckusic /* 1982187Smckusick * okay, then we have to execute the body, but first, 1992187Smckusick * assign the initial expression to the for variable. 2002187Smckusick * see the note in asgnop1 about why this is an rvalue. 2012187Smckusick */ 2023371Speter lvalue( lhs , NOUSE , RREQ ); 2032187Smckusick if ( opt( 't' ) ) { 2042187Smckusick precheck( fortype , "_RANG4" , "_RSNG4" ); 2052187Smckusick } 2063836Speter putRV( 0 , cbn , initnlp -> value[ NL_OFFS ] , 2073836Speter initnlp -> extra_flags , P2INT ); 2082187Smckusick if ( opt( 't' ) ) { 209*10363Smckusick postcheck(fortype, nl+T4INT); 2102187Smckusick } 211*10363Smckusick sconv(P2INT, p2type(fortype)); 2123836Speter putop( P2ASSIGN , p2type( fortype ) ); 2132187Smckusick putdot( filename , line ); 2142187Smckusick # endif PC 2152187Smckusick # ifdef OBJ 2163083Smckusic gen(O_AS2, O_AS2, sizeof(long), width(termtype)); 2172187Smckusick /* 2182187Smckusick * we can skip the loop altogether if !( init <= term ) 2192187Smckusick */ 2203836Speter put(2, O_RV4 | cbn<<8+INDX, initnlp -> value[ NL_OFFS ] ); 2213836Speter put(2, O_RV4 | cbn<<8+INDX, termnlp -> value[ NL_OFFS ] ); 2222187Smckusick gen(NIL, arg[0] == T_FORU ? T_LE : T_GE, sizeof(long), 2232187Smckusick sizeof(long)); 2242187Smckusick after = getlab(); 2252187Smckusick put(2, O_IF, after); 2262187Smckusick /* 2273278Smckusic * put down the label at the top of the loop 2283278Smckusic */ 2293278Smckusic again = getlab(); 2303278Smckusic putlab( again ); 2313278Smckusic /* 2322187Smckusick * okay, then we have to execute the body, but first, 2332187Smckusick * assign the initial expression to the for variable. 2342187Smckusick */ 2352187Smckusick lvalue( lhs , NOUSE , LREQ ); 2363836Speter put(2, O_RV4 | cbn<<8+INDX, initnlp -> value[ NL_OFFS ] ); 2372187Smckusick rangechk(fortype, nl+T4INT); 2383083Smckusic gen(O_AS2, O_AS2, width(fortype), sizeof(long)); 2392187Smckusick # endif OBJ 2402187Smckusick /* 2413584Speter * shadowing the real for variable 2423584Speter * with the initail expression temporary: 2433584Speter * save the real for variable's offset, flags 2443584Speter * (including nl_block). 2453584Speter * replace them with the initial expression's offset, 2463584Speter * and mark it as being a for variable. 2473584Speter */ 2485871Smckusic shadow_nl.nl_flags = forvar -> nl_flags; 2495775Smckusic *forvar = *initnlp; 2505775Smckusic forvar -> symbol = shadow_nl.symbol; 2515775Smckusic forvar -> nl_next = shadow_nl.nl_next; 2525871Smckusic forvar -> type = shadow_nl.type; 2533584Speter forvar -> value[ NL_FORV ] = FORVAR; 2543584Speter /* 2552187Smckusick * and don't forget ... 2562187Smckusick */ 2573278Smckusic putcnt(); 2583278Smckusic statement( stat ); 2592187Smckusick /* 2602187Smckusick * wasn't that fun? do we get to do it again? 2612187Smckusick * we don't do it again if ( !( forvar < limit ) ) 2622187Smckusick * pretend we were doing this at the top of the loop 2632187Smckusick */ 2642187Smckusick line = arg[ 1 ]; 2652187Smckusick # ifdef PC 2662187Smckusick if ( opt( 'p' ) ) { 2672187Smckusick if ( opt('t') ) { 2682187Smckusick putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 2692187Smckusick , "_LINO" ); 2702187Smckusick putop( P2UNARY P2CALL , P2INT ); 2712187Smckusick putdot( filename , line ); 2722187Smckusick } else { 2733836Speter putRV( STMTCOUNT , 0 , 0 , NGLOBAL , P2INT ); 2742187Smckusick putleaf( P2ICON , 1 , 0 , P2INT , 0 ); 2752187Smckusick putop( P2ASG P2PLUS , P2INT ); 2762187Smckusick putdot( filename , line ); 2772187Smckusick } 2782187Smckusick } 2793836Speter /*rvalue( lhs , NIL , RREQ );*/ 2803836Speter putRV( 0 , cbn , initnlp -> value[ NL_OFFS ] , 2813836Speter initnlp -> extra_flags , P2INT ); 2823836Speter putRV( 0 , cbn , termnlp -> value[ NL_OFFS ] , 2833836Speter termnlp -> extra_flags , P2INT ); 2843836Speter putop( ( arg[ 0 ] == T_FORU ? P2LT : P2GT ) , P2INT ); 2852187Smckusick putleaf( P2ICON , after , 0 , P2INT , 0 ); 2862187Smckusick putop( P2CBRANCH , P2INT ); 2872187Smckusick putdot( filename , line ); 2882187Smckusick /* 2892187Smckusick * okay, so we have to do it again, 2902187Smckusick * but first, increment the for variable. 2912187Smckusick * there it is again, an rvalue on the lhs of an assignment. 2922187Smckusick */ 2933836Speter /*lvalue( lhs , MOD , RREQ );*/ 2943836Speter putRV( 0 , cbn , initnlp -> value[ NL_OFFS ] , 2953836Speter initnlp -> extra_flags , P2INT ); 2962187Smckusick if ( opt( 't' ) ) { 2972187Smckusick precheck( fortype , "_RANG4" , "_RSNG4" ); 2982187Smckusick } 2993836Speter /*rvalue( lhs , NIL , RREQ );*/ 3003836Speter putRV( 0 , cbn , initnlp -> value[ NL_OFFS ] , 3013836Speter initnlp -> extra_flags , P2INT ); 3023633Smckusic putleaf( P2ICON , 1 , 0 , P2INT , 0 ); 3033633Smckusic putop( ( arg[0] == T_FORU ? P2PLUS : P2MINUS ) , P2INT ); 3042187Smckusick if ( opt( 't' ) ) { 305*10363Smckusick postcheck(fortype, nl+T4INT); 3062187Smckusick } 3073836Speter putop( P2ASSIGN , P2INT ); 3082187Smckusick putdot( filename , line ); 3092187Smckusick /* 3102187Smckusick * and do it all again 3112187Smckusick */ 3122187Smckusick putjbr( again ); 3132187Smckusick /* 3142187Smckusick * and here we are 3152187Smckusick */ 3162187Smckusick putlab( after ); 3172187Smckusick # endif PC 3182187Smckusick # ifdef OBJ 3192187Smckusick /* 3202187Smckusick * okay, so we have to do it again. 3212187Smckusick * Luckily we have a magic opcode which increments the 3222187Smckusick * index variable, checks the limit falling through if 3232187Smckusick * it has been reached, else range checking the result 3242187Smckusick * updating the index variable, and returning to the top 3252187Smckusick * of the loop. 3262187Smckusick */ 3272649Speter putline(); 3283836Speter put(2, O_RV4 | cbn<<8+INDX, termnlp -> value[ NL_OFFS ] ); 3292187Smckusick lvalue(lhs, MOD, LREQ); 3303083Smckusic if (width(fortype) <= 2) 3313083Smckusic put(4, (arg[0] == T_FORU ? O_FOR1U : O_FOR1D) + 3323083Smckusic (width(fortype)>>1), (int)fortype->range[0], 3333083Smckusic (int)fortype->range[1], again); 3343083Smckusic else 3353083Smckusic put(4, (arg[0] == T_FORU ? O_FOR4U : O_FOR4D), 3363083Smckusic fortype->range[0], fortype->range[1], again); 3372187Smckusick /* 3382187Smckusick * and here we are 3392187Smckusick */ 3402187Smckusick patch( after ); 3412187Smckusick # endif OBJ 3422187Smckusick byebye: 3432187Smckusick noreach = 0; 3443584Speter if (forvar != NIL) { 3455871Smckusic shadow_nl.nl_flags |= forvar -> nl_flags & (NUSED|NMOD); 3465775Smckusic *forvar = shadow_nl; 3472187Smckusick } 3482187Smckusick if ( goc != gocnt ) { 3492187Smckusick putcnt(); 3502187Smckusick } 3512187Smckusick } 352