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