CMSI 488/588
Homework #4
Partial Answers
  1. Here are two translations of a for-loop
    Translation ATranslation B
        i := low
        goto test
    top:
        loop body
        i +:= 1
    test:
        if i <= high goto top
        code after the loop
    
        i := low
        if i > high goto bottom
        loop invariants can go here
    top:
        loop body
        i +:= 1
    test:
        if i <= high goto top
        a delay slot for loop code!
    bottom:
        code after the loop
    
  2. The second version's a clear winner according to these criteria:

  3. Strength Reducing i2

    There are two ways to strength reduce the expression i * i inside a loop, where i is an integer loop index, incremented by one each time.

    The first way is to notice that in the progression ... 9 4 1 0 1 4 9 16 25 36 49 64 ..., differences between successive values increase by 2 each time (... -5 -3 -1 1 3 5 7 ...). We'd have code like:

        isquared := START * START;
        delta := 2 * START + 1;
        for i in START .. END loop
            -- loop body, using i and isquared
            delta +:= 2;
            isquared +:= delta;
        end loop;
    

    Another idea is to notice (i+1)2 = i2+2i+1, so to get ready for the next iteration just add 2i+1 to the current value of i2.

        isquared := START * START;
        for i in START .. END loop
            -- loop body, using i and isquared
            isquared +:= i << 1 + 1;
        end loop;
    
  4. Strength Reducing Division

    This is an integer arithmetic problem, so all attempts to answer this question by using the reciprocal of c are doomed.

    Anyway, to figure this problem out, let's see what a concrete example will yield. Say we have i/3 in a loop,

    i        -9 -8 -7 -6 -5 -4 -3 -2 -1  0  1  2  3  4  5  6  7  8  9
    i div 3  -3 -2 -2 -2 -1 -1 -1  0  0  0  0  0  1  1  1  2  2  2  3
    i mod 3   0 -2 -1  0 -2 -1  0 -2 -1  0  1  2  0  1  2  0  1  2  0
    

    What this tells us is that basically we have results coming in blocks of 3, except for around zero (when there is a block of 5). In other words, every time the mod value hits zero, we're in for a change for the NEXT value of i, EXCEPT when the mod value hits zero because i became 0. As we iterate through the loop we can do modular addition on the mod value, watching for it to become zero. But this is a real pain with the negative mod values, so we should do an initial adjustment so that they always count 0,1,2,0,1,2 even for negative start values. Our loop can be:

        idivc := START div c;
        imodc := START rem c;
        if (START < 0 && imodc != 0) imodc += i;
    
        for i in START .. END loop
            -- loop body, using i and idiv c
            if (imodc == 0 && i != 0) idivc++;
            imodc++;
            if (imodc == c) imodc = 0;
        end loop;
    

    What about negative denominators?

    i         -9 -8 -7 -6 -5 -4 -3 -2 -1  0  1  2  3  4  5  6  7  8  9
    i div -3   3  2  2  2  1  1  1  0  0  0  0  0 -1 -1 -1 -2 -2 -2 -3
    i mod -3   0 -2 -1  0 -2 -1  0 -2 -1  0  1  2  0  1  2  0  1  2  0
    

    Well the mods work the same way, but the quotients decrease as we increment i. Well, we can precompute the delta, I guess.

        idivc := START div c;
        imodc := START rem c;
        signc := c < 0 ? -1 : 1;
        if (START < 0 && imodc != 0) imodc += i;
    
        for i in START .. END loop
            -- loop body, using i and idiv c
            if (imodc == 0 && i != 0) idivc += signc;
            imodc++;
            if (imodc == c) imodc = 0;
        end loop;
    
  5. A Code Motion Exercise

    We can factor the invariant to prevent having a branch in a loop:

    read(n)
    if (n > 0)
        for i in 1..100
            B[i] := n * i
            A[i] := B[i]
    else
        for i in 1..100
            B[i] := n * i