aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.8/gcc/config/rs6000/sync.md
diff options
context:
space:
mode:
Diffstat (limited to 'gcc-4.8/gcc/config/rs6000/sync.md')
-rw-r--r--gcc-4.8/gcc/config/rs6000/sync.md365
1 files changed, 312 insertions, 53 deletions
diff --git a/gcc-4.8/gcc/config/rs6000/sync.md b/gcc-4.8/gcc/config/rs6000/sync.md
index 252e2690a..74b59ec2c 100644
--- a/gcc-4.8/gcc/config/rs6000/sync.md
+++ b/gcc-4.8/gcc/config/rs6000/sync.md
@@ -1,5 +1,5 @@
;; Machine description for PowerPC synchronization instructions.
-;; Copyright (C) 2005-2013 Free Software Foundation, Inc.
+;; Copyright (C) 2005-2014 Free Software Foundation, Inc.
;; Contributed by Geoffrey Keating.
;; This file is part of GCC.
@@ -18,14 +18,23 @@
;; along with GCC; see the file COPYING3. If not see
;; <http://www.gnu.org/licenses/>.
-(define_mode_attr larx [(SI "lwarx") (DI "ldarx")])
-(define_mode_attr stcx [(SI "stwcx.") (DI "stdcx.")])
+(define_mode_attr larx [(QI "lbarx")
+ (HI "lharx")
+ (SI "lwarx")
+ (DI "ldarx")
+ (TI "lqarx")])
+
+(define_mode_attr stcx [(QI "stbcx.")
+ (HI "sthcx.")
+ (SI "stwcx.")
+ (DI "stdcx.")
+ (TI "stqcx.")])
(define_code_iterator FETCHOP [plus minus ior xor and])
(define_code_attr fetchop_name
[(plus "add") (minus "sub") (ior "or") (xor "xor") (and "and")])
(define_code_attr fetchop_pred
- [(plus "add_operand") (minus "gpc_reg_operand")
+ [(plus "add_operand") (minus "int_reg_operand")
(ior "logical_operand") (xor "logical_operand") (and "and_operand")])
(define_expand "mem_thread_fence"
@@ -98,10 +107,17 @@
"isync"
[(set_attr "type" "isync")])
+;; Types that we should provide atomic instructions for.
+(define_mode_iterator AINT [QI
+ HI
+ SI
+ (DI "TARGET_POWERPC64")
+ (TI "TARGET_SYNC_TI")])
+
;; The control dependency used for load dependency described
;; in B.2.3 of the Power ISA 2.06B.
(define_insn "loadsync_<mode>"
- [(unspec_volatile:BLK [(match_operand:INT1 0 "register_operand" "r")]
+ [(unspec_volatile:BLK [(match_operand:AINT 0 "register_operand" "r")]
UNSPECV_ISYNC)
(clobber (match_scratch:CC 1 "=y"))]
""
@@ -109,18 +125,73 @@
[(set_attr "type" "isync")
(set_attr "length" "12")])
+(define_insn "load_quadpti"
+ [(set (match_operand:PTI 0 "quad_int_reg_operand" "=&r")
+ (unspec:PTI
+ [(match_operand:TI 1 "quad_memory_operand" "wQ")] UNSPEC_LSQ))]
+ "TARGET_SYNC_TI
+ && !reg_mentioned_p (operands[0], operands[1])"
+ "lq %0,%1"
+ [(set_attr "type" "load")
+ (set_attr "length" "4")])
+
(define_expand "atomic_load<mode>"
- [(set (match_operand:INT1 0 "register_operand" "") ;; output
- (match_operand:INT1 1 "memory_operand" "")) ;; memory
+ [(set (match_operand:AINT 0 "register_operand" "") ;; output
+ (match_operand:AINT 1 "memory_operand" "")) ;; memory
(use (match_operand:SI 2 "const_int_operand" ""))] ;; model
""
{
+ if (<MODE>mode == TImode && !TARGET_SYNC_TI)
+ FAIL;
+
enum memmodel model = (enum memmodel) INTVAL (operands[2]);
if (model == MEMMODEL_SEQ_CST)
emit_insn (gen_hwsync ());
+ if (<MODE>mode != TImode)
emit_move_insn (operands[0], operands[1]);
+ else
+ {
+ rtx op0 = operands[0];
+ rtx op1 = operands[1];
+ rtx pti_reg = gen_reg_rtx (PTImode);
+
+ // Can't have indexed address for 'lq'
+ if (indexed_address (XEXP (op1, 0), TImode))
+ {
+ rtx old_addr = XEXP (op1, 0);
+ rtx new_addr = force_reg (Pmode, old_addr);
+ operands[1] = op1 = replace_equiv_address (op1, new_addr);
+ }
+
+ emit_insn (gen_load_quadpti (pti_reg, op1));
+
+ /* For 4.8 we need to do explicit dword copies, even in big endian mode,
+ unless we are using the LRA register allocator. The 4.9 register
+ allocator is smart enough to assign an even/odd pair. */
+ if (WORDS_BIG_ENDIAN && rs6000_lra_flag)
+ emit_move_insn (op0, gen_lowpart (TImode, pti_reg));
+ else
+ {
+ rtx op0_lo = gen_lowpart (DImode, op0);
+ rtx op0_hi = gen_highpart (DImode, op0);
+ rtx pti_lo = gen_lowpart (DImode, pti_reg);
+ rtx pti_hi = gen_highpart (DImode, pti_reg);
+
+ emit_insn (gen_rtx_CLOBBER (VOIDmode, op0));
+ if (WORDS_BIG_ENDIAN)
+ {
+ emit_move_insn (op0_hi, pti_hi);
+ emit_move_insn (op0_lo, pti_lo);
+ }
+ else
+ {
+ emit_move_insn (op0_hi, pti_lo);
+ emit_move_insn (op0_lo, pti_hi);
+ }
+ }
+ }
switch (model)
{
@@ -129,16 +200,7 @@
case MEMMODEL_CONSUME:
case MEMMODEL_ACQUIRE:
case MEMMODEL_SEQ_CST:
- if (GET_MODE (operands[0]) == QImode)
- emit_insn (gen_loadsync_qi (operands[0]));
- else if (GET_MODE (operands[0]) == HImode)
- emit_insn (gen_loadsync_hi (operands[0]));
- else if (GET_MODE (operands[0]) == SImode)
- emit_insn (gen_loadsync_si (operands[0]));
- else if (GET_MODE (operands[0]) == DImode)
- emit_insn (gen_loadsync_di (operands[0]));
- else
- gcc_unreachable ();
+ emit_insn (gen_loadsync_<mode> (operands[0]));
break;
default:
gcc_unreachable ();
@@ -146,12 +208,24 @@
DONE;
})
+(define_insn "store_quadpti"
+ [(set (match_operand:PTI 0 "quad_memory_operand" "=wQ")
+ (unspec:PTI
+ [(match_operand:PTI 1 "quad_int_reg_operand" "r")] UNSPEC_LSQ))]
+ "TARGET_SYNC_TI"
+ "stq %1,%0"
+ [(set_attr "type" "store")
+ (set_attr "length" "4")])
+
(define_expand "atomic_store<mode>"
- [(set (match_operand:INT1 0 "memory_operand" "") ;; memory
- (match_operand:INT1 1 "register_operand" "")) ;; input
+ [(set (match_operand:AINT 0 "memory_operand" "") ;; memory
+ (match_operand:AINT 1 "register_operand" "")) ;; input
(use (match_operand:SI 2 "const_int_operand" ""))] ;; model
""
{
+ if (<MODE>mode == TImode && !TARGET_SYNC_TI)
+ FAIL;
+
enum memmodel model = (enum memmodel) INTVAL (operands[2]);
switch (model)
{
@@ -166,39 +240,224 @@
default:
gcc_unreachable ();
}
+ if (<MODE>mode != TImode)
emit_move_insn (operands[0], operands[1]);
+ else
+ {
+ rtx op0 = operands[0];
+ rtx op1 = operands[1];
+ rtx pti_reg = gen_reg_rtx (PTImode);
+
+ // Can't have indexed address for 'stq'
+ if (indexed_address (XEXP (op0, 0), TImode))
+ {
+ rtx old_addr = XEXP (op0, 0);
+ rtx new_addr = force_reg (Pmode, old_addr);
+ operands[0] = op0 = replace_equiv_address (op0, new_addr);
+ }
+
+ /* For 4.8 we need to do explicit dword copies, even in big endian mode,
+ unless we are using the LRA register allocator. The 4.9 register
+ allocator is smart enough to assign an even/odd pair. */
+ if (WORDS_BIG_ENDIAN && rs6000_lra_flag)
+ emit_move_insn (pti_reg, gen_lowpart (PTImode, op1));
+ else
+ {
+ rtx op1_lo = gen_lowpart (DImode, op1);
+ rtx op1_hi = gen_highpart (DImode, op1);
+ rtx pti_lo = gen_lowpart (DImode, pti_reg);
+ rtx pti_hi = gen_highpart (DImode, pti_reg);
+
+ emit_insn (gen_rtx_CLOBBER (VOIDmode, pti_reg));
+ if (WORDS_BIG_ENDIAN)
+ {
+ emit_move_insn (pti_hi, op1_hi);
+ emit_move_insn (pti_lo, op1_lo);
+ }
+ else
+ {
+ emit_move_insn (pti_hi, op1_lo);
+ emit_move_insn (pti_lo, op1_hi);
+ }
+ }
+
+ emit_insn (gen_store_quadpti (gen_lowpart (PTImode, op0), pti_reg));
+ }
+
DONE;
})
-;; ??? Power ISA 2.06B says that there *is* a load-{byte,half}-and-reserve
-;; opcode that is "phased-in". Not implemented as of Power7, so not yet used,
-;; but let's prepare the macros anyway.
-
-(define_mode_iterator ATOMIC [SI (DI "TARGET_POWERPC64")])
+;; Any supported integer mode that has atomic l<x>arx/st<x>cx. instrucitons
+;; other than the quad memory operations, which have special restrictions.
+;; Byte/halfword atomic instructions were added in ISA 2.06B, but were phased
+;; in and did not show up until power8. TImode atomic lqarx/stqcx. require
+;; special handling due to even/odd register requirements.
+(define_mode_iterator ATOMIC [(QI "TARGET_SYNC_HI_QI")
+ (HI "TARGET_SYNC_HI_QI")
+ SI
+ (DI "TARGET_POWERPC64")])
(define_insn "load_locked<mode>"
- [(set (match_operand:ATOMIC 0 "gpc_reg_operand" "=r")
+ [(set (match_operand:ATOMIC 0 "int_reg_operand" "=r")
(unspec_volatile:ATOMIC
[(match_operand:ATOMIC 1 "memory_operand" "Z")] UNSPECV_LL))]
""
"<larx> %0,%y1"
[(set_attr "type" "load_l")])
+(define_insn "load_locked<QHI:mode>_si"
+ [(set (match_operand:SI 0 "int_reg_operand" "=r")
+ (unspec_volatile:SI
+ [(match_operand:QHI 1 "memory_operand" "Z")] UNSPECV_LL))]
+ "TARGET_SYNC_HI_QI"
+ "<QHI:larx> %0,%y1"
+ [(set_attr "type" "load_l")])
+
+;; Use PTImode to get even/odd register pairs.
+
+;; Use a temporary register to force getting an even register for the
+;; lqarx/stqcrx. instructions. Under AT 7.0, we need use an explicit copy,
+;; even in big endian mode, unless we are using the LRA register allocator. In
+;; GCC 4.9, the register allocator is smart enough to assign a even/odd
+;; register pair.
+
+;; On little endian systems where non-atomic quad word load/store instructions
+;; are not used, the address can be register+offset, so make sure the address
+;; is indexed or indirect before register allocation.
+
+(define_expand "load_lockedti"
+ [(use (match_operand:TI 0 "quad_int_reg_operand" ""))
+ (use (match_operand:TI 1 "memory_operand" ""))]
+ "TARGET_SYNC_TI"
+{
+ rtx op0 = operands[0];
+ rtx op1 = operands[1];
+ rtx pti = gen_reg_rtx (PTImode);
+
+ if (!indexed_or_indirect_operand (op1, TImode))
+ {
+ rtx old_addr = XEXP (op1, 0);
+ rtx new_addr = force_reg (Pmode, old_addr);
+ operands[1] = op1 = change_address (op1, TImode, new_addr);
+ }
+
+ emit_insn (gen_load_lockedpti (pti, op1));
+ if (WORDS_BIG_ENDIAN && rs6000_lra_flag)
+ emit_move_insn (op0, gen_lowpart (TImode, pti));
+ else
+ {
+ rtx op0_lo = gen_lowpart (DImode, op0);
+ rtx op0_hi = gen_highpart (DImode, op0);
+ rtx pti_lo = gen_lowpart (DImode, pti);
+ rtx pti_hi = gen_highpart (DImode, pti);
+
+ emit_insn (gen_rtx_CLOBBER (VOIDmode, op0));
+ if (WORDS_BIG_ENDIAN)
+ {
+ emit_move_insn (op0_hi, pti_hi);
+ emit_move_insn (op0_lo, pti_lo);
+ }
+ else
+ {
+ emit_move_insn (op0_hi, pti_lo);
+ emit_move_insn (op0_lo, pti_hi);
+ }
+ }
+ DONE;
+})
+
+(define_insn "load_lockedpti"
+ [(set (match_operand:PTI 0 "quad_int_reg_operand" "=&r")
+ (unspec_volatile:PTI
+ [(match_operand:TI 1 "indexed_or_indirect_operand" "Z")] UNSPECV_LL))]
+ "TARGET_SYNC_TI
+ && !reg_mentioned_p (operands[0], operands[1])
+ && quad_int_reg_operand (operands[0], PTImode)"
+ "lqarx %0,%y1"
+ [(set_attr "type" "load_l")])
+
(define_insn "store_conditional<mode>"
[(set (match_operand:CC 0 "cc_reg_operand" "=x")
(unspec_volatile:CC [(const_int 0)] UNSPECV_SC))
(set (match_operand:ATOMIC 1 "memory_operand" "=Z")
- (match_operand:ATOMIC 2 "gpc_reg_operand" "r"))]
+ (match_operand:ATOMIC 2 "int_reg_operand" "r"))]
""
"<stcx> %2,%y1"
[(set_attr "type" "store_c")])
+;; Use a temporary register to force getting an even register for the
+;; lqarx/stqcrx. instructions. Under AT 7.0, we need use an explicit copy,
+;; even in big endian mode. In GCC 4.9, the register allocator is smart enough
+;; to assign a even/odd register pair.
+
+;; On little endian systems where non-atomic quad word load/store instructions
+;; are not used, the address can be register+offset, so make sure the address
+;; is indexed or indirect before register allocation.
+
+(define_expand "store_conditionalti"
+ [(use (match_operand:CC 0 "cc_reg_operand" ""))
+ (use (match_operand:TI 1 "memory_operand" ""))
+ (use (match_operand:TI 2 "quad_int_reg_operand" ""))]
+ "TARGET_SYNC_TI"
+{
+ rtx op0 = operands[0];
+ rtx op1 = operands[1];
+ rtx op2 = operands[2];
+ rtx addr = XEXP (op1, 0);
+ rtx pti_mem;
+ rtx pti_reg;
+
+ if (!indexed_or_indirect_operand (op1, TImode))
+ {
+ rtx new_addr = force_reg (Pmode, addr);
+ operands[1] = op1 = change_address (op1, TImode, new_addr);
+ addr = new_addr;
+ }
+
+ pti_mem = change_address (op1, PTImode, addr);
+ pti_reg = gen_reg_rtx (PTImode);
+
+ if (WORDS_BIG_ENDIAN && rs6000_lra_flag)
+ emit_move_insn (pti_reg, gen_lowpart (PTImode, op2));
+ else
+ {
+ rtx op2_lo = gen_lowpart (DImode, op2);
+ rtx op2_hi = gen_highpart (DImode, op2);
+ rtx pti_lo = gen_lowpart (DImode, pti_reg);
+ rtx pti_hi = gen_highpart (DImode, pti_reg);
+
+ emit_insn (gen_rtx_CLOBBER (VOIDmode, op0));
+ if (WORDS_BIG_ENDIAN)
+ {
+ emit_move_insn (pti_hi, op2_hi);
+ emit_move_insn (pti_lo, op2_lo);
+ }
+ else
+ {
+ emit_move_insn (pti_hi, op2_lo);
+ emit_move_insn (pti_lo, op2_hi);
+ }
+ }
+
+ emit_insn (gen_store_conditionalpti (op0, pti_mem, pti_reg));
+ DONE;
+})
+
+(define_insn "store_conditionalpti"
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x")
+ (unspec_volatile:CC [(const_int 0)] UNSPECV_SC))
+ (set (match_operand:PTI 1 "indexed_or_indirect_operand" "=Z")
+ (match_operand:PTI 2 "quad_int_reg_operand" "r"))]
+ "TARGET_SYNC_TI && quad_int_reg_operand (operands[2], PTImode)"
+ "stqcx. %2,%y1"
+ [(set_attr "type" "store_c")])
+
(define_expand "atomic_compare_and_swap<mode>"
- [(match_operand:SI 0 "gpc_reg_operand" "") ;; bool out
- (match_operand:INT1 1 "gpc_reg_operand" "") ;; val out
- (match_operand:INT1 2 "memory_operand" "") ;; memory
- (match_operand:INT1 3 "reg_or_short_operand" "") ;; expected
- (match_operand:INT1 4 "gpc_reg_operand" "") ;; desired
+ [(match_operand:SI 0 "int_reg_operand" "") ;; bool out
+ (match_operand:AINT 1 "int_reg_operand" "") ;; val out
+ (match_operand:AINT 2 "memory_operand" "") ;; memory
+ (match_operand:AINT 3 "reg_or_short_operand" "") ;; expected
+ (match_operand:AINT 4 "int_reg_operand" "") ;; desired
(match_operand:SI 5 "const_int_operand" "") ;; is_weak
(match_operand:SI 6 "const_int_operand" "") ;; model succ
(match_operand:SI 7 "const_int_operand" "")] ;; model fail
@@ -209,9 +468,9 @@
})
(define_expand "atomic_exchange<mode>"
- [(match_operand:INT1 0 "gpc_reg_operand" "") ;; output
- (match_operand:INT1 1 "memory_operand" "") ;; memory
- (match_operand:INT1 2 "gpc_reg_operand" "") ;; input
+ [(match_operand:AINT 0 "int_reg_operand" "") ;; output
+ (match_operand:AINT 1 "memory_operand" "") ;; memory
+ (match_operand:AINT 2 "int_reg_operand" "") ;; input
(match_operand:SI 3 "const_int_operand" "")] ;; model
""
{
@@ -220,9 +479,9 @@
})
(define_expand "atomic_<fetchop_name><mode>"
- [(match_operand:INT1 0 "memory_operand" "") ;; memory
- (FETCHOP:INT1 (match_dup 0)
- (match_operand:INT1 1 "<fetchop_pred>" "")) ;; operand
+ [(match_operand:AINT 0 "memory_operand" "") ;; memory
+ (FETCHOP:AINT (match_dup 0)
+ (match_operand:AINT 1 "<fetchop_pred>" "")) ;; operand
(match_operand:SI 2 "const_int_operand" "")] ;; model
""
{
@@ -232,8 +491,8 @@
})
(define_expand "atomic_nand<mode>"
- [(match_operand:INT1 0 "memory_operand" "") ;; memory
- (match_operand:INT1 1 "gpc_reg_operand" "") ;; operand
+ [(match_operand:AINT 0 "memory_operand" "") ;; memory
+ (match_operand:AINT 1 "int_reg_operand" "") ;; operand
(match_operand:SI 2 "const_int_operand" "")] ;; model
""
{
@@ -243,10 +502,10 @@
})
(define_expand "atomic_fetch_<fetchop_name><mode>"
- [(match_operand:INT1 0 "gpc_reg_operand" "") ;; output
- (match_operand:INT1 1 "memory_operand" "") ;; memory
- (FETCHOP:INT1 (match_dup 1)
- (match_operand:INT1 2 "<fetchop_pred>" "")) ;; operand
+ [(match_operand:AINT 0 "int_reg_operand" "") ;; output
+ (match_operand:AINT 1 "memory_operand" "") ;; memory
+ (FETCHOP:AINT (match_dup 1)
+ (match_operand:AINT 2 "<fetchop_pred>" "")) ;; operand
(match_operand:SI 3 "const_int_operand" "")] ;; model
""
{
@@ -256,9 +515,9 @@
})
(define_expand "atomic_fetch_nand<mode>"
- [(match_operand:INT1 0 "gpc_reg_operand" "") ;; output
- (match_operand:INT1 1 "memory_operand" "") ;; memory
- (match_operand:INT1 2 "gpc_reg_operand" "") ;; operand
+ [(match_operand:AINT 0 "int_reg_operand" "") ;; output
+ (match_operand:AINT 1 "memory_operand" "") ;; memory
+ (match_operand:AINT 2 "int_reg_operand" "") ;; operand
(match_operand:SI 3 "const_int_operand" "")] ;; model
""
{
@@ -268,10 +527,10 @@
})
(define_expand "atomic_<fetchop_name>_fetch<mode>"
- [(match_operand:INT1 0 "gpc_reg_operand" "") ;; output
- (match_operand:INT1 1 "memory_operand" "") ;; memory
- (FETCHOP:INT1 (match_dup 1)
- (match_operand:INT1 2 "<fetchop_pred>" "")) ;; operand
+ [(match_operand:AINT 0 "int_reg_operand" "") ;; output
+ (match_operand:AINT 1 "memory_operand" "") ;; memory
+ (FETCHOP:AINT (match_dup 1)
+ (match_operand:AINT 2 "<fetchop_pred>" "")) ;; operand
(match_operand:SI 3 "const_int_operand" "")] ;; model
""
{
@@ -281,9 +540,9 @@
})
(define_expand "atomic_nand_fetch<mode>"
- [(match_operand:INT1 0 "gpc_reg_operand" "") ;; output
- (match_operand:INT1 1 "memory_operand" "") ;; memory
- (match_operand:INT1 2 "gpc_reg_operand" "") ;; operand
+ [(match_operand:AINT 0 "int_reg_operand" "") ;; output
+ (match_operand:AINT 1 "memory_operand" "") ;; memory
+ (match_operand:AINT 2 "int_reg_operand" "") ;; operand
(match_operand:SI 3 "const_int_operand" "")] ;; model
""
{