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 /* This is used to create unique relax hint id value. 56 The initial value is 0. */ 57 static int relax_group_id = 0; 58 59 /* Group the following pattern as relax candidates: 60 61 1. sethi $ra, hi20(sym) 62 ori $ra, $ra, lo12(sym) 63 ==> 64 addi.gp $ra, sym 65 66 2. sethi $ra, hi20(sym) 67 lwi $rb, [$ra + lo12(sym)] 68 ==> 69 lwi.gp $rb, [(sym)] 70 71 3. sethi $ra, hi20(sym) 72 ori $ra, $ra, lo12(sym) 73 lwi $rb, [$ra] 74 swi $rc, [$ra] 75 ==> 76 lwi37 $rb, [(sym)] 77 swi37 $rc, [(sym)] */ 78 79 /* Return true if is load/store with REG addressing mode 80 and memory mode is SImode. */ 81 static bool 82 nds32_reg_base_load_store_p (rtx_insn *insn) 83 { 84 rtx mem_src = NULL_RTX; 85 86 switch (get_attr_type (insn)) 87 { 88 case TYPE_LOAD: 89 mem_src = SET_SRC (PATTERN (insn)); 90 break; 91 case TYPE_STORE: 92 mem_src = SET_DEST (PATTERN (insn)); 93 break; 94 default: 95 break; 96 } 97 98 /* Find load/store insn with addressing mode is REG. */ 99 if (mem_src != NULL_RTX) 100 { 101 if ((GET_CODE (mem_src) == ZERO_EXTEND) 102 || (GET_CODE (mem_src) == SIGN_EXTEND)) 103 mem_src = XEXP (mem_src, 0); 104 105 if (GET_CODE (XEXP (mem_src, 0)) == REG) 106 return true; 107 } 108 109 return false; 110 } 111 112 /* Return true if insn is a sp/fp base or sp/fp plus load-store instruction. */ 113 114 static bool 115 nds32_sp_base_or_plus_load_store_p (rtx_insn *insn) 116 { 117 rtx mem_src = NULL_RTX; 118 119 switch (get_attr_type (insn)) 120 { 121 case TYPE_LOAD: 122 mem_src = SET_SRC (PATTERN (insn)); 123 break; 124 case TYPE_STORE: 125 mem_src = SET_DEST (PATTERN (insn)); 126 break; 127 default: 128 break; 129 } 130 /* Find load/store insn with addressing mode is REG. */ 131 if (mem_src != NULL_RTX) 132 { 133 if ((GET_CODE (mem_src) == ZERO_EXTEND) 134 || (GET_CODE (mem_src) == SIGN_EXTEND)) 135 mem_src = XEXP (mem_src, 0); 136 137 if ((GET_CODE (XEXP (mem_src, 0)) == PLUS)) 138 mem_src = XEXP (mem_src, 0); 139 140 if (REG_P (XEXP (mem_src, 0)) 141 && ((frame_pointer_needed 142 && REGNO (XEXP (mem_src, 0)) == FP_REGNUM) 143 || REGNO (XEXP (mem_src, 0)) == SP_REGNUM)) 144 return true; 145 } 146 147 return false; 148 } 149 150 /* Return true if is load with [REG + REG/CONST_INT] addressing mode. */ 151 static bool 152 nds32_plus_reg_load_store_p (rtx_insn *insn) 153 { 154 rtx mem_src = NULL_RTX; 155 156 switch (get_attr_type (insn)) 157 { 158 case TYPE_LOAD: 159 mem_src = SET_SRC (PATTERN (insn)); 160 break; 161 case TYPE_STORE: 162 mem_src = SET_DEST (PATTERN (insn)); 163 break; 164 default: 165 break; 166 } 167 168 /* Find load/store insn with addressing mode is [REG + REG/CONST]. */ 169 if (mem_src != NULL_RTX) 170 { 171 if ((GET_CODE (mem_src) == ZERO_EXTEND) 172 || (GET_CODE (mem_src) == SIGN_EXTEND)) 173 mem_src = XEXP (mem_src, 0); 174 175 if ((GET_CODE (XEXP (mem_src, 0)) == PLUS)) 176 mem_src = XEXP (mem_src, 0); 177 else 178 return false; 179 180 if (GET_CODE (XEXP (mem_src, 0)) == REG) 181 return true; 182 183 } 184 185 return false; 186 } 187 188 /* Group the relax candidates with group id. */ 189 static void 190 nds32_group_insns (rtx sethi) 191 { 192 df_ref def_record, use_record; 193 df_link *link; 194 rtx_insn *use_insn = NULL; 195 rtx group_id; 196 197 def_record = DF_INSN_DEFS (sethi); 198 199 for (link = DF_REF_CHAIN (def_record); link; link = link->next) 200 { 201 if (!DF_REF_INSN_INFO (link->ref)) 202 continue; 203 204 use_insn = DF_REF_INSN (link->ref); 205 206 /* Skip if define insn and use insn not in the same basic block. */ 207 if (!dominated_by_p (CDI_DOMINATORS, 208 BLOCK_FOR_INSN (use_insn), 209 BLOCK_FOR_INSN (sethi))) 210 return; 211 212 /* Skip if the low-part used register is from different high-part 213 instructions. */ 214 use_record = DF_INSN_USES (use_insn); 215 if (DF_REF_CHAIN (use_record) && DF_REF_CHAIN (use_record)->next) 216 return; 217 218 /* Skip if use_insn not active insn. */ 219 if (!active_insn_p (use_insn)) 220 return; 221 222 /* Initial use_insn_type. */ 223 if (!(recog_memoized (use_insn) == CODE_FOR_lo_sum 224 || nds32_symbol_load_store_p (use_insn) 225 || (nds32_reg_base_load_store_p (use_insn) 226 &&!nds32_sp_base_or_plus_load_store_p (use_insn)))) 227 return; 228 } 229 230 group_id = GEN_INT (relax_group_id); 231 /* Insert .relax_* directive for sethi. */ 232 emit_insn_before (gen_relax_group (group_id), sethi); 233 234 /* Scan the use insns and insert the directive. */ 235 for (link = DF_REF_CHAIN (def_record); link; link = link->next) 236 { 237 if (!DF_REF_INSN_INFO (link->ref)) 238 continue; 239 240 use_insn = DF_REF_INSN (link->ref); 241 242 /* Insert .relax_* directive. */ 243 if (active_insn_p (use_insn)) 244 emit_insn_before (gen_relax_group (group_id), use_insn); 245 } 246 247 relax_group_id++; 248 } 249 250 /* Group the relax candidate instructions for linker. */ 251 static void 252 nds32_relax_group (void) 253 { 254 rtx_insn *insn; 255 256 compute_bb_for_insn (); 257 258 df_chain_add_problem (DF_DU_CHAIN | DF_UD_CHAIN); 259 df_insn_rescan_all (); 260 df_analyze (); 261 df_set_flags (DF_DEFER_INSN_RESCAN); 262 calculate_dominance_info (CDI_DOMINATORS); 263 264 insn = get_insns (); 265 gcc_assert (NOTE_P (insn)); 266 267 for (insn = next_active_insn (insn); insn; insn = next_active_insn (insn)) 268 { 269 if (NONJUMP_INSN_P (insn)) 270 { 271 /* Find sethi ra, symbol instruction. */ 272 if (recog_memoized (insn) == CODE_FOR_sethi 273 && nds32_symbolic_operand (XEXP (SET_SRC (PATTERN (insn)), 0), 274 SImode)) 275 nds32_group_insns (insn); 276 } 277 } 278 279 /* We must call df_finish_pass manually because it should be invoked before 280 BB information is destroyed. Hence we cannot set the TODO_df_finish flag 281 to the pass manager. */ 282 df_insn_rescan_all (); 283 df_finish_pass (false); 284 free_dominance_info (CDI_DOMINATORS); 285 } 286 287 static unsigned int 288 nds32_relax_opt (void) 289 { 290 if (TARGET_RELAX_HINT) 291 nds32_relax_group (); 292 return 1; 293 } 294 295 const pass_data pass_data_nds32_relax_opt = 296 { 297 RTL_PASS, /* type */ 298 "relax_opt", /* name */ 299 OPTGROUP_NONE, /* optinfo_flags */ 300 TV_MACH_DEP, /* tv_id */ 301 0, /* properties_required */ 302 0, /* properties_provided */ 303 0, /* properties_destroyed */ 304 0, /* todo_flags_start */ 305 TODO_df_finish, /* todo_flags_finish */ 306 }; 307 308 class pass_nds32_relax_opt : public rtl_opt_pass 309 { 310 public: 311 pass_nds32_relax_opt (gcc::context *ctxt) 312 : rtl_opt_pass (pass_data_nds32_relax_opt, ctxt) 313 {} 314 315 /* opt_pass methods: */ 316 bool gate (function *) { return TARGET_RELAX_HINT; } 317 unsigned int execute (function *) { return nds32_relax_opt (); } 318 }; 319 320 rtl_opt_pass * 321 make_pass_nds32_relax_opt (gcc::context *ctxt) 322 { 323 return new pass_nds32_relax_opt (ctxt); 324 } 325