diff options
Diffstat (limited to 'gcc/config/i386/sync.md')
-rw-r--r-- | gcc/config/i386/sync.md | 15 |
1 files changed, 13 insertions, 2 deletions
diff --git a/gcc/config/i386/sync.md b/gcc/config/i386/sync.md index 58e047b..9a0ae3f 100644 --- a/gcc/config/i386/sync.md +++ b/gcc/config/i386/sync.md @@ -98,6 +98,15 @@ "" "lock{\;| }cmpxchg<doublemodesuffix>b{\t| }%1") +;; Theoretically we'd like to use constraint "r" (any reg) for operand +;; 3, but that includes ecx. If operand 3 and 4 are the same (like when +;; the input is -1LL) GCC might chose to allocate operand 3 to ecx, like +;; operand 4. This breaks, as the xchg will move the PIC register contents +;; to %ecx then --> boom. Operands 3 and 4 really need to be different +;; registers, which in this case means operand 3 must not be ecx. +;; Instead of playing tricks with fake early clobbers or the like we +;; just enumerate all regs possible here, which (as this is !TARGET_64BIT) +;; are just esi and edi. (define_insn "*sync_double_compare_and_swapdi_pic" [(set (match_operand:DI 0 "register_operand" "=A") (match_operand:DI 1 "memory_operand" "+m")) @@ -105,7 +114,7 @@ (unspec_volatile:DI [(match_dup 1) (match_operand:DI 2 "register_operand" "A") - (match_operand:SI 3 "register_operand" "r") + (match_operand:SI 3 "register_operand" "SD") (match_operand:SI 4 "register_operand" "c")] UNSPECV_CMPXCHG_1)) (clobber (reg:CC FLAGS_REG))] @@ -189,6 +198,8 @@ "" "lock{\;| }cmpxchg<doublemodesuffix>b{\t| }%1") +;; See above for the explanation of using the constraint "SD" for +;; operand 3. (define_insn "*sync_double_compare_and_swap_ccdi_pic" [(set (match_operand:DI 0 "register_operand" "=A") (match_operand:DI 1 "memory_operand" "+m")) @@ -196,7 +207,7 @@ (unspec_volatile:DI [(match_dup 1) (match_operand:DI 2 "register_operand" "A") - (match_operand:SI 3 "register_operand" "r") + (match_operand:SI 3 "register_operand" "SD") (match_operand:SI 4 "register_operand" "c")] UNSPECV_CMPXCHG_1)) (set (reg:CCZ FLAGS_REG) |