Clang rejects inline assembly that has tied operands with different types

Hi All,

Does anyone remember why clang rejects inline assembly where an input and output are tied together but are differently sized types? The code that rejects it (Sema::ActOnGCCAsmStmt()) is looking like it’s intentional but it’s not clear why it does so.

My current theory is that it’s to avoid dealing with cases where a register has to be tied to its own subregister or something along those lines.

Here’s a trimmed version of the original failing case from the Linux Kernel:

static inline __sum16 csum_ipv6_magic(const struct in6_addr *saddr,

const struct in6_addr *daddr,

__u32 len, unsigned short proto,

__wsum sum)

{

asm(

/* snip */

" addu %0, %5 # proto (long in network byte order)\n"

" sltu $1, %0, %5 \n"

/* snip */

" lw %1, 0(%2) # four words source address\n"

/* snip */

: “=r” (sum), “=r” (proto)

: “r” (saddr), “r” (daddr),

“0” (htonl(len)), “1” (htonl(proto)), “r” (sum));

return csum_fold(sum);

}

Clang objects to the ‘htonl(proto)’ on the grounds that the type doesn’t match ‘proto’:

arch/mips/include/asm/checksum.h:285:27: error: unsupported inline asm: input with type ‘__be32’ (aka ‘unsigned int’) matching output with type ‘unsigned short’

“0” (htonl(len)), “1” (htonl(proto)), “r” (sum));

^~~~~~~~~~~~

Daniel Sanders

Leading Software Design Engineer, MIPS Processor IP

Imagination Technologies Limited

www.imgtec.com

I think Akira Hatanaka might have made this change recently.

I changed this function recently (yesterday), but I think this error message is unrelated to the change I made. The piece of code that emits this error was committed originally in r70142.
http://lists.cs.uiuc.edu/pipermail/cfe-commits/Week-of-Mon-20090420/016312.html

I’m not sure whether this restriction should be relaxed to allow operands with different size or it’s the source program that has to be fixed. I couldn’t find anything in gcc’s documentation that says whether or not this is legal.

https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#Extended-Asm

I’m not sure whether this restriction should be relaxed to allow operands with different size or it’s the

source program that has to be fixed. I couldn’t find anything in gcc’s documentation that says whether

or not this is legal.

I’m not sure either. I have some candidate patches to the source program and changing the source is my preference because there’s only a single instance of this construct as far as I know. However it also makes sense to be able to do something like:

int result;

short operand;

asm (“seh %0, %1” : “=r”(result) : “0”(operand)) // seh is a sign-extend instruction

as long as an int and a short can be stored in the same register.