llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
29.42k stars 12.15k forks source link

[X86] Missing support for ‘z’ asm operand modifier #116629

Open nathanchance opened 2 weeks ago

nathanchance commented 2 weeks ago

As initially reported on LKML: https://lore.kernel.org/202411180620.8uhr11le-lkp@intel.com/

void foo(unsigned char *var)
{
    asm("shr%z1 %1" : "+m"(*var));
}
$ gcc -c -o /dev/null test.c

$ clang -c -o /dev/null test.c
test.c:3:6: error: invalid operand in inline asm: 'shr${1:z} $1'
    3 |         asm("shr%z1 %1" : "+m"(*var));
      |             ^
test.c:3:6: error: ambiguous instructions require an explicit suffix (could be 'shrb', 'shrw', 'shrl', or 'shrq')
<inline asm>:1:2: note: instantiated into assembly here
    1 |         shr (%rax)
      |         ^
2 errors generated.

https://godbolt.org/z/o6bWzfh9x

From the GCC documentation:

z Print the opcode suffix for the size of the current integer operand (one of b/w/l/q). %z0 l

I see where the X86 specific modifiers are implemented in X86AsmPrinter::PrintAsmOperand() but I am not entirely sure how to implement this there. I am happy to try with any guidance.

llvmbot commented 2 weeks ago

@llvm/issue-subscribers-backend-x86

Author: Nathan Chancellor (nathanchance)

As initially reported on LKML: https://lore.kernel.org/202411180620.8uhr11le-lkp@intel.com/ ```c void foo(unsigned char *var) { asm("shr%z1 %1" : "+m"(*var)); } ``` ``` $ gcc -c -o /dev/null test.c $ clang -c -o /dev/null test.c test.c:3:6: error: invalid operand in inline asm: 'shr${1:z} $1' 3 | asm("shr%z1 %1" : "+m"(*var)); | ^ test.c:3:6: error: ambiguous instructions require an explicit suffix (could be 'shrb', 'shrw', 'shrl', or 'shrq') <inline asm>:1:2: note: instantiated into assembly here 1 | shr (%rax) | ^ 2 errors generated. ``` https://godbolt.org/z/o6bWzfh9x From [the GCC documentation](https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#x86-Operand-Modifiers): `z` | Print the opcode suffix for the size of the current integer operand (one of `b/w/l/q`). | `%z0` | `l` -- | -- | -- | -- I see where the X86 specific modifiers are implemented in `X86AsmPrinter::PrintAsmOperand()` but I am not entirely sure how to implement this there. I am happy to try with any guidance.
topperc commented 2 weeks ago

I'm not sure how to implement this for memory references. Seems like you'd need the frontend to pass along the size of the variable being referenced.