Error: matching constraint not valid in output ope

2019-09-19 12:45发布

问题:

I'm having trouble getting GCC inline assembler to accept some inline assembly for Power9.

The regular assembly I am trying to get GCC to accept is darn 3, 1, where 3 is r3 and 1 is parameter called L in the docs. It disassembles to this on big-endian:

0:   e6 05 61 7c    darn    r3,1

And on little-endian:

0:   7c 61 05 e6    darn    r3,1

Due to various reasons and problems, including old compilers and compilers that pretend to be other compilers, I want to issue byte codes for the instruction. My test program:

gcc112:~$ cat test.c
#include <stdint.h>

void random()
{
  volatile uint64_t x = __builtin_darn();

  __asm__ __volatile__ ("darn 3, 1");

  uint64_t y;
  __asm__ __volatile__ (".byte 0x7c, 0x61, 0x05, 0xe6  \n" : "=r3" (y));
}

Compiling it results in:

$ /opt/cfarm/gcc-latest/bin/gcc -mcpu=power9 -c test.c
test.c: In function 'random':
test.c:10:3: error: matching constraint not valid in output operand
   __asm__ __volatile__ (".byte 0x7c, 0x61, 0x05, 0xe6  \n" : "=r3" (y));
   ^~~~~~~
test.c:10:3: error: matching constraint not valid in output operand
test.c:10:3: error: invalid lvalue in asm output 0

Here's the section of the GCC inline assembly manual that should cover it, but I don't see it expalined: 6.45.2.3 Output Operands. I also checked simple and machine constraints but did not see it.

How do I tell GCC to execute the instruction, and then move r3 into y?


We do the same thing on x86 with rdrand. It works without problems on all version of GCC going back to 2.9:

uint64_t temp;
__asm__ __volatile__
(
    // radrand rax with retry
    "1:\n"
    ".byte 0x48, 0x0f, 0xc7, 0xf0;\n"
    "jnc 1b;\n"
    : "=a" (temp)
    : : "cc"
);

回答1:

Moving my (untested) comment to an answer to attempt to close this out

I'm not familiar with r3 as an output constraint. I'm guessing this is intended to indicate that the output will be in the 'r3' register, but I don't think you can do it this way (although I'm no expert on powerpc's machine constraints). Instead, perhaps you could try:

register uint64_t y asm("r3");

(ie make y a local register variable) and then just use "=r" as the constraint?