RISC-V: Fix for combine bug with shift and AND operations.
[official-gcc.git] / gcc / config / riscv / sync.md
blob8e8c37702aab69b8fd75eb8d512140f0674a11f8
1 ;; Machine description for RISC-V atomic operations.
2 ;; Copyright (C) 2011-2018 Free Software Foundation, Inc.
3 ;; Contributed by Andrew Waterman (andrew@sifive.com).
4 ;; Based on MIPS target for GNU compiler.
6 ;; This file is part of GCC.
8 ;; GCC is free software; you can redistribute it and/or modify
9 ;; it under the terms of the GNU General Public License as published by
10 ;; the Free Software Foundation; either version 3, or (at your option)
11 ;; any later version.
13 ;; GCC is distributed in the hope that it will be useful,
14 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 ;; GNU General Public License for more details.
18 ;; You should have received a copy of the GNU General Public License
19 ;; along with GCC; see the file COPYING3.  If not see
20 ;; <http://www.gnu.org/licenses/>.
22 (define_c_enum "unspec" [
23   UNSPEC_COMPARE_AND_SWAP
24   UNSPEC_SYNC_OLD_OP
25   UNSPEC_SYNC_EXCHANGE
26   UNSPEC_ATOMIC_STORE
27   UNSPEC_MEMORY_BARRIER
30 (define_code_iterator any_atomic [plus ior xor and])
31 (define_code_attr atomic_optab
32   [(plus "add") (ior "or") (xor "xor") (and "and")])
34 ;; Memory barriers.
36 (define_expand "mem_thread_fence"
37   [(match_operand:SI 0 "const_int_operand" "")] ;; model
38   ""
40   if (INTVAL (operands[0]) != MEMMODEL_RELAXED)
41     {
42       rtx mem = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (Pmode));
43       MEM_VOLATILE_P (mem) = 1;
44       emit_insn (gen_mem_thread_fence_1 (mem, operands[0]));
45     }
46   DONE;
49 ;; Until the RISC-V memory model (hence its mapping from C++) is finalized,
50 ;; conservatively emit a full FENCE.
51 (define_insn "mem_thread_fence_1"
52   [(set (match_operand:BLK 0 "" "")
53         (unspec:BLK [(match_dup 0)] UNSPEC_MEMORY_BARRIER))
54    (match_operand:SI 1 "const_int_operand" "")] ;; model
55   ""
56   "fence\tiorw,iorw")
58 ;; Atomic memory operations.
60 ;; Implement atomic stores with amoswap.  Fall back to fences for atomic loads.
61 (define_insn "atomic_store<mode>"
62   [(set (match_operand:GPR 0 "memory_operand" "=A")
63     (unspec_volatile:GPR
64       [(match_operand:GPR 1 "reg_or_0_operand" "rJ")
65        (match_operand:SI 2 "const_int_operand")]      ;; model
66       UNSPEC_ATOMIC_STORE))]
67   "TARGET_ATOMIC"
68   "%F2amoswap.<amo>%A2 zero,%z1,%0"
69   [(set (attr "length") (const_int 8))])
71 (define_insn "atomic_<atomic_optab><mode>"
72   [(set (match_operand:GPR 0 "memory_operand" "+A")
73         (unspec_volatile:GPR
74           [(any_atomic:GPR (match_dup 0)
75                      (match_operand:GPR 1 "reg_or_0_operand" "rJ"))
76            (match_operand:SI 2 "const_int_operand")] ;; model
77          UNSPEC_SYNC_OLD_OP))]
78   "TARGET_ATOMIC"
79   "%F2amo<insn>.<amo>%A2 zero,%z1,%0"
80   [(set (attr "length") (const_int 8))])
82 (define_insn "atomic_fetch_<atomic_optab><mode>"
83   [(set (match_operand:GPR 0 "register_operand" "=&r")
84         (match_operand:GPR 1 "memory_operand" "+A"))
85    (set (match_dup 1)
86         (unspec_volatile:GPR
87           [(any_atomic:GPR (match_dup 1)
88                      (match_operand:GPR 2 "reg_or_0_operand" "rJ"))
89            (match_operand:SI 3 "const_int_operand")] ;; model
90          UNSPEC_SYNC_OLD_OP))]
91   "TARGET_ATOMIC"
92   "%F3amo<insn>.<amo>%A3 %0,%z2,%1"
93   [(set (attr "length") (const_int 8))])
95 (define_insn "atomic_exchange<mode>"
96   [(set (match_operand:GPR 0 "register_operand" "=&r")
97         (unspec_volatile:GPR
98           [(match_operand:GPR 1 "memory_operand" "+A")
99            (match_operand:SI 3 "const_int_operand")] ;; model
100           UNSPEC_SYNC_EXCHANGE))
101    (set (match_dup 1)
102         (match_operand:GPR 2 "register_operand" "0"))]
103   "TARGET_ATOMIC"
104   "%F3amoswap.<amo>%A3 %0,%z2,%1"
105   [(set (attr "length") (const_int 8))])
107 (define_insn "atomic_cas_value_strong<mode>"
108   [(set (match_operand:GPR 0 "register_operand" "=&r")
109         (match_operand:GPR 1 "memory_operand" "+A"))
110    (set (match_dup 1)
111         (unspec_volatile:GPR [(match_operand:GPR 2 "reg_or_0_operand" "rJ")
112                               (match_operand:GPR 3 "reg_or_0_operand" "rJ")
113                               (match_operand:SI 4 "const_int_operand")  ;; mod_s
114                               (match_operand:SI 5 "const_int_operand")] ;; mod_f
115          UNSPEC_COMPARE_AND_SWAP))
116    (clobber (match_scratch:GPR 6 "=&r"))]
117   "TARGET_ATOMIC"
118   "%F5 1: lr.<amo>%A5 %0,%1; bne %0,%z2,1f; sc.<amo>%A4 %6,%z3,%1; bnez %6,1b; 1:"
119   [(set (attr "length") (const_int 20))])
121 (define_expand "atomic_compare_and_swap<mode>"
122   [(match_operand:SI 0 "register_operand" "")   ;; bool output
123    (match_operand:GPR 1 "register_operand" "")  ;; val output
124    (match_operand:GPR 2 "memory_operand" "")    ;; memory
125    (match_operand:GPR 3 "reg_or_0_operand" "")  ;; expected value
126    (match_operand:GPR 4 "reg_or_0_operand" "")  ;; desired value
127    (match_operand:SI 5 "const_int_operand" "")  ;; is_weak
128    (match_operand:SI 6 "const_int_operand" "")  ;; mod_s
129    (match_operand:SI 7 "const_int_operand" "")] ;; mod_f
130   "TARGET_ATOMIC"
132   emit_insn (gen_atomic_cas_value_strong<mode> (operands[1], operands[2],
133                                                 operands[3], operands[4],
134                                                 operands[6], operands[7]));
136   rtx compare = operands[1];
137   if (operands[3] != const0_rtx)
138     {
139       rtx difference = gen_rtx_MINUS (<MODE>mode, operands[1], operands[3]);
140       compare = gen_reg_rtx (<MODE>mode);
141       emit_insn (gen_rtx_SET (compare, difference));
142     }
144   if (word_mode != <MODE>mode)
145     {
146       rtx reg = gen_reg_rtx (word_mode);
147       emit_insn (gen_rtx_SET (reg, gen_rtx_SIGN_EXTEND (word_mode, compare)));
148       compare = reg;
149     }
151   emit_insn (gen_rtx_SET (operands[0], gen_rtx_EQ (SImode, compare, const0_rtx)));
152   DONE;
155 (define_expand "atomic_test_and_set"
156   [(match_operand:QI 0 "register_operand" "")     ;; bool output
157    (match_operand:QI 1 "memory_operand" "+A")    ;; memory
158    (match_operand:SI 2 "const_int_operand" "")]   ;; model
159   "TARGET_ATOMIC"
161   /* We have no QImode atomics, so use the address LSBs to form a mask,
162      then use an aligned SImode atomic. */
163   rtx result = operands[0];
164   rtx mem = operands[1];
165   rtx model = operands[2];
166   rtx addr = force_reg (Pmode, XEXP (mem, 0));
168   rtx aligned_addr = gen_reg_rtx (Pmode);
169   emit_move_insn (aligned_addr, gen_rtx_AND (Pmode, addr, GEN_INT (-4)));
171   rtx aligned_mem = change_address (mem, SImode, aligned_addr);
172   set_mem_alias_set (aligned_mem, 0);
174   rtx offset = gen_reg_rtx (SImode);
175   emit_move_insn (offset, gen_rtx_AND (SImode, gen_lowpart (SImode, addr),
176                                        GEN_INT (3)));
178   rtx tmp = gen_reg_rtx (SImode);
179   emit_move_insn (tmp, GEN_INT (1));
181   rtx shmt = gen_reg_rtx (SImode);
182   emit_move_insn (shmt, gen_rtx_ASHIFT (SImode, offset, GEN_INT (3)));
184   rtx word = gen_reg_rtx (SImode);
185   emit_move_insn (word, gen_rtx_ASHIFT (SImode, tmp,
186                                         gen_lowpart (QImode, shmt)));
188   tmp = gen_reg_rtx (SImode);
189   emit_insn (gen_atomic_fetch_orsi (tmp, aligned_mem, word, model));
191   emit_move_insn (gen_lowpart (SImode, result),
192                   gen_rtx_LSHIFTRT (SImode, tmp,
193                                     gen_lowpart (QImode, shmt)));
194   DONE;