Page 1 of 2

Inline asm calls ignored in devkitARM r43

Posted: Thu Jan 08, 2015 12:59 am
by Chano
Hi!

This code used to work devkitARM r42 without problems:

Code: Select all

    void biosDivision(s32 numerator, s32 denominator, s32* result, s32* remainder)
    {
        asm volatile
        (
            "mov   r0, %2   \n"
            "mov   r1, %3   \n"
            "swi   6        \n" // Put 6 here for Thumb C Compiler mode.
            "ldr   r2, %0   \n" // Put 0x60000 there for ARM C Compiler mode.
            "str   r0, [r2] \n"
            "ldr   r2, %1   \n"
            "str   r1, [r2] \n"
            : "=m" (result), "=m" (remainder)
            : "r" (numerator), "r" (denominator)
            : "r0","r1","r2","r3"
        );
    }
However, with r43 it only works if the gcc optimizations are disabled (-O0).

Any ideas?

Re: Inline asm calls ignored in devkitARM r43

Posted: Thu Jan 08, 2015 11:06 am
by WinterMute
Seems to be working for me, what compiler flags are you using?

You can detect thumb/arm mode at compile time - here's the code I used to test.

Code: Select all

#include <stdint.h>

typedef int32_t s32;

void biosDivision(s32 numerator, s32 denominator, s32* result, s32* remainder) {
    asm volatile (
        "\tmov   r0, %2   \n"
        "\tmov   r1, %3   \n"
#if	defined	( __thumb__ )
        "\tswi   6        \n" // Put 6 here for Thumb C Compiler mode.
#else
        "\tswi   6<<16    \n" // Put 0x60000 there for ARM C Compiler mode.
#endif
        "\tldr   r2, %0   \n"
        "\tstr   r0, [r2] \n"
        "\tldr   r2, %1   \n"
        "\tstr   r1, [r2] \n"
        : "=m" (result), "=m" (remainder)
        : "r" (numerator), "r" (denominator)
        : "r0","r1","r2","r3"
    );
}
I like to put \t in the assembly mainly because it makes the output from -save-temps a little more readable. Some people like to not do that because it makes it more obvious which parts are inline assembly & which parts are generated.

Re: Inline asm calls ignored in devkitARM r43

Posted: Thu Jan 08, 2015 7:08 pm
by Chano
I have copypasted the template project in the example folder.

The code below with the default flags shows "5 / 2 = 0".
However, with -O0 it shows "5 / 2 = 2":

Code: Select all

#include <gba_console.h>
#include <gba_video.h>
#include <gba_interrupt.h>
#include <gba_systemcalls.h>
#include <gba_input.h>
#include <stdio.h>
#include <stdlib.h>

void biosDivision(s32 numerator, s32 denominator, s32* result, s32* remainder)
{
    asm volatile (
        "\tmov   r0, %2   \n"
        "\tmov   r1, %3   \n"
#if   defined   ( __thumb__ )
        "\tswi   6        \n" // Put 6 here for Thumb C Compiler mode.
#else
        "\tswi   6<<16    \n" // Put 0x60000 there for ARM C Compiler mode.
#endif
        "\tldr   r2, %0   \n"
        "\tstr   r0, [r2] \n"
        "\tldr   r2, %1   \n"
        "\tstr   r1, [r2] \n"
        : "=m" (result), "=m" (remainder)
        : "r" (numerator), "r" (denominator)
        : "r0","r1","r2","r3"
    );
}

//---------------------------------------------------------------------------------
// Program entry point
//---------------------------------------------------------------------------------
int main(void) {
//---------------------------------------------------------------------------------


	// the vblank interrupt must be enabled for VBlankIntrWait() to work
	// since the default dispatcher handles the bios flags no vblank handler
	// is required
	irqInit();
	irqEnable(IRQ_VBLANK);

	consoleDemoInit();

    s32 numerator = 5;
    s32 denominator = 2;
    s32 result = 0;
    s32 remainder = 0;
    biosDivision(numerator, denominator, &result, &remainder);

	// ansi escape sequence to set print co-ordinates
	// /x1b[line;columnH
    iprintf("\x1b[10;10H%d / %d = %d\n", numerator, denominator, result);

	while (1) {
		VBlankIntrWait();
	}
}

Re: Inline asm calls ignored in devkitARM r43

Posted: Sat Jan 10, 2015 1:33 am
by Chano
I have tried to replace the function with a macro, but the result is the same:

Code: Select all

#include <gba_console.h>
#include <gba_video.h>
#include <gba_interrupt.h>
#include <gba_systemcalls.h>
#include <gba_input.h>
#include <stdio.h>
#include <stdlib.h>

#define BIOS_DIVISION(numerator, denominator, result, remainder) \
    do { \
        asm volatile \
        ( \
            "mov   r0, %2   \n" \
            "mov   r1, %3   \n" \
            "swi   6        \n" \
            "ldr   r2, %0   \n" \
            "str   r0, [r2] \n" \
            "ldr   r2, %1   \n" \
            "str   r1, [r2] \n" \
            : "=m" (result), "=m" (remainder) \
            : "r" (numerator), "r" (denominator) \
            : "r0","r1","r2","r3" \
        ); \
    } while(0)

