This bug was very hard to trace. I'm on the ScummVM dev team and I develop
specifically for the PSP(MIPS). I came across a crash when trying to start one
of our engines. The bug only occurred under very specific circumstances -- I
bisected it and adding class variables or adding some code made it go away, but
I'm not sure what the pattern is.

Here's the problematic code, packaged together easily:

void Logic::logicUp(uint32 new_script) {
       debug(5, "new pc = %d", new_script & 0xffff);

       // going up a level - and we'll keep going this cycle
       _curObjectHub.setLogicLevel(_curObjectHub.getLogicLevel() + 1);

       assert(_curObjectHub.getLogicLevel() < 3);      // Can be 0, 1, 2
       logicReplace(new_script);
}

void Logic::logicReplace(uint32 new_script) {
       uint32 level = _curObjectHub.getLogicLevel();

       _curObjectHub.setScriptId(level, new_script);
       _curObjectHub.setScriptPc(level, new_script & 0xffff);
}

        void setScriptId(int level, uint32 x) {
                WRITE_LE_UINT32(_addr + 20 + 4 * level, x);
        }

        uint32 getScriptId(int level) {
                return READ_LE_UINT32(_addr + 20 + 4 * level);
        }
        void setScriptPc(int level, uint32 x) {
                WRITE_LE_UINT32(_addr + 32 + 4 * level, x);
        }


G++ optimized these 2 functions into 1 and came up with this code:

8934bc0 <_ZN6Sword25Logic7logicUpEj>:
 8934bc0:       27bdfff0        addiu   sp,sp,-16
 8934bc4:       afb20008        sw      s2,8(sp)
 8934bc8:       afb10004        sw      s1,4(sp)
 8934bcc:       30b2ffff        andi    s2,a1,0xffff  # s2 = new_scip & 0xffff
 8934bd0:       00a08821        move    s1,a1 # s1 = new_scipt
 8934bd4:       3c0508aa        lui     a1,0x8aa # a1 = 0x8aa0000
 8934bd8:       afb00000        sw      s0,0(sp)
 8934bdc:       24a50d68        addiu   a1,a1,3432 # a1 = 0x8aa3432
 8934be0:       00808021        move    s0,a0 # s0 = this
 8934be4:       02403021        move    a2,s2 # a2 = new_script & 0xffff
 8934be8:       afbf000c        sw      ra,12(sp)
 8934bec:       0e286377        jal     8a18ddc <_Z5debugiPKcz>
 8934bf0:       24040005        li      a0,5 # a0 = 5 (jump)
 8934bf4:       8e0400d8        lw      a0,216(s0)  # a0 = *(this + 216)
 8934bf8:       88850007        lwl     a1,7(a0) # a1 =
 8934bfc:       98850004        lwr     a1,4(a0) # a1 = logicLevel
 8934c00:       24a20001        addiu   v0,a1,1 # v0 = logicLevel + 1
 8934c04:       a8820007        swl     v0,7(a0) # 7(a0) = 0.5 new logicLevel
 8934c08:       2ca30003        sltiu   v1,a1,3 # v1 = a1 < 3?
 8934c0c:       10600011        beqz    v1,8934c54
<_ZN6Sword25Logic7logicUpEj+0x94> # assert
 8934c10:       b8820004        swr     v0,4(a0) # 4(a0) = 0.5 new logicLevel
 8934c14:       24a20005        addiu   v0,a1,5 # v0 = logicLevel + 5 ???
 8934c18:       00021080        sll     v0,v0,0x2 # v0 = 4*logicLevel + 20
(scriptId offset)
 8934c1c:       00821021        addu    v0,a0,v0 # v0 = &scriptId
 8934c20:       24a30008        addiu   v1,a1,8 # v1 = logicLevel + 8
 8934c24:       a8510003        swl     s1,3(v0) # scriptId[3] = new_script
 8934c28:       00031880        sll     v1,v1,0x2 # v1 = logicLevel * 4 + 32
 8934c2c:       b8510000        swr     s1,0(v0) # scriptId[0] = new_script
 8934c30:       00831821        addu    v1,a0,v1 # v1 = *(this + 216)

Note the mistake in line 8934c00. v0 is used for incrementing the
logicLevel, and v0 is indeed saved into memory (ie.
_curObjectHub.setLogicLevel(_curObjectHub.getLogicLevel() + 1); )
But the optimization gcc made prevents it from realizing it needs to
use the newly incremented logicLevel value for the other calculations,
so instead it keeps using a1 in the rest of the function. This causes
it to write the new scriptId value in the wrong place, which causes
the VM to think its next scriptId is 0.

I'd like to attach the .ii files but I don't know how (can't find a button for
it). You can see the full code at
https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm. The 'problem' code
is under the engines/sword2 directory in header.h, logic.cpp and function.cpp.
This bug does not happen on any other platform as far as I know, but there's a
huge random element involved regarding a particular memory layout.

Thanks
Yotam Barnoy


-- 
           Summary: Bad optimization in -O3 sometimes
           Product: gcc
           Version: 4.3.3
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
        AssignedTo: unassigned at gcc dot gnu dot org
        ReportedBy: yotambarnoy at gmail dot com


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=45462

Reply via email to