1;; ARM ldrd/strd peephole optimizations.
2;;
3;; Copyright (C) 2013-2021 Free Software Foundation, Inc.
4;;
5;; Written by Greta Yorsh <greta.yorsh@arm.com>
6
7;; This file is part of GCC.
8;;
9;; GCC is free software; you can redistribute it and/or modify it
10;; under the terms of the GNU General Public License as published by
11;; the Free Software Foundation; either version 3, or (at your option)
12;; any later version.
13;;
14;; GCC is distributed in the hope that it will be useful, but
15;; WITHOUT ANY WARRANTY; without even the implied warranty of
16;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17;; General Public License for more details.
18;;
19;; You should have received a copy of the GNU General Public License
20;; along with GCC; see the file COPYING3.  If not see
21;; <http://www.gnu.org/licenses/>.
22
23;; The following peephole optimizations identify consecutive memory
24;; accesses, and try to rearrange the operands to enable generation of
25;; ldrd/strd.
26;;
27;; In many cases they behave in the same way that patterns in ldmstm.md behave,
28;; but there is extra logic in gen_operands_ldrd_strd to try and ensure the
29;; registers used are an (r<N>, r<N + 1>) pair where N is even.
30
31(define_peephole2 ; ldrd
32  [(set (match_operand:SI 0 "arm_general_register_operand" "")
33	(match_operand:SI 2 "memory_operand" ""))
34   (set (match_operand:SI 1 "arm_general_register_operand" "")
35	(match_operand:SI 3 "memory_operand" ""))]
36  "TARGET_LDRD"
37  [(parallel [(set (match_dup 0) (match_dup 2))
38	      (set (match_dup 1) (match_dup 3))])]
39{
40  if (!gen_operands_ldrd_strd (operands, true, false, false))
41    FAIL;
42})
43
44(define_peephole2 ; strd
45  [(set (match_operand:SI 2 "memory_operand" "")
46	(match_operand:SI 0 "arm_general_register_operand" ""))
47   (set (match_operand:SI 3 "memory_operand" "")
48	(match_operand:SI 1 "arm_general_register_operand" ""))]
49  "TARGET_LDRD"
50  [(parallel [(set (match_dup 2) (match_dup 0))
51	      (set (match_dup 3) (match_dup 1))])]
52{
53  if (!gen_operands_ldrd_strd (operands, false, false, false))
54    FAIL;
55})
56
57;; The following peepholes reorder registers to enable LDRD/STRD.
58(define_peephole2 ; strd of constants
59  [(set (match_operand:SI 0 "arm_general_register_operand" "")
60	(match_operand:SI 4 "const_int_operand" ""))
61   (set (match_operand:SI 2 "memory_operand" "")
62	(match_dup 0))
63   (set (match_operand:SI 1 "arm_general_register_operand" "")
64	(match_operand:SI 5 "const_int_operand" ""))
65   (set (match_operand:SI 3 "memory_operand" "")
66	(match_dup 1))]
67  "TARGET_LDRD"
68  [(set (match_dup 0) (match_dup 4))
69   (set (match_dup 1) (match_dup 5))
70   (parallel [(set (match_dup 2) (match_dup 0))
71	      (set (match_dup 3) (match_dup 1))])]
72{
73  if (!gen_operands_ldrd_strd (operands, false, true, false))
74    FAIL;
75})
76
77(define_peephole2 ; strd of constants
78  [(set (match_operand:SI 0 "arm_general_register_operand" "")
79	(match_operand:SI 4 "const_int_operand" ""))
80   (set (match_operand:SI 1 "arm_general_register_operand" "")
81	(match_operand:SI 5 "const_int_operand" ""))
82   (set (match_operand:SI 2 "memory_operand" "")
83	(match_dup 0))
84   (set (match_operand:SI 3 "memory_operand" "")
85	(match_dup 1))]
86  "TARGET_LDRD"
87  [(set (match_dup 0) (match_dup 4))
88   (set (match_dup 1) (match_dup 5))
89   (parallel [(set (match_dup 2) (match_dup 0))
90	      (set (match_dup 3) (match_dup 1))])]
91{
92  if (!gen_operands_ldrd_strd (operands, false, true, false))
93     FAIL;
94})
95
96;; The following two peephole optimizations are only relevant for ARM
97;; mode where LDRD/STRD require consecutive registers.
98
99(define_peephole2 ; swap the destination registers of two loads
100		  ; before a commutative operation.
101  [(set (match_operand:SI 0 "arm_general_register_operand" "")
102	(match_operand:SI 2 "memory_operand" ""))
103   (set (match_operand:SI 1 "arm_general_register_operand" "")
104	(match_operand:SI 3 "memory_operand" ""))
105   (set (match_operand:SI 4 "arm_general_register_operand" "")
106	(match_operator:SI 5 "commutative_binary_operator"
107			   [(match_operand 6 "arm_general_register_operand" "")
108			    (match_operand 7 "arm_general_register_operand" "") ]))]
109  "TARGET_LDRD && TARGET_ARM
110   && (  ((rtx_equal_p(operands[0], operands[6])) && (rtx_equal_p(operands[1], operands[7])))
111	||((rtx_equal_p(operands[0], operands[7])) && (rtx_equal_p(operands[1], operands[6]))))
112   && (peep2_reg_dead_p (3, operands[0]) || rtx_equal_p (operands[0], operands[4]))
113   && (peep2_reg_dead_p (3, operands[1]) || rtx_equal_p (operands[1], operands[4]))"
114  [(parallel [(set (match_dup 0) (match_dup 2))
115	      (set (match_dup 1) (match_dup 3))])
116   (set (match_dup 4) (match_op_dup 5 [(match_dup 6) (match_dup 7)]))]
117{
118  if (!gen_operands_ldrd_strd (operands, true, false, true))
119    FAIL;
120})
121
122(define_peephole2 ; swap the destination registers of two loads
123		  ; before a commutative operation that sets the flags.
124  [(set (match_operand:SI 0 "arm_general_register_operand" "")
125	(match_operand:SI 2 "memory_operand" ""))
126   (set (match_operand:SI 1 "arm_general_register_operand" "")
127	(match_operand:SI 3 "memory_operand" ""))
128   (parallel
129      [(set (match_operand:SI 4 "arm_general_register_operand" "")
130	    (match_operator:SI 5 "commutative_binary_operator"
131			       [(match_operand 6 "arm_general_register_operand" "")
132				(match_operand 7 "arm_general_register_operand" "") ]))
133       (clobber (reg:CC CC_REGNUM))])]
134  "TARGET_LDRD && TARGET_ARM
135   && (  ((rtx_equal_p(operands[0], operands[6])) && (rtx_equal_p(operands[1], operands[7])))
136       ||((rtx_equal_p(operands[0], operands[7])) && (rtx_equal_p(operands[1], operands[6]))))
137   && (peep2_reg_dead_p (3, operands[0]) || rtx_equal_p (operands[0], operands[4]))
138   && (peep2_reg_dead_p (3, operands[1]) || rtx_equal_p (operands[1], operands[4]))"
139  [(parallel [(set (match_dup 0) (match_dup 2))
140	      (set (match_dup 1) (match_dup 3))])
141   (parallel
142      [(set (match_dup 4)
143	    (match_op_dup 5 [(match_dup 6) (match_dup 7)]))
144       (clobber (reg:CC CC_REGNUM))])]
145{
146  if (!gen_operands_ldrd_strd (operands, true, false, true))
147    FAIL;
148})
149
150;; TODO: Handle LDRD/STRD with writeback:
151;; (a) memory operands can be POST_INC, POST_DEC, PRE_MODIFY, POST_MODIFY
152;; (b) Patterns may be followed by an update of the base address.
153
154
155;; insns matching the LDRD/STRD patterns that will get created by the above
156;; peepholes.
157;; We use gen_operands_ldrd_strd() with a modify argument as false so that the
158;; operands are not changed.
159(define_insn "*arm_ldrd"
160  [(parallel [(set (match_operand:SI 0 "s_register_operand" "=r")
161		   (match_operand:SI 2 "memory_operand" "m"))
162	      (set (match_operand:SI 1 "s_register_operand" "=rk")
163		   (match_operand:SI 3 "memory_operand" "m"))])]
164  "TARGET_LDRD && TARGET_ARM && reload_completed
165  && valid_operands_ldrd_strd (operands, true)"
166  {
167    rtx op[2];
168    op[0] = gen_rtx_REG (DImode, REGNO (operands[0]));
169    op[1] = adjust_address (operands[2], DImode, 0);
170    return output_move_double (op, true, NULL);
171  }
172  [(set (attr "length")
173	(symbol_ref "arm_count_ldrdstrd_insns (operands, true) * 4"))
174   (set (attr "ce_count") (symbol_ref "get_attr_length (insn) / 4"))
175   (set_attr "type" "load_8")
176   (set_attr "predicable" "yes")]
177)
178
179(define_insn "*arm_strd"
180  [(parallel [(set (match_operand:SI 2 "memory_operand" "=m")
181		   (match_operand:SI 0 "s_register_operand" "r"))
182	      (set (match_operand:SI 3 "memory_operand" "=m")
183		   (match_operand:SI 1 "s_register_operand" "rk"))])]
184  "TARGET_LDRD && TARGET_ARM && reload_completed
185  && valid_operands_ldrd_strd (operands, false)"
186  {
187    rtx op[2];
188    op[0] = adjust_address (operands[2], DImode, 0);
189    op[1] = gen_rtx_REG (DImode, REGNO (operands[0]));
190    return output_move_double (op, true, NULL);
191  }
192  [(set (attr "length")
193	(symbol_ref "arm_count_ldrdstrd_insns (operands, false) * 4"))
194   (set (attr "ce_count") (symbol_ref "get_attr_length (insn) / 4"))
195   (set_attr "type" "store_8")
196   (set_attr "predicable" "yes")]
197)
198