//---------------------------------------------------------------------------------
// Program entry point
//---------------------------------------------------------------------------------
int main(void) {
//---------------------------------------------------------------------------------


	// the vblank interrupt must be enabled for VBlankIntrWait() to work
	// since the default dispatcher handles the bios flags no vblank handler
	// is required
	irqInit();
	irqEnable(IRQ_VBLANK);

	consoleDemoInit();

    s32 numerator = 5;
    s32 denominator = 2;
    s32 result = 0;
    s32 remainder = 0;
    s32* resultPtr = &result;
    s32* remainderPtr = &remainder;
    BIOS_DIVISION(numerator, denominator, resultPtr, remainderPtr);

	// ansi escape sequence to set print co-ordinates
	// /x1b[line;columnH
    iprintf("\x1b[10;10H%d / %d = %d\n", numerator, denominator, result);

	while (1) {
		VBlankIntrWait();
	}
}

Re: Inline asm calls ignored in devkitARM r43

Posted: Sat Jan 10, 2015 1:30 pm
by Chano
Well, it works with -O3 if I put the bios call inside a .s file... it seems like a GCC bug, right?

Code: Select all

@ DECL: s32 biosDivisionAsm(s32 numerator, s32 denominator);
@ DESC:
	.align
	.thumb_func
	.global biosDivisionAsm
biosDivisionAsm:
	swi		0x06
	bx		lr

Re: Inline asm calls ignored in devkitARM r43

Posted: Sat Jan 10, 2015 5:27 pm
by WinterMute
Chano wrote:Well, it works with -O3 if I put the bios call inside a .s file... it seems like a GCC bug, right?
Possibly, I'm not really sure.

I've never entirely got inline assembly to work consistently so I tend to avoid it for anything more complex than getting access to conditions codes or arm registers. There's a good write up at http://www.ethernut.de/en/documents/arm-inline-asm.html which can be immensely helpful sometimes.

I got your code to work at -O1 by telling the compiler that result & remainder are inputs as well as outputs. Once the function gets inlined things start going strange though.

Code: Select all

//---------------------------------------------------------------------------------
// BIOS divison function
//---------------------------------------------------------------------------------
void biosDivision(s32 numerator, s32 denominator, s32* result, s32* remainder) {
//---------------------------------------------------------------------------------
    asm volatile (
        "mov   r0, %[numerator]   \n\t"
        "mov   r1, %[denominator]   \n\t"
#if   defined   ( __thumb__ )
        "swi   6        \n\t" // Put 6 here for Thumb C Compiler mode.
#else
        "swi   6<<16    \n\t" // Put 0x60000 there for ARM C Compiler mode.
#endif
        "mov   r2, %[result]\n\t"
        "str   r0, [r2]\n\t"
        "mov   r2, %[remainder]\n\t"
        "str   r1, [r2] \n\t"

        : [result] "+l" (result), [remainder] "+l" (remainder)

        : [numerator] "l" (numerator), [denominator] "l" (denominator)

        : "r0","r1","r2","r3"
    );
}
I was mainly just playing around to see what happens. "l" is a low register (r0-7), the "+" modifier says this operand is read as well as written

Re: Inline asm calls ignored in devkitARM r43

Posted: Sun Jan 11, 2015 2:28 pm
by Chano
Oh well, I'll try to put all asm code on .s files from now on.

Is there any way to get the result and the remainder of a division with only one bios call without using inline asm?
I am not able to get both values without two bios calls (yes, I'm an ARM asm noob u_u)

Anyways, thanks a lot for your help.

Re: Inline asm calls ignored in devkitARM r43

Posted: Sun Jan 11, 2015 6:10 pm
by Chano
By the way, I have more instances where functions are not called if -O0 is not enabled.

It wouldn't be possible to roll back to a previous version of GCC of devkitARM?
Nothing of this happened with r42...

Re: Inline asm calls ignored in devkitARM r43

Posted: Mon Jan 12, 2015 9:29 pm
by Chano
The issues I has having were related with more ignored inline asm calls.

It's weird, because some of them work fine and some not...

Re: Inline asm calls ignored in devkitARM r43

Posted: Tue Jan 27, 2015 10:20 pm
by WinterMute
I played around with this some more and discovered that using temp variables for the outputs gets the code working at -O2 and above.

Code: Select all

//---------------------------------------------------------------------------------
// BIOS divison function
//---------------------------------------------------------------------------------
void biosDivision(s32 numerator, s32 denominator, s32* result, s32* remainder) {
//---------------------------------------------------------------------------------
	s32 __result, __remainder;

    asm volatile (
        "mov   r0, %[numerator]   \n\t"
        "mov   r1, %[denominator]   \n\t"
#if   defined   ( __thumb__ )
        "swi   6        \n\t" // Put 6 here for Thumb C Compiler mode.
#else
        "swi   6<<16    \n\t" // Put 0x60000 there for ARM C Compiler mode.
#endif
        "mov   %[result], r0\n\t"
        "mov   %[remainder], r1\n\t"

        : [result] "=l" (__result), [remainder] "=l" (__remainder)

        : [numerator] "l" (numerator), [denominator] "l" (denominator)

		: "r0","r1","r2","r3"
    );
	
	*result = __result;
	*remainder = __remainder;
}
I still don't really 100% understand why but I think you'll agree that this version of the code is much clearer & easier to understand.