i386.c (x86_cmpxchg, x86_xadd): New.
* config/i386/i386.c (x86_cmpxchg, x86_xadd): New. (ix86_compare_emitted): New. (ix86_expand_compare): Use ix86_compare_emitted if set. (ix86_expand_setcc): Only emit REG_EQUAL if both ix86_compare_op0 and ix86_compare_op0 are set. * config/i386/i386.h (x86_cmpxchg, x86_xadd): Declare. (TARGET_CMPXCHG, TARGET_XADD): New. (ix86_compare_emitted): Declare. * config/i386/i386.md: Include sync.md (UNSPECV_CMPXCHG_1, UNSPECV_CMPXCHG_2): New. (UNSPECV_XCHG, UNSPECV_LOCK): New. * config/i386/sync.md: New file. From-SVN: r98155
This commit is contained in:
parent
48ae6c138c
commit
1ef45b7773
@ -1,3 +1,18 @@
|
||||
2004-04-14 Richard Henderson <rth@redhat.com>
|
||||
|
||||
* config/i386/i386.c (x86_cmpxchg, x86_xadd): New.
|
||||
(ix86_compare_emitted): New.
|
||||
(ix86_expand_compare): Use ix86_compare_emitted if set.
|
||||
(ix86_expand_setcc): Only emit REG_EQUAL if both ix86_compare_op0
|
||||
and ix86_compare_op0 are set.
|
||||
* config/i386/i386.h (x86_cmpxchg, x86_xadd): Declare.
|
||||
(TARGET_CMPXCHG, TARGET_XADD): New.
|
||||
(ix86_compare_emitted): Declare.
|
||||
* config/i386/i386.md: Include sync.md
|
||||
(UNSPECV_CMPXCHG_1, UNSPECV_CMPXCHG_2): New.
|
||||
(UNSPECV_XCHG, UNSPECV_LOCK): New.
|
||||
* config/i386/sync.md: New file.
|
||||
|
||||
2004-04-14 Richard Henderson <rth@redhat.com>
|
||||
|
||||
PR middle-end/14311
|
||||
|
@ -584,6 +584,10 @@ const int x86_ext_80387_constants = m_K6 | m_ATHLON | m_PENT4 | m_NOCONA | m_PPR
|
||||
const int x86_four_jump_limit = m_PPRO | m_ATHLON_K8 | m_PENT4 | m_NOCONA;
|
||||
const int x86_schedule = m_PPRO | m_ATHLON_K8 | m_K6 | m_PENT;
|
||||
const int x86_use_bt = m_ATHLON_K8;
|
||||
/* Compare and exchange was added for 80486. */
|
||||
const int x86_cmpxchg = ~m_386;
|
||||
/* Exchange and add was added for 80486. */
|
||||
const int x86_xadd = ~m_386;
|
||||
|
||||
/* In case the average insn count for single function invocation is
|
||||
lower than this constant, emit fast (but longer) prologue and
|
||||
@ -727,6 +731,7 @@ int const svr4_dbx_register_map[FIRST_PSEUDO_REGISTER] =
|
||||
|
||||
rtx ix86_compare_op0 = NULL_RTX;
|
||||
rtx ix86_compare_op1 = NULL_RTX;
|
||||
rtx ix86_compare_emitted = NULL_RTX;
|
||||
|
||||
#define MAX_386_STACK_LOCALS 3
|
||||
/* Size of the register save area. */
|
||||
@ -9049,7 +9054,12 @@ ix86_expand_compare (enum rtx_code code, rtx *second_test, rtx *bypass_test)
|
||||
if (bypass_test)
|
||||
*bypass_test = NULL_RTX;
|
||||
|
||||
if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_FLOAT)
|
||||
if (ix86_compare_emitted)
|
||||
{
|
||||
ret = gen_rtx_fmt_ee (code, VOIDmode, ix86_compare_emitted, const0_rtx);
|
||||
ix86_compare_emitted = NULL_RTX;
|
||||
}
|
||||
else if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_FLOAT)
|
||||
ret = ix86_expand_fp_compare (code, op0, op1, NULL_RTX,
|
||||
second_test, bypass_test);
|
||||
else
|
||||
@ -9378,10 +9388,13 @@ ix86_expand_setcc (enum rtx_code code, rtx dest)
|
||||
}
|
||||
|
||||
/* Attach a REG_EQUAL note describing the comparison result. */
|
||||
equiv = simplify_gen_relational (code, QImode,
|
||||
GET_MODE (ix86_compare_op0),
|
||||
ix86_compare_op0, ix86_compare_op1);
|
||||
set_unique_reg_note (get_last_insn (), REG_EQUAL, equiv);
|
||||
if (ix86_compare_op0 && ix86_compare_op1)
|
||||
{
|
||||
equiv = simplify_gen_relational (code, QImode,
|
||||
GET_MODE (ix86_compare_op0),
|
||||
ix86_compare_op0, ix86_compare_op1);
|
||||
set_unique_reg_note (get_last_insn (), REG_EQUAL, equiv);
|
||||
}
|
||||
|
||||
return 1; /* DONE */
|
||||
}
|
||||
|
@ -253,6 +253,7 @@ extern const int x86_sse_typeless_stores, x86_sse_load0_by_pxor;
|
||||
extern const int x86_use_ffreep;
|
||||
extern const int x86_inter_unit_moves, x86_schedule;
|
||||
extern const int x86_use_bt;
|
||||
extern const int x86_cmpxchg, x86_xadd;
|
||||
extern int x86_prefetch_sse;
|
||||
|
||||
#define TARGET_USE_LEAVE (x86_use_leave & TUNEMASK)
|
||||
@ -333,6 +334,9 @@ extern int x86_prefetch_sse;
|
||||
#define TARGET_GNU_TLS (ix86_tls_dialect == TLS_DIALECT_GNU)
|
||||
#define TARGET_SUN_TLS (ix86_tls_dialect == TLS_DIALECT_SUN)
|
||||
|
||||
#define TARGET_CMPXCHG (x86_cmpxchg & (1 << ix86_arch))
|
||||
#define TARGET_XADD (x86_xadd & (1 << ix86_arch))
|
||||
|
||||
/* WARNING: Do not mark empty strings for translation, as calling
|
||||
gettext on an empty string does NOT return an empty
|
||||
string. */
|
||||
@ -2463,6 +2467,7 @@ extern enum reg_class const regclass_map[FIRST_PSEUDO_REGISTER];
|
||||
|
||||
extern rtx ix86_compare_op0; /* operand 0 for comparisons */
|
||||
extern rtx ix86_compare_op1; /* operand 1 for comparisons */
|
||||
extern rtx ix86_compare_emitted;
|
||||
|
||||
/* To properly truncate FP values into integers, we need to set i387 control
|
||||
word. We can't emit proper mode switching code before reload, as spills
|
||||
|
@ -151,6 +151,10 @@
|
||||
(UNSPECV_ALIGN 7)
|
||||
(UNSPECV_MONITOR 8)
|
||||
(UNSPECV_MWAIT 9)
|
||||
(UNSPECV_CMPXCHG_1 10)
|
||||
(UNSPECV_CMPXCHG_2 11)
|
||||
(UNSPECV_XCHG 12)
|
||||
(UNSPECV_LOCK 13)
|
||||
])
|
||||
|
||||
;; Registers by name.
|
||||
@ -19757,3 +19761,4 @@
|
||||
|
||||
(include "sse.md")
|
||||
(include "mmx.md")
|
||||
(include "sync.md")
|
||||
|
158
gcc/config/i386/sync.md
Normal file
158
gcc/config/i386/sync.md
Normal file
@ -0,0 +1,158 @@
|
||||
;; GCC machine description for i386 synchronization instructions.
|
||||
;; Copyright (C) 2005
|
||||
;; Free Software Foundation, Inc.
|
||||
;;
|
||||
;; This file is part of GCC.
|
||||
;;
|
||||
;; GCC is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation; either version 2, or (at your option)
|
||||
;; any later version.
|
||||
;;
|
||||
;; GCC is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
;;
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GCC; see the file COPYING. If not, write to
|
||||
;; the Free Software Foundation, 59 Temple Place - Suite 330,
|
||||
;; Boston, MA 02111-1307, USA.
|
||||
|
||||
(define_mode_macro IMODE [QI HI SI (DI "TARGET_64BIT")])
|
||||
(define_mode_attr modesuffix [(QI "b") (HI "w") (SI "l") (DI "q")])
|
||||
(define_mode_attr modeconstraint [(QI "q") (HI "r") (SI "r") (DI "r")])
|
||||
(define_mode_attr immconstraint [(QI "i") (HI "i") (SI "i") (DI "e")])
|
||||
|
||||
;; ??? It would be possible to use cmpxchg8b on pentium for DImode
|
||||
;; changes. It's complicated because the insn uses ecx:ebx as the
|
||||
;; new value; note that the registers are reversed from the order
|
||||
;; that they'd be in with (reg:DI 2 ecx). Similarly for TImode
|
||||
;; data in 64-bit mode.
|
||||
|
||||
(define_insn "sync_compare_and_swap<mode>"
|
||||
[(set (match_operand:IMODE 0 "register_operand" "=a")
|
||||
(unspec_volatile:IMODE
|
||||
[(match_operand:IMODE 1 "memory_operand" "+m")
|
||||
(match_operand:IMODE 2 "register_operand" "a")
|
||||
(match_operand:IMODE 3 "register_operand" "<modeconstraint>")]
|
||||
UNSPECV_CMPXCHG_1))
|
||||
(set (match_dup 1)
|
||||
(unspec_volatile:IMODE
|
||||
[(match_dup 1) (match_dup 2) (match_dup 3)] UNSPECV_CMPXCHG_2))
|
||||
(clobber (reg:CC FLAGS_REG))]
|
||||
"TARGET_CMPXCHG"
|
||||
"lock\;cmpxchg{<modesuffix>}\t{%3, %1|%1, %3}")
|
||||
|
||||
(define_expand "sync_compare_and_swap_cc<mode>"
|
||||
[(parallel
|
||||
[(set (match_operand:IMODE 0 "register_operand" "")
|
||||
(unspec_volatile:IMODE
|
||||
[(match_operand:IMODE 1 "memory_operand" "")
|
||||
(match_operand:IMODE 2 "register_operand" "")
|
||||
(match_operand:IMODE 3 "register_operand" "")]
|
||||
UNSPECV_CMPXCHG_1))
|
||||
(set (match_dup 1)
|
||||
(unspec_volatile:IMODE
|
||||
[(match_dup 1) (match_dup 2) (match_dup 3)] UNSPECV_CMPXCHG_2))
|
||||
(set (match_dup 4)
|
||||
(compare:CCZ
|
||||
(unspec_volatile:IMODE
|
||||
[(match_dup 1) (match_dup 2) (match_dup 3)] UNSPECV_CMPXCHG_1)
|
||||
(match_dup 3)))])]
|
||||
"TARGET_CMPXCHG"
|
||||
{
|
||||
operands[4] = gen_rtx_REG (CCZmode, FLAGS_REG);
|
||||
ix86_compare_op0 = operands[3];
|
||||
ix86_compare_op1 = NULL;
|
||||
ix86_compare_emitted = operands[4];
|
||||
})
|
||||
|
||||
(define_insn "*sync_compare_and_swap_cc<mode>"
|
||||
[(set (match_operand:IMODE 0 "register_operand" "=a")
|
||||
(unspec_volatile:IMODE
|
||||
[(match_operand:IMODE 1 "memory_operand" "+m")
|
||||
(match_operand:IMODE 2 "register_operand" "a")
|
||||
(match_operand:IMODE 3 "register_operand" "<modeconstraint>")]
|
||||
UNSPECV_CMPXCHG_1))
|
||||
(set (match_dup 1)
|
||||
(unspec_volatile:IMODE
|
||||
[(match_dup 1) (match_dup 2) (match_dup 3)] UNSPECV_CMPXCHG_2))
|
||||
(set (reg:CCZ FLAGS_REG)
|
||||
(compare:CCZ
|
||||
(unspec_volatile:IMODE
|
||||
[(match_dup 1) (match_dup 2) (match_dup 3)] UNSPECV_CMPXCHG_1)
|
||||
(match_dup 3)))]
|
||||
"TARGET_CMPXCHG"
|
||||
"lock\;cmpxchg{<modesuffix>}\t{%3, %1|%1, %3}")
|
||||
|
||||
(define_insn "sync_old_add<mode>"
|
||||
[(set (match_operand:IMODE 0 "register_operand" "=<modeconstraint>")
|
||||
(unspec_volatile:IMODE
|
||||
[(match_operand:IMODE 1 "memory_operand" "+m")] UNSPECV_XCHG))
|
||||
(set (match_dup 1)
|
||||
(plus:IMODE (match_dup 1)
|
||||
(match_operand:IMODE 2 "register_operand" "0")))
|
||||
(clobber (reg:CC FLAGS_REG))]
|
||||
"TARGET_XADD"
|
||||
"lock\;xadd{<modesuffix>}\t{%0, %1|%1, %0}")
|
||||
|
||||
;; Recall that xchg implicitly sets LOCK#, so adding it again wastes space.
|
||||
(define_insn "sync_lock_test_and_set<mode>"
|
||||
[(set (match_operand:IMODE 0 "register_operand" "=<modeconstraint>")
|
||||
(unspec_volatile:IMODE
|
||||
[(match_operand:IMODE 1 "memory_operand" "+m")] UNSPECV_XCHG))
|
||||
(set (match_dup 1)
|
||||
(match_operand:IMODE 2 "register_operand" "0"))]
|
||||
""
|
||||
"xchg{<modesuffix>}\t{%1, %0|%0, %1}")
|
||||
|
||||
(define_insn "sync_add<mode>"
|
||||
[(set (match_operand:IMODE 0 "memory_operand" "=m")
|
||||
(unspec_volatile:IMODE
|
||||
[(plus:IMODE (match_dup 0)
|
||||
(match_operand:IMODE 1 "nonmemory_operand" "r<immconstraint>"))]
|
||||
UNSPECV_LOCK))
|
||||
(clobber (reg:CC FLAGS_REG))]
|
||||
""
|
||||
"lock\;add{<modesuffix>}\t{%1, %0|%0, %1}")
|
||||
|
||||
(define_insn "sync_sub<mode>"
|
||||
[(set (match_operand:IMODE 0 "memory_operand" "=m")
|
||||
(unspec_volatile:IMODE
|
||||
[(minus:IMODE (match_dup 0)
|
||||
(match_operand:IMODE 1 "nonmemory_operand" "r<immconstraint>"))]
|
||||
UNSPECV_LOCK))
|
||||
(clobber (reg:CC FLAGS_REG))]
|
||||
""
|
||||
"lock\;sub{<modesuffix>}\t{%1, %0|%0, %1}")
|
||||
|
||||
(define_insn "sync_ior<mode>"
|
||||
[(set (match_operand:IMODE 0 "memory_operand" "=m")
|
||||
(unspec_volatile:IMODE
|
||||
[(ior:IMODE (match_dup 0)
|
||||
(match_operand:IMODE 1 "nonmemory_operand" "r<immconstraint>"))]
|
||||
UNSPECV_LOCK))
|
||||
(clobber (reg:CC FLAGS_REG))]
|
||||
""
|
||||
"lock\;or{<modesuffix>}\t{%1, %0|%0, %1}")
|
||||
|
||||
(define_insn "sync_and<mode>"
|
||||
[(set (match_operand:IMODE 0 "memory_operand" "=m")
|
||||
(unspec_volatile:IMODE
|
||||
[(and:IMODE (match_dup 0)
|
||||
(match_operand:IMODE 1 "nonmemory_operand" "r<immconstraint>"))]
|
||||
UNSPECV_LOCK))
|
||||
(clobber (reg:CC FLAGS_REG))]
|
||||
""
|
||||
"lock\;and{<modesuffix>}\t{%1, %0|%0, %1}")
|
||||
|
||||
(define_insn "sync_xor<mode>"
|
||||
[(set (match_operand:IMODE 0 "memory_operand" "=m")
|
||||
(unspec_volatile:IMODE
|
||||
[(xor:IMODE (match_dup 0)
|
||||
(match_operand:IMODE 1 "nonmemory_operand" "r<immconstraint>"))]
|
||||
UNSPECV_LOCK))
|
||||
(clobber (reg:CC FLAGS_REG))]
|
||||
""
|
||||
"lock\;xor{<modesuffix>}\t{%1, %0|%0, %1}")
|
Loading…
Reference in New Issue
Block a user