1 /* relax-opt pass of Andes NDS32 cpu for GNU compiler
2 Copyright (C) 2012-2025 Free Software Foundation, Inc.
3 Contributed by Andes Technology Corporation.
5 This file is part of GCC.
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.
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.
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/>. */
21 /* ------------------------------------------------------------------------ */
23 #define IN_TARGET_CODE 1
27 #include "coretypes.h"
32 #include "stringpool.h"
37 #include "optabs.h" /* For GEN_FCN. */
41 #include "diagnostic-core.h"
42 #include "stor-layout.h"
48 #include "tm-constrs.h"
51 #include "insn-attr.h"
53 #include "tree-pass.h"
55 using namespace nds32
;
57 /* This is used to create unique relax hint id value.
58 The initial value is 0. */
59 static int relax_group_id
= 0;
61 /* Group the following pattern as relax candidates:
63 1. sethi $ra, hi20(sym)
64 ori $ra, $ra, lo12(sym)
68 2. sethi $ra, hi20(sym)
69 lwi $rb, [$ra + lo12(sym)]
73 3. sethi $ra, hi20(sym)
74 ori $ra, $ra, lo12(sym)
82 nds32_alloc_relax_group_id ()
84 return relax_group_id
++;
87 /* Return true if is load/store with REG addressing mode
88 and memory mode is SImode. */
90 nds32_reg_base_load_store_p (rtx_insn
*insn
)
92 rtx mem_src
= NULL_RTX
;
94 switch (get_attr_type (insn
))
97 mem_src
= SET_SRC (PATTERN (insn
));
100 mem_src
= SET_DEST (PATTERN (insn
));
106 /* Find load/store insn with addressing mode is REG. */
107 if (mem_src
!= NULL_RTX
)
109 if ((GET_CODE (mem_src
) == ZERO_EXTEND
)
110 || (GET_CODE (mem_src
) == SIGN_EXTEND
))
111 mem_src
= XEXP (mem_src
, 0);
113 if (GET_CODE (XEXP (mem_src
, 0)) == REG
)
120 /* Return true if insn is a sp/fp base or sp/fp plus load-store instruction. */
123 nds32_sp_base_or_plus_load_store_p (rtx_insn
*insn
)
125 rtx mem_src
= NULL_RTX
;
127 switch (get_attr_type (insn
))
130 mem_src
= SET_SRC (PATTERN (insn
));
133 mem_src
= SET_DEST (PATTERN (insn
));
138 /* Find load/store insn with addressing mode is REG. */
139 if (mem_src
!= NULL_RTX
)
141 if ((GET_CODE (mem_src
) == ZERO_EXTEND
)
142 || (GET_CODE (mem_src
) == SIGN_EXTEND
))
143 mem_src
= XEXP (mem_src
, 0);
145 if ((GET_CODE (XEXP (mem_src
, 0)) == PLUS
))
146 mem_src
= XEXP (mem_src
, 0);
148 if (REG_P (XEXP (mem_src
, 0))
149 && ((frame_pointer_needed
150 && REGNO (XEXP (mem_src
, 0)) == FP_REGNUM
)
151 || REGNO (XEXP (mem_src
, 0)) == SP_REGNUM
))
158 /* Return true if is load with [REG + REG/CONST_INT] addressing mode. */
160 nds32_plus_reg_load_store_p (rtx_insn
*insn
)
162 rtx mem_src
= NULL_RTX
;
164 switch (get_attr_type (insn
))
167 mem_src
= SET_SRC (PATTERN (insn
));
170 mem_src
= SET_DEST (PATTERN (insn
));
176 /* Find load/store insn with addressing mode is [REG + REG/CONST]. */
177 if (mem_src
!= NULL_RTX
)
179 if ((GET_CODE (mem_src
) == ZERO_EXTEND
)
180 || (GET_CODE (mem_src
) == SIGN_EXTEND
))
181 mem_src
= XEXP (mem_src
, 0);
183 if ((GET_CODE (XEXP (mem_src
, 0)) == PLUS
))
184 mem_src
= XEXP (mem_src
, 0);
188 if (GET_CODE (XEXP (mem_src
, 0)) == REG
)
196 /* Return true if x is const and the referance is ict symbol. */
198 nds32_ict_const_p (rtx x
)
200 if (GET_CODE (x
) == CONST
)
203 return nds32_indirect_call_referenced_p (x
);
208 /* Group the following pattern as relax candidates:
212 ori $ra, $ra, lo12(sym)
217 ori $ra, $ra, lo12(sym)
222 ori $ra, $ra, lo12(sym)
223 add $rb, $ra, $gp($tp)
227 ori $gp, $gp, lo12(sym)
230 static auto_vec
<rtx_insn
*, 32> nds32_group_infos
;
231 /* Group the PIC and TLS relax candidate instructions for linker. */
233 nds32_pic_tls_group (rtx_insn
*def_insn
,
234 enum nds32_relax_insn_type relax_type
,
239 rtx_insn
*use_insn
= NULL
;
241 def_record
= DF_INSN_DEFS (def_insn
);
242 for (link
= DF_REF_CHAIN (def_record
); link
; link
= link
->next
)
244 if (!DF_REF_INSN_INFO (link
->ref
))
247 use_insn
= DF_REF_INSN (link
->ref
);
249 /* Skip if define insn and use insn not in the same basic block. */
250 if (!dominated_by_p (CDI_DOMINATORS
,
251 BLOCK_FOR_INSN (use_insn
),
252 BLOCK_FOR_INSN (def_insn
)))
255 /* Skip if use_insn not active insn. */
256 if (!active_insn_p (use_insn
))
265 ori $ra, $ra, lo12(sym)
266 add $rb, $ra, $gp($tp) */
267 if ((sym_type
== UNSPEC_TLSLE
268 || sym_type
== UNSPEC_GOTOFF
)
269 && (recog_memoized (use_insn
) == CODE_FOR_addsi3
))
271 pat
= XEXP (PATTERN (use_insn
), 1);
273 gen_rtx_UNSPEC (SImode
,
274 gen_rtvec (2, XEXP (pat
, 0), XEXP (pat
, 1)),
276 validate_replace_rtx (pat
, new_pat
, use_insn
);
277 nds32_group_infos
.safe_push (use_insn
);
279 else if (nds32_plus_reg_load_store_p (use_insn
)
280 && !nds32_sp_base_or_plus_load_store_p (use_insn
))
281 nds32_group_infos
.safe_push (use_insn
);
294 nds32_pic_tls_symbol_type (rtx x
)
296 x
= XEXP (SET_SRC (PATTERN (x
)), 1);
298 if (GET_CODE (x
) == CONST
)
302 if (GET_CODE (x
) == PLUS
)
311 /* Group the relax candidates with group id. */
313 nds32_group_insns (rtx_insn
*sethi
)
315 df_ref def_record
, use_record
;
317 rtx_insn
*use_insn
= NULL
;
321 def_record
= DF_INSN_DEFS (sethi
);
323 for (link
= DF_REF_CHAIN (def_record
); link
; link
= link
->next
)
325 if (!DF_REF_INSN_INFO (link
->ref
))
328 use_insn
= DF_REF_INSN (link
->ref
);
330 /* Skip if define insn and use insn not in the same basic block. */
331 if (!dominated_by_p (CDI_DOMINATORS
,
332 BLOCK_FOR_INSN (use_insn
),
333 BLOCK_FOR_INSN (sethi
)))
336 /* Skip if the low-part used register is from different high-part
338 use_record
= DF_INSN_USES (use_insn
);
339 if (DF_REF_CHAIN (use_record
) && DF_REF_CHAIN (use_record
)->next
)
342 /* Skip if use_insn not active insn. */
343 if (!active_insn_p (use_insn
))
346 /* Initial use_insn_type. */
347 if (!(recog_memoized (use_insn
) == CODE_FOR_lo_sum
348 || nds32_symbol_load_store_p (use_insn
)
349 || (nds32_reg_base_load_store_p (use_insn
)
350 &&!nds32_sp_base_or_plus_load_store_p (use_insn
))))
354 group_id
= GEN_INT (nds32_alloc_relax_group_id ());
355 /* Insert .relax_* directive for sethi. */
356 emit_insn_before (gen_relax_group (group_id
), sethi
);
358 /* Scan the use insns and insert the directive. */
359 for (link
= DF_REF_CHAIN (def_record
); link
; link
= link
->next
)
361 if (!DF_REF_INSN_INFO (link
->ref
))
364 use_insn
= DF_REF_INSN (link
->ref
);
366 /* Insert .relax_* directive. */
367 if (active_insn_p (use_insn
))
368 emit_insn_before (gen_relax_group (group_id
), use_insn
);
370 /* Find ori ra, ra, unspec(symbol) instruction. */
372 && recog_memoized (use_insn
) == CODE_FOR_lo_sum
373 && !nds32_const_unspec_p (XEXP (SET_SRC (PATTERN (use_insn
)), 1)))
375 int sym_type
= nds32_pic_tls_symbol_type (use_insn
);
376 valid
= nds32_pic_tls_group (use_insn
, RELAX_ORI
, sym_type
);
378 /* Insert .relax_* directive. */
379 while (!nds32_group_infos
.is_empty ())
381 use_insn
= nds32_group_infos
.pop ();
383 emit_insn_before (gen_relax_group (group_id
), use_insn
);
389 /* Convert relax group id in rtl. */
392 nds32_group_tls_insn (rtx insn
)
394 rtx pat
= PATTERN (insn
);
395 rtx unspec_relax_group
= XEXP (XVECEXP (pat
, 0, 1), 0);
396 int group_id
= nds32_alloc_relax_group_id ();
398 while (GET_CODE (pat
) != SET
&& GET_CODE (pat
) == PARALLEL
)
400 pat
= XVECEXP (pat
, 0, 0);
403 if (GET_CODE (unspec_relax_group
) == UNSPEC
404 && XINT (unspec_relax_group
, 1) == UNSPEC_VOLATILE_RELAX_GROUP
)
406 XVECEXP (unspec_relax_group
, 0, 0) = GEN_INT (group_id
);
411 nds32_float_reg_load_store_p (rtx_insn
*insn
)
413 rtx pat
= PATTERN (insn
);
415 if (get_attr_type (insn
) == TYPE_FLOAD
416 && GET_CODE (pat
) == SET
417 && (GET_MODE (XEXP (pat
, 0)) == SFmode
418 || GET_MODE (XEXP (pat
, 0)) == DFmode
)
419 && MEM_P (XEXP (pat
, 1)))
421 rtx addr
= XEXP (XEXP (pat
, 1), 0);
427 if (GET_CODE (addr
) == PLUS
428 && REG_P (XEXP (addr
, 0))
429 && CONST_INT_P (XEXP (addr
, 1)))
436 /* Group float load-store instructions:
438 flsi $rt, [$ra + offset] */
441 nds32_group_float_insns (rtx_insn
*insn
)
443 df_ref def_record
, use_record
;
445 rtx_insn
*use_insn
= NULL
;
448 def_record
= DF_INSN_DEFS (insn
);
450 for (link
= DF_REF_CHAIN (def_record
); link
; link
= link
->next
)
452 if (!DF_REF_INSN_INFO (link
->ref
))
455 use_insn
= DF_REF_INSN (link
->ref
);
457 /* Skip if define insn and use insn not in the same basic block. */
458 if (!dominated_by_p (CDI_DOMINATORS
,
459 BLOCK_FOR_INSN (use_insn
),
460 BLOCK_FOR_INSN (insn
)))
463 /* Skip if the low-part used register is from different high-part
465 use_record
= DF_INSN_USES (use_insn
);
466 if (DF_REF_CHAIN (use_record
) && DF_REF_CHAIN (use_record
)->next
)
469 /* Skip if use_insn not active insn. */
470 if (!active_insn_p (use_insn
))
473 if (!nds32_float_reg_load_store_p (use_insn
)
474 || find_post_update_rtx (use_insn
) != -1)
478 group_id
= GEN_INT (nds32_alloc_relax_group_id ());
479 /* Insert .relax_* directive for insn. */
480 emit_insn_before (gen_relax_group (group_id
), insn
);
482 /* Scan the use insns and insert the directive. */
483 for (link
= DF_REF_CHAIN (def_record
); link
; link
= link
->next
)
485 if (!DF_REF_INSN_INFO (link
->ref
))
488 use_insn
= DF_REF_INSN (link
->ref
);
490 /* Insert .relax_* directive. */
491 emit_insn_before (gen_relax_group (group_id
), use_insn
);
495 /* Group the relax candidate instructions for linker. */
497 nds32_relax_group (void)
501 compute_bb_for_insn ();
503 df_chain_add_problem (DF_DU_CHAIN
| DF_UD_CHAIN
);
504 df_insn_rescan_all ();
506 df_set_flags (DF_DEFER_INSN_RESCAN
);
507 calculate_dominance_info (CDI_DOMINATORS
);
510 gcc_assert (NOTE_P (insn
));
512 for (insn
= next_active_insn (insn
); insn
; insn
= next_active_insn (insn
))
514 if (NONJUMP_INSN_P (insn
))
516 /* Find sethi ra, symbol instruction. */
517 if (recog_memoized (insn
) == CODE_FOR_sethi
518 && nds32_symbolic_operand (XEXP (SET_SRC (PATTERN (insn
)), 0),
520 && !nds32_ict_const_p (XEXP (SET_SRC (PATTERN (insn
)), 0)))
521 nds32_group_insns (insn
);
522 else if (recog_memoized (insn
) == CODE_FOR_tls_ie
)
523 nds32_group_tls_insn (insn
);
524 else if (TARGET_FPU_SINGLE
525 && recog_memoized (insn
) == CODE_FOR_move_addr
526 && !nds32_ict_const_p (XEXP (SET_SRC (PATTERN (insn
)), 0)))
528 nds32_group_float_insns (insn
);
531 else if (CALL_P (insn
) && recog_memoized (insn
) == CODE_FOR_tls_desc
)
533 nds32_group_tls_insn (insn
);
537 /* We must call df_finish_pass manually because it should be invoked before
538 BB information is destroyed. Hence we cannot set the TODO_df_finish flag
539 to the pass manager. */
540 df_insn_rescan_all ();
541 df_finish_pass (false);
542 free_dominance_info (CDI_DOMINATORS
);
546 nds32_relax_opt (void)
548 if (TARGET_RELAX_HINT
)
549 nds32_relax_group ();
553 const pass_data pass_data_nds32_relax_opt
=
556 "relax_opt", /* name */
557 OPTGROUP_NONE
, /* optinfo_flags */
558 TV_MACH_DEP
, /* tv_id */
559 0, /* properties_required */
560 0, /* properties_provided */
561 0, /* properties_destroyed */
562 0, /* todo_flags_start */
563 TODO_df_finish
, /* todo_flags_finish */
566 class pass_nds32_relax_opt
: public rtl_opt_pass
569 pass_nds32_relax_opt (gcc::context
*ctxt
)
570 : rtl_opt_pass (pass_data_nds32_relax_opt
, ctxt
)
573 /* opt_pass methods: */
574 bool gate (function
*) { return TARGET_RELAX_HINT
; }
575 unsigned int execute (function
*) { return nds32_relax_opt (); }
579 make_pass_nds32_relax_opt (gcc::context
*ctxt
)
581 return new pass_nds32_relax_opt (ctxt
);