'Confusion about different clobber description for arm inline assembly

I'm learning ARM inline assembly, and is confused about a very simple function: assign the value of x to y (both are int type), on arm32 and arm64 why different clobber description required?

Here is the code:

#include <arm_neon.h>
#include <stdio.h>

void asm_test()
{
    int x = 10;
    int y = 0;

#ifdef __aarch64__
    asm volatile(
        "mov %w[in], %w[out]"
        : [out] "=r"(y)
        : [in] "r"(x)
        : "r0" // r0 not working, but r1 or x1 works
    );
#else
    asm volattile(
        "mov %[in], %[out]"
        : [out] "=r"(y)
        : [in] "r"(x)
        : "r0"    // r0 works, but r1 not working
    );
#endif
    printf("y is %d\n", y);
}

int main() {
    arm_test();

    return 0;
}

Tested on my rooted android phone, for arm32, r0 generates correct result but r1 won't. For arm64, r1 or x1 generate correct result, and r0 won't. Why on arm32 and arm64 they are different? What is the concrete rule for this and where can I find it?



Solution 1:[1]

ARM / AArch64 syntax is mov dst, src

Your asm statement only works if the compiler happens to pick the same register for both "=r" output and "r" input (or something like that, given extra copies of x floating around).

Different clobbers simply perturb the compiler's register-allocation choices. Look at the generated asm (gcc -S or on https://godbolt.org/, especially with -fverbose-asm.)

Undefined Behaviour from getting the constraints mismatched with the instructions in the template string can still happen to work; never assume that an asm statement is correct just because it works with one set of compiler options and surrounding code.


BTW, x86 AT&T syntax does use mov src, dst, and many GNU C inline-asm examples / tutorials are written for that. Assembly language is specific to the ISA and the toolchain, but a lot of architectures have an instruction called mov. Seeing a mov does not mean this is an ARM example.

Also, you don't actually need a mov instruction to use inline asm to copy a valid. Just tell the compiler you want the input to be in the same register it picks for the output, whatever that happens to be:

  // not volatile: has no side effects and produces the same output if the input is the same; i.e. the output is a pure function of the input.
  asm ("" 
        : "=r"(output)      // pick any register
        : "0"(input)        // pick the same register as operand 0
        : // no clobbers
    );

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1