https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80148
Bug ID: 80148 Summary: operand has impossible constraints Product: gcc Version: 7.0.1 Status: UNCONFIRMED Severity: normal Priority: P3 Component: inline-asm Assignee: unassigned at gcc dot gnu.org Reporter: dvyukov at google dot com Target Milestone: --- This pop up in kernel code. We have: #define __cmpxchg_double(pfx, p1, p2, o1, o2, n1, n2) \ ({ \ bool __ret; \ __typeof__(*(p1)) __old1 = (o1), __new1 = (n1); \ __typeof__(*(p2)) __old2 = (o2), __new2 = (n2); \ asm volatile(pfx "cmpxchg%c4b %2; sete %0" \ : "=a" (__ret), "+d" (__old2), \ "+m" (*(p1)), "+m" (*(p2)) \ : "i" (2 * sizeof(long)), "a" (__old1), \ "b" (__new1), "c" (__new2)); \ __ret; \ }) #define arch_cmpxchg_double(p1, p2, o1, o2, n1, n2) \ __cmpxchg_double(LOCK_PREFIX, p1, p2, o1, o2, n1, n2) #define cmpxchg_double(p1, p2, o1, o2, n1, n2) \ ({ \ __typeof__(p1) ____p1 = (p1); \ kasan_check_write(____p1, 2 * sizeof(*____p1)); \ arch_cmpxchg_double(____p1, (p2), (o1), (o2), (n1), (n2)); \ }) And this is invoked as: if (cmpxchg_double(&page->freelist, &page->counters, freelist_old, counters_old, freelist_new, counters_new)) This fails with: error: ‘asm’ operand has impossible constraints However if I change cmpxchg_double as: - arch_cmpxchg_double(____p1, (p2), (o1), (o2), (n1), (n2)); \ + arch_cmpxchg_double((p1), (p2), (o1), (o2), (n1), (n2)); \ It works. I've tested with gcc version 7.0.1 20170307 (experimental) (GCC). Arnd Bergmann reported that the problem happens with 4.9 through 7.0.1 for him. I've also tried with gcc version 4.8.4 (Ubuntu 4.8.4-2ubuntu1~14.04.3) and both versions work. It's unclear to me why introducing a local variable as "__typeof__(p1) ____p1 = (p1)" and then using it fails. Whereas using p1 works. Essentially we have: asm volatile("" "cmpxchg%c4b %2; sete %0" : "=a" (__ret), "+d" (__old2), "+m" (*((&page->freelist))), "+m" (*((&page->counters))) : "i" (2 * sizeof(long)), "a" (__old1), "b" (__new1), "c" (__new2)); vs: __typeof__(&page->freelist) ____p1 = (&page->freelist); ... asm volatile("" "cmpxchg%c4b %2; sete %0" : "=a" (__ret), "+d" (__old2), "+m" (*(____p1)), "+m" (*((&page->counters))) : "i" (2 * sizeof(long)), "a" (__old1), "b" (__new1), "c" (__new2)); It seems to me that both versions should work the same way. I will attach preprocessed sources for both versions. They can be compiled as: gcc slub1.c -fno-strict-aliasing -fno-common -Wno-format-security -std=gnu89 -fno-PIE -mno-sse -mno-mmx -mno-sse2 -mno-3dnow -mno-avx -m32 -msoft-float -mregparm=3 -freg-struct-return -fno-pic -mpreferred-stack-boundary=2 -march=i686 -mtune=pentium3 -Wa,-mtune=generic32 -ffreestanding -DCONFIG_AS_CFI=1 -DCONFIG_AS_CFI_SIGNAL_FRAME=1 -DCONFIG_AS_CFI_SECTIONS=1 -DCONFIG_AS_SSSE3=1 -DCONFIG_AS_CRC32=1 -DCONFIG_AS_AVX=1 -DCONFIG_AS_AVX2=1 -DCONFIG_AS_SHA1_NI=1 -DCONFIG_AS_SHA256_NI=1 -pipe -Wno-sign-compare -fno-asynchronous-unwind-tables -fno-delete-null-pointer-checks -Wno-frame-address -O2 --param=allow-store-data-races=0 -Wframe-larger-than=1024 -fno-stack-protector -Wno-unused-but-set-variable -Wno-unused-const-variable -fno-omit-frame-pointer -fno-optimize-sibling-calls -fno-var-tracking-assignments -fno-inline-functions-called-once -Wdeclaration-after-statement -Wno-pointer-sign -fno-strict-overflow -fconserve-stack -Werror=implicit-int -Werror=strict-prototypes -Werror=date-time -Werror=incompatible-pointer-types -c