[comp.lang.perl] Local Variable Problem on NCR Tower

lbr@holos0.uucp (Len Reed) (09/12/90)

Perl will not work properly on an NCR Tower when compiled with full
optimization (-O2).  I have confirmed this on a Tower 32-600 running
System V.2 and a Tower 32-500 running V.3.

It *does* pass the test suite, however.  The problems concern local
variable handling.  Perl seems to get confused when deallocating local
variables.   It's not a simple as saying when the local $i is deallocated
that the previous one doesn't reappear; rather, when the local $i is deallocated
other variables suddenly take on the wrong values.  The problem is especially
acute when using recursion.  In general, though, it doesn't happen often.

The debugger script also messes up, probably due to the same problem.

I think I know what the problem is, but I don't understand why this problem
doesn't occur on other machines.

The following script causes the problem:

#!/usr/acct/lbin/perl
sub doubleary {
    local(*someary, *another) = @_;
    local ($elem);
	foreach $elem (@someary) {
        $elem *= 2;
    }
    foreach $elem (@another) {
        $elem += 5;
    }
}

@foo = (1,3,5);
@bar = (9,11,13);
@other = (21,23,25);

do doubleary(*foo, *other);
do doubleary(*bar, *other);

print "@foo\n";
print "@bar\n";
print "@other\n";
__END__

It should yield
2 6 10
18 22 26
31 33 35

but with the bug will yield
2 6 10
18 22 26
21 23 25

The Tower manuals warn against using -O2 with setjmp and longjmp.
The compiler will do global register allocation, using registers
rather than stack variables for automatic variables it decides are heavily
used.  The manual says go to -O1 or make these static, not auto.

Consider the following code:

#include <setjmp.h>

#define VOLATILE        /* Tower doesn't know about volatile */

int main()
{
    static jmp_buf saveit;
    VOLATILE int x;
    int y, z;   /* used to cause optimizer to put x into a register */

    x = 12;
    if (setjmp(saveit)) {
        printf("x is %d\n", x);
        return 0;
    }
    y = 2*x;        /* tickle the register allocation heuristic */
    x = 25;
    longjmp(saveit, 1);
    z = 4*x + 23;   /* tickle the heuristic */
}

The printf should give 25 but it gives 12 under cc -O2.

Well, why doesn't this problem occur on other machines?  Surely other
compilers perform this kind of optimization.  If fact, the mappings
from variables to registers are not necessarily static; e.g., r4 might
be x some places and y others.

I presume that this is the purpose of VOLATILE in Larry's code.  SCO Xenix
386, which supports volatile, experienced no such problems.  The Tower does
not recognize volatile, though.

Presuming that volatile is the key to this puzzle, I recompiled perly.c
and cmd.c with -O1.  The other files that use setjmp/longjmp don't
use VOLATILE, so I presume that there are no traps there.  It might
be better to allocate static variables and use -O2, but what I have
works satisfactorily.

I'm still puzzled, though, as to why similar problems don't occur on other
machines.  Is the global register optimization plus no volatile keyword
combination all that rare?
-- 
Len Reed
Holos Software, Inc.
Voice: (404) 496-1358
UUCP: ...!gatech!holos0!lbr