diff options
author | Richard Henderson <rth@redhat.com> | 2005-04-14 16:42:50 -0700 |
---|---|---|
committer | Richard Henderson <rth@gcc.gnu.org> | 2005-04-14 16:42:50 -0700 |
commit | 1ef45b7773cfcce6e6e952b8a15713bd321adc9e (patch) | |
tree | 4e525ea00c5d64969cf58aac3b3103b4bb6779d2 /gcc | |
parent | 48ae6c138ca30c4c5e876a0be47c9a0b5c8bf5c2 (diff) | |
download | gcc-1ef45b7773cfcce6e6e952b8a15713bd321adc9e.zip gcc-1ef45b7773cfcce6e6e952b8a15713bd321adc9e.tar.gz gcc-1ef45b7773cfcce6e6e952b8a15713bd321adc9e.tar.bz2 |
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
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 15 | ||||
-rw-r--r-- | gcc/config/i386/i386.c | 23 | ||||
-rw-r--r-- | gcc/config/i386/i386.h | 5 | ||||
-rw-r--r-- | gcc/config/i386/i386.md | 5 | ||||
-rw-r--r-- | gcc/config/i386/sync.md | 158 |
5 files changed, 201 insertions, 5 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 88c3a03..2e0aa6c 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,20 @@ 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 * 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, diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index 2c68075..b543a7a 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -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 */ } diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h index 20bd099..5854944 100644 --- a/gcc/config/i386/i386.h +++ b/gcc/config/i386/i386.h @@ -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 diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index e65d9c7..f60d3d2 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -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") diff --git a/gcc/config/i386/sync.md b/gcc/config/i386/sync.md new file mode 100644 index 0000000..477b398 --- /dev/null +++ b/gcc/config/i386/sync.md @@ -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}") |