comparison gcc/config/nds32/nds32-relax-opt.c @ 131:84e7813d76e9

gcc-8.2
author mir3636
date Thu, 25 Oct 2018 07:37:49 +0900
parents
children 1830386684a0
comparison
equal deleted inserted replaced
111:04ced10e8804 131:84e7813d76e9
1 /* relax-opt pass of Andes NDS32 cpu for GNU compiler
2 Copyright (C) 2012-2018 Free Software Foundation, Inc.
3 Contributed by Andes Technology Corporation.
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 /* ------------------------------------------------------------------------ */
22
23 #define IN_TARGET_CODE 1
24
25 #include "config.h"
26 #include "system.h"
27 #include "coretypes.h"
28 #include "backend.h"
29 #include "target.h"
30 #include "rtl.h"
31 #include "tree.h"
32 #include "stringpool.h"
33 #include "attribs.h"
34 #include "df.h"
35 #include "memmodel.h"
36 #include "tm_p.h"
37 #include "optabs.h" /* For GEN_FCN. */
38 #include "regs.h"
39 #include "emit-rtl.h"
40 #include "recog.h"
41 #include "diagnostic-core.h"
42 #include "stor-layout.h"
43 #include "varasm.h"
44 #include "calls.h"
45 #include "output.h"
46 #include "explow.h"
47 #include "expr.h"
48 #include "tm-constrs.h"
49 #include "builtins.h"
50 #include "cpplib.h"
51 #include "insn-attr.h"
52 #include "cfgrtl.h"
53 #include "tree-pass.h"
54
55 using namespace nds32;
56
57 /* This is used to create unique relax hint id value.
58 The initial value is 0. */
59 static int relax_group_id = 0;
60
61 /* Group the following pattern as relax candidates:
62
63 1. sethi $ra, hi20(sym)
64 ori $ra, $ra, lo12(sym)
65 ==>
66 addi.gp $ra, sym
67
68 2. sethi $ra, hi20(sym)
69 lwi $rb, [$ra + lo12(sym)]
70 ==>
71 lwi.gp $rb, [(sym)]
72
73 3. sethi $ra, hi20(sym)
74 ori $ra, $ra, lo12(sym)
75 lwi $rb, [$ra]
76 swi $rc, [$ra]
77 ==>
78 lwi37 $rb, [(sym)]
79 swi37 $rc, [(sym)] */
80
81 /* Return true if is load/store with REG addressing mode
82 and memory mode is SImode. */
83 static bool
84 nds32_reg_base_load_store_p (rtx_insn *insn)
85 {
86 rtx mem_src = NULL_RTX;
87
88 switch (get_attr_type (insn))
89 {
90 case TYPE_LOAD:
91 mem_src = SET_SRC (PATTERN (insn));
92 break;
93 case TYPE_STORE:
94 mem_src = SET_DEST (PATTERN (insn));
95 break;
96 default:
97 break;
98 }
99
100 /* Find load/store insn with addressing mode is REG. */
101 if (mem_src != NULL_RTX)
102 {
103 if ((GET_CODE (mem_src) == ZERO_EXTEND)
104 || (GET_CODE (mem_src) == SIGN_EXTEND))
105 mem_src = XEXP (mem_src, 0);
106
107 if (GET_CODE (XEXP (mem_src, 0)) == REG)
108 return true;
109 }
110
111 return false;
112 }
113
114 /* Return true if insn is a sp/fp base or sp/fp plus load-store instruction. */
115
116 static bool
117 nds32_sp_base_or_plus_load_store_p (rtx_insn *insn)
118 {
119 rtx mem_src = NULL_RTX;
120
121 switch (get_attr_type (insn))
122 {
123 case TYPE_LOAD:
124 mem_src = SET_SRC (PATTERN (insn));
125 break;
126 case TYPE_STORE:
127 mem_src = SET_DEST (PATTERN (insn));
128 break;
129 default:
130 break;
131 }
132 /* Find load/store insn with addressing mode is REG. */
133 if (mem_src != NULL_RTX)
134 {
135 if ((GET_CODE (mem_src) == ZERO_EXTEND)
136 || (GET_CODE (mem_src) == SIGN_EXTEND))
137 mem_src = XEXP (mem_src, 0);
138
139 if ((GET_CODE (XEXP (mem_src, 0)) == PLUS))
140 mem_src = XEXP (mem_src, 0);
141
142 if (REG_P (XEXP (mem_src, 0))
143 && ((frame_pointer_needed
144 && REGNO (XEXP (mem_src, 0)) == FP_REGNUM)
145 || REGNO (XEXP (mem_src, 0)) == SP_REGNUM))
146 return true;
147 }
148
149 return false;
150 }
151
152 /* Return true if is load with [REG + REG/CONST_INT] addressing mode. */
153 static bool
154 nds32_plus_reg_load_store_p (rtx_insn *insn)
155 {
156 rtx mem_src = NULL_RTX;
157
158 switch (get_attr_type (insn))
159 {
160 case TYPE_LOAD:
161 mem_src = SET_SRC (PATTERN (insn));
162 break;
163 case TYPE_STORE:
164 mem_src = SET_DEST (PATTERN (insn));
165 break;
166 default:
167 break;
168 }
169
170 /* Find load/store insn with addressing mode is [REG + REG/CONST]. */
171 if (mem_src != NULL_RTX)
172 {
173 if ((GET_CODE (mem_src) == ZERO_EXTEND)
174 || (GET_CODE (mem_src) == SIGN_EXTEND))
175 mem_src = XEXP (mem_src, 0);
176
177 if ((GET_CODE (XEXP (mem_src, 0)) == PLUS))
178 mem_src = XEXP (mem_src, 0);
179 else
180 return false;
181
182 if (GET_CODE (XEXP (mem_src, 0)) == REG)
183 return true;
184
185 }
186
187 return false;
188 }
189
190 /* Return true if x is const and the referance is ict symbol. */
191 static bool
192 nds32_ict_const_p (rtx x)
193 {
194 if (GET_CODE (x) == CONST)
195 {
196 x = XEXP (x, 0);
197 return nds32_indirect_call_referenced_p (x);
198 }
199 return FALSE;
200 }
201
202 /* Group the following pattern as relax candidates:
203
204 GOT:
205 sethi $ra, hi20(sym)
206 ori $ra, $ra, lo12(sym)
207 lw $rb, [$ra + $gp]
208
209 GOTOFF, TLSLE:
210 sethi $ra, hi20(sym)
211 ori $ra, $ra, lo12(sym)
212 LS $rb, [$ra + $gp]
213
214 GOTOFF, TLSLE:
215 sethi $ra, hi20(sym)
216 ori $ra, $ra, lo12(sym)
217 add $rb, $ra, $gp($tp)
218
219 Initial GOT table:
220 sethi $gp,hi20(sym)
221 ori $gp, $gp, lo12(sym)
222 add5.pc $gp */
223
224 static auto_vec<rtx_insn *, 32> nds32_group_infos;
225 /* Group the PIC and TLS relax candidate instructions for linker. */
226 static bool
227 nds32_pic_tls_group (rtx_insn *def_insn,
228 enum nds32_relax_insn_type relax_type,
229 int sym_type)
230 {
231 df_ref def_record;
232 df_link *link;
233 rtx_insn *use_insn = NULL;
234 rtx pat, new_pat;
235 def_record = DF_INSN_DEFS (def_insn);
236 for (link = DF_REF_CHAIN (def_record); link; link = link->next)
237 {
238 if (!DF_REF_INSN_INFO (link->ref))
239 continue;
240
241 use_insn = DF_REF_INSN (link->ref);
242
243 /* Skip if define insn and use insn not in the same basic block. */
244 if (!dominated_by_p (CDI_DOMINATORS,
245 BLOCK_FOR_INSN (use_insn),
246 BLOCK_FOR_INSN (def_insn)))
247 return FALSE;
248
249 /* Skip if use_insn not active insn. */
250 if (!active_insn_p (use_insn))
251 return FALSE;
252
253 switch (relax_type)
254 {
255 case RELAX_ORI:
256
257 /* GOTOFF, TLSLE:
258 sethi $ra, hi20(sym)
259 ori $ra, $ra, lo12(sym)
260 add $rb, $ra, $gp($tp) */
261 if ((sym_type == UNSPEC_TLSLE
262 || sym_type == UNSPEC_GOTOFF)
263 && (recog_memoized (use_insn) == CODE_FOR_addsi3))
264 {
265 pat = XEXP (PATTERN (use_insn), 1);
266 new_pat =
267 gen_rtx_UNSPEC (SImode,
268 gen_rtvec (2, XEXP (pat, 0), XEXP (pat, 1)),
269 UNSPEC_ADD32);
270 validate_replace_rtx (pat, new_pat, use_insn);
271 nds32_group_infos.safe_push (use_insn);
272 }
273 else if (nds32_plus_reg_load_store_p (use_insn)
274 && !nds32_sp_base_or_plus_load_store_p (use_insn))
275 nds32_group_infos.safe_push (use_insn);
276 else
277 return FALSE;
278 break;
279
280 default:
281 return FALSE;
282 }
283 }
284 return TRUE;
285 }
286
287 static int
288 nds32_pic_tls_symbol_type (rtx x)
289 {
290 x = XEXP (SET_SRC (PATTERN (x)), 1);
291
292 if (GET_CODE (x) == CONST)
293 {
294 x = XEXP (x, 0);
295
296 if (GET_CODE (x) == PLUS)
297 x = XEXP (x, 0);
298
299 return XINT (x, 1);
300 }
301
302 return XINT (x, 1);
303 }
304
305 /* Group the relax candidates with group id. */
306 static void
307 nds32_group_insns (rtx_insn *sethi)
308 {
309 df_ref def_record, use_record;
310 df_link *link;
311 rtx_insn *use_insn = NULL;
312 rtx group_id;
313 bool valid;
314
315 def_record = DF_INSN_DEFS (sethi);
316
317 for (link = DF_REF_CHAIN (def_record); link; link = link->next)
318 {
319 if (!DF_REF_INSN_INFO (link->ref))
320 continue;
321
322 use_insn = DF_REF_INSN (link->ref);
323
324 /* Skip if define insn and use insn not in the same basic block. */
325 if (!dominated_by_p (CDI_DOMINATORS,
326 BLOCK_FOR_INSN (use_insn),
327 BLOCK_FOR_INSN (sethi)))
328 return;
329
330 /* Skip if the low-part used register is from different high-part
331 instructions. */
332 use_record = DF_INSN_USES (use_insn);
333 if (DF_REF_CHAIN (use_record) && DF_REF_CHAIN (use_record)->next)
334 return;
335
336 /* Skip if use_insn not active insn. */
337 if (!active_insn_p (use_insn))
338 return;
339
340 /* Initial use_insn_type. */
341 if (!(recog_memoized (use_insn) == CODE_FOR_lo_sum
342 || nds32_symbol_load_store_p (use_insn)
343 || (nds32_reg_base_load_store_p (use_insn)
344 &&!nds32_sp_base_or_plus_load_store_p (use_insn))))
345 return;
346 }
347
348 group_id = GEN_INT (relax_group_id);
349 /* Insert .relax_* directive for sethi. */
350 emit_insn_before (gen_relax_group (group_id), sethi);
351
352 /* Scan the use insns and insert the directive. */
353 for (link = DF_REF_CHAIN (def_record); link; link = link->next)
354 {
355 if (!DF_REF_INSN_INFO (link->ref))
356 continue;
357
358 use_insn = DF_REF_INSN (link->ref);
359
360 /* Insert .relax_* directive. */
361 if (active_insn_p (use_insn))
362 emit_insn_before (gen_relax_group (group_id), use_insn);
363
364 /* Find ori ra, ra, unspec(symbol) instruction. */
365 if (use_insn != NULL
366 && recog_memoized (use_insn) == CODE_FOR_lo_sum
367 && !nds32_const_unspec_p (XEXP (SET_SRC (PATTERN (use_insn)), 1)))
368 {
369 int sym_type = nds32_pic_tls_symbol_type (use_insn);
370 valid = nds32_pic_tls_group (use_insn, RELAX_ORI, sym_type);
371
372 /* Insert .relax_* directive. */
373 while (!nds32_group_infos.is_empty ())
374 {
375 use_insn = nds32_group_infos.pop ();
376 if (valid)
377 emit_insn_before (gen_relax_group (group_id), use_insn);
378 }
379 }
380 }
381
382 relax_group_id++;
383 }
384
385 /* Convert relax group id in rtl. */
386
387 static void
388 nds32_group_tls_insn (rtx insn)
389 {
390 rtx pat = PATTERN (insn);
391 rtx unspec_relax_group = XEXP (XVECEXP (pat, 0, 1), 0);
392
393 while (GET_CODE (pat) != SET && GET_CODE (pat) == PARALLEL)
394 {
395 pat = XVECEXP (pat, 0, 0);
396 }
397
398 if (GET_CODE (unspec_relax_group) == UNSPEC
399 && XINT (unspec_relax_group, 1) == UNSPEC_VOLATILE_RELAX_GROUP)
400 {
401 XVECEXP (unspec_relax_group, 0, 0) = GEN_INT (relax_group_id);
402 }
403
404 relax_group_id++;
405 }
406
407 static bool
408 nds32_float_reg_load_store_p (rtx_insn *insn)
409 {
410 rtx pat = PATTERN (insn);
411
412 if (get_attr_type (insn) == TYPE_FLOAD
413 && GET_CODE (pat) == SET
414 && (GET_MODE (XEXP (pat, 0)) == SFmode
415 || GET_MODE (XEXP (pat, 0)) == DFmode)
416 && MEM_P (XEXP (pat, 1)))
417 {
418 rtx addr = XEXP (XEXP (pat, 1), 0);
419
420 /* [$ra] */
421 if (REG_P (addr))
422 return true;
423 /* [$ra + offset] */
424 if (GET_CODE (addr) == PLUS
425 && REG_P (XEXP (addr, 0))
426 && CONST_INT_P (XEXP (addr, 1)))
427 return true;
428 }
429 return false;
430 }
431
432
433 /* Group float load-store instructions:
434 la $ra, symbol
435 flsi $rt, [$ra + offset] */
436
437 static void
438 nds32_group_float_insns (rtx_insn *insn)
439 {
440 df_ref def_record, use_record;
441 df_link *link;
442 rtx_insn *use_insn = NULL;
443 rtx group_id;
444
445 def_record = DF_INSN_DEFS (insn);
446
447 for (link = DF_REF_CHAIN (def_record); link; link = link->next)
448 {
449 if (!DF_REF_INSN_INFO (link->ref))
450 continue;
451
452 use_insn = DF_REF_INSN (link->ref);
453
454 /* Skip if define insn and use insn not in the same basic block. */
455 if (!dominated_by_p (CDI_DOMINATORS,
456 BLOCK_FOR_INSN (use_insn),
457 BLOCK_FOR_INSN (insn)))
458 return;
459
460 /* Skip if the low-part used register is from different high-part
461 instructions. */
462 use_record = DF_INSN_USES (use_insn);
463 if (DF_REF_CHAIN (use_record) && DF_REF_CHAIN (use_record)->next)
464 return;
465
466 /* Skip if use_insn not active insn. */
467 if (!active_insn_p (use_insn))
468 return;
469
470 if (!nds32_float_reg_load_store_p (use_insn)
471 || find_post_update_rtx (use_insn) != -1)
472 return;
473 }
474
475 group_id = GEN_INT (relax_group_id);
476 /* Insert .relax_* directive for insn. */
477 emit_insn_before (gen_relax_group (group_id), insn);
478
479 /* Scan the use insns and insert the directive. */
480 for (link = DF_REF_CHAIN (def_record); link; link = link->next)
481 {
482 if (!DF_REF_INSN_INFO (link->ref))
483 continue;
484
485 use_insn = DF_REF_INSN (link->ref);
486
487 /* Insert .relax_* directive. */
488 emit_insn_before (gen_relax_group (group_id), use_insn);
489 }
490
491 relax_group_id++;
492 }
493
494 /* Group the relax candidate instructions for linker. */
495 static void
496 nds32_relax_group (void)
497 {
498 rtx_insn *insn;
499
500 compute_bb_for_insn ();
501
502 df_chain_add_problem (DF_DU_CHAIN | DF_UD_CHAIN);
503 df_insn_rescan_all ();
504 df_analyze ();
505 df_set_flags (DF_DEFER_INSN_RESCAN);
506 calculate_dominance_info (CDI_DOMINATORS);
507
508 insn = get_insns ();
509 gcc_assert (NOTE_P (insn));
510
511 for (insn = next_active_insn (insn); insn; insn = next_active_insn (insn))
512 {
513 if (NONJUMP_INSN_P (insn))
514 {
515 /* Find sethi ra, symbol instruction. */
516 if (recog_memoized (insn) == CODE_FOR_sethi
517 && nds32_symbolic_operand (XEXP (SET_SRC (PATTERN (insn)), 0),
518 SImode)
519 && !nds32_ict_const_p (XEXP (SET_SRC (PATTERN (insn)), 0)))
520 nds32_group_insns (insn);
521 else if (recog_memoized (insn) == CODE_FOR_tls_ie)
522 nds32_group_tls_insn (insn);
523 else if (TARGET_FPU_SINGLE
524 && recog_memoized (insn) == CODE_FOR_move_addr
525 && !nds32_ict_const_p (XEXP (SET_SRC (PATTERN (insn)), 0)))
526 {
527 nds32_group_float_insns (insn);
528 }
529 }
530 else if (CALL_P (insn) && recog_memoized (insn) == CODE_FOR_tls_desc)
531 {
532 nds32_group_tls_insn (insn);
533 }
534 }
535
536 /* We must call df_finish_pass manually because it should be invoked before
537 BB information is destroyed. Hence we cannot set the TODO_df_finish flag
538 to the pass manager. */
539 df_insn_rescan_all ();
540 df_finish_pass (false);
541 free_dominance_info (CDI_DOMINATORS);
542 }
543
544 static unsigned int
545 nds32_relax_opt (void)
546 {
547 if (TARGET_RELAX_HINT)
548 nds32_relax_group ();
549 return 1;
550 }
551
552 const pass_data pass_data_nds32_relax_opt =
553 {
554 RTL_PASS, /* type */
555 "relax_opt", /* name */
556 OPTGROUP_NONE, /* optinfo_flags */
557 TV_MACH_DEP, /* tv_id */
558 0, /* properties_required */
559 0, /* properties_provided */
560 0, /* properties_destroyed */
561 0, /* todo_flags_start */
562 TODO_df_finish, /* todo_flags_finish */
563 };
564
565 class pass_nds32_relax_opt : public rtl_opt_pass
566 {
567 public:
568 pass_nds32_relax_opt (gcc::context *ctxt)
569 : rtl_opt_pass (pass_data_nds32_relax_opt, ctxt)
570 {}
571
572 /* opt_pass methods: */
573 bool gate (function *) { return TARGET_RELAX_HINT; }
574 unsigned int execute (function *) { return nds32_relax_opt (); }
575 };
576
577 rtl_opt_pass *
578 make_pass_nds32_relax_opt (gcc::context *ctxt)
579 {
580 return new pass_nds32_relax_opt (ctxt);
581 }