1 /* Auxiliary functions for output asm template or expand rtl 2 pattern of Andes 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 "output.h" 38 #include "tm-constrs.h" 39 #include "expr.h" 40 #include "emit-rtl.h" 41 #include "explow.h" 42 #include "stringpool.h" 43 #include "attribs.h" 44 45 46 /* ------------------------------------------------------------------------ */ 47 48 static int 49 nds32_regno_to_enable4 (unsigned regno) 50 { 51 switch (regno) 52 { 53 case 28: /* $r28/fp */ 54 return 0x8; 55 case 29: /* $r29/gp */ 56 return 0x4; 57 case 30: /* $r30/lp */ 58 return 0x2; 59 case 31: /* $r31/sp */ 60 return 0x1; 61 default: 62 gcc_unreachable (); 63 } 64 } 65 66 /* A helper function to return character based on byte size. */ 67 static char 68 nds32_byte_to_size (int byte) 69 { 70 switch (byte) 71 { 72 case 4: 73 return 'w'; 74 case 2: 75 return 'h'; 76 case 1: 77 return 'b'; 78 default: 79 /* Normally it should not be here. */ 80 gcc_unreachable (); 81 } 82 } 83 84 static int 85 nds32_inverse_cond_code (int code) 86 { 87 switch (code) 88 { 89 case NE: 90 return EQ; 91 case EQ: 92 return NE; 93 case GT: 94 return LE; 95 case LE: 96 return GT; 97 case GE: 98 return LT; 99 case LT: 100 return GE; 101 default: 102 gcc_unreachable (); 103 } 104 } 105 106 static const char * 107 nds32_cond_code_str (int code) 108 { 109 switch (code) 110 { 111 case NE: 112 return "ne"; 113 case EQ: 114 return "eq"; 115 case GT: 116 return "gt"; 117 case LE: 118 return "le"; 119 case GE: 120 return "ge"; 121 case LT: 122 return "lt"; 123 default: 124 gcc_unreachable (); 125 } 126 } 127 128 static void 129 output_cond_branch (int code, const char *suffix, bool r5_p, 130 bool long_jump_p, rtx *operands) 131 { 132 char pattern[256]; 133 const char *cond_code; 134 bool align_p = NDS32_ALIGN_P (); 135 const char *align = align_p ? "\t.align\t2\n" : ""; 136 137 if (r5_p && REGNO (operands[2]) == 5 && TARGET_16_BIT) 138 { 139 /* This is special case for beqs38 and bnes38, 140 second operand 2 can't be $r5 and it's almost meanless, 141 however it may occur after copy propgation. */ 142 if (code == EQ) 143 { 144 /* $r5 == $r5 always taken! */ 145 if (long_jump_p) 146 snprintf (pattern, sizeof (pattern), 147 "j\t%%3"); 148 else 149 snprintf (pattern, sizeof (pattern), 150 "j8\t%%3"); 151 } 152 else 153 /* Don't output anything since $r5 != $r5 never taken! */ 154 pattern[0] = '\0'; 155 } 156 else if (long_jump_p) 157 { 158 int inverse_code = nds32_inverse_cond_code (code); 159 cond_code = nds32_cond_code_str (inverse_code); 160 161 /* b<cond><suffix> $r0, $r1, .L0 162 => 163 b<inverse_cond><suffix> $r0, $r1, .LCB0 164 j .L0 165 .LCB0: 166 167 or 168 169 b<cond><suffix> $r0, $r1, .L0 170 => 171 b<inverse_cond><suffix> $r0, $r1, .LCB0 172 j .L0 173 .LCB0: 174 */ 175 if (r5_p && TARGET_16_BIT) 176 { 177 snprintf (pattern, sizeof (pattern), 178 "b%ss38\t %%2, .LCB%%=\n\tj\t%%3\n%s.LCB%%=:", 179 cond_code, align); 180 } 181 else 182 { 183 snprintf (pattern, sizeof (pattern), 184 "b%s%s\t%%1, %%2, .LCB%%=\n\tj\t%%3\n%s.LCB%%=:", 185 cond_code, suffix, align); 186 } 187 } 188 else 189 { 190 cond_code = nds32_cond_code_str (code); 191 if (r5_p && TARGET_16_BIT) 192 { 193 /* b<cond>s38 $r1, .L0 */ 194 snprintf (pattern, sizeof (pattern), 195 "b%ss38\t %%2, %%3", cond_code); 196 } 197 else 198 { 199 /* b<cond><suffix> $r0, $r1, .L0 */ 200 snprintf (pattern, sizeof (pattern), 201 "b%s%s\t%%1, %%2, %%3", cond_code, suffix); 202 } 203 } 204 205 output_asm_insn (pattern, operands); 206 } 207 208 static void 209 output_cond_branch_compare_zero (int code, const char *suffix, 210 bool long_jump_p, rtx *operands, 211 bool ta_implied_p) 212 { 213 char pattern[256]; 214 const char *cond_code; 215 bool align_p = NDS32_ALIGN_P (); 216 const char *align = align_p ? "\t.align\t2\n" : ""; 217 if (long_jump_p) 218 { 219 int inverse_code = nds32_inverse_cond_code (code); 220 cond_code = nds32_cond_code_str (inverse_code); 221 222 if (ta_implied_p && TARGET_16_BIT) 223 { 224 /* b<cond>z<suffix> .L0 225 => 226 b<inverse_cond>z<suffix> .LCB0 227 j .L0 228 .LCB0: 229 */ 230 snprintf (pattern, sizeof (pattern), 231 "b%sz%s\t.LCB%%=\n\tj\t%%2\n%s.LCB%%=:", 232 cond_code, suffix, align); 233 } 234 else 235 { 236 /* b<cond>z<suffix> $r0, .L0 237 => 238 b<inverse_cond>z<suffix> $r0, .LCB0 239 j .L0 240 .LCB0: 241 */ 242 snprintf (pattern, sizeof (pattern), 243 "b%sz%s\t%%1, .LCB%%=\n\tj\t%%2\n%s.LCB%%=:", 244 cond_code, suffix, align); 245 } 246 } 247 else 248 { 249 cond_code = nds32_cond_code_str (code); 250 if (ta_implied_p && TARGET_16_BIT) 251 { 252 /* b<cond>z<suffix> .L0 */ 253 snprintf (pattern, sizeof (pattern), 254 "b%sz%s\t%%2", cond_code, suffix); 255 } 256 else 257 { 258 /* b<cond>z<suffix> $r0, .L0 */ 259 snprintf (pattern, sizeof (pattern), 260 "b%sz%s\t%%1, %%2", cond_code, suffix); 261 } 262 } 263 264 output_asm_insn (pattern, operands); 265 } 266 267 static void 268 nds32_split_shiftrtdi3 (rtx dst, rtx src, rtx shiftamount, bool logic_shift_p) 269 { 270 rtx src_high_part; 271 rtx dst_high_part, dst_low_part; 272 273 dst_high_part = nds32_di_high_part_subreg (dst); 274 src_high_part = nds32_di_high_part_subreg (src); 275 dst_low_part = nds32_di_low_part_subreg (dst); 276 277 if (CONST_INT_P (shiftamount)) 278 { 279 if (INTVAL (shiftamount) < 32) 280 { 281 if (logic_shift_p) 282 { 283 emit_insn (gen_uwext (dst_low_part, src, 284 shiftamount)); 285 emit_insn (gen_lshrsi3 (dst_high_part, src_high_part, 286 shiftamount)); 287 } 288 else 289 { 290 emit_insn (gen_wext (dst_low_part, src, 291 shiftamount)); 292 emit_insn (gen_ashrsi3 (dst_high_part, src_high_part, 293 shiftamount)); 294 } 295 } 296 else 297 { 298 rtx new_shift_amout = gen_int_mode(INTVAL (shiftamount) - 32, SImode); 299 300 if (logic_shift_p) 301 { 302 emit_insn (gen_lshrsi3 (dst_low_part, src_high_part, 303 new_shift_amout)); 304 emit_move_insn (dst_high_part, const0_rtx); 305 } 306 else 307 { 308 emit_insn (gen_ashrsi3 (dst_low_part, src_high_part, 309 new_shift_amout)); 310 emit_insn (gen_ashrsi3 (dst_high_part, src_high_part, 311 GEN_INT (31))); 312 } 313 } 314 } 315 else 316 { 317 rtx dst_low_part_l32, dst_high_part_l32; 318 rtx dst_low_part_g32, dst_high_part_g32; 319 rtx new_shift_amout, select_reg; 320 dst_low_part_l32 = gen_reg_rtx (SImode); 321 dst_high_part_l32 = gen_reg_rtx (SImode); 322 dst_low_part_g32 = gen_reg_rtx (SImode); 323 dst_high_part_g32 = gen_reg_rtx (SImode); 324 new_shift_amout = gen_reg_rtx (SImode); 325 select_reg = gen_reg_rtx (SImode); 326 327 emit_insn (gen_andsi3 (shiftamount, shiftamount, GEN_INT (0x3f))); 328 329 if (logic_shift_p) 330 { 331 /* 332 if (shiftamount < 32) 333 dst_low_part = wext (src, shiftamount) 334 dst_high_part = src_high_part >> shiftamount 335 else 336 dst_low_part = src_high_part >> (shiftamount & 0x1f) 337 dst_high_part = 0 338 */ 339 emit_insn (gen_uwext (dst_low_part_l32, src, shiftamount)); 340 emit_insn (gen_lshrsi3 (dst_high_part_l32, src_high_part, 341 shiftamount)); 342 343 emit_insn (gen_andsi3 (new_shift_amout, shiftamount, GEN_INT (0x1f))); 344 emit_insn (gen_lshrsi3 (dst_low_part_g32, src_high_part, 345 new_shift_amout)); 346 emit_move_insn (dst_high_part_g32, const0_rtx); 347 } 348 else 349 { 350 /* 351 if (shiftamount < 32) 352 dst_low_part = wext (src, shiftamount) 353 dst_high_part = src_high_part >> shiftamount 354 else 355 dst_low_part = src_high_part >> (shiftamount & 0x1f) 356 # shift 31 for sign extend 357 dst_high_part = src_high_part >> 31 358 */ 359 emit_insn (gen_wext (dst_low_part_l32, src, shiftamount)); 360 emit_insn (gen_ashrsi3 (dst_high_part_l32, src_high_part, 361 shiftamount)); 362 363 emit_insn (gen_andsi3 (new_shift_amout, shiftamount, GEN_INT (0x1f))); 364 emit_insn (gen_ashrsi3 (dst_low_part_g32, src_high_part, 365 new_shift_amout)); 366 emit_insn (gen_ashrsi3 (dst_high_part_g32, src_high_part, 367 GEN_INT (31))); 368 } 369 370 emit_insn (gen_slt_compare (select_reg, shiftamount, GEN_INT (32))); 371 372 emit_insn (gen_cmovnsi (dst_low_part, select_reg, 373 dst_low_part_l32, dst_low_part_g32)); 374 emit_insn (gen_cmovnsi (dst_high_part, select_reg, 375 dst_high_part_l32, dst_high_part_g32)); 376 } 377 } 378 379 /* ------------------------------------------------------------------------ */ 380 381 /* Auxiliary function for expand RTL pattern. */ 382 383 enum nds32_expand_result_type 384 nds32_expand_cbranch (rtx *operands) 385 { 386 rtx tmp_reg; 387 enum rtx_code code; 388 389 code = GET_CODE (operands[0]); 390 391 /* If operands[2] is (const_int 0), 392 we can use beqz,bnez,bgtz,bgez,bltz,or blez instructions. 393 So we have gcc generate original template rtx. */ 394 if (GET_CODE (operands[2]) == CONST_INT) 395 if (INTVAL (operands[2]) == 0) 396 if ((code != GTU) 397 && (code != GEU) 398 && (code != LTU) 399 && (code != LEU)) 400 return EXPAND_CREATE_TEMPLATE; 401 402 /* For other comparison, NDS32 ISA only has slt (Set-on-Less-Than) 403 behavior for the comparison, we might need to generate other 404 rtx patterns to achieve same semantic. */ 405 switch (code) 406 { 407 case GT: 408 case GTU: 409 if (GET_CODE (operands[2]) == CONST_INT) 410 { 411 /* GT reg_A, const_int => !(LT reg_A, const_int + 1) */ 412 if (optimize_size || optimize == 0) 413 tmp_reg = gen_rtx_REG (SImode, TA_REGNUM); 414 else 415 tmp_reg = gen_reg_rtx (SImode); 416 417 /* We want to plus 1 into the integer value 418 of operands[2] to create 'slt' instruction. 419 This caculation is performed on the host machine, 420 which may be 64-bit integer. 421 So the meaning of caculation result may be 422 different from the 32-bit nds32 target. 423 424 For example: 425 0x7fffffff + 0x1 -> 0x80000000, 426 this value is POSITIVE on 64-bit machine, 427 but the expected value on 32-bit nds32 target 428 should be NEGATIVE value. 429 430 Hence, instead of using GEN_INT(), we use gen_int_mode() to 431 explicitly create SImode constant rtx. */ 432 enum rtx_code cmp_code; 433 434 rtx plus1 = gen_int_mode (INTVAL (operands[2]) + 1, SImode); 435 if (satisfies_constraint_Is15 (plus1)) 436 { 437 operands[2] = plus1; 438 cmp_code = EQ; 439 if (code == GT) 440 { 441 /* GT, use slts instruction */ 442 emit_insn ( 443 gen_slts_compare (tmp_reg, operands[1], operands[2])); 444 } 445 else 446 { 447 /* GTU, use slt instruction */ 448 emit_insn ( 449 gen_slt_compare (tmp_reg, operands[1], operands[2])); 450 } 451 } 452 else 453 { 454 cmp_code = NE; 455 if (code == GT) 456 { 457 /* GT, use slts instruction */ 458 emit_insn ( 459 gen_slts_compare (tmp_reg, operands[2], operands[1])); 460 } 461 else 462 { 463 /* GTU, use slt instruction */ 464 emit_insn ( 465 gen_slt_compare (tmp_reg, operands[2], operands[1])); 466 } 467 } 468 469 PUT_CODE (operands[0], cmp_code); 470 operands[1] = tmp_reg; 471 operands[2] = const0_rtx; 472 emit_insn (gen_cbranchsi4 (operands[0], operands[1], 473 operands[2], operands[3])); 474 475 return EXPAND_DONE; 476 } 477 else 478 { 479 /* GT reg_A, reg_B => LT reg_B, reg_A */ 480 if (optimize_size || optimize == 0) 481 tmp_reg = gen_rtx_REG (SImode, TA_REGNUM); 482 else 483 tmp_reg = gen_reg_rtx (SImode); 484 485 if (code == GT) 486 { 487 /* GT, use slts instruction */ 488 emit_insn (gen_slts_compare (tmp_reg, operands[2], operands[1])); 489 } 490 else 491 { 492 /* GTU, use slt instruction */ 493 emit_insn (gen_slt_compare (tmp_reg, operands[2], operands[1])); 494 } 495 496 PUT_CODE (operands[0], NE); 497 operands[1] = tmp_reg; 498 operands[2] = const0_rtx; 499 emit_insn (gen_cbranchsi4 (operands[0], operands[1], 500 operands[2], operands[3])); 501 502 return EXPAND_DONE; 503 } 504 505 case GE: 506 case GEU: 507 /* GE reg_A, reg_B => !(LT reg_A, reg_B) */ 508 /* GE reg_A, const_int => !(LT reg_A, const_int) */ 509 if (optimize_size || optimize == 0) 510 tmp_reg = gen_rtx_REG (SImode, TA_REGNUM); 511 else 512 tmp_reg = gen_reg_rtx (SImode); 513 514 if (code == GE) 515 { 516 /* GE, use slts instruction */ 517 emit_insn (gen_slts_compare (tmp_reg, operands[1], operands[2])); 518 } 519 else 520 { 521 /* GEU, use slt instruction */ 522 emit_insn (gen_slt_compare (tmp_reg, operands[1], operands[2])); 523 } 524 525 PUT_CODE (operands[0], EQ); 526 operands[1] = tmp_reg; 527 operands[2] = const0_rtx; 528 emit_insn (gen_cbranchsi4 (operands[0], operands[1], 529 operands[2], operands[3])); 530 531 return EXPAND_DONE; 532 533 case LT: 534 case LTU: 535 /* LT reg_A, reg_B => LT reg_A, reg_B */ 536 /* LT reg_A, const_int => LT reg_A, const_int */ 537 if (optimize_size || optimize == 0) 538 tmp_reg = gen_rtx_REG (SImode, TA_REGNUM); 539 else 540 tmp_reg = gen_reg_rtx (SImode); 541 542 if (code == LT) 543 { 544 /* LT, use slts instruction */ 545 emit_insn (gen_slts_compare (tmp_reg, operands[1], operands[2])); 546 } 547 else 548 { 549 /* LTU, use slt instruction */ 550 emit_insn (gen_slt_compare (tmp_reg, operands[1], operands[2])); 551 } 552 553 PUT_CODE (operands[0], NE); 554 operands[1] = tmp_reg; 555 operands[2] = const0_rtx; 556 emit_insn (gen_cbranchsi4 (operands[0], operands[1], 557 operands[2], operands[3])); 558 559 return EXPAND_DONE; 560 561 case LE: 562 case LEU: 563 if (GET_CODE (operands[2]) == CONST_INT) 564 { 565 /* LE reg_A, const_int => LT reg_A, const_int + 1 */ 566 if (optimize_size || optimize == 0) 567 tmp_reg = gen_rtx_REG (SImode, TA_REGNUM); 568 else 569 tmp_reg = gen_reg_rtx (SImode); 570 571 enum rtx_code cmp_code; 572 /* Note that (le:SI X INT_MAX) is not the same as (lt:SI X INT_MIN). 573 We better have an assert here in case GCC does not properly 574 optimize it away. The INT_MAX here is 0x7fffffff for target. */ 575 rtx plus1 = gen_int_mode (INTVAL (operands[2]) + 1, SImode); 576 if (satisfies_constraint_Is15 (plus1)) 577 { 578 operands[2] = plus1; 579 cmp_code = NE; 580 if (code == LE) 581 { 582 /* LE, use slts instruction */ 583 emit_insn ( 584 gen_slts_compare (tmp_reg, operands[1], operands[2])); 585 } 586 else 587 { 588 /* LEU, use slt instruction */ 589 emit_insn ( 590 gen_slt_compare (tmp_reg, operands[1], operands[2])); 591 } 592 } 593 else 594 { 595 cmp_code = EQ; 596 if (code == LE) 597 { 598 /* LE, use slts instruction */ 599 emit_insn ( 600 gen_slts_compare (tmp_reg, operands[2], operands[1])); 601 } 602 else 603 { 604 /* LEU, use slt instruction */ 605 emit_insn ( 606 gen_slt_compare (tmp_reg, operands[2], operands[1])); 607 } 608 } 609 610 PUT_CODE (operands[0], cmp_code); 611 operands[1] = tmp_reg; 612 operands[2] = const0_rtx; 613 emit_insn (gen_cbranchsi4 (operands[0], operands[1], 614 operands[2], operands[3])); 615 616 return EXPAND_DONE; 617 } 618 else 619 { 620 /* LE reg_A, reg_B => !(LT reg_B, reg_A) */ 621 if (optimize_size || optimize == 0) 622 tmp_reg = gen_rtx_REG (SImode, TA_REGNUM); 623 else 624 tmp_reg = gen_reg_rtx (SImode); 625 626 if (code == LE) 627 { 628 /* LE, use slts instruction */ 629 emit_insn (gen_slts_compare (tmp_reg, operands[2], operands[1])); 630 } 631 else 632 { 633 /* LEU, use slt instruction */ 634 emit_insn (gen_slt_compare (tmp_reg, operands[2], operands[1])); 635 } 636 637 PUT_CODE (operands[0], EQ); 638 operands[1] = tmp_reg; 639 operands[2] = const0_rtx; 640 emit_insn (gen_cbranchsi4 (operands[0], operands[1], 641 operands[2], operands[3])); 642 643 return EXPAND_DONE; 644 } 645 646 case EQ: 647 case NE: 648 /* NDS32 ISA has various form for eq/ne behavior no matter 649 what kind of the operand is. 650 So just generate original template rtx. */ 651 652 /* Put operands[2] into register if operands[2] is a large 653 const_int or ISAv2. */ 654 if (GET_CODE (operands[2]) == CONST_INT 655 && (!satisfies_constraint_Is11 (operands[2]) 656 || TARGET_ISA_V2)) 657 operands[2] = force_reg (SImode, operands[2]); 658 659 return EXPAND_CREATE_TEMPLATE; 660 661 default: 662 return EXPAND_FAIL; 663 } 664 } 665 666 enum nds32_expand_result_type 667 nds32_expand_cstore (rtx *operands) 668 { 669 rtx tmp_reg; 670 enum rtx_code code; 671 672 code = GET_CODE (operands[1]); 673 674 switch (code) 675 { 676 case EQ: 677 case NE: 678 if (GET_CODE (operands[3]) == CONST_INT) 679 { 680 /* reg_R = (reg_A == const_int_B) 681 --> xori reg_C, reg_A, const_int_B 682 slti reg_R, reg_C, const_int_1 683 reg_R = (reg_A != const_int_B) 684 --> xori reg_C, reg_A, const_int_B 685 slti reg_R, const_int0, reg_C */ 686 tmp_reg = gen_reg_rtx (SImode); 687 688 /* If the integer value is not in the range of imm15s, 689 we need to force register first because our addsi3 pattern 690 only accept nds32_rimm15s_operand predicate. */ 691 rtx new_imm = gen_int_mode (-INTVAL (operands[3]), SImode); 692 if (satisfies_constraint_Is15 (new_imm)) 693 emit_insn (gen_addsi3 (tmp_reg, operands[2], new_imm)); 694 else 695 { 696 if (!(satisfies_constraint_Iu15 (operands[3]) 697 || (TARGET_EXT_PERF 698 && satisfies_constraint_It15 (operands[3])))) 699 operands[3] = force_reg (SImode, operands[3]); 700 emit_insn (gen_xorsi3 (tmp_reg, operands[2], operands[3])); 701 } 702 703 if (code == EQ) 704 emit_insn (gen_slt_eq0 (operands[0], tmp_reg)); 705 else 706 emit_insn (gen_slt_compare (operands[0], const0_rtx, tmp_reg)); 707 708 return EXPAND_DONE; 709 } 710 else 711 { 712 /* reg_R = (reg_A == reg_B) 713 --> xor reg_C, reg_A, reg_B 714 slti reg_R, reg_C, const_int_1 715 reg_R = (reg_A != reg_B) 716 --> xor reg_C, reg_A, reg_B 717 slti reg_R, const_int0, reg_C */ 718 tmp_reg = gen_reg_rtx (SImode); 719 emit_insn (gen_xorsi3 (tmp_reg, operands[2], operands[3])); 720 if (code == EQ) 721 emit_insn (gen_slt_eq0 (operands[0], tmp_reg)); 722 else 723 emit_insn (gen_slt_compare (operands[0], const0_rtx, tmp_reg)); 724 725 return EXPAND_DONE; 726 } 727 case GT: 728 case GTU: 729 /* reg_R = (reg_A > reg_B) --> slt reg_R, reg_B, reg_A */ 730 /* reg_R = (reg_A > const_int_B) --> slt reg_R, const_int_B, reg_A */ 731 if (code == GT) 732 { 733 /* GT, use slts instruction */ 734 emit_insn (gen_slts_compare (operands[0], operands[3], operands[2])); 735 } 736 else 737 { 738 /* GTU, use slt instruction */ 739 emit_insn (gen_slt_compare (operands[0], operands[3], operands[2])); 740 } 741 742 return EXPAND_DONE; 743 744 case GE: 745 case GEU: 746 if (GET_CODE (operands[3]) == CONST_INT) 747 { 748 /* reg_R = (reg_A >= const_int_B) 749 --> movi reg_C, const_int_B - 1 750 slt reg_R, reg_C, reg_A */ 751 tmp_reg = gen_reg_rtx (SImode); 752 753 emit_insn (gen_movsi (tmp_reg, 754 gen_int_mode (INTVAL (operands[3]) - 1, 755 SImode))); 756 if (code == GE) 757 { 758 /* GE, use slts instruction */ 759 emit_insn (gen_slts_compare (operands[0], tmp_reg, operands[2])); 760 } 761 else 762 { 763 /* GEU, use slt instruction */ 764 emit_insn (gen_slt_compare (operands[0], tmp_reg, operands[2])); 765 } 766 767 return EXPAND_DONE; 768 } 769 else 770 { 771 /* reg_R = (reg_A >= reg_B) 772 --> slt reg_R, reg_A, reg_B 773 xori reg_R, reg_R, const_int_1 */ 774 if (code == GE) 775 { 776 /* GE, use slts instruction */ 777 emit_insn (gen_slts_compare (operands[0], 778 operands[2], operands[3])); 779 } 780 else 781 { 782 /* GEU, use slt instruction */ 783 emit_insn (gen_slt_compare (operands[0], 784 operands[2], operands[3])); 785 } 786 787 /* perform 'not' behavior */ 788 emit_insn (gen_xorsi3 (operands[0], operands[0], const1_rtx)); 789 790 return EXPAND_DONE; 791 } 792 793 case LT: 794 case LTU: 795 /* reg_R = (reg_A < reg_B) --> slt reg_R, reg_A, reg_B */ 796 /* reg_R = (reg_A < const_int_B) --> slt reg_R, reg_A, const_int_B */ 797 if (code == LT) 798 { 799 /* LT, use slts instruction */ 800 emit_insn (gen_slts_compare (operands[0], operands[2], operands[3])); 801 } 802 else 803 { 804 /* LTU, use slt instruction */ 805 emit_insn (gen_slt_compare (operands[0], operands[2], operands[3])); 806 } 807 808 return EXPAND_DONE; 809 810 case LE: 811 case LEU: 812 if (GET_CODE (operands[3]) == CONST_INT) 813 { 814 /* reg_R = (reg_A <= const_int_B) 815 --> movi reg_C, const_int_B + 1 816 slt reg_R, reg_A, reg_C */ 817 tmp_reg = gen_reg_rtx (SImode); 818 819 emit_insn (gen_movsi (tmp_reg, 820 gen_int_mode (INTVAL (operands[3]) + 1, 821 SImode))); 822 if (code == LE) 823 { 824 /* LE, use slts instruction */ 825 emit_insn (gen_slts_compare (operands[0], operands[2], tmp_reg)); 826 } 827 else 828 { 829 /* LEU, use slt instruction */ 830 emit_insn (gen_slt_compare (operands[0], operands[2], tmp_reg)); 831 } 832 833 return EXPAND_DONE; 834 } 835 else 836 { 837 /* reg_R = (reg_A <= reg_B) --> slt reg_R, reg_B, reg_A 838 xori reg_R, reg_R, const_int_1 */ 839 if (code == LE) 840 { 841 /* LE, use slts instruction */ 842 emit_insn (gen_slts_compare (operands[0], 843 operands[3], operands[2])); 844 } 845 else 846 { 847 /* LEU, use slt instruction */ 848 emit_insn (gen_slt_compare (operands[0], 849 operands[3], operands[2])); 850 } 851 852 /* perform 'not' behavior */ 853 emit_insn (gen_xorsi3 (operands[0], operands[0], const1_rtx)); 854 855 return EXPAND_DONE; 856 } 857 858 859 default: 860 gcc_unreachable (); 861 } 862 } 863 864 void 865 nds32_expand_float_cbranch (rtx *operands) 866 { 867 enum rtx_code code = GET_CODE (operands[0]); 868 enum rtx_code new_code = code; 869 rtx cmp_op0 = operands[1]; 870 rtx cmp_op1 = operands[2]; 871 rtx tmp_reg; 872 rtx tmp; 873 874 int reverse = 0; 875 876 /* Main Goal: Use compare instruction + branch instruction. 877 878 For example: 879 GT, GE: swap condition and swap operands and generate 880 compare instruction(LT, LE) + branch not equal instruction. 881 882 UNORDERED, LT, LE, EQ: no need to change and generate 883 compare instruction(UNORDERED, LT, LE, EQ) + branch not equal instruction. 884 885 ORDERED, NE: reverse condition and generate 886 compare instruction(EQ) + branch equal instruction. */ 887 888 switch (code) 889 { 890 case GT: 891 case GE: 892 tmp = cmp_op0; 893 cmp_op0 = cmp_op1; 894 cmp_op1 = tmp; 895 new_code = swap_condition (new_code); 896 break; 897 case UNORDERED: 898 case LT: 899 case LE: 900 case EQ: 901 break; 902 case ORDERED: 903 case NE: 904 new_code = reverse_condition (new_code); 905 reverse = 1; 906 break; 907 case UNGT: 908 case UNGE: 909 new_code = reverse_condition_maybe_unordered (new_code); 910 reverse = 1; 911 break; 912 case UNLT: 913 case UNLE: 914 new_code = reverse_condition_maybe_unordered (new_code); 915 tmp = cmp_op0; 916 cmp_op0 = cmp_op1; 917 cmp_op1 = tmp; 918 new_code = swap_condition (new_code); 919 reverse = 1; 920 break; 921 default: 922 return; 923 } 924 925 tmp_reg = gen_reg_rtx (SImode); 926 emit_insn (gen_rtx_SET (tmp_reg, 927 gen_rtx_fmt_ee (new_code, SImode, 928 cmp_op0, cmp_op1))); 929 930 PUT_CODE (operands[0], reverse ? EQ : NE); 931 emit_insn (gen_cbranchsi4 (operands[0], tmp_reg, 932 const0_rtx, operands[3])); 933 } 934 935 void 936 nds32_expand_float_cstore (rtx *operands) 937 { 938 enum rtx_code code = GET_CODE (operands[1]); 939 enum rtx_code new_code = code; 940 machine_mode mode = GET_MODE (operands[2]); 941 942 rtx cmp_op0 = operands[2]; 943 rtx cmp_op1 = operands[3]; 944 rtx tmp; 945 946 /* Main Goal: Use compare instruction to store value. 947 948 For example: 949 GT, GE: swap condition and swap operands. 950 reg_R = (reg_A > reg_B) --> fcmplt reg_R, reg_B, reg_A 951 reg_R = (reg_A >= reg_B) --> fcmple reg_R, reg_B, reg_A 952 953 LT, LE, EQ: no need to change, it is already LT, LE, EQ. 954 reg_R = (reg_A < reg_B) --> fcmplt reg_R, reg_A, reg_B 955 reg_R = (reg_A <= reg_B) --> fcmple reg_R, reg_A, reg_B 956 reg_R = (reg_A == reg_B) --> fcmpeq reg_R, reg_A, reg_B 957 958 ORDERED: reverse condition and using xor insturction to achieve 'ORDERED'. 959 reg_R = (reg_A != reg_B) --> fcmpun reg_R, reg_A, reg_B 960 xor reg_R, reg_R, const1_rtx 961 962 NE: reverse condition and using xor insturction to achieve 'NE'. 963 reg_R = (reg_A != reg_B) --> fcmpeq reg_R, reg_A, reg_B 964 xor reg_R, reg_R, const1_rtx */ 965 switch (code) 966 { 967 case GT: 968 case GE: 969 tmp = cmp_op0; 970 cmp_op0 = cmp_op1; 971 cmp_op1 =tmp; 972 new_code = swap_condition (new_code); 973 break; 974 case UNORDERED: 975 case LT: 976 case LE: 977 case EQ: 978 break; 979 case ORDERED: 980 if (mode == SFmode) 981 emit_insn (gen_cmpsf_un (operands[0], cmp_op0, cmp_op1)); 982 else 983 emit_insn (gen_cmpdf_un (operands[0], cmp_op0, cmp_op1)); 984 985 emit_insn (gen_xorsi3 (operands[0], operands[0], const1_rtx)); 986 return; 987 case NE: 988 if (mode == SFmode) 989 emit_insn (gen_cmpsf_eq (operands[0], cmp_op0, cmp_op1)); 990 else 991 emit_insn (gen_cmpdf_eq (operands[0], cmp_op0, cmp_op1)); 992 993 emit_insn (gen_xorsi3 (operands[0], operands[0], const1_rtx)); 994 return; 995 default: 996 return; 997 } 998 999 emit_insn (gen_rtx_SET (operands[0], 1000 gen_rtx_fmt_ee (new_code, SImode, 1001 cmp_op0, cmp_op1))); 1002 } 1003 1004 enum nds32_expand_result_type 1005 nds32_expand_movcc (rtx *operands) 1006 { 1007 enum rtx_code code = GET_CODE (operands[1]); 1008 enum rtx_code new_code = code; 1009 machine_mode cmp0_mode = GET_MODE (XEXP (operands[1], 0)); 1010 rtx cmp_op0 = XEXP (operands[1], 0); 1011 rtx cmp_op1 = XEXP (operands[1], 1); 1012 rtx tmp; 1013 1014 if ((GET_CODE (operands[1]) == EQ || GET_CODE (operands[1]) == NE) 1015 && XEXP (operands[1], 1) == const0_rtx) 1016 { 1017 /* If the operands[1] rtx is already (eq X 0) or (ne X 0), 1018 we have gcc generate original template rtx. */ 1019 return EXPAND_CREATE_TEMPLATE; 1020 } 1021 else if ((TARGET_FPU_SINGLE && cmp0_mode == SFmode) 1022 || (TARGET_FPU_DOUBLE && cmp0_mode == DFmode)) 1023 { 1024 nds32_expand_float_movcc (operands); 1025 } 1026 else 1027 { 1028 /* Since there is only 'slt'(Set when Less Than) instruction for 1029 comparison in Andes ISA, the major strategy we use here is to 1030 convert conditional move into 'LT + EQ' or 'LT + NE' rtx combination. 1031 We design constraints properly so that the reload phase will assist 1032 to make one source operand to use same register as result operand. 1033 Then we can use cmovz/cmovn to catch the other source operand 1034 which has different register. */ 1035 int reverse = 0; 1036 1037 /* Main Goal: Use 'LT + EQ' or 'LT + NE' to target "then" part 1038 Strategy : Reverse condition and swap comparison operands 1039 1040 For example: 1041 1042 a <= b ? P : Q (LE or LEU) 1043 --> a > b ? Q : P (reverse condition) 1044 --> b < a ? Q : P (swap comparison operands to achieve 'LT/LTU') 1045 1046 a >= b ? P : Q (GE or GEU) 1047 --> a < b ? Q : P (reverse condition to achieve 'LT/LTU') 1048 1049 a < b ? P : Q (LT or LTU) 1050 --> (NO NEED TO CHANGE, it is already 'LT/LTU') 1051 1052 a > b ? P : Q (GT or GTU) 1053 --> b < a ? P : Q (swap comparison operands to achieve 'LT/LTU') */ 1054 switch (code) 1055 { 1056 case GE: case GEU: case LE: case LEU: 1057 new_code = reverse_condition (code); 1058 reverse = 1; 1059 break; 1060 case EQ: 1061 case NE: 1062 /* no need to reverse condition */ 1063 break; 1064 default: 1065 return EXPAND_FAIL; 1066 } 1067 1068 /* For '>' comparison operator, we swap operands 1069 so that we can have 'LT/LTU' operator. */ 1070 if (new_code == GT || new_code == GTU) 1071 { 1072 tmp = cmp_op0; 1073 cmp_op0 = cmp_op1; 1074 cmp_op1 = tmp; 1075 1076 new_code = swap_condition (new_code); 1077 } 1078 1079 /* Use a temporary register to store slt/slts result. */ 1080 tmp = gen_reg_rtx (SImode); 1081 1082 if (new_code == EQ || new_code == NE) 1083 { 1084 emit_insn (gen_xorsi3 (tmp, cmp_op0, cmp_op1)); 1085 /* tmp == 0 if cmp_op0 == cmp_op1. */ 1086 operands[1] = gen_rtx_fmt_ee (new_code, VOIDmode, tmp, const0_rtx); 1087 } 1088 else 1089 { 1090 /* This emit_insn will create corresponding 'slt/slts' 1091 insturction. */ 1092 if (new_code == LT) 1093 emit_insn (gen_slts_compare (tmp, cmp_op0, cmp_op1)); 1094 else if (new_code == LTU) 1095 emit_insn (gen_slt_compare (tmp, cmp_op0, cmp_op1)); 1096 else 1097 gcc_unreachable (); 1098 1099 /* Change comparison semantic into (eq X 0) or (ne X 0) behavior 1100 so that cmovz or cmovn will be matched later. 1101 1102 For reverse condition cases, we want to create a semantic that: 1103 (eq X 0) --> pick up "else" part 1104 For normal cases, we want to create a semantic that: 1105 (ne X 0) --> pick up "then" part 1106 1107 Later we will have cmovz/cmovn instruction pattern to 1108 match corresponding behavior and output instruction. */ 1109 operands[1] = gen_rtx_fmt_ee (reverse ? EQ : NE, 1110 VOIDmode, tmp, const0_rtx); 1111 } 1112 } 1113 return EXPAND_CREATE_TEMPLATE; 1114 } 1115 1116 void 1117 nds32_expand_float_movcc (rtx *operands) 1118 { 1119 if ((GET_CODE (operands[1]) == EQ || GET_CODE (operands[1]) == NE) 1120 && GET_MODE (XEXP (operands[1], 0)) == SImode 1121 && XEXP (operands[1], 1) == const0_rtx) 1122 { 1123 /* If the operands[1] rtx is already (eq X 0) or (ne X 0), 1124 we have gcc generate original template rtx. */ 1125 return; 1126 } 1127 else 1128 { 1129 enum rtx_code code = GET_CODE (operands[1]); 1130 enum rtx_code new_code = code; 1131 machine_mode cmp0_mode = GET_MODE (XEXP (operands[1], 0)); 1132 machine_mode cmp1_mode = GET_MODE (XEXP (operands[1], 1)); 1133 rtx cmp_op0 = XEXP (operands[1], 0); 1134 rtx cmp_op1 = XEXP (operands[1], 1); 1135 rtx tmp; 1136 1137 /* Compare instruction Operations: (cmp_op0 condition cmp_op1) ? 1 : 0, 1138 when result is 1, and 'reverse' be set 1 for fcmovzs instructuin. */ 1139 int reverse = 0; 1140 1141 /* Main Goal: Use cmpare instruction + conditional move instruction. 1142 Strategy : swap condition and swap comparison operands. 1143 1144 For example: 1145 a > b ? P : Q (GT) 1146 --> a < b ? Q : P (swap condition) 1147 --> b < a ? Q : P (swap comparison operands to achieve 'GT') 1148 1149 a >= b ? P : Q (GE) 1150 --> a <= b ? Q : P (swap condition) 1151 --> b <= a ? Q : P (swap comparison operands to achieve 'GE') 1152 1153 a < b ? P : Q (LT) 1154 --> (NO NEED TO CHANGE, it is already 'LT') 1155 1156 a >= b ? P : Q (LE) 1157 --> (NO NEED TO CHANGE, it is already 'LE') 1158 1159 a == b ? P : Q (EQ) 1160 --> (NO NEED TO CHANGE, it is already 'EQ') */ 1161 1162 switch (code) 1163 { 1164 case GT: 1165 case GE: 1166 tmp = cmp_op0; 1167 cmp_op0 = cmp_op1; 1168 cmp_op1 =tmp; 1169 new_code = swap_condition (new_code); 1170 break; 1171 case UNORDERED: 1172 case LT: 1173 case LE: 1174 case EQ: 1175 break; 1176 case ORDERED: 1177 case NE: 1178 reverse = 1; 1179 new_code = reverse_condition (new_code); 1180 break; 1181 case UNGT: 1182 case UNGE: 1183 new_code = reverse_condition_maybe_unordered (new_code); 1184 reverse = 1; 1185 break; 1186 case UNLT: 1187 case UNLE: 1188 new_code = reverse_condition_maybe_unordered (new_code); 1189 tmp = cmp_op0; 1190 cmp_op0 = cmp_op1; 1191 cmp_op1 = tmp; 1192 new_code = swap_condition (new_code); 1193 reverse = 1; 1194 break; 1195 default: 1196 return; 1197 } 1198 1199 /* Use a temporary register to store fcmpxxs result. */ 1200 tmp = gen_reg_rtx (SImode); 1201 1202 /* Create float compare instruction for SFmode and DFmode, 1203 other MODE using cstoresi create compare instruction. */ 1204 if ((cmp0_mode == DFmode || cmp0_mode == SFmode) 1205 && (cmp1_mode == DFmode || cmp1_mode == SFmode)) 1206 { 1207 /* This emit_insn create corresponding float compare instruction */ 1208 emit_insn (gen_rtx_SET (tmp, 1209 gen_rtx_fmt_ee (new_code, SImode, 1210 cmp_op0, cmp_op1))); 1211 } 1212 else 1213 { 1214 /* This emit_insn using cstoresi create corresponding 1215 compare instruction */ 1216 PUT_CODE (operands[1], new_code); 1217 emit_insn (gen_cstoresi4 (tmp, operands[1], 1218 cmp_op0, cmp_op1)); 1219 } 1220 /* operands[1] crete corresponding condition move instruction 1221 for fcmovzs and fcmovns. */ 1222 operands[1] = gen_rtx_fmt_ee (reverse ? EQ : NE, 1223 VOIDmode, tmp, const0_rtx); 1224 } 1225 } 1226 1227 void 1228 nds32_emit_push_fpr_callee_saved (int base_offset) 1229 { 1230 rtx fpu_insn; 1231 rtx reg, mem; 1232 unsigned int regno = cfun->machine->callee_saved_first_fpr_regno; 1233 unsigned int last_fpr = cfun->machine->callee_saved_last_fpr_regno; 1234 1235 while (regno <= last_fpr) 1236 { 1237 /* Handling two registers, using fsdi instruction. */ 1238 reg = gen_rtx_REG (DFmode, regno); 1239 mem = gen_frame_mem (DFmode, plus_constant (Pmode, 1240 stack_pointer_rtx, 1241 base_offset)); 1242 base_offset += 8; 1243 regno += 2; 1244 fpu_insn = emit_move_insn (mem, reg); 1245 RTX_FRAME_RELATED_P (fpu_insn) = 1; 1246 } 1247 } 1248 1249 void 1250 nds32_emit_pop_fpr_callee_saved (int gpr_padding_size) 1251 { 1252 rtx fpu_insn; 1253 rtx reg, mem, addr; 1254 rtx dwarf, adjust_sp_rtx; 1255 unsigned int regno = cfun->machine->callee_saved_first_fpr_regno; 1256 unsigned int last_fpr = cfun->machine->callee_saved_last_fpr_regno; 1257 int padding = 0; 1258 1259 while (regno <= last_fpr) 1260 { 1261 /* Handling two registers, using fldi.bi instruction. */ 1262 if ((regno + 1) >= last_fpr) 1263 padding = gpr_padding_size; 1264 1265 reg = gen_rtx_REG (DFmode, (regno)); 1266 addr = gen_rtx_POST_MODIFY (Pmode, stack_pointer_rtx, 1267 gen_rtx_PLUS (Pmode, stack_pointer_rtx, 1268 GEN_INT (8 + padding))); 1269 mem = gen_frame_mem (DFmode, addr); 1270 regno += 2; 1271 fpu_insn = emit_move_insn (reg, mem); 1272 1273 adjust_sp_rtx = 1274 gen_rtx_SET (stack_pointer_rtx, 1275 plus_constant (Pmode, stack_pointer_rtx, 1276 8 + padding)); 1277 1278 dwarf = alloc_reg_note (REG_CFA_RESTORE, reg, NULL_RTX); 1279 /* Tell gcc we adjust SP in this insn. */ 1280 dwarf = alloc_reg_note (REG_CFA_ADJUST_CFA, copy_rtx (adjust_sp_rtx), 1281 dwarf); 1282 RTX_FRAME_RELATED_P (fpu_insn) = 1; 1283 REG_NOTES (fpu_insn) = dwarf; 1284 } 1285 } 1286 1287 void 1288 nds32_emit_v3pop_fpr_callee_saved (int base) 1289 { 1290 int fpu_base_addr = base; 1291 int regno; 1292 rtx fpu_insn; 1293 rtx reg, mem; 1294 rtx dwarf; 1295 1296 regno = cfun->machine->callee_saved_first_fpr_regno; 1297 while (regno <= cfun->machine->callee_saved_last_fpr_regno) 1298 { 1299 /* Handling two registers, using fldi instruction. */ 1300 reg = gen_rtx_REG (DFmode, regno); 1301 mem = gen_frame_mem (DFmode, plus_constant (Pmode, 1302 stack_pointer_rtx, 1303 fpu_base_addr)); 1304 fpu_base_addr += 8; 1305 regno += 2; 1306 fpu_insn = emit_move_insn (reg, mem); 1307 dwarf = alloc_reg_note (REG_CFA_RESTORE, reg, NULL_RTX); 1308 RTX_FRAME_RELATED_P (fpu_insn) = 1; 1309 REG_NOTES (fpu_insn) = dwarf; 1310 } 1311 } 1312 1313 enum nds32_expand_result_type 1314 nds32_expand_extv (rtx *operands) 1315 { 1316 gcc_assert (CONST_INT_P (operands[2]) && CONST_INT_P (operands[3])); 1317 HOST_WIDE_INT width = INTVAL (operands[2]); 1318 HOST_WIDE_INT bitpos = INTVAL (operands[3]); 1319 rtx dst = operands[0]; 1320 rtx src = operands[1]; 1321 1322 if (MEM_P (src) 1323 && width == 32 1324 && (bitpos % BITS_PER_UNIT) == 0 1325 && GET_MODE_BITSIZE (GET_MODE (dst)) == width) 1326 { 1327 rtx newmem = adjust_address (src, GET_MODE (dst), 1328 bitpos / BITS_PER_UNIT); 1329 1330 rtx base_addr = force_reg (Pmode, XEXP (newmem, 0)); 1331 1332 emit_insn (gen_unaligned_loadsi (dst, base_addr)); 1333 1334 return EXPAND_DONE; 1335 } 1336 return EXPAND_FAIL; 1337 } 1338 1339 enum nds32_expand_result_type 1340 nds32_expand_insv (rtx *operands) 1341 { 1342 gcc_assert (CONST_INT_P (operands[1]) && CONST_INT_P (operands[2])); 1343 HOST_WIDE_INT width = INTVAL (operands[1]); 1344 HOST_WIDE_INT bitpos = INTVAL (operands[2]); 1345 rtx dst = operands[0]; 1346 rtx src = operands[3]; 1347 1348 if (MEM_P (dst) 1349 && width == 32 1350 && (bitpos % BITS_PER_UNIT) == 0 1351 && GET_MODE_BITSIZE (GET_MODE (src)) == width) 1352 { 1353 rtx newmem = adjust_address (dst, GET_MODE (src), 1354 bitpos / BITS_PER_UNIT); 1355 1356 rtx base_addr = force_reg (Pmode, XEXP (newmem, 0)); 1357 1358 emit_insn (gen_unaligned_storesi (base_addr, src)); 1359 1360 return EXPAND_DONE; 1361 } 1362 return EXPAND_FAIL; 1363 } 1364 1365 /* ------------------------------------------------------------------------ */ 1366 1367 /* Function to generate PC relative jump table. 1368 Refer to nds32.md for more details. 1369 1370 The following is the sample for the case that diff value 1371 can be presented in '.short' size. 1372 1373 addi $r1, $r1, -(case_lower_bound) 1374 slti $ta, $r1, (case_number) 1375 beqz $ta, .L_skip_label 1376 1377 la $ta, .L35 ! get jump table address 1378 lh $r1, [$ta + $r1 << 1] ! load symbol diff from jump table entry 1379 addi $ta, $r1, $ta 1380 jr5 $ta 1381 1382 ! jump table entry 1383 L35: 1384 .short .L25-.L35 1385 .short .L26-.L35 1386 .short .L27-.L35 1387 .short .L28-.L35 1388 .short .L29-.L35 1389 .short .L30-.L35 1390 .short .L31-.L35 1391 .short .L32-.L35 1392 .short .L33-.L35 1393 .short .L34-.L35 */ 1394 const char * 1395 nds32_output_casesi_pc_relative (rtx *operands) 1396 { 1397 machine_mode mode; 1398 rtx diff_vec; 1399 1400 diff_vec = PATTERN (NEXT_INSN (as_a <rtx_insn *> (operands[1]))); 1401 1402 gcc_assert (GET_CODE (diff_vec) == ADDR_DIFF_VEC); 1403 1404 /* Step C: "t <-- operands[1]". */ 1405 if (flag_pic) 1406 { 1407 output_asm_insn ("sethi\t$ta, hi20(%l1@GOTOFF)", operands); 1408 output_asm_insn ("ori\t$ta, $ta, lo12(%l1@GOTOFF)", operands); 1409 output_asm_insn ("add\t$ta, $ta, $gp", operands); 1410 } 1411 else 1412 output_asm_insn ("la\t$ta, %l1", operands); 1413 1414 /* Get the mode of each element in the difference vector. */ 1415 mode = GET_MODE (diff_vec); 1416 1417 /* Step D: "z <-- (mem (plus (operands[0] << m) t))", 1418 where m is 0, 1, or 2 to load address-diff value from table. */ 1419 switch (mode) 1420 { 1421 case E_QImode: 1422 output_asm_insn ("lb\t%2, [$ta + %0 << 0]", operands); 1423 break; 1424 case E_HImode: 1425 output_asm_insn ("lh\t%2, [$ta + %0 << 1]", operands); 1426 break; 1427 case E_SImode: 1428 output_asm_insn ("lw\t%2, [$ta + %0 << 2]", operands); 1429 break; 1430 default: 1431 gcc_unreachable (); 1432 } 1433 1434 /* Step E: "t <-- z + t". 1435 Add table label_ref with address-diff value to 1436 obtain target case address. */ 1437 output_asm_insn ("add\t$ta, %2, $ta", operands); 1438 1439 /* Step F: jump to target with register t. */ 1440 if (TARGET_16_BIT) 1441 return "jr5\t$ta"; 1442 else 1443 return "jr\t$ta"; 1444 } 1445 1446 /* Function to generate normal jump table. */ 1447 const char * 1448 nds32_output_casesi (rtx *operands) 1449 { 1450 /* Step C: "t <-- operands[1]". */ 1451 if (flag_pic) 1452 { 1453 output_asm_insn ("sethi\t$ta, hi20(%l1@GOTOFF)", operands); 1454 output_asm_insn ("ori\t$ta, $ta, lo12(%l1@GOTOFF)", operands); 1455 output_asm_insn ("add\t$ta, $ta, $gp", operands); 1456 } 1457 else 1458 output_asm_insn ("la\t$ta, %l1", operands); 1459 1460 /* Step D: "z <-- (mem (plus (operands[0] << 2) t))". */ 1461 output_asm_insn ("lw\t%2, [$ta + %0 << 2]", operands); 1462 1463 /* No need to perform Step E, which is only used for 1464 pc relative jump table. */ 1465 1466 /* Step F: jump to target with register z. */ 1467 if (TARGET_16_BIT) 1468 return "jr5\t%2"; 1469 else 1470 return "jr\t%2"; 1471 } 1472 1473 /* Function to return memory format. */ 1474 enum nds32_16bit_address_type 1475 nds32_mem_format (rtx op) 1476 { 1477 machine_mode mode_test; 1478 int val; 1479 int regno; 1480 1481 if (!TARGET_16_BIT) 1482 return ADDRESS_NOT_16BIT_FORMAT; 1483 1484 mode_test = GET_MODE (op); 1485 1486 op = XEXP (op, 0); 1487 1488 /* 45 format. */ 1489 if (GET_CODE (op) == REG 1490 && ((mode_test == SImode) || (mode_test == SFmode))) 1491 return ADDRESS_REG; 1492 1493 /* 333 format for QI/HImode. */ 1494 if (GET_CODE (op) == REG && (REGNO (op) < R8_REGNUM)) 1495 return ADDRESS_LO_REG_IMM3U; 1496 1497 /* post_inc 333 format. */ 1498 if ((GET_CODE (op) == POST_INC) 1499 && ((mode_test == SImode) || (mode_test == SFmode))) 1500 { 1501 regno = REGNO(XEXP (op, 0)); 1502 1503 if (regno < 8) 1504 return ADDRESS_POST_INC_LO_REG_IMM3U; 1505 } 1506 1507 /* post_inc 333 format. */ 1508 if ((GET_CODE (op) == POST_MODIFY) 1509 && ((mode_test == SImode) || (mode_test == SFmode)) 1510 && (REG_P (XEXP (XEXP (op, 1), 0))) 1511 && (CONST_INT_P (XEXP (XEXP (op, 1), 1)))) 1512 { 1513 regno = REGNO (XEXP (XEXP (op, 1), 0)); 1514 val = INTVAL (XEXP (XEXP (op, 1), 1)); 1515 if (regno < 8 && val > 0 && val < 32) 1516 return ADDRESS_POST_MODIFY_LO_REG_IMM3U; 1517 } 1518 1519 if ((GET_CODE (op) == PLUS) 1520 && (GET_CODE (XEXP (op, 0)) == REG) 1521 && (GET_CODE (XEXP (op, 1)) == CONST_INT)) 1522 { 1523 val = INTVAL (XEXP (op, 1)); 1524 1525 regno = REGNO(XEXP (op, 0)); 1526 1527 if (regno > 8 1528 && regno != SP_REGNUM 1529 && regno != FP_REGNUM) 1530 return ADDRESS_NOT_16BIT_FORMAT; 1531 1532 switch (mode_test) 1533 { 1534 case E_QImode: 1535 /* 333 format. */ 1536 if (val >= 0 && val < 8 && regno < 8) 1537 return ADDRESS_LO_REG_IMM3U; 1538 break; 1539 1540 case E_HImode: 1541 /* 333 format. */ 1542 if (val >= 0 && val < 16 && (val % 2 == 0) && regno < 8) 1543 return ADDRESS_LO_REG_IMM3U; 1544 break; 1545 1546 case E_SImode: 1547 case E_SFmode: 1548 case E_DFmode: 1549 /* r8 imply fe format. */ 1550 if ((regno == 8) && 1551 (val >= -128 && val <= -4 && (val % 4 == 0))) 1552 return ADDRESS_R8_IMM7U; 1553 /* fp imply 37 format. */ 1554 if ((regno == FP_REGNUM) && 1555 (val >= 0 && val < 512 && (val % 4 == 0))) 1556 return ADDRESS_FP_IMM7U; 1557 /* sp imply 37 format. */ 1558 else if ((regno == SP_REGNUM) && 1559 (val >= 0 && val < 512 && (val % 4 == 0))) 1560 return ADDRESS_SP_IMM7U; 1561 /* 333 format. */ 1562 else if (val >= 0 && val < 32 && (val % 4 == 0) && regno < 8) 1563 return ADDRESS_LO_REG_IMM3U; 1564 break; 1565 1566 default: 1567 break; 1568 } 1569 } 1570 1571 return ADDRESS_NOT_16BIT_FORMAT; 1572 } 1573 1574 /* Output 16-bit store. */ 1575 const char * 1576 nds32_output_16bit_store (rtx *operands, int byte) 1577 { 1578 char pattern[100]; 1579 char size; 1580 rtx code = XEXP (operands[0], 0); 1581 1582 size = nds32_byte_to_size (byte); 1583 1584 switch (nds32_mem_format (operands[0])) 1585 { 1586 case ADDRESS_REG: 1587 operands[0] = code; 1588 output_asm_insn ("swi450\t%1, [%0]", operands); 1589 break; 1590 case ADDRESS_LO_REG_IMM3U: 1591 snprintf (pattern, sizeof (pattern), "s%ci333\t%%1, %%0", size); 1592 output_asm_insn (pattern, operands); 1593 break; 1594 case ADDRESS_POST_INC_LO_REG_IMM3U: 1595 snprintf (pattern, sizeof (pattern), "swi333.bi\t%%1, %%0, 4"); 1596 output_asm_insn (pattern, operands); 1597 break; 1598 case ADDRESS_POST_MODIFY_LO_REG_IMM3U: 1599 snprintf (pattern, sizeof (pattern), "swi333.bi\t%%1, %%0"); 1600 output_asm_insn (pattern, operands); 1601 break; 1602 case ADDRESS_FP_IMM7U: 1603 output_asm_insn ("swi37\t%1, %0", operands); 1604 break; 1605 case ADDRESS_SP_IMM7U: 1606 /* Get immediate value and set back to operands[1]. */ 1607 operands[0] = XEXP (code, 1); 1608 output_asm_insn ("swi37.sp\t%1, [ + (%0)]", operands); 1609 break; 1610 default: 1611 break; 1612 } 1613 1614 return ""; 1615 } 1616 1617 /* Output 16-bit load. */ 1618 const char * 1619 nds32_output_16bit_load (rtx *operands, int byte) 1620 { 1621 char pattern[100]; 1622 unsigned char size; 1623 rtx code = XEXP (operands[1], 0); 1624 1625 size = nds32_byte_to_size (byte); 1626 1627 switch (nds32_mem_format (operands[1])) 1628 { 1629 case ADDRESS_REG: 1630 operands[1] = code; 1631 output_asm_insn ("lwi450\t%0, [%1]", operands); 1632 break; 1633 case ADDRESS_LO_REG_IMM3U: 1634 snprintf (pattern, sizeof (pattern), "l%ci333\t%%0, %%1", size); 1635 output_asm_insn (pattern, operands); 1636 break; 1637 case ADDRESS_POST_INC_LO_REG_IMM3U: 1638 snprintf (pattern, sizeof (pattern), "lwi333.bi\t%%0, %%1, 4"); 1639 output_asm_insn (pattern, operands); 1640 break; 1641 case ADDRESS_POST_MODIFY_LO_REG_IMM3U: 1642 snprintf (pattern, sizeof (pattern), "lwi333.bi\t%%0, %%1"); 1643 output_asm_insn (pattern, operands); 1644 break; 1645 case ADDRESS_R8_IMM7U: 1646 output_asm_insn ("lwi45.fe\t%0, %e1", operands); 1647 break; 1648 case ADDRESS_FP_IMM7U: 1649 output_asm_insn ("lwi37\t%0, %1", operands); 1650 break; 1651 case ADDRESS_SP_IMM7U: 1652 /* Get immediate value and set back to operands[0]. */ 1653 operands[1] = XEXP (code, 1); 1654 output_asm_insn ("lwi37.sp\t%0, [ + (%1)]", operands); 1655 break; 1656 default: 1657 break; 1658 } 1659 1660 return ""; 1661 } 1662 1663 /* Output 32-bit store. */ 1664 const char * 1665 nds32_output_32bit_store (rtx *operands, int byte) 1666 { 1667 char pattern[100]; 1668 unsigned char size; 1669 rtx code = XEXP (operands[0], 0); 1670 1671 size = nds32_byte_to_size (byte); 1672 1673 switch (GET_CODE (code)) 1674 { 1675 case REG: 1676 /* (mem (reg X)) 1677 => access location by using register, 1678 use "sbi / shi / swi" */ 1679 snprintf (pattern, sizeof (pattern), "s%ci\t%%1, %%0", size); 1680 break; 1681 1682 case SYMBOL_REF: 1683 case CONST: 1684 /* (mem (symbol_ref X)) 1685 (mem (const (...))) 1686 => access global variables, 1687 use "sbi.gp / shi.gp / swi.gp" */ 1688 operands[0] = XEXP (operands[0], 0); 1689 snprintf (pattern, sizeof (pattern), "s%ci.gp\t%%1, [ + %%0]", size); 1690 break; 1691 1692 case POST_INC: 1693 /* (mem (post_inc reg)) 1694 => access location by using register which will be post increment, 1695 use "sbi.bi / shi.bi / swi.bi" */ 1696 snprintf (pattern, sizeof (pattern), 1697 "s%ci.bi\t%%1, %%0, %d", size, byte); 1698 break; 1699 1700 case POST_DEC: 1701 /* (mem (post_dec reg)) 1702 => access location by using register which will be post decrement, 1703 use "sbi.bi / shi.bi / swi.bi" */ 1704 snprintf (pattern, sizeof (pattern), 1705 "s%ci.bi\t%%1, %%0, -%d", size, byte); 1706 break; 1707 1708 case POST_MODIFY: 1709 switch (GET_CODE (XEXP (XEXP (code, 1), 1))) 1710 { 1711 case REG: 1712 case SUBREG: 1713 /* (mem (post_modify (reg) (plus (reg) (reg)))) 1714 => access location by using register which will be 1715 post modified with reg, 1716 use "sb.bi/ sh.bi / sw.bi" */ 1717 snprintf (pattern, sizeof (pattern), "s%c.bi\t%%1, %%0", size); 1718 break; 1719 case CONST_INT: 1720 /* (mem (post_modify (reg) (plus (reg) (const_int)))) 1721 => access location by using register which will be 1722 post modified with const_int, 1723 use "sbi.bi/ shi.bi / swi.bi" */ 1724 snprintf (pattern, sizeof (pattern), "s%ci.bi\t%%1, %%0", size); 1725 break; 1726 default: 1727 abort (); 1728 } 1729 break; 1730 1731 case PLUS: 1732 switch (GET_CODE (XEXP (code, 1))) 1733 { 1734 case REG: 1735 case SUBREG: 1736 /* (mem (plus reg reg)) or (mem (plus (mult reg const_int) reg)) 1737 => access location by adding two registers, 1738 use "sb / sh / sw" */ 1739 snprintf (pattern, sizeof (pattern), "s%c\t%%1, %%0", size); 1740 break; 1741 case CONST_INT: 1742 /* (mem (plus reg const_int)) 1743 => access location by adding one register with const_int, 1744 use "sbi / shi / swi" */ 1745 snprintf (pattern, sizeof (pattern), "s%ci\t%%1, %%0", size); 1746 break; 1747 default: 1748 abort (); 1749 } 1750 break; 1751 1752 case LO_SUM: 1753 operands[2] = XEXP (code, 1); 1754 operands[0] = XEXP (code, 0); 1755 snprintf (pattern, sizeof (pattern), 1756 "s%ci\t%%1, [%%0 + lo12(%%2)]", size); 1757 break; 1758 1759 default: 1760 abort (); 1761 } 1762 1763 output_asm_insn (pattern, operands); 1764 return ""; 1765 } 1766 1767 /* Output 32-bit load. */ 1768 const char * 1769 nds32_output_32bit_load (rtx *operands, int byte) 1770 { 1771 char pattern[100]; 1772 unsigned char size; 1773 rtx code; 1774 1775 code = XEXP (operands[1], 0); 1776 1777 size = nds32_byte_to_size (byte); 1778 1779 switch (GET_CODE (code)) 1780 { 1781 case REG: 1782 /* (mem (reg X)) 1783 => access location by using register, 1784 use "lbi / lhi / lwi" */ 1785 snprintf (pattern, sizeof (pattern), "l%ci\t%%0, %%1", size); 1786 break; 1787 1788 case SYMBOL_REF: 1789 case CONST: 1790 /* (mem (symbol_ref X)) 1791 (mem (const (...))) 1792 => access global variables, 1793 use "lbi.gp / lhi.gp / lwi.gp" */ 1794 operands[1] = XEXP (operands[1], 0); 1795 snprintf (pattern, sizeof (pattern), "l%ci.gp\t%%0, [ + %%1]", size); 1796 break; 1797 1798 case POST_INC: 1799 /* (mem (post_inc reg)) 1800 => access location by using register which will be post increment, 1801 use "lbi.bi / lhi.bi / lwi.bi" */ 1802 snprintf (pattern, sizeof (pattern), 1803 "l%ci.bi\t%%0, %%1, %d", size, byte); 1804 break; 1805 1806 case POST_DEC: 1807 /* (mem (post_dec reg)) 1808 => access location by using register which will be post decrement, 1809 use "lbi.bi / lhi.bi / lwi.bi" */ 1810 snprintf (pattern, sizeof (pattern), 1811 "l%ci.bi\t%%0, %%1, -%d", size, byte); 1812 break; 1813 1814 case POST_MODIFY: 1815 switch (GET_CODE (XEXP (XEXP (code, 1), 1))) 1816 { 1817 case REG: 1818 case SUBREG: 1819 /* (mem (post_modify (reg) (plus (reg) (reg)))) 1820 => access location by using register which will be 1821 post modified with reg, 1822 use "lb.bi/ lh.bi / lw.bi" */ 1823 snprintf (pattern, sizeof (pattern), "l%c.bi\t%%0, %%1", size); 1824 break; 1825 case CONST_INT: 1826 /* (mem (post_modify (reg) (plus (reg) (const_int)))) 1827 => access location by using register which will be 1828 post modified with const_int, 1829 use "lbi.bi/ lhi.bi / lwi.bi" */ 1830 snprintf (pattern, sizeof (pattern), "l%ci.bi\t%%0, %%1", size); 1831 break; 1832 default: 1833 abort (); 1834 } 1835 break; 1836 1837 case PLUS: 1838 switch (GET_CODE (XEXP (code, 1))) 1839 { 1840 case REG: 1841 case SUBREG: 1842 /* (mem (plus reg reg)) or (mem (plus (mult reg const_int) reg)) 1843 use "lb / lh / lw" */ 1844 snprintf (pattern, sizeof (pattern), "l%c\t%%0, %%1", size); 1845 break; 1846 case CONST_INT: 1847 /* (mem (plus reg const_int)) 1848 => access location by adding one register with const_int, 1849 use "lbi / lhi / lwi" */ 1850 snprintf (pattern, sizeof (pattern), "l%ci\t%%0, %%1", size); 1851 break; 1852 default: 1853 abort (); 1854 } 1855 break; 1856 1857 case LO_SUM: 1858 operands[2] = XEXP (code, 1); 1859 operands[1] = XEXP (code, 0); 1860 snprintf (pattern, sizeof (pattern), 1861 "l%ci\t%%0, [%%1 + lo12(%%2)]", size); 1862 break; 1863 1864 default: 1865 abort (); 1866 } 1867 1868 output_asm_insn (pattern, operands); 1869 return ""; 1870 } 1871 1872 /* Output 32-bit load with signed extension. */ 1873 const char * 1874 nds32_output_32bit_load_s (rtx *operands, int byte) 1875 { 1876 char pattern[100]; 1877 unsigned char size; 1878 rtx code; 1879 1880 code = XEXP (operands[1], 0); 1881 1882 size = nds32_byte_to_size (byte); 1883 1884 switch (GET_CODE (code)) 1885 { 1886 case REG: 1887 /* (mem (reg X)) 1888 => access location by using register, 1889 use "lbsi / lhsi" */ 1890 snprintf (pattern, sizeof (pattern), "l%csi\t%%0, %%1", size); 1891 break; 1892 1893 case SYMBOL_REF: 1894 case CONST: 1895 /* (mem (symbol_ref X)) 1896 (mem (const (...))) 1897 => access global variables, 1898 use "lbsi.gp / lhsi.gp" */ 1899 operands[1] = XEXP (operands[1], 0); 1900 snprintf (pattern, sizeof (pattern), "l%csi.gp\t%%0, [ + %%1]", size); 1901 break; 1902 1903 case POST_INC: 1904 /* (mem (post_inc reg)) 1905 => access location by using register which will be post increment, 1906 use "lbsi.bi / lhsi.bi" */ 1907 snprintf (pattern, sizeof (pattern), 1908 "l%csi.bi\t%%0, %%1, %d", size, byte); 1909 break; 1910 1911 case POST_DEC: 1912 /* (mem (post_dec reg)) 1913 => access location by using register which will be post decrement, 1914 use "lbsi.bi / lhsi.bi" */ 1915 snprintf (pattern, sizeof (pattern), 1916 "l%csi.bi\t%%0, %%1, -%d", size, byte); 1917 break; 1918 1919 case POST_MODIFY: 1920 switch (GET_CODE (XEXP (XEXP (code, 1), 1))) 1921 { 1922 case REG: 1923 case SUBREG: 1924 /* (mem (post_modify (reg) (plus (reg) (reg)))) 1925 => access location by using register which will be 1926 post modified with reg, 1927 use "lbs.bi/ lhs.bi" */ 1928 snprintf (pattern, sizeof (pattern), "l%cs.bi\t%%0, %%1", size); 1929 break; 1930 case CONST_INT: 1931 /* (mem (post_modify (reg) (plus (reg) (const_int)))) 1932 => access location by using register which will be 1933 post modified with const_int, 1934 use "lbsi.bi/ lhsi.bi" */ 1935 snprintf (pattern, sizeof (pattern), "l%csi.bi\t%%0, %%1", size); 1936 break; 1937 default: 1938 abort (); 1939 } 1940 break; 1941 1942 case PLUS: 1943 switch (GET_CODE (XEXP (code, 1))) 1944 { 1945 case REG: 1946 case SUBREG: 1947 /* (mem (plus reg reg)) or (mem (plus (mult reg const_int) reg)) 1948 use "lbs / lhs" */ 1949 snprintf (pattern, sizeof (pattern), "l%cs\t%%0, %%1", size); 1950 break; 1951 case CONST_INT: 1952 /* (mem (plus reg const_int)) 1953 => access location by adding one register with const_int, 1954 use "lbsi / lhsi" */ 1955 snprintf (pattern, sizeof (pattern), "l%csi\t%%0, %%1", size); 1956 break; 1957 default: 1958 abort (); 1959 } 1960 break; 1961 1962 case LO_SUM: 1963 operands[2] = XEXP (code, 1); 1964 operands[1] = XEXP (code, 0); 1965 snprintf (pattern, sizeof (pattern), 1966 "l%csi\t%%0, [%%1 + lo12(%%2)]", size); 1967 break; 1968 1969 default: 1970 abort (); 1971 } 1972 1973 output_asm_insn (pattern, operands); 1974 return ""; 1975 } 1976 1977 /* Function to output stack push operation. 1978 We need to deal with normal stack push multiple or stack v3push. */ 1979 const char * 1980 nds32_output_stack_push (rtx par_rtx) 1981 { 1982 /* A string pattern for output_asm_insn(). */ 1983 char pattern[100]; 1984 /* The operands array which will be used in output_asm_insn(). */ 1985 rtx operands[3]; 1986 /* Pick up varargs first regno and last regno for further use. */ 1987 int rb_va_args = cfun->machine->va_args_first_regno; 1988 int re_va_args = cfun->machine->va_args_last_regno; 1989 int last_argument_regno = NDS32_FIRST_GPR_REGNUM 1990 + NDS32_MAX_GPR_REGS_FOR_ARGS 1991 - 1; 1992 /* Pick up first and last eh data regno for further use. */ 1993 int rb_eh_data = cfun->machine->eh_return_data_first_regno; 1994 int re_eh_data = cfun->machine->eh_return_data_last_regno; 1995 int first_eh_data_regno = EH_RETURN_DATA_REGNO (0); 1996 /* Pick up callee-saved first regno and last regno for further use. */ 1997 int rb_callee_saved = cfun->machine->callee_saved_first_gpr_regno; 1998 int re_callee_saved = cfun->machine->callee_saved_last_gpr_regno; 1999 2000 /* First we need to check if we are pushing argument registers not used 2001 for the named arguments. If so, we have to create 'smw.adm' (push.s) 2002 instruction. */ 2003 if (reg_mentioned_p (gen_rtx_REG (SImode, last_argument_regno), par_rtx)) 2004 { 2005 /* Set operands[0] and operands[1]. */ 2006 operands[0] = gen_rtx_REG (SImode, rb_va_args); 2007 operands[1] = gen_rtx_REG (SImode, re_va_args); 2008 /* Create assembly code pattern: "Rb, Re, { }". */ 2009 snprintf (pattern, sizeof (pattern), "push.s\t%s", "%0, %1, { }"); 2010 /* We use output_asm_insn() to output assembly code by ourself. */ 2011 output_asm_insn (pattern, operands); 2012 return ""; 2013 } 2014 2015 /* If last_argument_regno is not mentioned in par_rtx, we can confirm that 2016 we do not need to push argument registers for variadic function. 2017 But we still need to check if we need to push exception handling 2018 data registers. */ 2019 if (reg_mentioned_p (gen_rtx_REG (SImode, first_eh_data_regno), par_rtx)) 2020 { 2021 /* Set operands[0] and operands[1]. */ 2022 operands[0] = gen_rtx_REG (SImode, rb_eh_data); 2023 operands[1] = gen_rtx_REG (SImode, re_eh_data); 2024 /* Create assembly code pattern: "Rb, Re, { }". */ 2025 snprintf (pattern, sizeof (pattern), "push.s\t%s", "%0, %1, { }"); 2026 /* We use output_asm_insn() to output assembly code by ourself. */ 2027 output_asm_insn (pattern, operands); 2028 return ""; 2029 } 2030 2031 /* If we step here, we are going to do v3push or multiple push operation. */ 2032 2033 /* Refer to nds32.h, where we comment when push25/pop25 are available. */ 2034 if (NDS32_V3PUSH_AVAILABLE_P) 2035 { 2036 /* For stack v3push: 2037 operands[0]: Re 2038 operands[1]: imm8u */ 2039 2040 /* This variable is to check if 'push25 Re,imm8u' is available. */ 2041 int sp_adjust; 2042 2043 /* Set operands[0]. */ 2044 operands[0] = gen_rtx_REG (SImode, re_callee_saved); 2045 2046 /* Check if we can generate 'push25 Re,imm8u', 2047 otherwise, generate 'push25 Re,0'. */ 2048 sp_adjust = cfun->machine->local_size 2049 + cfun->machine->out_args_size 2050 + cfun->machine->callee_saved_area_gpr_padding_bytes 2051 + cfun->machine->callee_saved_fpr_regs_size; 2052 if (satisfies_constraint_Iu08 (GEN_INT (sp_adjust)) 2053 && NDS32_DOUBLE_WORD_ALIGN_P (sp_adjust)) 2054 operands[1] = GEN_INT (sp_adjust); 2055 else 2056 { 2057 /* Allocate callee saved fpr space. */ 2058 if (cfun->machine->callee_saved_first_fpr_regno != SP_REGNUM) 2059 { 2060 sp_adjust = cfun->machine->callee_saved_area_gpr_padding_bytes 2061 + cfun->machine->callee_saved_fpr_regs_size; 2062 operands[1] = GEN_INT (sp_adjust); 2063 } 2064 else 2065 { 2066 operands[1] = GEN_INT (0); 2067 } 2068 } 2069 2070 /* Create assembly code pattern. */ 2071 snprintf (pattern, sizeof (pattern), "push25\t%%0, %%1"); 2072 } 2073 else 2074 { 2075 /* For normal stack push multiple: 2076 operands[0]: Rb 2077 operands[1]: Re 2078 operands[2]: En4 */ 2079 2080 /* This variable is used to check if we only need to generate En4 field. 2081 As long as Rb==Re=SP_REGNUM, we set this variable to 1. */ 2082 int push_en4_only_p = 0; 2083 2084 /* Set operands[0] and operands[1]. */ 2085 operands[0] = gen_rtx_REG (SImode, rb_callee_saved); 2086 operands[1] = gen_rtx_REG (SImode, re_callee_saved); 2087 2088 /* 'smw.adm $sp,[$sp],$sp,0' means push nothing. */ 2089 if (!cfun->machine->fp_size 2090 && !cfun->machine->gp_size 2091 && !cfun->machine->lp_size 2092 && REGNO (operands[0]) == SP_REGNUM 2093 && REGNO (operands[1]) == SP_REGNUM) 2094 { 2095 /* No need to generate instruction. */ 2096 return ""; 2097 } 2098 else 2099 { 2100 /* If Rb==Re=SP_REGNUM, we only need to generate En4 field. */ 2101 if (REGNO (operands[0]) == SP_REGNUM 2102 && REGNO (operands[1]) == SP_REGNUM) 2103 push_en4_only_p = 1; 2104 2105 /* Create assembly code pattern. 2106 We need to handle the form: "Rb, Re, { $fp $gp $lp }". */ 2107 snprintf (pattern, sizeof (pattern), 2108 "push.s\t%s{%s%s%s }", 2109 push_en4_only_p ? "" : "%0, %1, ", 2110 cfun->machine->fp_size ? " $fp" : "", 2111 cfun->machine->gp_size ? " $gp" : "", 2112 cfun->machine->lp_size ? " $lp" : ""); 2113 } 2114 } 2115 2116 /* We use output_asm_insn() to output assembly code by ourself. */ 2117 output_asm_insn (pattern, operands); 2118 return ""; 2119 } 2120 2121 /* Function to output stack pop operation. 2122 We need to deal with normal stack pop multiple or stack v3pop. */ 2123 const char * 2124 nds32_output_stack_pop (rtx par_rtx ATTRIBUTE_UNUSED) 2125 { 2126 /* A string pattern for output_asm_insn(). */ 2127 char pattern[100]; 2128 /* The operands array which will be used in output_asm_insn(). */ 2129 rtx operands[3]; 2130 /* Pick up first and last eh data regno for further use. */ 2131 int rb_eh_data = cfun->machine->eh_return_data_first_regno; 2132 int re_eh_data = cfun->machine->eh_return_data_last_regno; 2133 int first_eh_data_regno = EH_RETURN_DATA_REGNO (0); 2134 /* Pick up callee-saved first regno and last regno for further use. */ 2135 int rb_callee_saved = cfun->machine->callee_saved_first_gpr_regno; 2136 int re_callee_saved = cfun->machine->callee_saved_last_gpr_regno; 2137 2138 /* We need to check if we need to push exception handling 2139 data registers. */ 2140 if (reg_mentioned_p (gen_rtx_REG (SImode, first_eh_data_regno), par_rtx)) 2141 { 2142 /* Set operands[0] and operands[1]. */ 2143 operands[0] = gen_rtx_REG (SImode, rb_eh_data); 2144 operands[1] = gen_rtx_REG (SImode, re_eh_data); 2145 /* Create assembly code pattern: "Rb, Re, { }". */ 2146 snprintf (pattern, sizeof (pattern), "pop.s\t%s", "%0, %1, { }"); 2147 /* We use output_asm_insn() to output assembly code by ourself. */ 2148 output_asm_insn (pattern, operands); 2149 return ""; 2150 } 2151 2152 /* If we step here, we are going to do v3pop or multiple pop operation. */ 2153 2154 /* Refer to nds32.h, where we comment when push25/pop25 are available. */ 2155 if (NDS32_V3PUSH_AVAILABLE_P) 2156 { 2157 /* For stack v3pop: 2158 operands[0]: Re 2159 operands[1]: imm8u */ 2160 2161 /* This variable is to check if 'pop25 Re,imm8u' is available. */ 2162 int sp_adjust; 2163 2164 /* Set operands[0]. */ 2165 operands[0] = gen_rtx_REG (SImode, re_callee_saved); 2166 2167 /* Check if we can generate 'pop25 Re,imm8u', 2168 otherwise, generate 'pop25 Re,0'. 2169 We have to consider alloca issue as well. 2170 If the function does call alloca(), the stack pointer is not fixed. 2171 In that case, we cannot use 'pop25 Re,imm8u' directly. 2172 We have to caculate stack pointer from frame pointer 2173 and then use 'pop25 Re,0'. */ 2174 sp_adjust = cfun->machine->local_size 2175 + cfun->machine->out_args_size 2176 + cfun->machine->callee_saved_area_gpr_padding_bytes 2177 + cfun->machine->callee_saved_fpr_regs_size; 2178 if (satisfies_constraint_Iu08 (GEN_INT (sp_adjust)) 2179 && NDS32_DOUBLE_WORD_ALIGN_P (sp_adjust) 2180 && !cfun->calls_alloca) 2181 operands[1] = GEN_INT (sp_adjust); 2182 else 2183 { 2184 if (cfun->machine->callee_saved_first_fpr_regno != SP_REGNUM) 2185 { 2186 /* If has fpr need to restore, the $sp on callee saved fpr 2187 position, so we need to consider gpr pading bytes and 2188 callee saved fpr size. */ 2189 sp_adjust = cfun->machine->callee_saved_area_gpr_padding_bytes 2190 + cfun->machine->callee_saved_fpr_regs_size; 2191 operands[1] = GEN_INT (sp_adjust); 2192 } 2193 else 2194 { 2195 operands[1] = GEN_INT (0); 2196 } 2197 } 2198 2199 /* Create assembly code pattern. */ 2200 snprintf (pattern, sizeof (pattern), "pop25\t%%0, %%1"); 2201 } 2202 else 2203 { 2204 /* For normal stack pop multiple: 2205 operands[0]: Rb 2206 operands[1]: Re 2207 operands[2]: En4 */ 2208 2209 /* This variable is used to check if we only need to generate En4 field. 2210 As long as Rb==Re=SP_REGNUM, we set this variable to 1. */ 2211 int pop_en4_only_p = 0; 2212 2213 /* Set operands[0] and operands[1]. */ 2214 operands[0] = gen_rtx_REG (SImode, rb_callee_saved); 2215 operands[1] = gen_rtx_REG (SImode, re_callee_saved); 2216 2217 /* 'lmw.bim $sp,[$sp],$sp,0' means pop nothing. */ 2218 if (!cfun->machine->fp_size 2219 && !cfun->machine->gp_size 2220 && !cfun->machine->lp_size 2221 && REGNO (operands[0]) == SP_REGNUM 2222 && REGNO (operands[1]) == SP_REGNUM) 2223 { 2224 /* No need to generate instruction. */ 2225 return ""; 2226 } 2227 else 2228 { 2229 /* If Rb==Re=SP_REGNUM, we only need to generate En4 field. */ 2230 if (REGNO (operands[0]) == SP_REGNUM 2231 && REGNO (operands[1]) == SP_REGNUM) 2232 pop_en4_only_p = 1; 2233 2234 /* Create assembly code pattern. 2235 We need to handle the form: "Rb, Re, { $fp $gp $lp }". */ 2236 snprintf (pattern, sizeof (pattern), 2237 "pop.s\t%s{%s%s%s }", 2238 pop_en4_only_p ? "" : "%0, %1, ", 2239 cfun->machine->fp_size ? " $fp" : "", 2240 cfun->machine->gp_size ? " $gp" : "", 2241 cfun->machine->lp_size ? " $lp" : ""); 2242 } 2243 } 2244 2245 /* We use output_asm_insn() to output assembly code by ourself. */ 2246 output_asm_insn (pattern, operands); 2247 return ""; 2248 } 2249 2250 /* Function to output return operation. */ 2251 const char * 2252 nds32_output_return (void) 2253 { 2254 /* A string pattern for output_asm_insn(). */ 2255 char pattern[100]; 2256 /* The operands array which will be used in output_asm_insn(). */ 2257 rtx operands[2]; 2258 /* For stack v3pop: 2259 operands[0]: Re 2260 operands[1]: imm8u */ 2261 int re_callee_saved = cfun->machine->callee_saved_last_gpr_regno; 2262 int sp_adjust; 2263 2264 /* Set operands[0]. */ 2265 operands[0] = gen_rtx_REG (SImode, re_callee_saved); 2266 2267 /* Check if we can generate 'pop25 Re,imm8u', 2268 otherwise, generate 'pop25 Re,0'. 2269 We have to consider alloca issue as well. 2270 If the function does call alloca(), the stack pointer is not fixed. 2271 In that case, we cannot use 'pop25 Re,imm8u' directly. 2272 We have to caculate stack pointer from frame pointer 2273 and then use 'pop25 Re,0'. */ 2274 sp_adjust = cfun->machine->local_size 2275 + cfun->machine->out_args_size 2276 + cfun->machine->callee_saved_area_gpr_padding_bytes 2277 + cfun->machine->callee_saved_fpr_regs_size; 2278 if (satisfies_constraint_Iu08 (GEN_INT (sp_adjust)) 2279 && NDS32_DOUBLE_WORD_ALIGN_P (sp_adjust) 2280 && !cfun->calls_alloca) 2281 operands[1] = GEN_INT (sp_adjust); 2282 else 2283 operands[1] = GEN_INT (0); 2284 2285 /* Create assembly code pattern. */ 2286 snprintf (pattern, sizeof (pattern), "pop25\t%%0, %%1"); 2287 /* We use output_asm_insn() to output assembly code by ourself. */ 2288 output_asm_insn (pattern, operands); 2289 return ""; 2290 } 2291 2292 2293 /* output a float load instruction */ 2294 const char * 2295 nds32_output_float_load (rtx *operands) 2296 { 2297 char buff[100]; 2298 const char *pattern; 2299 rtx addr, addr_op0, addr_op1; 2300 int dp = GET_MODE_SIZE (GET_MODE (operands[0])) == 8; 2301 addr = XEXP (operands[1], 0); 2302 switch (GET_CODE (addr)) 2303 { 2304 case REG: 2305 pattern = "fl%ci\t%%0, %%1"; 2306 break; 2307 2308 case PLUS: 2309 addr_op0 = XEXP (addr, 0); 2310 addr_op1 = XEXP (addr, 1); 2311 2312 if (REG_P (addr_op0) && REG_P (addr_op1)) 2313 pattern = "fl%c\t%%0, %%1"; 2314 else if (REG_P (addr_op0) && CONST_INT_P (addr_op1)) 2315 pattern = "fl%ci\t%%0, %%1"; 2316 else if (GET_CODE (addr_op0) == MULT && REG_P (addr_op1) 2317 && REG_P (XEXP (addr_op0, 0)) 2318 && CONST_INT_P (XEXP (addr_op0, 1))) 2319 pattern = "fl%c\t%%0, %%1"; 2320 else 2321 gcc_unreachable (); 2322 break; 2323 2324 case POST_MODIFY: 2325 addr_op0 = XEXP (addr, 0); 2326 addr_op1 = XEXP (addr, 1); 2327 2328 if (REG_P (addr_op0) && GET_CODE (addr_op1) == PLUS 2329 && REG_P (XEXP (addr_op1, 1))) 2330 pattern = "fl%c.bi\t%%0, %%1"; 2331 else if (REG_P (addr_op0) && GET_CODE (addr_op1) == PLUS 2332 && CONST_INT_P (XEXP (addr_op1, 1))) 2333 pattern = "fl%ci.bi\t%%0, %%1"; 2334 else 2335 gcc_unreachable (); 2336 break; 2337 2338 case POST_INC: 2339 if (REG_P (XEXP (addr, 0))) 2340 { 2341 if (dp) 2342 pattern = "fl%ci.bi\t%%0, %%1, 8"; 2343 else 2344 pattern = "fl%ci.bi\t%%0, %%1, 4"; 2345 } 2346 else 2347 gcc_unreachable (); 2348 break; 2349 2350 case POST_DEC: 2351 if (REG_P (XEXP (addr, 0))) 2352 { 2353 if (dp) 2354 pattern = "fl%ci.bi\t%%0, %%1, -8"; 2355 else 2356 pattern = "fl%ci.bi\t%%0, %%1, -4"; 2357 } 2358 else 2359 gcc_unreachable (); 2360 break; 2361 2362 default: 2363 gcc_unreachable (); 2364 } 2365 2366 sprintf (buff, pattern, dp ? 'd' : 's'); 2367 output_asm_insn (buff, operands); 2368 return ""; 2369 } 2370 2371 /* output a float store instruction */ 2372 const char * 2373 nds32_output_float_store (rtx *operands) 2374 { 2375 char buff[100]; 2376 const char *pattern; 2377 rtx addr, addr_op0, addr_op1; 2378 int dp = GET_MODE_SIZE (GET_MODE (operands[0])) == 8; 2379 addr = XEXP (operands[0], 0); 2380 switch (GET_CODE (addr)) 2381 { 2382 case REG: 2383 pattern = "fs%ci\t%%1, %%0"; 2384 break; 2385 2386 case PLUS: 2387 addr_op0 = XEXP (addr, 0); 2388 addr_op1 = XEXP (addr, 1); 2389 2390 if (REG_P (addr_op0) && REG_P (addr_op1)) 2391 pattern = "fs%c\t%%1, %%0"; 2392 else if (REG_P (addr_op0) && CONST_INT_P (addr_op1)) 2393 pattern = "fs%ci\t%%1, %%0"; 2394 else if (GET_CODE (addr_op0) == MULT && REG_P (addr_op1) 2395 && REG_P (XEXP (addr_op0, 0)) 2396 && CONST_INT_P (XEXP (addr_op0, 1))) 2397 pattern = "fs%c\t%%1, %%0"; 2398 else 2399 gcc_unreachable (); 2400 break; 2401 2402 case POST_MODIFY: 2403 addr_op0 = XEXP (addr, 0); 2404 addr_op1 = XEXP (addr, 1); 2405 2406 if (REG_P (addr_op0) && GET_CODE (addr_op1) == PLUS 2407 && REG_P (XEXP (addr_op1, 1))) 2408 pattern = "fs%c.bi\t%%1, %%0"; 2409 else if (REG_P (addr_op0) && GET_CODE (addr_op1) == PLUS 2410 && CONST_INT_P (XEXP (addr_op1, 1))) 2411 pattern = "fs%ci.bi\t%%1, %%0"; 2412 else 2413 gcc_unreachable (); 2414 break; 2415 2416 case POST_INC: 2417 if (REG_P (XEXP (addr, 0))) 2418 { 2419 if (dp) 2420 pattern = "fs%ci.bi\t%%1, %%0, 8"; 2421 else 2422 pattern = "fs%ci.bi\t%%1, %%0, 4"; 2423 } 2424 else 2425 gcc_unreachable (); 2426 break; 2427 2428 case POST_DEC: 2429 if (REG_P (XEXP (addr, 0))) 2430 { 2431 if (dp) 2432 pattern = "fs%ci.bi\t%%1, %%0, -8"; 2433 else 2434 pattern = "fs%ci.bi\t%%1, %%0, -4"; 2435 } 2436 else 2437 gcc_unreachable (); 2438 break; 2439 2440 default: 2441 gcc_unreachable (); 2442 } 2443 2444 sprintf (buff, pattern, dp ? 'd' : 's'); 2445 output_asm_insn (buff, operands); 2446 return ""; 2447 } 2448 2449 const char * 2450 nds32_output_smw_single_word (rtx *operands) 2451 { 2452 char buff[100]; 2453 unsigned regno; 2454 int enable4; 2455 bool update_base_p; 2456 rtx base_addr = operands[0]; 2457 rtx base_reg; 2458 rtx otherops[2]; 2459 2460 if (REG_P (XEXP (base_addr, 0))) 2461 { 2462 update_base_p = false; 2463 base_reg = XEXP (base_addr, 0); 2464 } 2465 else 2466 { 2467 update_base_p = true; 2468 base_reg = XEXP (XEXP (base_addr, 0), 0); 2469 } 2470 2471 const char *update_base = update_base_p ? "m" : ""; 2472 2473 regno = REGNO (operands[1]); 2474 2475 otherops[0] = base_reg; 2476 otherops[1] = operands[1]; 2477 2478 if (regno >= 28) 2479 { 2480 enable4 = nds32_regno_to_enable4 (regno); 2481 sprintf (buff, "smw.bi%s\t$sp, [%%0], $sp, %x", update_base, enable4); 2482 } 2483 else 2484 { 2485 sprintf (buff, "smw.bi%s\t%%1, [%%0], %%1", update_base); 2486 } 2487 output_asm_insn (buff, otherops); 2488 return ""; 2489 } 2490 2491 /* ------------------------------------------------------------------------ */ 2492 const char * 2493 nds32_output_smw_double_word (rtx *operands) 2494 { 2495 char buff[100]; 2496 unsigned regno; 2497 int enable4; 2498 bool update_base_p; 2499 rtx base_addr = operands[0]; 2500 rtx base_reg; 2501 rtx otherops[3]; 2502 2503 if (REG_P (XEXP (base_addr, 0))) 2504 { 2505 update_base_p = false; 2506 base_reg = XEXP (base_addr, 0); 2507 } 2508 else 2509 { 2510 update_base_p = true; 2511 base_reg = XEXP (XEXP (base_addr, 0), 0); 2512 } 2513 2514 const char *update_base = update_base_p ? "m" : ""; 2515 2516 regno = REGNO (operands[1]); 2517 2518 otherops[0] = base_reg; 2519 otherops[1] = operands[1]; 2520 otherops[2] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1);; 2521 2522 if (regno >= 28) 2523 { 2524 enable4 = nds32_regno_to_enable4 (regno) 2525 | nds32_regno_to_enable4 (regno + 1); 2526 sprintf (buff, "smw.bi%s\t$sp, [%%0], $sp, %x", update_base, enable4); 2527 } 2528 else if (regno == 27) 2529 { 2530 enable4 = nds32_regno_to_enable4 (regno + 1); 2531 sprintf (buff, "smw.bi%s\t%%1, [%%0], %%1, %x", update_base, enable4); 2532 } 2533 else 2534 { 2535 sprintf (buff, "smw.bi%s\t%%1, [%%0], %%2", update_base); 2536 } 2537 output_asm_insn (buff, otherops); 2538 return ""; 2539 } 2540 2541 const char * 2542 nds32_output_lmw_single_word (rtx *operands) 2543 { 2544 char buff[100]; 2545 unsigned regno; 2546 bool update_base_p; 2547 int enable4; 2548 rtx base_addr = operands[1]; 2549 rtx base_reg; 2550 rtx otherops[2]; 2551 2552 if (REG_P (XEXP (base_addr, 0))) 2553 { 2554 update_base_p = false; 2555 base_reg = XEXP (base_addr, 0); 2556 } 2557 else 2558 { 2559 update_base_p = true; 2560 base_reg = XEXP (XEXP (base_addr, 0), 0); 2561 } 2562 2563 const char *update_base = update_base_p ? "m" : ""; 2564 2565 regno = REGNO (operands[0]); 2566 2567 otherops[0] = operands[0]; 2568 otherops[1] = base_reg; 2569 2570 if (regno >= 28) 2571 { 2572 enable4 = nds32_regno_to_enable4 (regno); 2573 sprintf (buff, "lmw.bi%s\t$sp, [%%1], $sp, %x", update_base, enable4); 2574 } 2575 else 2576 { 2577 sprintf (buff, "lmw.bi%s\t%%0, [%%1], %%0", update_base); 2578 } 2579 output_asm_insn (buff, otherops); 2580 return ""; 2581 } 2582 2583 void 2584 nds32_expand_unaligned_load (rtx *operands, enum machine_mode mode) 2585 { 2586 /* Initial memory offset. */ 2587 int offset = WORDS_BIG_ENDIAN ? GET_MODE_SIZE (mode) - 1 : 0; 2588 int offset_adj = WORDS_BIG_ENDIAN ? -1 : 1; 2589 /* Initial register shift byte. */ 2590 int shift = 0; 2591 /* The first load byte instruction is not the same. */ 2592 int width = GET_MODE_SIZE (mode) - 1; 2593 rtx mem[2]; 2594 rtx reg[2]; 2595 rtx sub_reg; 2596 rtx temp_reg, temp_sub_reg; 2597 int num_reg; 2598 2599 /* Generating a series of load byte instructions. 2600 The first load byte instructions and other 2601 load byte instructions are not the same. like: 2602 First: 2603 lbi reg0, [mem] 2604 zeh reg0, reg0 2605 Second: 2606 lbi temp_reg, [mem + offset] 2607 sll temp_reg, (8 * shift) 2608 ior reg0, temp_reg 2609 2610 lbi temp_reg, [mem + (offset + 1)] 2611 sll temp_reg, (8 * (shift + 1)) 2612 ior reg0, temp_reg */ 2613 2614 temp_reg = gen_reg_rtx (SImode); 2615 temp_sub_reg = gen_lowpart (QImode, temp_reg); 2616 2617 if (mode == DImode) 2618 { 2619 /* Load doubleword, we need two registers to access. */ 2620 reg[0] = nds32_di_low_part_subreg (operands[0]); 2621 reg[1] = nds32_di_high_part_subreg (operands[0]); 2622 /* A register only store 4 byte. */ 2623 width = GET_MODE_SIZE (SImode) - 1; 2624 } 2625 else 2626 { 2627 if (VECTOR_MODE_P (mode)) 2628 reg[0] = gen_reg_rtx (SImode); 2629 else 2630 reg[0] = operands[0]; 2631 } 2632 2633 for (num_reg = (mode == DImode) ? 2 : 1; num_reg > 0; num_reg--) 2634 { 2635 sub_reg = gen_lowpart (QImode, reg[0]); 2636 mem[0] = gen_rtx_MEM (QImode, plus_constant (Pmode, operands[1], offset)); 2637 2638 /* Generating the first part instructions. 2639 lbi reg0, [mem] 2640 zeh reg0, reg0 */ 2641 emit_move_insn (sub_reg, mem[0]); 2642 emit_insn (gen_zero_extendqisi2 (reg[0], sub_reg)); 2643 2644 while (width > 0) 2645 { 2646 offset = offset + offset_adj; 2647 shift++; 2648 width--; 2649 2650 mem[1] = gen_rtx_MEM (QImode, plus_constant (Pmode, 2651 operands[1], 2652 offset)); 2653 /* Generating the second part instructions. 2654 lbi temp_reg, [mem + offset] 2655 sll temp_reg, (8 * shift) 2656 ior reg0, temp_reg */ 2657 emit_move_insn (temp_sub_reg, mem[1]); 2658 emit_insn (gen_ashlsi3 (temp_reg, temp_reg, 2659 GEN_INT (shift * 8))); 2660 emit_insn (gen_iorsi3 (reg[0], reg[0], temp_reg)); 2661 } 2662 2663 if (mode == DImode) 2664 { 2665 /* Using the second register to load memory information. */ 2666 reg[0] = reg[1]; 2667 shift = 0; 2668 width = GET_MODE_SIZE (SImode) - 1; 2669 offset = offset + offset_adj; 2670 } 2671 } 2672 if (VECTOR_MODE_P (mode)) 2673 convert_move (operands[0], reg[0], false); 2674 } 2675 2676 void 2677 nds32_expand_unaligned_store (rtx *operands, enum machine_mode mode) 2678 { 2679 /* Initial memory offset. */ 2680 int offset = WORDS_BIG_ENDIAN ? GET_MODE_SIZE (mode) - 1 : 0; 2681 int offset_adj = WORDS_BIG_ENDIAN ? -1 : 1; 2682 /* Initial register shift byte. */ 2683 int shift = 0; 2684 /* The first load byte instruction is not the same. */ 2685 int width = GET_MODE_SIZE (mode) - 1; 2686 rtx mem[2]; 2687 rtx reg[2]; 2688 rtx sub_reg; 2689 rtx temp_reg, temp_sub_reg; 2690 int num_reg; 2691 2692 /* Generating a series of store byte instructions. 2693 The first store byte instructions and other 2694 load byte instructions are not the same. like: 2695 First: 2696 sbi reg0, [mem + 0] 2697 Second: 2698 srli temp_reg, reg0, (8 * shift) 2699 sbi temp_reg, [mem + offset] */ 2700 2701 temp_reg = gen_reg_rtx (SImode); 2702 temp_sub_reg = gen_lowpart (QImode, temp_reg); 2703 2704 if (mode == DImode) 2705 { 2706 /* Load doubleword, we need two registers to access. */ 2707 reg[0] = nds32_di_low_part_subreg (operands[1]); 2708 reg[1] = nds32_di_high_part_subreg (operands[1]); 2709 /* A register only store 4 byte. */ 2710 width = GET_MODE_SIZE (SImode) - 1; 2711 } 2712 else 2713 { 2714 if (VECTOR_MODE_P (mode)) 2715 { 2716 reg[0] = gen_reg_rtx (SImode); 2717 convert_move (reg[0], operands[1], false); 2718 } 2719 else 2720 reg[0] = operands[1]; 2721 } 2722 2723 for (num_reg = (mode == DImode) ? 2 : 1; num_reg > 0; num_reg--) 2724 { 2725 sub_reg = gen_lowpart (QImode, reg[0]); 2726 mem[0] = gen_rtx_MEM (QImode, plus_constant (Pmode, operands[0], offset)); 2727 2728 /* Generating the first part instructions. 2729 sbi reg0, [mem + 0] */ 2730 emit_move_insn (mem[0], sub_reg); 2731 2732 while (width > 0) 2733 { 2734 offset = offset + offset_adj; 2735 shift++; 2736 width--; 2737 2738 mem[1] = gen_rtx_MEM (QImode, plus_constant (Pmode, 2739 operands[0], 2740 offset)); 2741 /* Generating the second part instructions. 2742 srli temp_reg, reg0, (8 * shift) 2743 sbi temp_reg, [mem + offset] */ 2744 emit_insn (gen_lshrsi3 (temp_reg, reg[0], 2745 GEN_INT (shift * 8))); 2746 emit_move_insn (mem[1], temp_sub_reg); 2747 } 2748 2749 if (mode == DImode) 2750 { 2751 /* Using the second register to load memory information. */ 2752 reg[0] = reg[1]; 2753 shift = 0; 2754 width = GET_MODE_SIZE (SImode) - 1; 2755 offset = offset + offset_adj; 2756 } 2757 } 2758 } 2759 2760 /* Using multiple load/store instruction to output doubleword instruction. */ 2761 const char * 2762 nds32_output_double (rtx *operands, bool load_p) 2763 { 2764 char pattern[100]; 2765 int reg = load_p ? 0 : 1; 2766 int mem = load_p ? 1 : 0; 2767 rtx otherops[3]; 2768 rtx addr = XEXP (operands[mem], 0); 2769 2770 otherops[0] = gen_rtx_REG (SImode, REGNO (operands[reg])); 2771 otherops[1] = gen_rtx_REG (SImode, REGNO (operands[reg]) + 1); 2772 2773 if (GET_CODE (addr) == POST_INC) 2774 { 2775 /* (mem (post_inc (reg))) */ 2776 otherops[2] = XEXP (addr, 0); 2777 snprintf (pattern, sizeof (pattern), 2778 "%cmw.bim\t%%0, [%%2], %%1, 0", load_p ? 'l' : 's'); 2779 } 2780 else 2781 { 2782 /* (mem (reg)) */ 2783 otherops[2] = addr; 2784 snprintf (pattern, sizeof (pattern), 2785 "%cmw.bi\t%%0, [%%2], %%1, 0", load_p ? 'l' : 's'); 2786 2787 } 2788 2789 output_asm_insn (pattern, otherops); 2790 return ""; 2791 } 2792 2793 const char * 2794 nds32_output_cbranchsi4_equality_zero (rtx_insn *insn, rtx *operands) 2795 { 2796 enum rtx_code code; 2797 bool long_jump_p = false; 2798 2799 code = GET_CODE (operands[0]); 2800 2801 /* This zero-comparison conditional branch has two forms: 2802 32-bit instruction => beqz/bnez imm16s << 1 2803 16-bit instruction => beqzs8/bnezs8/beqz38/bnez38 imm8s << 1 2804 2805 For 32-bit case, 2806 we assume it is always reachable. (but check range -65500 ~ 65500) 2807 2808 For 16-bit case, 2809 it must satisfy { 255 >= (label - pc) >= -256 } condition. 2810 However, since the $pc for nds32 is at the beginning of the instruction, 2811 we should leave some length space for current insn. 2812 So we use range -250 ~ 250. */ 2813 2814 switch (get_attr_length (insn)) 2815 { 2816 case 8: 2817 long_jump_p = true; 2818 /* fall through */ 2819 case 2: 2820 if (which_alternative == 0) 2821 { 2822 /* constraint: t */ 2823 /* b<cond>zs8 .L0 2824 or 2825 b<inverse_cond>zs8 .LCB0 2826 j .L0 2827 .LCB0: 2828 */ 2829 output_cond_branch_compare_zero (code, "s8", long_jump_p, 2830 operands, true); 2831 return ""; 2832 } 2833 else if (which_alternative == 1) 2834 { 2835 /* constraint: l */ 2836 /* b<cond>z38 $r0, .L0 2837 or 2838 b<inverse_cond>z38 $r0, .LCB0 2839 j .L0 2840 .LCB0: 2841 */ 2842 output_cond_branch_compare_zero (code, "38", long_jump_p, 2843 operands, false); 2844 return ""; 2845 } 2846 else 2847 { 2848 /* constraint: r */ 2849 /* For which_alternative==2, it should not be here. */ 2850 gcc_unreachable (); 2851 } 2852 case 10: 2853 /* including constraints: t, l, and r */ 2854 long_jump_p = true; 2855 /* fall through */ 2856 case 4: 2857 /* including constraints: t, l, and r */ 2858 output_cond_branch_compare_zero (code, "", long_jump_p, operands, false); 2859 return ""; 2860 2861 default: 2862 gcc_unreachable (); 2863 } 2864 } 2865 2866 const char * 2867 nds32_output_cbranchsi4_equality_reg (rtx_insn *insn, rtx *operands) 2868 { 2869 enum rtx_code code; 2870 bool long_jump_p, r5_p; 2871 int insn_length; 2872 2873 insn_length = get_attr_length (insn); 2874 2875 long_jump_p = (insn_length == 10 || insn_length == 8) ? true : false; 2876 r5_p = (insn_length == 2 || insn_length == 8) ? true : false; 2877 2878 code = GET_CODE (operands[0]); 2879 2880 /* This register-comparison conditional branch has one form: 2881 32-bit instruction => beq/bne imm14s << 1 2882 2883 For 32-bit case, 2884 we assume it is always reachable. (but check range -16350 ~ 16350). */ 2885 2886 switch (code) 2887 { 2888 case EQ: 2889 case NE: 2890 output_cond_branch (code, "", r5_p, long_jump_p, operands); 2891 return ""; 2892 2893 default: 2894 gcc_unreachable (); 2895 } 2896 } 2897 2898 const char * 2899 nds32_output_cbranchsi4_equality_reg_or_const_int (rtx_insn *insn, 2900 rtx *operands) 2901 { 2902 enum rtx_code code; 2903 bool long_jump_p, r5_p; 2904 int insn_length; 2905 2906 insn_length = get_attr_length (insn); 2907 2908 long_jump_p = (insn_length == 10 || insn_length == 8) ? true : false; 2909 r5_p = (insn_length == 2 || insn_length == 8) ? true : false; 2910 2911 code = GET_CODE (operands[0]); 2912 2913 /* This register-comparison conditional branch has one form: 2914 32-bit instruction => beq/bne imm14s << 1 2915 32-bit instruction => beqc/bnec imm8s << 1 2916 2917 For 32-bit case, we assume it is always reachable. 2918 (but check range -16350 ~ 16350 and -250 ~ 250). */ 2919 2920 switch (code) 2921 { 2922 case EQ: 2923 case NE: 2924 if (which_alternative == 2) 2925 { 2926 /* r, Is11 */ 2927 /* b<cond>c */ 2928 output_cond_branch (code, "c", r5_p, long_jump_p, operands); 2929 } 2930 else 2931 { 2932 /* r, r */ 2933 /* v, r */ 2934 output_cond_branch (code, "", r5_p, long_jump_p, operands); 2935 } 2936 return ""; 2937 default: 2938 gcc_unreachable (); 2939 } 2940 } 2941 2942 const char * 2943 nds32_output_cbranchsi4_greater_less_zero (rtx_insn *insn, rtx *operands) 2944 { 2945 enum rtx_code code; 2946 bool long_jump_p; 2947 int insn_length; 2948 2949 insn_length = get_attr_length (insn); 2950 2951 gcc_assert (insn_length == 4 || insn_length == 10); 2952 2953 long_jump_p = (insn_length == 10) ? true : false; 2954 2955 code = GET_CODE (operands[0]); 2956 2957 /* This zero-greater-less-comparison conditional branch has one form: 2958 32-bit instruction => bgtz/bgez/bltz/blez imm16s << 1 2959 2960 For 32-bit case, we assume it is always reachable. 2961 (but check range -65500 ~ 65500). */ 2962 2963 switch (code) 2964 { 2965 case GT: 2966 case GE: 2967 case LT: 2968 case LE: 2969 output_cond_branch_compare_zero (code, "", long_jump_p, operands, false); 2970 break; 2971 default: 2972 gcc_unreachable (); 2973 } 2974 return ""; 2975 } 2976 2977 const char * 2978 nds32_output_unpkd8 (rtx output, rtx input, 2979 rtx high_idx_rtx, rtx low_idx_rtx, 2980 bool signed_p) 2981 { 2982 char pattern[100]; 2983 rtx output_operands[2]; 2984 HOST_WIDE_INT high_idx, low_idx; 2985 high_idx = INTVAL (high_idx_rtx); 2986 low_idx = INTVAL (low_idx_rtx); 2987 2988 gcc_assert (high_idx >= 0 && high_idx <= 3); 2989 gcc_assert (low_idx >= 0 && low_idx <= 3); 2990 2991 /* We only have 10, 20, 30 and 31. */ 2992 if ((low_idx != 0 || high_idx == 0) && 2993 !(low_idx == 1 && high_idx == 3)) 2994 return "#"; 2995 2996 char sign_char = signed_p ? 's' : 'z'; 2997 2998 sprintf (pattern, 2999 "%cunpkd8" HOST_WIDE_INT_PRINT_DEC HOST_WIDE_INT_PRINT_DEC "\t%%0, %%1", 3000 sign_char, high_idx, low_idx); 3001 output_operands[0] = output; 3002 output_operands[1] = input; 3003 output_asm_insn (pattern, output_operands); 3004 return ""; 3005 } 3006 3007 /* Return true if SYMBOL_REF X binds locally. */ 3008 3009 static bool 3010 nds32_symbol_binds_local_p (const_rtx x) 3011 { 3012 return (SYMBOL_REF_DECL (x) 3013 ? targetm.binds_local_p (SYMBOL_REF_DECL (x)) 3014 : SYMBOL_REF_LOCAL_P (x)); 3015 } 3016 3017 const char * 3018 nds32_output_call (rtx insn, rtx *operands, rtx symbol, const char *long_call, 3019 const char *call, bool align_p) 3020 { 3021 char pattern[100]; 3022 bool noreturn_p; 3023 3024 if (nds32_long_call_p (symbol)) 3025 strcpy (pattern, long_call); 3026 else 3027 strcpy (pattern, call); 3028 3029 if (flag_pic && CONSTANT_P (symbol) 3030 && !nds32_symbol_binds_local_p (symbol)) 3031 strcat (pattern, "@PLT"); 3032 3033 if (align_p) 3034 strcat (pattern, "\n\t.align 2"); 3035 3036 noreturn_p = find_reg_note (insn, REG_NORETURN, NULL_RTX) != NULL_RTX; 3037 3038 if (noreturn_p) 3039 { 3040 if (TARGET_16_BIT) 3041 strcat (pattern, "\n\tnop16"); 3042 else 3043 strcat (pattern, "\n\tnop"); 3044 } 3045 3046 output_asm_insn (pattern, operands); 3047 return ""; 3048 } 3049 3050 bool 3051 nds32_need_split_sms_p (rtx in0_idx0, rtx in1_idx0, 3052 rtx in0_idx1, rtx in1_idx1) 3053 { 3054 /* smds or smdrs. */ 3055 if (INTVAL (in0_idx0) == INTVAL (in1_idx0) 3056 && INTVAL (in0_idx1) == INTVAL (in1_idx1) 3057 && INTVAL (in0_idx0) != INTVAL (in0_idx1)) 3058 return false; 3059 3060 /* smxds. */ 3061 if (INTVAL (in0_idx0) != INTVAL (in0_idx1) 3062 && INTVAL (in1_idx0) != INTVAL (in1_idx1)) 3063 return false; 3064 3065 return true; 3066 } 3067 3068 const char * 3069 nds32_output_sms (rtx in0_idx0, rtx in1_idx0, 3070 rtx in0_idx1, rtx in1_idx1) 3071 { 3072 if (nds32_need_split_sms_p (in0_idx0, in1_idx0, 3073 in0_idx1, in1_idx1)) 3074 return "#"; 3075 /* out = in0[in0_idx0] * in1[in1_idx0] - in0[in0_idx1] * in1[in1_idx1] */ 3076 3077 /* smds or smdrs. */ 3078 if (INTVAL (in0_idx0) == INTVAL (in1_idx0) 3079 && INTVAL (in0_idx1) == INTVAL (in1_idx1) 3080 && INTVAL (in0_idx0) != INTVAL (in0_idx1)) 3081 { 3082 if (INTVAL (in0_idx0) == 0) 3083 { 3084 if (TARGET_BIG_ENDIAN) 3085 return "smds\t%0, %1, %2"; 3086 else 3087 return "smdrs\t%0, %1, %2"; 3088 } 3089 else 3090 { 3091 if (TARGET_BIG_ENDIAN) 3092 return "smdrs\t%0, %1, %2"; 3093 else 3094 return "smds\t%0, %1, %2"; 3095 } 3096 } 3097 3098 if (INTVAL (in0_idx0) != INTVAL (in0_idx1) 3099 && INTVAL (in1_idx0) != INTVAL (in1_idx1)) 3100 { 3101 if (INTVAL (in0_idx0) == 1) 3102 { 3103 if (TARGET_BIG_ENDIAN) 3104 return "smxds\t%0, %2, %1"; 3105 else 3106 return "smxds\t%0, %1, %2"; 3107 } 3108 else 3109 { 3110 if (TARGET_BIG_ENDIAN) 3111 return "smxds\t%0, %1, %2"; 3112 else 3113 return "smxds\t%0, %2, %1"; 3114 } 3115 } 3116 3117 gcc_unreachable (); 3118 return ""; 3119 } 3120 3121 void 3122 nds32_split_sms (rtx out, rtx in0, rtx in1, 3123 rtx in0_idx0, rtx in1_idx0, 3124 rtx in0_idx1, rtx in1_idx1) 3125 { 3126 rtx result0 = gen_reg_rtx (SImode); 3127 rtx result1 = gen_reg_rtx (SImode); 3128 emit_insn (gen_mulhisi3v (result0, in0, in1, 3129 in0_idx0, in1_idx0)); 3130 emit_insn (gen_mulhisi3v (result1, in0, in1, 3131 in0_idx1, in1_idx1)); 3132 emit_insn (gen_subsi3 (out, result0, result1)); 3133 } 3134 3135 /* Spilt a doubleword instrucion to two single word instructions. */ 3136 void 3137 nds32_spilt_doubleword (rtx *operands, bool load_p) 3138 { 3139 int reg = load_p ? 0 : 1; 3140 int mem = load_p ? 1 : 0; 3141 rtx reg_rtx = load_p ? operands[0] : operands[1]; 3142 rtx mem_rtx = load_p ? operands[1] : operands[0]; 3143 rtx low_part[2], high_part[2]; 3144 rtx sub_mem = XEXP (mem_rtx, 0); 3145 3146 /* Generate low_part and high_part register pattern. 3147 i.e. register pattern like: 3148 (reg:DI) -> (subreg:SI (reg:DI)) 3149 (subreg:SI (reg:DI)) */ 3150 low_part[reg] = simplify_gen_subreg (SImode, reg_rtx, GET_MODE (reg_rtx), 0); 3151 high_part[reg] = simplify_gen_subreg (SImode, reg_rtx, GET_MODE (reg_rtx), 4); 3152 3153 /* Generate low_part and high_part memory pattern. 3154 Memory format is (post_dec) will generate: 3155 low_part: lwi.bi reg, [mem], 4 3156 high_part: lwi.bi reg, [mem], -12 */ 3157 if (GET_CODE (sub_mem) == POST_DEC) 3158 { 3159 /* memory format is (post_dec (reg)), 3160 so that extract (reg) from the (post_dec (reg)) pattern. */ 3161 sub_mem = XEXP (sub_mem, 0); 3162 3163 /* generate low_part and high_part memory format: 3164 low_part: (post_modify ((reg) (plus (reg) (const 4))) 3165 high_part: (post_modify ((reg) (plus (reg) (const -12))) */ 3166 low_part[mem] = gen_rtx_MEM (SImode, 3167 gen_rtx_POST_MODIFY (Pmode, sub_mem, 3168 gen_rtx_PLUS (Pmode, 3169 sub_mem, 3170 GEN_INT (4)))); 3171 high_part[mem] = gen_rtx_MEM (SImode, 3172 gen_rtx_POST_MODIFY (Pmode, sub_mem, 3173 gen_rtx_PLUS (Pmode, 3174 sub_mem, 3175 GEN_INT (-12)))); 3176 } 3177 else if (GET_CODE (sub_mem) == POST_INC) 3178 { 3179 /* memory format is (post_inc (reg)), 3180 so that extract (reg) from the (post_inc (reg)) pattern. */ 3181 sub_mem = XEXP (sub_mem, 0); 3182 3183 /* generate low_part and high_part memory format: 3184 low_part: (post_inc (reg)) 3185 high_part: (post_inc (reg)) */ 3186 low_part[mem] = gen_rtx_MEM (SImode, 3187 gen_rtx_POST_INC (Pmode, sub_mem)); 3188 high_part[mem] = gen_rtx_MEM (SImode, 3189 gen_rtx_POST_INC (Pmode, sub_mem)); 3190 } 3191 else if (GET_CODE (sub_mem) == POST_MODIFY) 3192 { 3193 /* Memory format is (post_modify (reg) (plus (reg) (const))), 3194 so that extract (reg) from the post_modify pattern. */ 3195 rtx post_mem = XEXP (sub_mem, 0); 3196 3197 /* Extract (const) from the (post_modify (reg) (plus (reg) (const))) 3198 pattern. */ 3199 3200 rtx plus_op = XEXP (sub_mem, 1); 3201 rtx post_val = XEXP (plus_op, 1); 3202 3203 /* Generate low_part and high_part memory format: 3204 low_part: (post_modify ((reg) (plus (reg) (const))) 3205 high_part: ((plus (reg) (const 4))) */ 3206 low_part[mem] = gen_rtx_MEM (SImode, 3207 gen_rtx_POST_MODIFY (Pmode, post_mem, 3208 gen_rtx_PLUS (Pmode, 3209 post_mem, 3210 post_val))); 3211 high_part[mem] = gen_rtx_MEM (SImode, plus_constant (Pmode, 3212 post_mem, 3213 4)); 3214 } 3215 else 3216 { 3217 /* memory format: (symbol_ref), (const), (reg + const_int). */ 3218 low_part[mem] = adjust_address (mem_rtx, SImode, 0); 3219 high_part[mem] = adjust_address (mem_rtx, SImode, 4); 3220 } 3221 3222 /* After reload completed, we have dependent issue by low part register and 3223 higt part memory. i.e. we cannot split a sequence 3224 like: 3225 load $r0, [%r1] 3226 spilt to 3227 lw $r0, [%r0] 3228 lwi $r1, [%r0 + 4] 3229 swap position 3230 lwi $r1, [%r0 + 4] 3231 lw $r0, [%r0] 3232 For store instruction we don't have a problem. 3233 3234 When memory format is [post_modify], we need to emit high part instruction, 3235 before low part instruction. 3236 expamle: 3237 load $r0, [%r2], post_val 3238 spilt to 3239 load $r1, [%r2 + 4] 3240 load $r0, [$r2], post_val. */ 3241 if ((load_p && reg_overlap_mentioned_p (low_part[0], high_part[1])) 3242 || GET_CODE (sub_mem) == POST_MODIFY) 3243 { 3244 operands[2] = high_part[0]; 3245 operands[3] = high_part[1]; 3246 operands[4] = low_part[0]; 3247 operands[5] = low_part[1]; 3248 } 3249 else 3250 { 3251 operands[2] = low_part[0]; 3252 operands[3] = low_part[1]; 3253 operands[4] = high_part[0]; 3254 operands[5] = high_part[1]; 3255 } 3256 } 3257 3258 void 3259 nds32_split_ashiftdi3 (rtx dst, rtx src, rtx shiftamount) 3260 { 3261 rtx src_high_part, src_low_part; 3262 rtx dst_high_part, dst_low_part; 3263 3264 dst_high_part = nds32_di_high_part_subreg (dst); 3265 dst_low_part = nds32_di_low_part_subreg (dst); 3266 3267 src_high_part = nds32_di_high_part_subreg (src); 3268 src_low_part = nds32_di_low_part_subreg (src); 3269 3270 /* We need to handle shift more than 32 bit!!!! */ 3271 if (CONST_INT_P (shiftamount)) 3272 { 3273 if (INTVAL (shiftamount) < 32) 3274 { 3275 rtx ext_start; 3276 ext_start = gen_int_mode(32 - INTVAL (shiftamount), SImode); 3277 3278 emit_insn (gen_wext (dst_high_part, src, ext_start)); 3279 emit_insn (gen_ashlsi3 (dst_low_part, src_low_part, shiftamount)); 3280 } 3281 else 3282 { 3283 rtx new_shift_amout = gen_int_mode(INTVAL (shiftamount) - 32, SImode); 3284 3285 emit_insn (gen_ashlsi3 (dst_high_part, src_low_part, 3286 new_shift_amout)); 3287 3288 emit_move_insn (dst_low_part, GEN_INT (0)); 3289 } 3290 } 3291 else 3292 { 3293 rtx dst_low_part_l32, dst_high_part_l32; 3294 rtx dst_low_part_g32, dst_high_part_g32; 3295 rtx new_shift_amout, select_reg; 3296 dst_low_part_l32 = gen_reg_rtx (SImode); 3297 dst_high_part_l32 = gen_reg_rtx (SImode); 3298 dst_low_part_g32 = gen_reg_rtx (SImode); 3299 dst_high_part_g32 = gen_reg_rtx (SImode); 3300 new_shift_amout = gen_reg_rtx (SImode); 3301 select_reg = gen_reg_rtx (SImode); 3302 3303 rtx ext_start; 3304 ext_start = gen_reg_rtx (SImode); 3305 3306 /* 3307 # In fact, we want to check shift amonut is great than or equal 32, 3308 # but in some corner case, the shift amount might be very large value, 3309 # however we've defined SHIFT_COUNT_TRUNCATED, so GCC think we've 3310 # handle that correctly without any truncate. 3311 # so check the the condition of (shiftamount & 32) is most 3312 # safe way to do. 3313 if (shiftamount & 32) 3314 dst_low_part = 0 3315 dst_high_part = src_low_part << shiftamount & 0x1f 3316 else 3317 dst_low_part = src_low_part << shiftamout 3318 dst_high_part = wext (src, 32 - shiftamount) 3319 # wext can't handle wext (src, 32) since it's only take rb[0:4] 3320 # for extract. 3321 dst_high_part = shiftamount == 0 ? src_high_part : dst_high_part 3322 3323 */ 3324 3325 emit_insn (gen_subsi3 (ext_start, 3326 gen_int_mode (32, SImode), 3327 shiftamount)); 3328 emit_insn (gen_wext (dst_high_part_l32, src, ext_start)); 3329 3330 /* Handle for shiftamout == 0. */ 3331 emit_insn (gen_cmovzsi (dst_high_part_l32, shiftamount, 3332 src_high_part, dst_high_part_l32)); 3333 3334 emit_insn (gen_ashlsi3 (dst_low_part_l32, src_low_part, shiftamount)); 3335 3336 emit_move_insn (dst_low_part_g32, const0_rtx); 3337 emit_insn (gen_andsi3 (new_shift_amout, shiftamount, GEN_INT (0x1f))); 3338 emit_insn (gen_ashlsi3 (dst_high_part_g32, src_low_part, 3339 new_shift_amout)); 3340 3341 emit_insn (gen_andsi3 (select_reg, shiftamount, GEN_INT (32))); 3342 3343 emit_insn (gen_cmovzsi (dst_low_part, select_reg, 3344 dst_low_part_l32, dst_low_part_g32)); 3345 emit_insn (gen_cmovzsi (dst_high_part, select_reg, 3346 dst_high_part_l32, dst_high_part_g32)); 3347 } 3348 } 3349 3350 void 3351 nds32_split_ashiftrtdi3 (rtx dst, rtx src, rtx shiftamount) 3352 { 3353 nds32_split_shiftrtdi3 (dst, src, shiftamount, false); 3354 } 3355 3356 void 3357 nds32_split_lshiftrtdi3 (rtx dst, rtx src, rtx shiftamount) 3358 { 3359 nds32_split_shiftrtdi3 (dst, src, shiftamount, true); 3360 } 3361 3362 void 3363 nds32_split_rotatertdi3 (rtx dst, rtx src, rtx shiftamount) 3364 { 3365 rtx dst_low_part_l32, dst_high_part_l32; 3366 rtx dst_low_part_g32, dst_high_part_g32; 3367 rtx select_reg, low5bit, low5bit_inv, minus32sa; 3368 rtx dst_low_part_g32_tmph; 3369 rtx dst_low_part_g32_tmpl; 3370 rtx dst_high_part_l32_tmph; 3371 rtx dst_high_part_l32_tmpl; 3372 3373 rtx src_low_part, src_high_part; 3374 rtx dst_high_part, dst_low_part; 3375 3376 shiftamount = force_reg (SImode, shiftamount); 3377 3378 emit_insn (gen_andsi3 (shiftamount, 3379 shiftamount, 3380 gen_int_mode (0x3f, SImode))); 3381 3382 dst_high_part = nds32_di_high_part_subreg (dst); 3383 dst_low_part = nds32_di_low_part_subreg (dst); 3384 3385 src_high_part = nds32_di_high_part_subreg (src); 3386 src_low_part = nds32_di_low_part_subreg (src); 3387 3388 dst_low_part_l32 = gen_reg_rtx (SImode); 3389 dst_high_part_l32 = gen_reg_rtx (SImode); 3390 dst_low_part_g32 = gen_reg_rtx (SImode); 3391 dst_high_part_g32 = gen_reg_rtx (SImode); 3392 low5bit = gen_reg_rtx (SImode); 3393 low5bit_inv = gen_reg_rtx (SImode); 3394 minus32sa = gen_reg_rtx (SImode); 3395 select_reg = gen_reg_rtx (SImode); 3396 3397 dst_low_part_g32_tmph = gen_reg_rtx (SImode); 3398 dst_low_part_g32_tmpl = gen_reg_rtx (SImode); 3399 3400 dst_high_part_l32_tmph = gen_reg_rtx (SImode); 3401 dst_high_part_l32_tmpl = gen_reg_rtx (SImode); 3402 3403 emit_insn (gen_slt_compare (select_reg, shiftamount, GEN_INT (32))); 3404 3405 /* if shiftamount < 32 3406 dst_low_part = wext(src, shiftamount) 3407 else 3408 dst_low_part = ((src_high_part >> (shiftamount & 0x1f)) 3409 | (src_low_part << (32 - (shiftamount & 0x1f)))) 3410 */ 3411 emit_insn (gen_andsi3 (low5bit, shiftamount, gen_int_mode (0x1f, SImode))); 3412 emit_insn (gen_subsi3 (low5bit_inv, gen_int_mode (32, SImode), low5bit)); 3413 3414 emit_insn (gen_wext (dst_low_part_l32, src, shiftamount)); 3415 3416 emit_insn (gen_lshrsi3 (dst_low_part_g32_tmpl, src_high_part, low5bit)); 3417 emit_insn (gen_ashlsi3 (dst_low_part_g32_tmph, src_low_part, low5bit_inv)); 3418 3419 emit_insn (gen_iorsi3 (dst_low_part_g32, 3420 dst_low_part_g32_tmpl, 3421 dst_low_part_g32_tmph)); 3422 3423 emit_insn (gen_cmovnsi (dst_low_part, select_reg, 3424 dst_low_part_l32, dst_low_part_g32)); 3425 3426 /* if shiftamount < 32 3427 dst_high_part = ((src_high_part >> shiftamount) 3428 | (src_low_part << (32 - shiftamount))) 3429 dst_high_part = shiftamount == 0 ? src_high_part : dst_high_part 3430 else 3431 dst_high_part = wext(src, shiftamount & 0x1f) 3432 */ 3433 3434 emit_insn (gen_subsi3 (minus32sa, gen_int_mode (32, SImode), shiftamount)); 3435 3436 emit_insn (gen_lshrsi3 (dst_high_part_l32_tmpl, src_high_part, shiftamount)); 3437 emit_insn (gen_ashlsi3 (dst_high_part_l32_tmph, src_low_part, minus32sa)); 3438 3439 emit_insn (gen_iorsi3 (dst_high_part_l32, 3440 dst_high_part_l32_tmpl, 3441 dst_high_part_l32_tmph)); 3442 3443 emit_insn (gen_cmovzsi (dst_high_part_l32, shiftamount, 3444 src_high_part, dst_high_part_l32)); 3445 3446 emit_insn (gen_wext (dst_high_part_g32, src, low5bit)); 3447 3448 emit_insn (gen_cmovnsi (dst_high_part, select_reg, 3449 dst_high_part_l32, dst_high_part_g32)); 3450 } 3451 3452 /* Return true if OP contains a symbol reference. */ 3453 bool 3454 symbolic_reference_mentioned_p (rtx op) 3455 { 3456 const char *fmt; 3457 int i; 3458 3459 if (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF) 3460 return true; 3461 3462 fmt = GET_RTX_FORMAT (GET_CODE (op)); 3463 for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--) 3464 { 3465 if (fmt[i] == 'E') 3466 { 3467 int j; 3468 3469 for (j = XVECLEN (op, i) - 1; j >= 0; j--) 3470 if (symbolic_reference_mentioned_p (XVECEXP (op, i, j))) 3471 return true; 3472 } 3473 3474 else if (fmt[i] == 'e' && symbolic_reference_mentioned_p (XEXP (op, i))) 3475 return true; 3476 } 3477 3478 return false; 3479 } 3480 3481 /* Expand PIC code for @GOTOFF and @GOT. 3482 3483 Example for @GOTOFF: 3484 3485 la $r0, symbol@GOTOFF 3486 -> sethi $ta, hi20(symbol@GOTOFF) 3487 ori $ta, $ta, lo12(symbol@GOTOFF) 3488 add $r0, $ta, $gp 3489 3490 Example for @GOT: 3491 3492 la $r0, symbol@GOT 3493 -> sethi $ta, hi20(symbol@GOT) 3494 ori $ta, $ta, lo12(symbol@GOT) 3495 lw $r0, [$ta + $gp] 3496 */ 3497 rtx 3498 nds32_legitimize_pic_address (rtx x) 3499 { 3500 rtx addr = x; 3501 rtx reg = gen_reg_rtx (Pmode); 3502 rtx pat; 3503 int relax_group_id = nds32_alloc_relax_group_id (); 3504 3505 if (GET_CODE (x) == LABEL_REF 3506 || (GET_CODE (x) == SYMBOL_REF 3507 && (CONSTANT_POOL_ADDRESS_P (x) 3508 || SYMBOL_REF_LOCAL_P (x)))) 3509 { 3510 addr = gen_rtx_UNSPEC (SImode, gen_rtvec (1, x), UNSPEC_GOTOFF); 3511 addr = gen_rtx_CONST (SImode, addr); 3512 emit_insn (gen_sym_got (reg, addr, GEN_INT (relax_group_id))); 3513 x = gen_rtx_PLUS (Pmode, reg, pic_offset_table_rtx); 3514 } 3515 else if (GET_CODE (x) == SYMBOL_REF) 3516 { 3517 addr = gen_rtx_UNSPEC (SImode, gen_rtvec (1, x), UNSPEC_GOT); 3518 addr = gen_rtx_CONST (SImode, addr); 3519 emit_insn (gen_sym_got (reg, addr, GEN_INT (relax_group_id))); 3520 3521 x = gen_const_mem (SImode, gen_rtx_PLUS (Pmode, pic_offset_table_rtx, 3522 reg)); 3523 } 3524 else if (GET_CODE (x) == CONST) 3525 { 3526 /* We don't split constant in expand_pic_move because GOTOFF can combine 3527 the addend with the symbol. */ 3528 addr = XEXP (x, 0); 3529 gcc_assert (GET_CODE (addr) == PLUS); 3530 3531 rtx op0 = XEXP (addr, 0); 3532 rtx op1 = XEXP (addr, 1); 3533 3534 if ((GET_CODE (op0) == LABEL_REF 3535 || (GET_CODE (op0) == SYMBOL_REF 3536 && (CONSTANT_POOL_ADDRESS_P (op0) 3537 || SYMBOL_REF_LOCAL_P (op0)))) 3538 && GET_CODE (op1) == CONST_INT) 3539 { 3540 pat = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op0), UNSPEC_GOTOFF); 3541 pat = gen_rtx_PLUS (Pmode, pat, op1); 3542 pat = gen_rtx_CONST (Pmode, pat); 3543 emit_insn (gen_sym_got (reg, pat, GEN_INT (relax_group_id))); 3544 x = gen_rtx_PLUS (Pmode, reg, pic_offset_table_rtx); 3545 } 3546 else if (GET_CODE (op0) == SYMBOL_REF 3547 && GET_CODE (op1) == CONST_INT) 3548 { 3549 /* This is a constant offset from a @GOT symbol reference. */ 3550 addr = gen_rtx_UNSPEC (SImode, gen_rtvec (1, op0), UNSPEC_GOT); 3551 addr = gen_rtx_CONST (SImode, addr); 3552 emit_insn (gen_sym_got (reg, addr, GEN_INT (relax_group_id))); 3553 3554 addr = gen_const_mem (SImode, gen_rtx_PLUS (Pmode, 3555 pic_offset_table_rtx, 3556 reg)); 3557 emit_move_insn (reg, addr); 3558 if (satisfies_constraint_Is15 (op1)) 3559 x = gen_rtx_PLUS (Pmode, reg, op1); 3560 else 3561 { 3562 rtx tmp_reg = gen_reg_rtx (SImode); 3563 emit_insn (gen_movsi (tmp_reg, op1)); 3564 x = gen_rtx_PLUS (Pmode, reg, tmp_reg); 3565 } 3566 } 3567 else 3568 { 3569 /* Don't handle this pattern. */ 3570 debug_rtx (x); 3571 gcc_unreachable (); 3572 } 3573 } 3574 return x; 3575 } 3576 3577 void 3578 nds32_expand_pic_move (rtx *operands) 3579 { 3580 rtx src; 3581 3582 src = nds32_legitimize_pic_address (operands[1]); 3583 emit_move_insn (operands[0], src); 3584 } 3585 3586 /* Expand ICT symbol. 3587 Example for @ICT and ICT model=large: 3588 3589 la $r0, symbol@ICT 3590 -> sethi $rt, hi20(symbol@ICT) 3591 lwi $r0, [$rt + lo12(symbol@ICT)] 3592 3593 */ 3594 rtx 3595 nds32_legitimize_ict_address (rtx x) 3596 { 3597 rtx symbol = x; 3598 rtx addr = x; 3599 rtx reg = gen_reg_rtx (Pmode); 3600 gcc_assert (GET_CODE (x) == SYMBOL_REF 3601 && nds32_indirect_call_referenced_p (x)); 3602 3603 addr = gen_rtx_UNSPEC (SImode, gen_rtvec (1, symbol), UNSPEC_ICT); 3604 addr = gen_rtx_CONST (SImode, addr); 3605 emit_insn (gen_sethi (reg, addr)); 3606 3607 x = gen_const_mem (SImode, gen_rtx_LO_SUM (Pmode, reg, addr)); 3608 3609 return x; 3610 } 3611 3612 void 3613 nds32_expand_ict_move (rtx *operands) 3614 { 3615 rtx src = operands[1]; 3616 3617 src = nds32_legitimize_ict_address (src); 3618 3619 emit_move_insn (operands[0], src); 3620 } 3621 3622 /* Return true X is a indirect call symbol. */ 3623 bool 3624 nds32_indirect_call_referenced_p (rtx x) 3625 { 3626 if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_ICT) 3627 x = XVECEXP (x, 0, 0); 3628 3629 if (GET_CODE (x) == SYMBOL_REF) 3630 { 3631 tree decl = SYMBOL_REF_DECL (x); 3632 3633 return decl 3634 && (lookup_attribute("indirect_call", 3635 DECL_ATTRIBUTES(decl)) 3636 != NULL); 3637 } 3638 3639 return false; 3640 } 3641 3642 /* Return true X is need use long call. */ 3643 bool 3644 nds32_long_call_p (rtx symbol) 3645 { 3646 if (nds32_indirect_call_referenced_p (symbol)) 3647 return TARGET_ICT_MODEL_LARGE; 3648 else 3649 return TARGET_CMODEL_LARGE; 3650 } 3651 3652 /* Return true if X contains a thread-local symbol. */ 3653 bool 3654 nds32_tls_referenced_p (rtx x) 3655 { 3656 if (!targetm.have_tls) 3657 return false; 3658 3659 if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS) 3660 x = XEXP (XEXP (x, 0), 0); 3661 3662 if (GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (x)) 3663 return true; 3664 3665 return false; 3666 } 3667 3668 /* ADDR contains a thread-local SYMBOL_REF. Generate code to compute 3669 this (thread-local) address. */ 3670 rtx 3671 nds32_legitimize_tls_address (rtx x) 3672 { 3673 rtx tmp_reg; 3674 rtx tp_reg = gen_rtx_REG (Pmode, TP_REGNUM); 3675 rtx pat, insns, reg0; 3676 int relax_group_id = nds32_alloc_relax_group_id (); 3677 3678 if (GET_CODE (x) == SYMBOL_REF) 3679 switch (SYMBOL_REF_TLS_MODEL (x)) 3680 { 3681 case TLS_MODEL_GLOBAL_DYNAMIC: 3682 case TLS_MODEL_LOCAL_DYNAMIC: 3683 /* Emit UNSPEC_TLS_DESC rather than expand rtl directly because spill 3684 may destroy the define-use chain anylysis to insert relax_hint. */ 3685 if (SYMBOL_REF_TLS_MODEL (x) == TLS_MODEL_GLOBAL_DYNAMIC) 3686 pat = gen_rtx_UNSPEC (SImode, gen_rtvec (1, x), UNSPEC_TLSGD); 3687 else 3688 pat = gen_rtx_UNSPEC (SImode, gen_rtvec (1, x), UNSPEC_TLSLD); 3689 3690 pat = gen_rtx_CONST (SImode, pat); 3691 reg0 = gen_rtx_REG (Pmode, 0); 3692 /* If we can confirm all clobber reigsters, it doesn't have to use call 3693 instruction. */ 3694 insns = emit_call_insn (gen_tls_desc (pat, GEN_INT (relax_group_id))); 3695 use_reg (&CALL_INSN_FUNCTION_USAGE (insns), pic_offset_table_rtx); 3696 RTL_CONST_CALL_P (insns) = 1; 3697 tmp_reg = gen_reg_rtx (SImode); 3698 emit_move_insn (tmp_reg, reg0); 3699 x = tmp_reg; 3700 break; 3701 3702 case TLS_MODEL_INITIAL_EXEC: 3703 pat = gen_rtx_UNSPEC (SImode, gen_rtvec (1, x), UNSPEC_TLSIE); 3704 tmp_reg = gen_reg_rtx (SImode); 3705 pat = gen_rtx_CONST (SImode, pat); 3706 emit_insn (gen_tls_ie (tmp_reg, pat, GEN_INT (relax_group_id))); 3707 if (flag_pic) 3708 emit_use (pic_offset_table_rtx); 3709 x = gen_rtx_PLUS (Pmode, tmp_reg, tp_reg); 3710 break; 3711 3712 case TLS_MODEL_LOCAL_EXEC: 3713 /* Expand symbol_ref@TPOFF': 3714 sethi $ta, hi20(symbol_ref@TPOFF) 3715 ori $ta, $ta, lo12(symbol_ref@TPOFF) 3716 add $r0, $ta, $tp */ 3717 tmp_reg = gen_reg_rtx (SImode); 3718 pat = gen_rtx_UNSPEC (SImode, gen_rtvec (1, x), UNSPEC_TLSLE); 3719 pat = gen_rtx_CONST (SImode, pat); 3720 emit_insn (gen_tls_le (tmp_reg, pat, GEN_INT (relax_group_id))); 3721 x = gen_rtx_PLUS (Pmode, tmp_reg, tp_reg); 3722 break; 3723 3724 default: 3725 gcc_unreachable (); 3726 } 3727 else if (GET_CODE (x) == CONST) 3728 { 3729 rtx base, addend; 3730 split_const (x, &base, &addend); 3731 3732 if (SYMBOL_REF_TLS_MODEL (base) == TLS_MODEL_LOCAL_EXEC) 3733 { 3734 /* Expand symbol_ref@TPOFF': 3735 sethi $ta, hi20(symbol_ref@TPOFF + addend) 3736 ori $ta, $ta, lo12(symbol_ref@TPOFF + addend) 3737 add $r0, $ta, $tp */ 3738 tmp_reg = gen_reg_rtx (SImode); 3739 pat = gen_rtx_UNSPEC (SImode, gen_rtvec (1, base), UNSPEC_TLSLE); 3740 pat = gen_rtx_PLUS (SImode, pat, addend); 3741 pat = gen_rtx_CONST (SImode, pat); 3742 emit_insn (gen_tls_le (tmp_reg, pat, GEN_INT (relax_group_id))); 3743 x = gen_rtx_PLUS (Pmode, tmp_reg, tp_reg); 3744 } 3745 } 3746 3747 return x; 3748 } 3749 3750 void 3751 nds32_expand_tls_move (rtx *operands) 3752 { 3753 rtx src = operands[1]; 3754 rtx base, addend; 3755 3756 if (CONSTANT_P (src)) 3757 split_const (src, &base, &addend); 3758 3759 if (SYMBOL_REF_TLS_MODEL (base) == TLS_MODEL_LOCAL_EXEC) 3760 src = nds32_legitimize_tls_address (src); 3761 else 3762 { 3763 src = nds32_legitimize_tls_address (base); 3764 if (addend != const0_rtx) 3765 { 3766 src = gen_rtx_PLUS (SImode, src, addend); 3767 src = force_operand (src, operands[0]); 3768 } 3769 } 3770 3771 emit_move_insn (operands[0], src); 3772 } 3773 3774 void 3775 nds32_expand_constant (machine_mode mode, HOST_WIDE_INT val, 3776 rtx target, rtx source) 3777 { 3778 rtx temp = gen_reg_rtx (mode); 3779 int clear_sign_bit_copies = 0; 3780 int clear_zero_bit_copies = 0; 3781 unsigned HOST_WIDE_INT remainder = val & 0xffffffffUL; 3782 3783 /* Count number of leading zeros. */ 3784 clear_sign_bit_copies = __builtin_clz (remainder); 3785 /* Count number of trailing zeros. */ 3786 clear_zero_bit_copies = __builtin_ctz (remainder); 3787 3788 HOST_WIDE_INT sign_shift_mask = ((0xffffffffUL 3789 << (32 - clear_sign_bit_copies)) 3790 & 0xffffffffUL); 3791 HOST_WIDE_INT zero_shift_mask = (1 << clear_zero_bit_copies) - 1; 3792 3793 if (clear_sign_bit_copies > 0 && clear_sign_bit_copies < 17 3794 && (remainder | sign_shift_mask) == 0xffffffffUL) 3795 { 3796 /* Transfer AND to two shifts, example: 3797 a = b & 0x7fffffff => (b << 1) >> 1 */ 3798 rtx shift = GEN_INT (clear_sign_bit_copies); 3799 3800 emit_insn (gen_ashlsi3 (temp, source, shift)); 3801 emit_insn (gen_lshrsi3 (target, temp, shift)); 3802 } 3803 else if (clear_zero_bit_copies > 0 && clear_sign_bit_copies < 17 3804 && (remainder | zero_shift_mask) == 0xffffffffUL) 3805 { 3806 /* Transfer AND to two shifts, example: 3807 a = b & 0xfff00000 => (b >> 20) << 20 */ 3808 rtx shift = GEN_INT (clear_zero_bit_copies); 3809 3810 emit_insn (gen_lshrsi3 (temp, source, shift)); 3811 emit_insn (gen_ashlsi3 (target, temp, shift)); 3812 } 3813 else 3814 { 3815 emit_move_insn (temp, GEN_INT (val)); 3816 emit_move_insn (target, gen_rtx_fmt_ee (AND, mode, source, temp)); 3817 } 3818 } 3819 3820 /* Auxiliary functions for lwm/smw. */ 3821 bool 3822 nds32_valid_smw_lwm_base_p (rtx op) 3823 { 3824 rtx base_addr; 3825 3826 if (!MEM_P (op)) 3827 return false; 3828 3829 base_addr = XEXP (op, 0); 3830 3831 if (REG_P (base_addr)) 3832 return true; 3833 else 3834 { 3835 if (GET_CODE (base_addr) == POST_INC 3836 && REG_P (XEXP (base_addr, 0))) 3837 return true; 3838 } 3839 3840 return false; 3841 } 3842 3843 /* Auxiliary functions for manipulation DI mode. */ 3844 rtx nds32_di_high_part_subreg(rtx reg) 3845 { 3846 unsigned high_part_offset = subreg_highpart_offset (SImode, DImode); 3847 3848 return simplify_gen_subreg ( 3849 SImode, reg, 3850 DImode, high_part_offset); 3851 } 3852 3853 rtx nds32_di_low_part_subreg(rtx reg) 3854 { 3855 unsigned low_part_offset = subreg_lowpart_offset (SImode, DImode); 3856 3857 return simplify_gen_subreg ( 3858 SImode, reg, 3859 DImode, low_part_offset); 3860 } 3861 3862 /* ------------------------------------------------------------------------ */ 3863 3864 /* Auxiliary function for output TLS patterns. */ 3865 3866 const char * 3867 nds32_output_tls_desc (rtx *operands) 3868 { 3869 char pattern[1000]; 3870 3871 if (TARGET_RELAX_HINT) 3872 snprintf (pattern, sizeof (pattern), 3873 ".relax_hint %%1\n\tsethi $r0, hi20(%%0)\n\t" 3874 ".relax_hint %%1\n\tori $r0, $r0, lo12(%%0)\n\t" 3875 ".relax_hint %%1\n\tlw $r15, [$r0 + $gp]\n\t" 3876 ".relax_hint %%1\n\tadd $r0, $r0, $gp\n\t" 3877 ".relax_hint %%1\n\tjral $r15"); 3878 else 3879 snprintf (pattern, sizeof (pattern), 3880 "sethi $r0, hi20(%%0)\n\t" 3881 "ori $r0, $r0, lo12(%%0)\n\t" 3882 "lw $r15, [$r0 + $gp]\n\t" 3883 "add $r0, $r0, $gp\n\t" 3884 "jral $r15"); 3885 output_asm_insn (pattern, operands); 3886 return ""; 3887 } 3888 3889 const char * 3890 nds32_output_tls_ie (rtx *operands) 3891 { 3892 char pattern[1000]; 3893 3894 if (flag_pic) 3895 { 3896 if (TARGET_RELAX_HINT) 3897 snprintf (pattern, sizeof (pattern), 3898 ".relax_hint %%2\n\tsethi %%0, hi20(%%1)\n\t" 3899 ".relax_hint %%2\n\tori %%0, %%0, lo12(%%1)\n\t" 3900 ".relax_hint %%2\n\tlw %%0, [%%0 + $gp]"); 3901 else 3902 snprintf (pattern, sizeof (pattern), 3903 "sethi %%0, hi20(%%1)\n\t" 3904 "ori %%0, %%0, lo12(%%1)\n\t" 3905 "lw %%0, [%%0 + $gp]"); 3906 } 3907 else 3908 { 3909 if (TARGET_RELAX_HINT) 3910 snprintf (pattern, sizeof (pattern), 3911 ".relax_hint %%2\n\tsethi %%0, hi20(%%1)\n\t" 3912 ".relax_hint %%2\n\tlwi %%0, [%%0 + lo12(%%1)]"); 3913 else 3914 snprintf (pattern, sizeof (pattern), 3915 "sethi %%0, hi20(%%1)\n\t" 3916 "lwi %%0, [%%0 + lo12(%%1)]"); 3917 } 3918 output_asm_insn (pattern, operands); 3919 return ""; 3920 } 3921 3922 const char * 3923 nds32_output_symrel (rtx *operands) 3924 { 3925 char pattern[1000]; 3926 3927 if (TARGET_RELAX_HINT) 3928 snprintf (pattern, sizeof (pattern), 3929 ".relax_hint %%2\n\tsethi %%0, hi20(%%1)\n\t" 3930 ".relax_hint %%2\n\tori %%0, %%0, lo12(%%1)"); 3931 else 3932 snprintf (pattern, sizeof (pattern), 3933 "sethi %%0, hi20(%%1)\n\t" 3934 "ori %%0, %%0, lo12(%%1)"); 3935 3936 output_asm_insn (pattern, operands); 3937 return ""; 3938 } 3939