Lurking compiler bug? Caught a param not being initialized!

Technical questions regarding the XTC tools and programming with XMOS.
TjBordelon
Active Member
Posts: 39
Joined: Mon Jul 29, 2013 4:41 pm

Lurking compiler bug? Caught a param not being initialized!

Post by TjBordelon »

This is an odd one. I'm passing a parameter in argument 2 to my function and the watch window shows it as "0", however in the function it's showing as 5.

Code: Select all

dest_channel = xcore_getep_wait( control_channel,  desc.xcore_endpoint);

ldw (ru6)       r2, sp[0x10]   <--- r2 is the value of control_channel
ldc (ru6)       r1, 0x20         <--- r1 is 0x20
stw (ru6)       r0, sp[0xa]     Saving R0 for whatever reason
add (2rus)      r0, r2, 0x0     <-- Parameter 1 is now correct... set to control_channel
stw (ru6)       r1, sp[0x9]     Saving R1 for whatever reason
add (2rus)      r1, r3, 0x0     <---- R3 is '5' so at this point, which is wrong ***
bl (lu10)       0x13c
stw (ru6)       r0, sp[0x12]
As you can see above, r3 is never set, but it's moved into r1*

My initial thought was that r3 was being clobbered by one of the functions, and isn't loaded here because it's a register variable/optimization. The compiler keeps it around to use. however according to the ABI docs r3 is "caller save".

I'm at a loss here. Why is the compiler adding in 'r3' when it is never set up? Is r3 really callee save and the docs are incorrect?

R3 is set many lines above this code and used below this code. It seems like it's trying to cache into this variable, which doesn't seem right.

So my question:

Will the compiler use r0-r4 caller save registers if it thinks it can? Am I supposed to somehow list these in "side effects" in the assembler function declarations? According to everything I am reading on the ABI, r3 should be OK to clobber in asm functions. So I'm not sure why the compiler thinks it doesn't have to initialize it here.

Interesting to note that changing the code slightly fixes it, which really proves nothing:

Code: Select all

unsigned int dbg  = desc.xcore_endpoint;
ld8u (3r)       r2, r0[r1]
stw (ru6)       r2, sp[0xd]

dest_channel = xcore_getep_wait( control_channel,  dbg);
ldw (ru6)       r3, sp[0x11]  
bl (u10)        0x354
add (2rus)      r0, r3, 0x0
stw (ru6)       r1, sp[0x9]
add (2rus)      r1, r2, 0x0
bl (lu10)       0x13c
stw (ru6)       r0, sp[0x13]

In this second case, r0[r1] is used to load the 2nd parameter that ultimately ends up in r1. So obviously the compiler likes to use caller save registers when it thinks it can. Somehow it's either getting it wrong or I'm supposed to somehow tell it I'm using r3.

I'm going to try to preserve r0-r3 in all my asm calls and see if that helps. But this still seems odd.
Last edited by TjBordelon on Thu Aug 15, 2013 12:17 am, edited 1 time in total.


TjBordelon
Active Member
Posts: 39
Joined: Mon Jul 29, 2013 4:41 pm

Post by TjBordelon »

And in a strange turn of events, I added r3 to all my assembly functions' prolog/epilog, and look what happened to the compiler generated code:

Code: Select all

dest_channel = xcore_getep_wait( control_channel,   desc.xcore_endpoint);
ldw (ru6)       r2, sp[0x10]
ld8u (3r)       r3, r0[r1]     <---- Long lost R3 load!!!! Where did you come from?
stw (ru6)       r0, sp[0xa]
add (2rus)      r0, r2, 0x0
stw (ru6)       r1, sp[0x9]
add (2rus)      r1, r3, 0x0
bl (lu10)       0x13c
stw (ru6)       r0, sp[0x12]
Magically the missing load instruction arises from the ether. I remove the changes and rebuild. Still works.

I'm not sure why this happened. If it comes back I'm logging a ticket. The exact same code I compiled earlier today produces different output. I reverted this morning, and just reverted 10 minutes ago. Both times I did a clean rebuild. Spookey.