1 /* Auxiliary functions for pipeline descriptions pattern of Andes 2 NDS32 cpu for GNU compiler 3 Copyright (C) 2012-2019 Free Software Foundation, Inc. 4 Contributed by Andes Technology Corporation. 5 6 This file is part of GCC. 7 8 GCC is free software; you can redistribute it and/or modify it 9 under the terms of the GNU General Public License as published 10 by the Free Software Foundation; either version 3, or (at your 11 option) any later version. 12 13 GCC is distributed in the hope that it will be useful, but WITHOUT 14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 15 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 16 License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with GCC; see the file COPYING3. If not see 20 <http://www.gnu.org/licenses/>. */ 21 22 /* ------------------------------------------------------------------------ */ 23 24 #define IN_TARGET_CODE 1 25 26 #include "config.h" 27 #include "system.h" 28 #include "coretypes.h" 29 #include "backend.h" 30 #include "target.h" 31 #include "rtl.h" 32 #include "tree.h" 33 #include "memmodel.h" 34 #include "tm_p.h" 35 #include "optabs.h" /* For GEN_FCN. */ 36 #include "recog.h" 37 #include "tm-constrs.h" 38 #include "insn-attr.h" 39 40 41 namespace nds32 { 42 43 /* Get the rtx in the PATTERN field of an insn. If INSN is not an insn, 44 the funciton doesn't change anything and returns it directly. */ 45 rtx 46 extract_pattern_from_insn (rtx insn) 47 { 48 if (INSN_P (insn)) 49 return PATTERN (insn); 50 51 return insn; 52 } 53 54 /* Get the number of elements in a parallel rtx. */ 55 size_t 56 parallel_elements (rtx parallel_rtx) 57 { 58 parallel_rtx = extract_pattern_from_insn (parallel_rtx); 59 gcc_assert (GET_CODE (parallel_rtx) == PARALLEL); 60 61 return XVECLEN (parallel_rtx, 0); 62 } 63 64 /* Extract an rtx from a parallel rtx with index NTH. If NTH is a negative 65 value, the function returns the last NTH rtx. */ 66 rtx 67 parallel_element (rtx parallel_rtx, int nth) 68 { 69 parallel_rtx = extract_pattern_from_insn (parallel_rtx); 70 gcc_assert (GET_CODE (parallel_rtx) == PARALLEL); 71 72 int len = parallel_elements (parallel_rtx); 73 74 if (nth >= 0) 75 { 76 if (nth >= len) 77 return NULL_RTX; 78 79 return XVECEXP (parallel_rtx, 0, nth); 80 } 81 else 82 { 83 if (len + nth < 0) 84 return NULL_RTX; 85 86 return XVECEXP (parallel_rtx, 0, len + nth); 87 } 88 } 89 90 /* Functions to determine whether INSN is single-word, double-word 91 or partial-word load/store insn. */ 92 93 bool 94 load_single_p (rtx_insn *insn) 95 { 96 if (get_attr_type (insn) != TYPE_LOAD) 97 return false; 98 99 if (INSN_CODE (insn) == CODE_FOR_move_di || 100 INSN_CODE (insn) == CODE_FOR_move_df) 101 return false; 102 103 return true; 104 } 105 106 bool 107 store_single_p (rtx_insn *insn) 108 { 109 if (get_attr_type (insn) != TYPE_STORE) 110 return false; 111 112 if (INSN_CODE (insn) == CODE_FOR_move_di || 113 INSN_CODE (insn) == CODE_FOR_move_df) 114 return false; 115 116 return true; 117 } 118 119 bool 120 load_double_p (rtx_insn *insn) 121 { 122 if (get_attr_type (insn) != TYPE_LOAD) 123 return false; 124 125 if (INSN_CODE (insn) != CODE_FOR_move_di && 126 INSN_CODE (insn) != CODE_FOR_move_df) 127 return false; 128 129 return true; 130 } 131 132 bool 133 store_double_p (rtx_insn *insn) 134 { 135 if (get_attr_type (insn) != TYPE_STORE) 136 return false; 137 138 if (INSN_CODE (insn) != CODE_FOR_move_di && 139 INSN_CODE (insn) != CODE_FOR_move_df) 140 return false; 141 142 return true; 143 } 144 145 bool 146 store_offset_reg_p (rtx_insn *insn) 147 { 148 if (get_attr_type (insn) != TYPE_STORE) 149 return false; 150 151 rtx offset_rtx = extract_offset_rtx (insn); 152 153 if (offset_rtx == NULL_RTX) 154 return false; 155 156 if (REG_P (offset_rtx)) 157 return true; 158 159 return false; 160 } 161 162 /* Determine if INSN is a post update insn. */ 163 bool 164 post_update_insn_p (rtx_insn *insn) 165 { 166 if (find_post_update_rtx (insn) == -1) 167 return false; 168 else 169 return true; 170 } 171 172 /* Check if the address of MEM_RTX consists of a base register and an 173 immediate offset. */ 174 bool 175 immed_offset_p (rtx mem_rtx) 176 { 177 gcc_assert (MEM_P (mem_rtx)); 178 179 rtx addr_rtx = XEXP (mem_rtx, 0); 180 181 /* (mem (reg)) is equivalent to (mem (plus (reg) (const_int 0))) */ 182 if (REG_P (addr_rtx)) 183 return true; 184 185 /* (mem (plus (reg) (const_int))) */ 186 if (GET_CODE (addr_rtx) == PLUS 187 && GET_CODE (XEXP (addr_rtx, 1)) == CONST_INT) 188 return true; 189 190 return false; 191 } 192 193 /* Find the post update rtx in INSN. If INSN is a load/store multiple insn, 194 the function returns the vector index of its parallel part. If INSN is a 195 single load/store insn, the function returns 0. If INSN is not a post- 196 update insn, the function returns -1. */ 197 int 198 find_post_update_rtx (rtx_insn *insn) 199 { 200 rtx mem_rtx; 201 int i, len; 202 203 switch (get_attr_type (insn)) 204 { 205 case TYPE_LOAD_MULTIPLE: 206 case TYPE_STORE_MULTIPLE: 207 /* Find a pattern in a parallel rtx: 208 (set (reg) (plus (reg) (const_int))) */ 209 len = parallel_elements (insn); 210 for (i = 0; i < len; ++i) 211 { 212 rtx curr_insn = parallel_element (insn, i); 213 214 if (GET_CODE (curr_insn) == SET 215 && REG_P (SET_DEST (curr_insn)) 216 && GET_CODE (SET_SRC (curr_insn)) == PLUS) 217 return i; 218 } 219 return -1; 220 221 case TYPE_LOAD: 222 case TYPE_FLOAD: 223 case TYPE_STORE: 224 case TYPE_FSTORE: 225 mem_rtx = extract_mem_rtx (insn); 226 /* (mem (post_inc (reg))) */ 227 switch (GET_CODE (XEXP (mem_rtx, 0))) 228 { 229 case POST_INC: 230 case POST_DEC: 231 case POST_MODIFY: 232 return 0; 233 234 default: 235 return -1; 236 } 237 238 default: 239 gcc_unreachable (); 240 } 241 } 242 243 /* Extract the MEM rtx from a load/store insn. */ 244 rtx 245 extract_mem_rtx (rtx_insn *insn) 246 { 247 rtx body = PATTERN (insn); 248 249 switch (get_attr_type (insn)) 250 { 251 case TYPE_LOAD: 252 case TYPE_FLOAD: 253 if (MEM_P (SET_SRC (body))) 254 return SET_SRC (body); 255 256 /* unaligned address: (unspec [(mem)]) */ 257 if (GET_CODE (SET_SRC (body)) == UNSPEC) 258 { 259 gcc_assert (MEM_P (XVECEXP (SET_SRC (body), 0, 0))); 260 return XVECEXP (SET_SRC (body), 0, 0); 261 } 262 263 /* (sign_extend (mem)) */ 264 gcc_assert (MEM_P (XEXP (SET_SRC (body), 0))); 265 return XEXP (SET_SRC (body), 0); 266 267 case TYPE_STORE: 268 case TYPE_FSTORE: 269 if (MEM_P (SET_DEST (body))) 270 return SET_DEST (body); 271 272 /* unaligned address: (unspec [(mem)]) */ 273 if (GET_CODE (SET_DEST (body)) == UNSPEC) 274 { 275 gcc_assert (MEM_P (XVECEXP (SET_DEST (body), 0, 0))); 276 return XVECEXP (SET_DEST (body), 0, 0); 277 } 278 279 /* (sign_extend (mem)) */ 280 gcc_assert (MEM_P (XEXP (SET_DEST (body), 0))); 281 return XEXP (SET_DEST (body), 0); 282 283 default: 284 gcc_unreachable (); 285 } 286 } 287 288 /* Extract the base register from load/store insns. The function returns 289 NULL_RTX if the address is not consist of any registers. */ 290 rtx 291 extract_base_reg (rtx_insn *insn) 292 { 293 int post_update_rtx_index; 294 rtx mem_rtx; 295 rtx plus_rtx; 296 297 /* Find the MEM rtx. If we can find an insn updating the base register, 298 the base register will be returned directly. */ 299 switch (get_attr_type (insn)) 300 { 301 case TYPE_LOAD_MULTIPLE: 302 post_update_rtx_index = find_post_update_rtx (insn); 303 304 if (post_update_rtx_index != -1) 305 return SET_DEST (parallel_element (insn, post_update_rtx_index)); 306 307 mem_rtx = SET_SRC (parallel_element (insn, 0)); 308 break; 309 310 case TYPE_STORE_MULTIPLE: 311 post_update_rtx_index = find_post_update_rtx (insn); 312 313 if (post_update_rtx_index != -1) 314 return SET_DEST (parallel_element (insn, post_update_rtx_index)); 315 316 mem_rtx = SET_DEST (parallel_element (insn, 0)); 317 break; 318 319 case TYPE_LOAD: 320 case TYPE_FLOAD: 321 case TYPE_STORE: 322 case TYPE_FSTORE: 323 mem_rtx = extract_mem_rtx (insn); 324 break; 325 326 default: 327 gcc_unreachable (); 328 } 329 330 gcc_assert (MEM_P (mem_rtx)); 331 332 /* (mem (reg)) */ 333 if (REG_P (XEXP (mem_rtx, 0))) 334 return XEXP (mem_rtx, 0); 335 336 /* (mem (lo_sum (reg) (symbol_ref)) */ 337 if (GET_CODE (XEXP (mem_rtx, 0)) == LO_SUM) 338 return XEXP (XEXP (mem_rtx, 0), 0); 339 340 plus_rtx = XEXP (mem_rtx, 0); 341 342 if (GET_CODE (plus_rtx) == SYMBOL_REF 343 || GET_CODE (plus_rtx) == CONST) 344 return NULL_RTX; 345 346 /* (mem (plus (reg) (const_int))) or 347 (mem (plus (mult (reg) (const_int 4)) (reg))) or 348 (mem (post_inc (reg))) or 349 (mem (post_dec (reg))) or 350 (mem (post_modify (reg) (plus (reg) (reg)))) */ 351 gcc_assert (GET_CODE (plus_rtx) == PLUS 352 || GET_CODE (plus_rtx) == POST_INC 353 || GET_CODE (plus_rtx) == POST_DEC 354 || GET_CODE (plus_rtx) == POST_MODIFY); 355 356 if (REG_P (XEXP (plus_rtx, 0))) 357 return XEXP (plus_rtx, 0); 358 359 gcc_assert (REG_P (XEXP (plus_rtx, 1))); 360 return XEXP (plus_rtx, 1); 361 } 362 363 /* Extract the offset rtx from load/store insns. The function returns 364 NULL_RTX if offset is absent. */ 365 rtx 366 extract_offset_rtx (rtx_insn *insn) 367 { 368 rtx mem_rtx; 369 rtx plus_rtx; 370 rtx offset_rtx; 371 372 /* Find the MEM rtx. The multiple load/store insns doens't have 373 the offset field so we can return NULL_RTX here. */ 374 switch (get_attr_type (insn)) 375 { 376 case TYPE_LOAD_MULTIPLE: 377 case TYPE_STORE_MULTIPLE: 378 return NULL_RTX; 379 380 case TYPE_LOAD: 381 case TYPE_FLOAD: 382 case TYPE_STORE: 383 case TYPE_FSTORE: 384 mem_rtx = extract_mem_rtx (insn); 385 break; 386 387 default: 388 gcc_unreachable (); 389 } 390 391 gcc_assert (MEM_P (mem_rtx)); 392 393 /* (mem (reg)) */ 394 if (REG_P (XEXP (mem_rtx, 0))) 395 return NULL_RTX; 396 397 plus_rtx = XEXP (mem_rtx, 0); 398 399 switch (GET_CODE (plus_rtx)) 400 { 401 case SYMBOL_REF: 402 case CONST: 403 case POST_INC: 404 case POST_DEC: 405 return NULL_RTX; 406 407 case PLUS: 408 /* (mem (plus (reg) (const_int))) or 409 (mem (plus (mult (reg) (const_int 4)) (reg))) */ 410 if (REG_P (XEXP (plus_rtx, 0))) 411 offset_rtx = XEXP (plus_rtx, 1); 412 else 413 { 414 gcc_assert (REG_P (XEXP (plus_rtx, 1))); 415 offset_rtx = XEXP (plus_rtx, 0); 416 } 417 418 if (ARITHMETIC_P (offset_rtx)) 419 { 420 gcc_assert (GET_CODE (offset_rtx) == MULT); 421 gcc_assert (REG_P (XEXP (offset_rtx, 0))); 422 offset_rtx = XEXP (offset_rtx, 0); 423 } 424 break; 425 426 case LO_SUM: 427 /* (mem (lo_sum (reg) (symbol_ref)) */ 428 offset_rtx = XEXP (plus_rtx, 1); 429 break; 430 431 case POST_MODIFY: 432 /* (mem (post_modify (reg) (plus (reg) (reg / const_int)))) */ 433 gcc_assert (REG_P (XEXP (plus_rtx, 0))); 434 plus_rtx = XEXP (plus_rtx, 1); 435 gcc_assert (GET_CODE (plus_rtx) == PLUS); 436 offset_rtx = XEXP (plus_rtx, 0); 437 break; 438 439 default: 440 gcc_unreachable (); 441 } 442 443 return offset_rtx; 444 } 445 446 /* Extract the register of the shift operand from an ALU_SHIFT rtx. */ 447 rtx 448 extract_shift_reg (rtx alu_shift_rtx) 449 { 450 alu_shift_rtx = extract_pattern_from_insn (alu_shift_rtx); 451 452 rtx alu_rtx = SET_SRC (alu_shift_rtx); 453 rtx shift_rtx; 454 455 /* Various forms of ALU_SHIFT can be made by the combiner. 456 See the difference between add_slli and sub_slli in nds32.md. */ 457 if (REG_P (XEXP (alu_rtx, 0))) 458 shift_rtx = XEXP (alu_rtx, 1); 459 else 460 shift_rtx = XEXP (alu_rtx, 0); 461 462 return XEXP (shift_rtx, 0); 463 } 464 465 /* Check if INSN is a movd44 insn. */ 466 bool 467 movd44_insn_p (rtx_insn *insn) 468 { 469 if (get_attr_type (insn) == TYPE_ALU 470 && (INSN_CODE (insn) == CODE_FOR_move_di 471 || INSN_CODE (insn) == CODE_FOR_move_df)) 472 { 473 rtx body = PATTERN (insn); 474 gcc_assert (GET_CODE (body) == SET); 475 476 rtx src = SET_SRC (body); 477 rtx dest = SET_DEST (body); 478 479 if ((REG_P (src) || GET_CODE (src) == SUBREG) 480 && (REG_P (dest) || GET_CODE (dest) == SUBREG)) 481 return true; 482 483 return false; 484 } 485 486 return false; 487 } 488 489 /* Extract the second result (odd reg) of a movd44 insn. */ 490 rtx 491 extract_movd44_odd_reg (rtx_insn *insn) 492 { 493 gcc_assert (movd44_insn_p (insn)); 494 495 rtx def_reg = SET_DEST (PATTERN (insn)); 496 machine_mode mode; 497 498 gcc_assert (REG_P (def_reg) || GET_CODE (def_reg) == SUBREG); 499 switch (GET_MODE (def_reg)) 500 { 501 case E_DImode: 502 mode = SImode; 503 break; 504 505 case E_DFmode: 506 mode = SFmode; 507 break; 508 509 default: 510 gcc_unreachable (); 511 } 512 513 return gen_highpart (mode, def_reg); 514 } 515 516 /* Extract the rtx representing non-accumulation operands of a MAC insn. */ 517 rtx 518 extract_mac_non_acc_rtx (rtx_insn *insn) 519 { 520 rtx exp = SET_SRC (PATTERN (insn)); 521 522 switch (get_attr_type (insn)) 523 { 524 case TYPE_MAC: 525 case TYPE_DMAC: 526 if (REG_P (XEXP (exp, 0))) 527 return XEXP (exp, 1); 528 else 529 return XEXP (exp, 0); 530 531 default: 532 gcc_unreachable (); 533 } 534 } 535 536 /* Check if the DIV insn needs two write ports. */ 537 bool 538 divmod_p (rtx_insn *insn) 539 { 540 gcc_assert (get_attr_type (insn) == TYPE_DIV); 541 542 if (INSN_CODE (insn) == CODE_FOR_divmodsi4 543 || INSN_CODE (insn) == CODE_FOR_udivmodsi4) 544 return true; 545 546 return false; 547 } 548 549 /* Extract the rtx representing the branch target to help recognize 550 data hazards. */ 551 rtx 552 extract_branch_target_rtx (rtx_insn *insn) 553 { 554 gcc_assert (CALL_P (insn) || JUMP_P (insn)); 555 556 rtx body = PATTERN (insn); 557 558 if (GET_CODE (body) == SET) 559 { 560 /* RTXs in IF_THEN_ELSE are branch conditions. */ 561 if (GET_CODE (SET_SRC (body)) == IF_THEN_ELSE) 562 return NULL_RTX; 563 564 return SET_SRC (body); 565 } 566 567 if (GET_CODE (body) == CALL) 568 return XEXP (body, 0); 569 570 if (GET_CODE (body) == PARALLEL) 571 { 572 rtx first_rtx = parallel_element (body, 0); 573 574 if (GET_CODE (first_rtx) == SET) 575 return SET_SRC (first_rtx); 576 577 if (GET_CODE (first_rtx) == CALL) 578 return XEXP (first_rtx, 0); 579 } 580 581 /* Handle special cases of bltzal, bgezal and jralnez. */ 582 if (GET_CODE (body) == COND_EXEC) 583 { 584 rtx addr_rtx = XEXP (body, 1); 585 586 if (GET_CODE (addr_rtx) == SET) 587 return SET_SRC (addr_rtx); 588 589 if (GET_CODE (addr_rtx) == PARALLEL) 590 { 591 rtx first_rtx = parallel_element (addr_rtx, 0); 592 593 if (GET_CODE (first_rtx) == SET) 594 { 595 rtx call_rtx = SET_SRC (first_rtx); 596 gcc_assert (GET_CODE (call_rtx) == CALL); 597 598 return XEXP (call_rtx, 0); 599 } 600 601 if (GET_CODE (first_rtx) == CALL) 602 return XEXP (first_rtx, 0); 603 } 604 } 605 606 gcc_unreachable (); 607 } 608 609 /* Extract the rtx representing the branch condition to help recognize 610 data hazards. */ 611 rtx 612 extract_branch_condition_rtx (rtx_insn *insn) 613 { 614 gcc_assert (CALL_P (insn) || JUMP_P (insn)); 615 616 rtx body = PATTERN (insn); 617 618 if (GET_CODE (body) == SET) 619 { 620 rtx if_then_else_rtx = SET_SRC (body); 621 622 if (GET_CODE (if_then_else_rtx) == IF_THEN_ELSE) 623 return XEXP (if_then_else_rtx, 0); 624 625 return NULL_RTX; 626 } 627 628 if (GET_CODE (body) == COND_EXEC) 629 return XEXP (body, 0); 630 631 return NULL_RTX; 632 } 633 634 } // namespace nds32 635