]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/config/rs6000/pcrel-opt.md
Update copyright years.
[thirdparty/gcc.git] / gcc / config / rs6000 / pcrel-opt.md
1 ;; Machine description for the PCREL_OPT optimization.
2 ;; Copyright (C) 2020-2024 Free Software Foundation, Inc.
3 ;; Contributed by Michael Meissner (meissner@linux.ibm.com)
4
5 ;; This file is part of GCC.
6
7 ;; GCC is free software; you can redistribute it and/or modify it
8 ;; under the terms of the GNU General Public License as published
9 ;; by the Free Software Foundation; either version 3, or (at your
10 ;; option) any later version.
11
12 ;; GCC is distributed in the hope that it will be useful, but WITHOUT
13 ;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 ;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
15 ;; License for more details.
16
17 ;; You should have received a copy of the GNU General Public License
18 ;; along with GCC; see the file COPYING3. If not see
19 ;; <http://www.gnu.org/licenses/>.
20
21 ;; Support for the PCREL_OPT optimization. PCREL_OPT looks for instances where
22 ;; an external variable is used only once, either for reading or for writing.
23 ;;
24 ;; If we are optimizing a single read, normally the code would look like:
25 ;;
26 ;; (set (reg:DI <ptr>)
27 ;; (symbol_ref:DI "<extern_addr>")) # <data> is currently dead
28 ;;
29 ;; ... # insns do not need to be adjacent
30 ;;
31 ;; (set (reg:SI <data>)
32 ;; (mem:SI (reg:DI <xxx>))) # <ptr> dies with this insn
33 ;;
34 ;; We transform this into:
35 ;;
36 ;; (parallel [(set (reg:DI <ptr>)
37 ;; (unspec:SI [(symbol_ref:DI <extern_addr>)
38 ;; (const_int <marker>)]
39 ;; UNSPEC_PCREL_OPT_LD_ADDR))
40 ;; (set (reg:DI <data>)
41 ;; (unspec:DI [(const_int 0)]
42 ;; UNSPEC_PCREL_OPT_LD_DATA))])
43 ;;
44 ;; ...
45 ;;
46 ;; (parallel [(set (reg:SI <data>)
47 ;; (unspec:SI [(mem:SI (reg:DI <ptr>))
48 ;; (reg:DI <data>)
49 ;; (const_int <marker>)]
50 ;; UNSPEC_PCREL_OPT_LD_RELOC))
51 ;; (clobber (reg:DI <ptr>))])
52 ;;
53 ;; The marker is an integer constant that links the load of the external
54 ;; address to the load of the actual variable.
55 ;;
56 ;; In the first insn, we set both the address of the external variable, and
57 ;; mark that the variable being loaded both are created in that insn, and are
58 ;; consumed in the second insn. It doesn't matter what mode the register that
59 ;; we will ultimately do the load into, so we use DImode. We just need to mark
60 ;; that both registers may be set in the first insn, and will be used in the
61 ;; second insn.
62 ;;
63 ;; Since we use UNSPEC's and link both the register holding the external
64 ;; address and the value being loaded, it should prevent other passes from
65 ;; modifying it.
66 ;;
67 ;; If the register being loaded is the same as the base register, we use an
68 ;; alternate form of the insns.
69 ;;
70 ;; (set (reg:DI <data_ptr>)
71 ;; (unspec:DI [(symbol_ref:DI <extern_addr>)
72 ;; (const_int <marker>)]
73 ;; UNSPEC_PCREL_OPT_LD_SAME_REG))
74 ;;
75 ;; ...
76 ;;
77 ;; (parallel [(set (reg:SI <data>)
78 ;; (unspec:SI [(mem:SI (reg:DI <ptr>))
79 ;; (reg:DI <data>)
80 ;; (const_int <marker>)]
81 ;; UNSPEC_PCREL_OPT_LD_RELOC))
82 ;; (clobber (reg:DI <ptr>))])
83
84 (define_c_enum "unspec"
85 [UNSPEC_PCREL_OPT_LD_ADDR
86 UNSPEC_PCREL_OPT_LD_DATA
87 UNSPEC_PCREL_OPT_LD_SAME_REG
88 UNSPEC_PCREL_OPT_LD_RELOC
89 UNSPEC_PCREL_OPT_ST_ADDR
90 UNSPEC_PCREL_OPT_ST_RELOC])
91
92 ;; Modes that are supported for PCREL_OPT
93 (define_mode_iterator PCRELOPT [QI HI SI DI TI SF DF KF
94 V1TI V2DI V4SI V8HI V16QI V2DF V4SF
95 (TF "TARGET_FLOAT128_TYPE && TARGET_IEEEQUAD")])
96
97 ;; Vector modes for PCREL_OPT
98 (define_mode_iterator PCRELOPT_VECT [TI KF V1TI V2DI V4SI V8HI V16QI V2DF V4SF
99 (TF "TARGET_FLOAT128_TYPE && TARGET_IEEEQUAD")])
100
101 ;; Insn for loading the external address, where the register being loaded is not
102 ;; the same as the register being loaded with the data.
103 (define_insn "pcrel_opt_ld_addr"
104 [(set (match_operand:DI 0 "base_reg_operand" "=&b,&b")
105 (unspec:DI [(match_operand:DI 1 "pcrel_external_address")
106 (match_operand 2 "const_int_operand" "n,n")]
107 UNSPEC_PCREL_OPT_LD_ADDR))
108 (set (match_operand:DI 3 "gpc_reg_operand" "=r,wa")
109 (unspec:DI [(const_int 0)]
110 UNSPEC_PCREL_OPT_LD_DATA))]
111 "TARGET_PCREL_OPT
112 && reg_or_subregno (operands[0]) != reg_or_subregno (operands[3])"
113 "ld %0,%a1\n.Lpcrel%2:"
114 [(set_attr "prefixed" "yes")
115 (set_attr "type" "load")
116 (set_attr "loads_external_address" "yes")])
117
118 ;; Alternate form of loading up the external address that is the same register
119 ;; as the final load.
120 (define_insn "pcrel_opt_ld_addr_same_reg"
121 [(set (match_operand:DI 0 "base_reg_operand" "=b")
122 (unspec:DI [(match_operand:DI 1 "pcrel_external_address")
123 (match_operand 2 "const_int_operand" "n")]
124 UNSPEC_PCREL_OPT_LD_SAME_REG))]
125 "TARGET_PCREL_OPT"
126 "ld %0,%a1\n.Lpcrel%2:"
127 [(set_attr "prefixed" "yes")
128 (set_attr "type" "load")
129 (set_attr "loads_external_address" "yes")])
130
131 ;; PCREL_OPT modes that are optimized for loading or storing GPRs.
132 (define_mode_iterator PCRELOPT_GPR [QI HI SI DI SF DF])
133
134 (define_mode_attr PCRELOPT_GPR_LD [(QI "lbz")
135 (HI "lhz")
136 (SI "lwz")
137 (SF "lwz")
138 (DI "ld")
139 (DF "ld")])
140
141 ;; PCREL_OPT load operation of GPRs. Operand 4 (the register used to hold the
142 ;; address of the external symbol) is SCRATCH if the same register is used for
143 ;; the normal load.
144 (define_insn "*pcrel_opt_ld<mode>_gpr"
145 [(parallel [(set (match_operand:PCRELOPT_GPR 0 "int_reg_operand" "+r")
146 (unspec:PCRELOPT_GPR [
147 (match_operand:PCRELOPT_GPR 1 "d_form_memory" "m")
148 (match_operand:DI 2 "int_reg_operand" "0")
149 (match_operand 3 "const_int_operand" "n")]
150 UNSPEC_PCREL_OPT_LD_RELOC))
151 (clobber (match_scratch:DI 4 "=bX"))])]
152 "TARGET_PCREL_OPT
153 && (GET_CODE (operands[4]) == SCRATCH
154 || reg_mentioned_p (operands[4], operands[1]))"
155 {
156 output_pcrel_opt_reloc (operands[3]);
157 return "<PCRELOPT_GPR_LD> %0,%1";
158 }
159 [(set_attr "type" "load")])
160
161 ;; PCREL_OPT load with sign/zero extension
162 (define_insn "*pcrel_opt_ldsi_<u><mode>_gpr"
163 [(set (match_operand:EXTSI 0 "int_reg_operand" "+r")
164 (any_extend:EXTSI
165 (unspec:SI [(match_operand:SI 1 "d_form_memory" "m")
166 (match_operand:DI 2 "int_reg_operand" "0")
167 (match_operand 3 "const_int_operand" "n")]
168 UNSPEC_PCREL_OPT_LD_RELOC)))
169 (clobber (match_scratch:DI 4 "=bX"))]
170 "TARGET_PCREL_OPT"
171 {
172 output_pcrel_opt_reloc (operands[3]);
173 return "lw<az> %0,%1";
174 }
175 [(set_attr "type" "load")])
176
177 (define_insn "*pcrel_opt_ldhi_<u><mode>_gpr"
178 [(set (match_operand:EXTHI 0 "int_reg_operand" "+r")
179 (any_extend:EXTHI
180 (unspec:HI [(match_operand:HI 1 "d_form_memory" "m")
181 (match_operand:DI 2 "int_reg_operand" "0")
182 (match_operand 3 "const_int_operand" "n")]
183 UNSPEC_PCREL_OPT_LD_RELOC)))
184 (clobber (match_scratch:DI 4 "=bX"))]
185 "TARGET_PCREL_OPT"
186 {
187 output_pcrel_opt_reloc (operands[3]);
188 return "lh<az> %0,%1";
189 }
190 [(set_attr "type" "load")])
191
192 (define_insn "*pcrel_opt_ldqi_u<mode>_gpr"
193 [(set (match_operand:EXTQI 0 "int_reg_operand" "+r")
194 (zero_extend:EXTQI
195 (unspec:QI [(match_operand:QI 1 "d_form_memory" "m")
196 (match_operand:DI 2 "int_reg_operand" "0")
197 (match_operand 3 "const_int_operand" "n")]
198 UNSPEC_PCREL_OPT_LD_RELOC)))
199 (clobber (match_scratch:DI 4 "=bX"))]
200 "TARGET_PCREL_OPT"
201 {
202 output_pcrel_opt_reloc (operands[3]);
203 return "lbz %0,%1";
204 }
205 [(set_attr "type" "load")])
206
207 ;; Scalar types that can be optimized by loading them into floating point
208 ;; or Altivec registers.
209 (define_mode_iterator PCRELOPT_FP [DI DF SF])
210
211 ;; Load instructions to load up scalar floating point or 64-bit integer values
212 ;; into floating point registers or Altivec registers.
213 (define_mode_attr PCRELOPT_FPR_LD [(DI "lfd") (DF "lfd") (SF "lfs")])
214 (define_mode_attr PCRELOPT_VMX_LD [(DI "lxsd") (DF "lxsd") (SF "lxssp")])
215
216 ;; PCREL_OPT load operation of scalar DF/DI/SF into vector registers.
217 (define_insn "*pcrel_opt_ld<mode>_vsx"
218 [(set (match_operand:PCRELOPT_FP 0 "vsx_register_operand" "+d,v")
219 (unspec:PCRELOPT_FP [(match_operand:PCRELOPT_FP 1 "d_form_memory" "m,m")
220 (match_operand:DI 2 "vsx_register_operand" "0,0")
221 (match_operand 3 "const_int_operand" "n,n")]
222 UNSPEC_PCREL_OPT_LD_RELOC))
223 (clobber (match_operand:DI 4 "base_reg_operand" "=b,b"))]
224 "TARGET_PCREL_OPT"
225 {
226 output_pcrel_opt_reloc (operands[3]);
227 return which_alternative ? "<PCRELOPT_VMX_LD> %0,%1"
228 : "<PCRELOPT_FPR_LD> %0,%1";
229 }
230 [(set_attr "type" "fpload")])
231
232 ;; PCREL_OPT optimization extending SFmode to DFmode via a load.
233 (define_insn "*pcrel_opt_ldsf_df"
234 [(set (match_operand:DF 0 "vsx_register_operand" "+d,v")
235 (float_extend:DF
236 (unspec:SF [(match_operand:SF 1 "d_form_memory" "m,m")
237 (match_operand:DI 2 "vsx_register_operand" "0,0")
238 (match_operand 3 "const_int_operand" "n,n")]
239 UNSPEC_PCREL_OPT_LD_RELOC)))
240 (clobber (match_operand:DI 4 "base_reg_operand" "=b,b"))]
241 "TARGET_PCREL_OPT"
242 {
243 output_pcrel_opt_reloc (operands[3]);
244 return which_alternative ? "lxssp %0,%1" : "lfs %0,%1";
245 }
246 [(set_attr "type" "fpload")])
247
248 ;; PCREL_OPT load operation of vector/float128 types into vector registers.
249 (define_insn "*pcrel_opt_ld<mode>"
250 [(set (match_operand:PCRELOPT_VECT 0 "vsx_register_operand" "+wa")
251 (unspec:PCRELOPT_VECT [(match_operand:PCRELOPT_VECT 1 "d_form_memory" "m")
252 (match_operand:DI 2 "vsx_register_operand" "0")
253 (match_operand 3 "const_int_operand" "n")]
254 UNSPEC_PCREL_OPT_LD_RELOC))
255 (clobber (match_operand:DI 4 "base_reg_operand" "=b"))]
256 "TARGET_PCREL_OPT"
257 {
258 output_pcrel_opt_reloc (operands[3]);
259 return "lxv %x0,%1";
260 }
261 [(set_attr "type" "vecload")])
262
263 \f
264 ;; PCREL_OPT optimization for stores. We need to put the label after the PLD
265 ;; instruction, because the assembler might insert a NOP before the PLD for
266 ;; alignment.
267 ;;
268 ;; If we are optimizing a single write, normally the code would look like:
269 ;;
270 ;; (set (reg:DI <ptr>)
271 ;; (symbol_ref:DI "<extern_addr>")) # <data> must be live here
272 ;;
273 ;; ... # insns do not need to be adjacent
274 ;;
275 ;; (set (mem:SI (reg:DI <xxx>))
276 ;; (reg:SI <data>)) # <ptr> dies with this insn
277 ;;
278 ;; We optimize this to be:
279 ;;
280 ;; (parallel [(set (reg:DI <ptr>)
281 ;; (unspec:DI [(symbol_ref:DI "<extern_addr>")
282 ;; (const_int <marker>)]
283 ;; UNSPEC_PCREL_OPT_ST_ADDR))
284 ;; (use (reg:<MODE> <data>))])
285 ;;
286 ;; ... # insns do not need to be adjacent
287 ;;
288 ;; (parallel [(set (mem:<MODE> (reg:DI <ptr>))
289 ;; (unspec:<MODE> [(reg:<MODE> <data>)
290 ;; (const_int <marker>)]
291 ;; UNSPEC_PCREL_OPT_ST_RELOC))
292 ;; (clobber (reg:DI <ptr>))])
293
294 (define_insn "*pcrel_opt_st_addr<mode>"
295 [(set (match_operand:DI 0 "gpc_reg_operand" "=b")
296 (unspec:DI [(match_operand:DI 1 "pcrel_external_address")
297 (match_operand 2 "const_int_operand" "n")]
298 UNSPEC_PCREL_OPT_ST_ADDR))
299 (use (match_operand:PCRELOPT 3 "gpc_reg_operand" "rwa"))]
300 "TARGET_PCREL_OPT"
301 "ld %0,%a1\n.Lpcrel%2:"
302 [(set_attr "prefixed" "yes")
303 (set_attr "type" "load")
304 (set_attr "loads_external_address" "yes")])
305
306 ;; PCREL_OPT stores.
307 (define_insn "*pcrel_opt_st<mode>"
308 [(set (match_operand:QHSI 0 "d_form_memory" "=m")
309 (unspec:QHSI [(match_operand:QHSI 1 "gpc_reg_operand" "r")
310 (match_operand 2 "const_int_operand" "n")]
311 UNSPEC_PCREL_OPT_ST_RELOC))
312 (clobber (match_operand:DI 3 "base_reg_operand" "=b"))]
313 "TARGET_PCREL_OPT"
314 {
315 output_pcrel_opt_reloc (operands[2]);
316 return "st<wd> %1,%0";
317 }
318 [(set_attr "type" "store")])
319
320 (define_insn "*pcrel_opt_stdi"
321 [(set (match_operand:DI 0 "d_form_memory" "=m,m,m")
322 (unspec:DI [(match_operand:DI 1 "gpc_reg_operand" "r,d,v")
323 (match_operand 2 "const_int_operand" "n,n,n")]
324 UNSPEC_PCREL_OPT_ST_RELOC))
325 (clobber (match_operand:DI 3 "base_reg_operand" "=b,b,b"))]
326 "TARGET_PCREL_OPT && TARGET_POWERPC64"
327 {
328 output_pcrel_opt_reloc (operands[2]);
329 switch (which_alternative)
330 {
331 case 0:
332 return "std %1,%0";
333 case 1:
334 return "stfd %1,%0";
335 case 2:
336 return "stxsd %1,%0";
337 default:
338 gcc_unreachable ();
339 }
340 }
341 [(set_attr "type" "store,fpstore,fpstore")])
342
343 (define_insn "*pcrel_opt_stsf"
344 [(set (match_operand:SF 0 "d_form_memory" "=m,m,m")
345 (unspec:SF [(match_operand:SF 1 "gpc_reg_operand" "d,v,r")
346 (match_operand 2 "const_int_operand" "n,n,n")]
347 UNSPEC_PCREL_OPT_ST_RELOC))
348 (clobber (match_operand:DI 3 "base_reg_operand" "=b,b,b"))]
349 "TARGET_PCREL_OPT"
350 {
351 output_pcrel_opt_reloc (operands[2]);
352 switch (which_alternative)
353 {
354 case 0:
355 return "stfs %1,%0";
356 case 1:
357 return "stxssp %1,%0";
358 case 2:
359 return "stw %1,%0";
360 default:
361 gcc_unreachable ();
362 }
363 }
364 [(set_attr "type" "fpstore,fpstore,store")])
365
366 (define_insn "*pcrel_opt_stdf"
367 [(set (match_operand:DF 0 "d_form_memory" "=m,m,m")
368 (unspec:DF [(match_operand:DF 1 "gpc_reg_operand" "d,v,r")
369 (match_operand 2 "const_int_operand" "n,n,n")]
370 UNSPEC_PCREL_OPT_ST_RELOC))
371 (clobber (match_operand:DI 3 "base_reg_operand" "=b,b,b"))]
372 "TARGET_PCREL_OPT
373 && (TARGET_POWERPC64 || vsx_register_operand (operands[1], DFmode))"
374 {
375 output_pcrel_opt_reloc (operands[2]);
376 switch (which_alternative)
377 {
378 case 0:
379 return "stfd %1,%0";
380 case 1:
381 return "stxsd %1,%0";
382 case 2:
383 return "std %1,%0";
384 default:
385 gcc_unreachable ();
386 }
387 }
388 [(set_attr "type" "fpstore,fpstore,store")])
389
390 (define_insn "*pcrel_opt_st<mode>"
391 [(set (match_operand:PCRELOPT_VECT 0 "d_form_memory" "=m")
392 (unspec:PCRELOPT_VECT [(match_operand:PCRELOPT_VECT 1 "gpc_reg_operand" "wa")
393 (match_operand 2 "const_int_operand" "n")]
394 UNSPEC_PCREL_OPT_ST_RELOC))
395 (clobber (match_operand:DI 3 "base_reg_operand" "=b"))]
396 "TARGET_PCREL_OPT"
397 {
398 output_pcrel_opt_reloc (operands[2]);
399 return "stxv %x1,%0";
400 }
401 [(set_attr "type" "vecstore")])