MinGW32 compiled GCC 7.2.0 Toolchain (mipsel-unknown-elf)

Downloadable items posted by PSXDEV members are within this forum.
User avatar
LameGuy64
Verified
Psy-Q Enthusiast
Psy-Q Enthusiast
Posts: 388
Joined: Apr 10, 2013
I am a: Hobbyist Game Developer
Motto: Commercial or not, play it!
PlayStation Model: H2000/7000
Location: Philippines
Contact:

Post by LameGuy64 » December 16th, 2018, 11:46 pm

I've been experiencing some really annoying bugs with GCC 7.2.0 as of late, most notably when optimizations are specified. The most significant bug I've encountered is if you compile the following:

Code: Select all

void myfunc() {

        ival = 0;

        somefunc( ival );

        do {

                ival++;
                ival = ival * 2;

                somefunc( ival );
                somefunc( ival/2 );

        } while( 1 );

}
It comes out as:

Code: Select all

myfunc:
        sw      $0,%gp_rel(ival)($28)
$L4:
        b       $L4
        nop
Which is basically an infinite loop. I've also had occurrences where certain arithmetic won't work correctly (ie. i |= 25 will replace the value of i instead of OR'ing the specified value into i) and a while loop would sometimes come out as an infinite loop which can sometimes be fixed by adding dummy code in it.

The worst part about this is I cannot seem to find anything on the internet regarding this issue probably because people haven't used GCC to compile MIPS code for years or those who do don't use any optimizations so they didn't notice these issues. I suspect these optimizer problems cropped up after GCC 4.8.x as anything above it has large portions of the toolchain rewritten to make use of C++.

I've tried to compile GCC 4.8.2 but I haven't been successful at it either because newer versions of the toolchain don't play well with 4.8.2 source or configure scripts failing with a unable to calculate EOF error.
Please don't forget to include my name if you share my work around. Credit where it is due.

Dev. Console: SCPH-7000 with SCPH-7501 ROM, MM3, PAL color fix, Direct AV ports, DB-9 port for Serial I/O, and a Xplorer FX with Caetla 0.35.

DTL-H2000 PC: Dell Optiplex GX110, Windows 98SE & Windows XP, Pentium III 933MHz, 384MB SDRAM, ATI Radeon 7000 VE 64MB, Soundblaster Audigy, 40GB Seagate HDD, Hitachi Lite-on CD-RW Drive, ZIP 250 and 3.5" Floppy.

Xavi92
Verified
C Programming Expert
C Programming Expert
Posts: 161
Joined: Oct 06, 2012
PlayStation Model: SCPH-5502
Contact:

Post by Xavi92 » December 17th, 2018, 5:18 am

After ~7 years of using different versions of mipsel-unknown-elf (initially GCC 4, now 8.2.0), I have never found any compiler bugs. What assembly does GCC generate if you declare ival as volatile? It could be related to that.

User avatar
gwald
Verified
Net Yaroze Enthusiast
Net Yaroze Enthusiast
Posts: 282
Joined: Sep 18, 2013
I am a: programmer/DBA
PlayStation Model: Net Yaroze
Contact:

Post by gwald » December 17th, 2018, 8:01 am

I'm not the best C coder, but isn't do while(1); an infinite loop?

Yagotzirck
Verified
Extreme PSXDEV User
Extreme PSXDEV User
Posts: 131
Joined: Jul 17, 2013

Post by Yagotzirck » December 17th, 2018, 8:31 am

gwald wrote: December 17th, 2018, 8:01 am I'm not the best C coder, but isn't do while(1); an infinite loop?
I think he means that the compiler discards the dummy multiplication/addition operations followed by the two calls to somefunc(), rather than doing a 1:1 assembly translation... It's hard to guess since he didn't post the code for somefunc(), but I guess somefunc() does nothing more than some more dummy operations, the compiler notices that and just optimizes away all the dummy code, leaving just an infinite loop... but yeah, optimizations are bugs apparently :roll:
Xavi92 wrote: December 17th, 2018, 5:18 am After ~7 years of using different versions of mipsel-unknown-elf (initially GCC 4, now 8.2.0), I have never found any compiler bugs. What assembly does GCC generate if you declare ival as volatile? It could be related to that.
That's what I already suggested him to do in this thread's first page, but he plain ignored it and went on with the compiler optimizations-turned-into-bugs conspiracy; I guess I'm unknowingly cosplaying as Bruce Willis in The 6th Sense and whatever I said went unnoticed.

User avatar
LameGuy64
Verified
Psy-Q Enthusiast
Psy-Q Enthusiast
Posts: 388
Joined: Apr 10, 2013
I am a: Hobbyist Game Developer
Motto: Commercial or not, play it!
PlayStation Model: H2000/7000
Location: Philippines
Contact:

Post by LameGuy64 » December 17th, 2018, 12:06 pm

Oh, so they're actually part of the optimizations? I didn't know it is that clever omitting variables that are never used elsewhere and turning very small functions into in-line code :oops:.

somefunc() simply sets a global variable:

Code: Select all

void somefunc(int value) {
	
	global_var = value;
	
}
I decided to do another test but this time with a volatile variable set to a hardcoded address (ie. an I/O port):

Code: Select all

char global_array[256];
int global_var;
int ival;

volatile int *ioport = (int*)0x1f800000;

void somefunc(int value) {
	
	global_var = value;
	*ioport = value;
	
}

void myfunc() {
	
	ival = 0;
	
	somefunc( ival );
	
	do {
		
		ival++;
		ival = ival * 2;
		
		somefunc( ival );
		somefunc( ival/2 );
		
	} while( 1 );

}
And the assembler output looks like this:

Code: Select all

somefunc:
        .frame  $sp,0,$31               # v
        .mask   0x00000000,0
        .fmask  0x00000000,0
        .set    noreorder
        .set    nomacro
        lw      $2,%gp_rel(ioport)($28)
        sw      $4,%gp_rel(global_var)($28)
        sw      $4,0($2)
        jr      $31
        nop

        .set    macro
        .set    reorder
        .end    somefunc
        .size   somefunc, .-somefunc
        .align  2
        .globl  myfunc
        .set    nomips16
        .set    nomicromips
        .ent    myfunc
        .type   myfunc, @function
myfunc:
        .frame  $sp,0,$31               # v
        .mask   0x00000000,0
        .fmask  0x00000000,0
        .set    noreorder
        .set    nomacro
        lw      $4,%gp_rel(ioport)($28)
        sw      $0,%gp_rel(ival)($28)
        sw      $0,0($4)
$L4:
        lw      $2,%gp_rel(ival)($28)
        nop
        addiu   $2,$2,1
        sll     $2,$2,1
        sw      $2,%gp_rel(ival)($28)
        sw      $2,0($4)
        lw      $3,%gp_rel(ival)($28)
        nop
        srl     $2,$3,31
        addu    $2,$2,$3
        sra     $2,$2,1
        sw      $2,%gp_rel(global_var)($28)
        sw      $2,0($4)
        b       $L4
        nop
Looks like it reduces somefunc() into just a few instructions and it calls it as in-line. I really didn't know that GCC's optimizer is this sophisticated.

I still remember running into a few compiler bugs with GCC like this bit of code from PSXSDK's SsUpload() would produce an infinite loop which I had to fix by placing some dummy operations in it:

Code: Select all

while( ( SPU_STATUS2 & 0x7ff ) != spu_status );
And there was also an instance where performing an OR operation behaved like I was doing an = operation instead:

Code: Select all

// To avoid confusion, these are from homebrew libs of my own that follow Sony's syntax

typedef struct {
	unsigned int	tag;
	unsigned int	code[1];
} DR_TPAGE;

DR_TPAGE *tpri = (DR_TPAGE*)nextpri;

setTPagePri( tpri, 0, 0, tim.prect->x, tim.prect->y );	// Sets tag and code[0]
tpri->code[0] |= 0x200;					// OR 0x200 to code[0] (behaved like = at one point)

Strangely, that OR bug I ran into above is gone now.
Please don't forget to include my name if you share my work around. Credit where it is due.

Dev. Console: SCPH-7000 with SCPH-7501 ROM, MM3, PAL color fix, Direct AV ports, DB-9 port for Serial I/O, and a Xplorer FX with Caetla 0.35.

DTL-H2000 PC: Dell Optiplex GX110, Windows 98SE & Windows XP, Pentium III 933MHz, 384MB SDRAM, ATI Radeon 7000 VE 64MB, Soundblaster Audigy, 40GB Seagate HDD, Hitachi Lite-on CD-RW Drive, ZIP 250 and 3.5" Floppy.

Xavi92
Verified
C Programming Expert
C Programming Expert
Posts: 161
Joined: Oct 06, 2012
PlayStation Model: SCPH-5502
Contact:

Post by Xavi92 » December 17th, 2018, 5:04 pm

In fact, many variables in stock PSXSDK 0.5.99 missed the "volatile" qualifier and because of this reason it would not work with compiler optimizations. That's one of the first changes that I made on my own fork of PSXSDK: https://github.com/XaviDCR92/psxsdk-20150729
As a rule of thumb, always declare variables as "volatile" if they could be modified outside normal code execution flow (e.g.: from an interrupt handler) or if you really want to ensure the compiler does not optimize them away for any particular reason. Obviously, hardware registers must be then always declared as "volatile" since they can be modified by the hardware itself (e.g.: GPU ready flag), and the compiler will not be aware of that unless clearly specified.

Yagotzirck
Verified
Extreme PSXDEV User
Extreme PSXDEV User
Posts: 131
Joined: Jul 17, 2013

Post by Yagotzirck » December 18th, 2018, 12:11 am

And there was also an instance where performing an OR operation behaved like I was doing an = operation instead:

Code: Select all

// To avoid confusion, these are from homebrew libs of my own that follow Sony's syntax

typedef struct {
	unsigned int	tag;
	unsigned int	code[1];
} DR_TPAGE;

DR_TPAGE *tpri = (DR_TPAGE*)nextpri;

setTPagePri( tpri, 0, 0, tim.prect->x, tim.prect->y );	// Sets tag and code[0]
tpri->code[0] |= 0x200;					// OR 0x200 to code[0] (behaved like = at one point)

Strangely, that OR bug I ran into above is gone now.
How is the struct nextpri points to allocated/initialized? If it's initialized to 0 (e.g. with calloc()) and there aren't any other assignments to code[0] between initialization and the OR operation above, the compiler might again have noticed that, and since 0 | 0x200 = 0x200 it simply replaced the OR operation with an assignment; otherwise, it's a strange thing indeed.

User avatar
LameGuy64
Verified
Psy-Q Enthusiast
Psy-Q Enthusiast
Posts: 388
Joined: Apr 10, 2013
I am a: Hobbyist Game Developer
Motto: Commercial or not, play it!
PlayStation Model: H2000/7000
Location: Philippines
Contact:

Post by LameGuy64 » December 18th, 2018, 12:59 am

nextpri points to a primitive buffer (in this case a fixed sized global array), usually to a spot where the next primitive should be written to. setTPagePri sets tpri->tag to 0x01000000 and tpri->code[0] to 0xe100xxxx. Reason I wanted to OR 0x200 in it is to set a bit that enables dithering but at one time the OR operation sets tpri->code[0] to 0x00000200 turning it into an invalid 'nop' primitive.
Please don't forget to include my name if you share my work around. Credit where it is due.

Dev. Console: SCPH-7000 with SCPH-7501 ROM, MM3, PAL color fix, Direct AV ports, DB-9 port for Serial I/O, and a Xplorer FX with Caetla 0.35.

DTL-H2000 PC: Dell Optiplex GX110, Windows 98SE & Windows XP, Pentium III 933MHz, 384MB SDRAM, ATI Radeon 7000 VE 64MB, Soundblaster Audigy, 40GB Seagate HDD, Hitachi Lite-on CD-RW Drive, ZIP 250 and 3.5" Floppy.

Yagotzirck
Verified
Extreme PSXDEV User
Extreme PSXDEV User
Posts: 131
Joined: Jul 17, 2013

Post by Yagotzirck » December 18th, 2018, 1:26 am

How are tpri->code[0]'s lower 2 bytes undefined (Unless the "xxxx" part means something else)? I initially guessed that you used LUI instruction, but AFAIK it zeroes out the lower 2 bytes :shrug

Anyway, any clue about how it got fixed, or did a simple recompilation without changing anything fix it? In the latter case that would be rather weird.

User avatar
LameGuy64
Verified
Psy-Q Enthusiast
Psy-Q Enthusiast
Posts: 388
Joined: Apr 10, 2013
I am a: Hobbyist Game Developer
Motto: Commercial or not, play it!
PlayStation Model: H2000/7000
Location: Philippines
Contact:

Post by LameGuy64 » December 20th, 2018, 11:58 am

The undefined values in the lower 2 bytes of tpri->code[0] are texture page coordinates which varies depending on the arguments specified on setTpagePri and the 4th byte being 0xe1 is the primitive code for setting a texture page which is also set by setTpagePri. I suppose you're unfamiliar with GPU packets on the PS1.

Not sure why but when I went to uncomment tpri->code[0] |= 0x200; later on the bug mysteriously disappeared.
Please don't forget to include my name if you share my work around. Credit where it is due.

Dev. Console: SCPH-7000 with SCPH-7501 ROM, MM3, PAL color fix, Direct AV ports, DB-9 port for Serial I/O, and a Xplorer FX with Caetla 0.35.

DTL-H2000 PC: Dell Optiplex GX110, Windows 98SE & Windows XP, Pentium III 933MHz, 384MB SDRAM, ATI Radeon 7000 VE 64MB, Soundblaster Audigy, 40GB Seagate HDD, Hitachi Lite-on CD-RW Drive, ZIP 250 and 3.5" Floppy.

Post Reply

Who is online

Users browsing this forum: No registered users and 2 guests