diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2015-12-01 15:18:30 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2015-12-01 15:18:30 +0000 |
commit | c4ed28f037019ca260a3072f1055dec3e602b153 (patch) | |
tree | 950a6c79ed05d7f141dda7ca571aeed3b37ac887 | |
parent | 30000b8919882a928a596832f53b03b74c6c3ec5 (diff) |
Fix __sync_val_compare_and_swap_8() on i386 for code compiled with -fPIC.
In some cases GCC would generate a cmpxchg8b instruction with a memory
reference that used %ebx. This is wrong (and will almost certainly result
in SIGSEGV). This fix uses a new memory constraint "W" to prevent the use
of %ebx in this case. This differs from the approach taken by upstream so
there are no GPLv3 issues here.
Fixes the Mesa i965 dri module on i386.
ok jsg@
-rw-r--r-- | gnu/gcc/gcc/config/i386/constraints.md | 4 | ||||
-rw-r--r-- | gnu/gcc/gcc/config/i386/i386.c | 28 | ||||
-rw-r--r-- | gnu/gcc/gcc/config/i386/sync.md | 4 |
3 files changed, 34 insertions, 2 deletions
diff --git a/gnu/gcc/gcc/config/i386/constraints.md b/gnu/gcc/gcc/config/i386/constraints.md index 0ab4995f3b8..149a69878b4 100644 --- a/gnu/gcc/gcc/config/i386/constraints.md +++ b/gnu/gcc/gcc/config/i386/constraints.md @@ -150,3 +150,7 @@ to fit that range (for immediate operands in zero-extending x86-64 instructions)." (match_operand 0 "x86_64_zext_immediate_operand")) + +(define_memory_constraint "W" + "CMPXCHG8B memory reference." + (match_test "cmpxchg8b_mem_constraint (op)")) diff --git a/gnu/gcc/gcc/config/i386/i386.c b/gnu/gcc/gcc/config/i386/i386.c index 6fab6d81312..6f77b9ba5a7 100644 --- a/gnu/gcc/gcc/config/i386/i386.c +++ b/gnu/gcc/gcc/config/i386/i386.c @@ -4719,6 +4719,34 @@ standard_sse_constant_opcode (rtx insn, rtx x) gcc_unreachable (); } +int +cmpxchg8b_mem_constraint (rtx op) +{ + struct ix86_address parts; + + if (TARGET_64BIT || !flag_pic) + return 1; + + if (GET_CODE (op) != MEM) + return 0; + if (!ix86_decompose_address (XEXP (op, 0), &parts)) + return 0; + + if (parts.base && GET_CODE (parts.base) == SUBREG) + parts.base = SUBREG_REG (parts.base); + if (parts.index && GET_CODE (parts.index) == SUBREG) + parts.index = SUBREG_REG (parts.index); + + if (parts.base && REG_P (parts.base) + && REGNO_REG_CLASS (REGNO (parts.base)) == BREG) + return 0; + if (parts.index && REG_P (parts.index) + && REGNO_REG_CLASS (REGNO (parts.index)) == BREG) + return 0; + + return 1; +} + /* Returns 1 if OP contains a symbol reference */ int diff --git a/gnu/gcc/gcc/config/i386/sync.md b/gnu/gcc/gcc/config/i386/sync.md index 8c2fdb230b0..30566450fa4 100644 --- a/gnu/gcc/gcc/config/i386/sync.md +++ b/gnu/gcc/gcc/config/i386/sync.md @@ -109,7 +109,7 @@ ;; 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")) + (match_operand:DI 1 "memory_operand" "+W")) (set (match_dup 1) (unspec_volatile:DI [(match_dup 1) @@ -202,7 +202,7 @@ ;; 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")) + (match_operand:DI 1 "memory_operand" "+W")) (set (match_dup 1) (unspec_volatile:DI [(match_dup 1) |