Commit 1ef45b77 by Richard Henderson Committed by Richard Henderson

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
parent 48ae6c13
2004-04-14 Richard Henderson <rth@redhat.com> 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 PR middle-end/14311
* builtin-types.def (BT_BOOL, BT_VOLATILE_PTR, BT_I1, BT_I2, * builtin-types.def (BT_BOOL, BT_VOLATILE_PTR, BT_I1, BT_I2,
BT_I4, BT_I8, BT_FN_VOID_VPTR, BT_FN_I1_VPTR_I1, BT_FN_I2_VPTR_I2, BT_I4, BT_I8, BT_FN_VOID_VPTR, BT_FN_I1_VPTR_I1, BT_FN_I2_VPTR_I2,
......
...@@ -584,6 +584,10 @@ const int x86_ext_80387_constants = m_K6 | m_ATHLON | m_PENT4 | m_NOCONA | m_PPR ...@@ -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_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_schedule = m_PPRO | m_ATHLON_K8 | m_K6 | m_PENT;
const int x86_use_bt = m_ATHLON_K8; 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 /* In case the average insn count for single function invocation is
lower than this constant, emit fast (but longer) prologue and lower than this constant, emit fast (but longer) prologue and
...@@ -727,6 +731,7 @@ int const svr4_dbx_register_map[FIRST_PSEUDO_REGISTER] = ...@@ -727,6 +731,7 @@ int const svr4_dbx_register_map[FIRST_PSEUDO_REGISTER] =
rtx ix86_compare_op0 = NULL_RTX; rtx ix86_compare_op0 = NULL_RTX;
rtx ix86_compare_op1 = NULL_RTX; rtx ix86_compare_op1 = NULL_RTX;
rtx ix86_compare_emitted = NULL_RTX;
#define MAX_386_STACK_LOCALS 3 #define MAX_386_STACK_LOCALS 3
/* Size of the register save area. */ /* Size of the register save area. */
...@@ -9049,7 +9054,12 @@ ix86_expand_compare (enum rtx_code code, rtx *second_test, rtx *bypass_test) ...@@ -9049,7 +9054,12 @@ ix86_expand_compare (enum rtx_code code, rtx *second_test, rtx *bypass_test)
if (bypass_test) if (bypass_test)
*bypass_test = NULL_RTX; *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, ret = ix86_expand_fp_compare (code, op0, op1, NULL_RTX,
second_test, bypass_test); second_test, bypass_test);
else else
...@@ -9378,10 +9388,13 @@ ix86_expand_setcc (enum rtx_code code, rtx dest) ...@@ -9378,10 +9388,13 @@ ix86_expand_setcc (enum rtx_code code, rtx dest)
} }
/* Attach a REG_EQUAL note describing the comparison result. */ /* Attach a REG_EQUAL note describing the comparison result. */
equiv = simplify_gen_relational (code, QImode, if (ix86_compare_op0 && ix86_compare_op1)
GET_MODE (ix86_compare_op0), {
ix86_compare_op0, ix86_compare_op1); equiv = simplify_gen_relational (code, QImode,
set_unique_reg_note (get_last_insn (), REG_EQUAL, equiv); GET_MODE (ix86_compare_op0),
ix86_compare_op0, ix86_compare_op1);
set_unique_reg_note (get_last_insn (), REG_EQUAL, equiv);
}
return 1; /* DONE */ return 1; /* DONE */
} }
......
...@@ -253,6 +253,7 @@ extern const int x86_sse_typeless_stores, x86_sse_load0_by_pxor; ...@@ -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_use_ffreep;
extern const int x86_inter_unit_moves, x86_schedule; extern const int x86_inter_unit_moves, x86_schedule;
extern const int x86_use_bt; extern const int x86_use_bt;
extern const int x86_cmpxchg, x86_xadd;
extern int x86_prefetch_sse; extern int x86_prefetch_sse;
#define TARGET_USE_LEAVE (x86_use_leave & TUNEMASK) #define TARGET_USE_LEAVE (x86_use_leave & TUNEMASK)
...@@ -333,6 +334,9 @@ extern int x86_prefetch_sse; ...@@ -333,6 +334,9 @@ extern int x86_prefetch_sse;
#define TARGET_GNU_TLS (ix86_tls_dialect == TLS_DIALECT_GNU) #define TARGET_GNU_TLS (ix86_tls_dialect == TLS_DIALECT_GNU)
#define TARGET_SUN_TLS (ix86_tls_dialect == TLS_DIALECT_SUN) #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 /* WARNING: Do not mark empty strings for translation, as calling
gettext on an empty string does NOT return an empty gettext on an empty string does NOT return an empty
string. */ string. */
...@@ -2463,6 +2467,7 @@ extern enum reg_class const regclass_map[FIRST_PSEUDO_REGISTER]; ...@@ -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_op0; /* operand 0 for comparisons */
extern rtx ix86_compare_op1; /* operand 1 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 /* 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 word. We can't emit proper mode switching code before reload, as spills
......
...@@ -151,6 +151,10 @@ ...@@ -151,6 +151,10 @@
(UNSPECV_ALIGN 7) (UNSPECV_ALIGN 7)
(UNSPECV_MONITOR 8) (UNSPECV_MONITOR 8)
(UNSPECV_MWAIT 9) (UNSPECV_MWAIT 9)
(UNSPECV_CMPXCHG_1 10)
(UNSPECV_CMPXCHG_2 11)
(UNSPECV_XCHG 12)
(UNSPECV_LOCK 13)
]) ])
;; Registers by name. ;; Registers by name.
...@@ -19757,3 +19761,4 @@ ...@@ -19757,3 +19761,4 @@
(include "sse.md") (include "sse.md")
(include "mmx.md") (include "mmx.md")
(include "sync.md")
;; 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}")
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment