1/* Subroutines used for code generation on Ubicom IP2022 2 Communications Controller. 3 Copyright (C) 2000, 2001, 2002, 2003 Free Software Foundation, Inc. 4 Contributed by Red Hat, Inc and Ubicom, Inc. 5 6 This file is part of GNU CC. 7 8 GNU CC is free software; you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation; either version 2, or (at your option) 11 any later version. 12 13 GNU CC is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with GNU CC; see the file COPYING. If not, write to 20 the Free Software Foundation, 59 Temple Place - Suite 330, 21 Boston, MA 02111-1307, USA. */ 22 23#include "config.h" 24#include "system.h" 25#include "rtl.h" 26#include "regs.h" 27#include "hard-reg-set.h" 28#include "real.h" 29#include "insn-config.h" 30#include "conditions.h" 31#include "insn-flags.h" 32#include "output.h" 33#include "insn-attr.h" 34#include "insn-addr.h" 35#include "flags.h" 36#include "reload.h" 37#include "tree.h" 38#include "expr.h" 39#include "toplev.h" 40#include "obstack.h" 41#include "function.h" 42#include "recog.h" 43#include "tm_p.h" 44#include "target.h" 45#include "target-def.h" 46#include "basic-block.h" 47 48/* There are problems with 'frame_pointer_needed'. If we force it 49 on, we either end up not eliminating uses of FP, which results in 50 SPILL register failures or we may end up with calculation errors in 51 the stack offsets. Isolate the decision process into a simple macro. */ 52#define CHAIN_FRAMES (frame_pointer_needed || FRAME_POINTER_REQUIRED) 53 54static int ip2k_naked_function_p PARAMS ((tree)); 55#ifdef IP2K_MD_REORG_PASS 56static void mdr_resequence_xy_yx PARAMS ((rtx)); 57static void mdr_pres_replace_and_recurse PARAMS ((rtx, rtx, rtx)); 58static void mdr_propagate_reg_equivs_sequence PARAMS ((rtx, rtx, rtx)); 59static void mdr_propagate_reg_equivs PARAMS ((rtx)); 60static int track_dp_reload PARAMS ((rtx , rtx *, int , int)); 61static void mdr_try_dp_reload_elim PARAMS ((rtx)); 62static void mdr_try_move_dp_reload PARAMS ((rtx)); 63static void mdr_try_move_pushes PARAMS ((rtx)); 64static void mdr_try_propagate_clr_sequence PARAMS ((rtx, unsigned int)); 65static void mdr_try_propagate_clr PARAMS ((rtx)); 66static void mdr_try_propagate_move_sequence PARAMS ((rtx, rtx, rtx)); 67static void mdr_try_propagate_move PARAMS ((rtx)); 68static void mdr_try_remove_redundant_insns PARAMS ((rtx)); 69static int track_w_reload PARAMS ((rtx, rtx *, int , int)); 70static void mdr_try_wreg_elim PARAMS ((rtx)); 71#endif /* IP2K_MD_REORG_PASS */ 72static int ip2k_check_can_adjust_stack_ref PARAMS ((rtx, int)); 73static void ip2k_adjust_stack_ref PARAMS ((rtx *, int)); 74static int ip2k_xexp_not_uses_reg_for_mem PARAMS ((rtx, unsigned int)); 75static tree ip2k_handle_progmem_attribute PARAMS ((tree *, tree, tree, int, 76 bool *)); 77static tree ip2k_handle_fndecl_attribute PARAMS ((tree *, tree, tree, int, 78 bool *)); 79const struct attribute_spec ip2k_attribute_table[]; 80 81 82/* Initialize the GCC target structure. */ 83#undef TARGET_ASM_ALIGNED_HI_OP 84#define TARGET_ASM_ALIGNED_HI_OP "\t.word\t" 85 86#undef TARGET_ASM_FUNCTION_PROLOGUE 87#define TARGET_ASM_FUNCTION_PROLOGUE function_prologue 88 89#undef TARGET_ASM_FUNCTION_EPILOGUE 90#define TARGET_ASM_FUNCTION_EPILOGUE function_epilogue 91 92#undef TARGET_ASM_UNIQUE_SECTION 93#define TARGET_ASM_UNIQUE_SECTION unique_section 94 95#undef TARGET_ENCODE_SECTION_INFO 96#define TARGET_ENCODE_SECTION_INFO encode_section_info 97 98#undef TARGET_ATTRIBUTE_TABLE 99#define TARGET_ATTRIBUTE_TABLE ip2k_attribute_table 100 101struct gcc_target targetm = TARGET_INITIALIZER; 102 103/* Commands in the functions prologues in the compiled file. */ 104static int commands_in_prologues; 105 106/* Commands in the functions epilogues in the compiled file. */ 107static int commands_in_epilogues; 108 109/* Prologue/Epilogue size in words. */ 110static int prologue_size; 111static int epilogue_size; 112 113/* compare and test instructions for the IP2K are materialized by 114 the conditional branch that uses them. This is because conditional 115 branches are skips over unconditional branches. */ 116rtx ip2k_compare_operands[3]; /* Additional operands for condition code. */ 117int ip2k_test_flag; /* Indicates Z, WREG contain condition code 118 information. */ 119 120/* Some ip2k patterns push a byte onto the stack and then access 121 SP-relative addresses. Since reload doesn't know about these 122 pushes, we must track them internally with a %< (push) or %> (pop) 123 indicator. */ 124static int ip2k_stack_delta; 125 126/* Track if or how far our ip2k reorganization pass has run. */ 127int ip2k_reorg_in_progress = 0; 128int ip2k_reorg_completed = 0; 129int ip2k_reorg_split_dimode = 0; 130int ip2k_reorg_split_simode = 0; 131int ip2k_reorg_split_himode = 0; 132int ip2k_reorg_split_qimode = 0; 133int ip2k_reorg_merge_qimode = 0; 134 135/* Set up local allocation order. */ 136 137void 138ip2k_init_local_alloc (rao) 139 int * rao; 140{ 141 static const int alloc_order[] = REG_ALLOC_ORDER; 142 143 memcpy (rao, alloc_order, sizeof (alloc_order)); 144} 145 146/* Returns the number of bytes of arguments automatically 147 popped when returning from a subroutine call. 148 FUNDECL is the declaration node of the function (as a tree), 149 FUNTYPE is the data type of the function (as a tree), 150 or for a library call it is an identifier node for the subroutine name. 151 SIZE is the number of bytes of arguments passed on the stack. */ 152 153int 154ip2k_return_pops_args (fundecl, funtype, size) 155 tree fundecl ATTRIBUTE_UNUSED; 156 tree funtype; 157 int size; 158{ 159 if (TREE_CODE (funtype) == IDENTIFIER_NODE) 160 return size; 161 162 if (TYPE_ARG_TYPES (funtype) == NULL_TREE 163 || (TREE_VALUE (tree_last (TYPE_ARG_TYPES (funtype))) == void_type_node)) 164 return size; 165 166 return 0; 167} 168 169/* Return nonzero if FUNC is a naked function. */ 170 171static int 172ip2k_naked_function_p (func) 173 tree func; 174{ 175 tree a; 176 177 if (TREE_CODE (func) != FUNCTION_DECL) 178 abort (); 179 180 a = lookup_attribute ("naked", DECL_ATTRIBUTES (func)); 181 return a != NULL_TREE; 182} 183 184/* Output function prologue. */ 185void 186function_prologue (file, size) 187 FILE *file; 188 HOST_WIDE_INT size; 189{ 190 int leaf_func_p; 191 int main_p; 192 int reg; 193 rtx operands[2]; 194 195 prologue_size = epilogue_size = 0; 196 197 if (ip2k_naked_function_p (current_function_decl)) 198 { 199 fprintf (file, "/* prologue: naked */\n"); 200 return; 201 } 202 203 leaf_func_p = leaf_function_p (); 204 main_p = ! strcmp ("main", current_function_name); 205 206 /* For now, we compute all these facts about the function, but don't 207 take any action based on the information. */ 208 209 prologue_size = 0; 210 fprintf (file, "/* prologue: frame size=%d */\n", size); 211 212 /* Unless we're a leaf we need to save the return PC. */ 213 214 if (! leaf_func_p) 215 { 216 OUT_AS1 (push, calll); 217 OUT_AS1 (push, callh); 218 prologue_size += 4; 219 } 220 221 /* We need to save the old FP and set the new FP pointing at the 222 stack location where the old one is saved. Note that because of 223 post-decrement addressing, the SP is off-by-one after the 224 push, so we harvest the SP address BEFORE we push the MSBs of 225 the FP. */ 226 if (CHAIN_FRAMES) 227 { 228 OUT_AS1 (push, REG_FP+1); /* Save old LSBs. */ 229 OUT_AS2 (mov, w, spl); 230 OUT_AS2 (mov, REG_FP+1, w); /* SPL -> FPL */ 231 232 OUT_AS2 (mov, w, sph); /* Freeze SP MSBs */ 233 OUT_AS1 (push, REG_FP); /* Save old MSBs */ 234 OUT_AS2 (mov, REG_FP, w); /* SPH -> FPH */ 235 prologue_size += 12; 236 } 237 238 for (reg = (CHAIN_FRAMES) ? (REG_FP - 1) : (REG_FP + 1); 239 reg > 0; --reg) 240 { 241 if (regs_ever_live[reg] && ! call_used_regs[reg]) 242 { 243 fprintf (file, "\t" AS1 (push,%s) "\n", reg_names[reg]); 244 prologue_size += 2; 245 } 246 } 247 248 if (size) 249 { 250 operands[0] = GEN_INT (size); 251 252 switch (size & 0xff) 253 { 254 case 0: 255 break; 256 case 1: 257 OUT_AS1 (dec, spl); 258 prologue_size += 2; 259 break; 260 default: 261 OUT_AS2 (mov, w, %L0); 262 OUT_AS2 (sub, spl, w); 263 prologue_size += 4; 264 } 265 266 switch (size & 0xff00) 267 { 268 case 0: 269 break; 270 case 0x100: 271 OUT_AS1 (dec, sph); 272 prologue_size += 2; 273 break; 274 default: 275 if ((size & 0xff) != ((size >> 8) & 0xff)) 276 OUT_AS2 (mov, w, %H0); /* Otherwise W has value we want. */ 277 OUT_AS2 (sub, sph, w); 278 prologue_size += 4; 279 } 280 } 281 282/* XXX - change this to use the carry-propagating subtract trick. */ 283 if (flag_stack_check) 284 { 285 OUT_AS2 (mov, w, sph); 286 OUT_AS2 (cmp, w, #%%hi8data(_end)); 287 OUT_AS1 (sc, ); /* C == 0 -> hi8(edata) < sph */ 288 OUT_AS1 (page, 1f); 289 OUT_AS1 (jmp, 1f); 290 OUT_AS1 (sz, ); /* Z == 1 -> look at low byte */ 291 OUT_AS1 (page,0f); 292 OUT_AS1 (jmp,0f); /* sp < edata, so raise stack fault */ 293 OUT_AS2 (mov, w, spl); 294 OUT_AS2 (cmp, w, #%%lo8data(_end)); 295 OUT_AS1 (sc,); /* C==1 -> lo8(edata) >= spl */ 296 OUT_AS1 (page,1f); 297 OUT_AS1 (jmp,1f); 298 OUT_AS1 (0:,); 299 output_asm_insn ("push\t$ff", operands); 300 OUT_AS1 (system,); 301 OUT_AS1 (1:, ); 302 prologue_size += 30; 303 } 304} 305 306/* Output function epilogue. */ 307void 308function_epilogue (file, size) 309 FILE *file; 310 HOST_WIDE_INT size; 311{ 312 int leaf_func_p; 313 int reg,savelimit; 314 rtx operands[2]; /* Dummy used by OUT_ASn */ 315 int args_locals_size = current_function_args_size; 316 int saved_regs_p = 0; 317 int need_ret = 1; 318 319 /* Use this opportunity to reset the reorg flags! */ 320 ip2k_reorg_in_progress = 0; 321 ip2k_reorg_completed = 0; 322 ip2k_reorg_split_dimode = 0; 323 ip2k_reorg_split_simode = 0; 324 ip2k_reorg_split_himode = 0; 325 ip2k_reorg_split_qimode = 0; 326 ip2k_reorg_merge_qimode = 0; 327 328 if (ip2k_naked_function_p (current_function_decl)) 329 { 330 fprintf (file, "/* epilogue: naked */\n"); 331 return; 332 } 333 334 leaf_func_p = leaf_function_p (); 335 epilogue_size = 0; 336 fprintf (file, "/* epilogue: frame size=%d */\n", size); 337 338 savelimit = (CHAIN_FRAMES) ? REG_FP : (REG_FP + 2); 339 for (reg = 0; reg < savelimit; reg++) 340 if (regs_ever_live[reg] && ! call_used_regs[reg]) 341 { 342 saved_regs_p = 1; 343 break; 344 } 345 346 if (size) 347 { 348 if (leaf_func_p && !CHAIN_FRAMES && !saved_regs_p 349 && current_function_pops_args) 350 args_locals_size = current_function_args_size + size; 351 else 352 { 353 operands[0] = GEN_INT (size); 354 355 switch (size & 0xff) 356 { 357 default: 358 OUT_AS2 (mov, w, %L0); 359 OUT_AS2 (add, spl, w); 360 epilogue_size += 4; 361 /* fall-thru */ 362 case 0: 363 break; 364 case 1: 365 OUT_AS1 (inc, spl); 366 epilogue_size += 2; 367 } 368 369 switch (size & 0xff00) 370 { 371 default: 372 if ((size & 0xff) != ((size >> 8) & 0xff)) 373 OUT_AS2 (mov, w, %H0); 374 OUT_AS2 (add, sph, w); 375 epilogue_size += 4; 376 /* fall-thru */ 377 case 0: 378 break; 379 case 0x100: 380 OUT_AS1 (inc, sph); 381 epilogue_size += 2; 382 } 383 } 384 } 385 386 for (reg = 0; reg < savelimit; reg++) 387 { 388 if (regs_ever_live[reg] && ! call_used_regs[reg]) 389 { 390 fprintf (file, "\t" AS1 (pop,%s) "\n", reg_names[reg]); 391 prologue_size += 2; 392 } 393 } 394 395 if (CHAIN_FRAMES 396 && ! (current_function_pops_args 397 && current_function_args_size >= 2 398 && current_function_args_size < 0x100)) 399 { 400 OUT_AS1 (pop, REG_FP); 401 OUT_AS1 (pop, REG_FP+1); 402 epilogue_size += 4; 403 } 404 405 if (! leaf_func_p) 406 { 407 if (current_function_pops_args 408 && current_function_args_size >= 2 409 && current_function_args_size < 0x100) 410 { 411 if (current_function_args_size == 2) 412 { 413 if (CHAIN_FRAMES) 414 { 415 OUT_AS1 (page, __fp_pop2_args_ret); 416 OUT_AS1 (jmp, __fp_pop2_args_ret); 417 } 418 else 419 { 420 OUT_AS1 (page, __pop2_args_ret); 421 OUT_AS1 (jmp, __pop2_args_ret); 422 } 423 epilogue_size += 4; 424 } 425 else 426 { 427 operands[0] = GEN_INT (current_function_args_size); 428 OUT_AS2 (mov, w, %L0); 429 if (CHAIN_FRAMES) 430 { 431 OUT_AS1 (page, __fp_pop_args_ret); 432 OUT_AS1 (jmp, __fp_pop_args_ret); 433 } 434 else 435 { 436 OUT_AS1 (page, __pop_args_ret); 437 OUT_AS1 (jmp, __pop_args_ret); 438 } 439 epilogue_size += 6; 440 } 441 need_ret = 0; 442 } 443 else 444 { 445 OUT_AS1 (pop, callh); 446 OUT_AS1 (pop, calll); 447 epilogue_size += 4; 448 } 449 } 450 else 451 { 452 if (current_function_pops_args 453 && args_locals_size >= 2 454 && args_locals_size < 0x100) 455 { 456 if (args_locals_size == 2) 457 { 458 if (CHAIN_FRAMES) 459 { 460 OUT_AS1 (page, __leaf_fp_pop2_args_ret); 461 OUT_AS1 (jmp, __leaf_fp_pop2_args_ret); 462 epilogue_size += 4; 463 need_ret = 0; 464 } 465 } 466 else 467 { 468 operands[0] = GEN_INT (args_locals_size); 469 if (CHAIN_FRAMES) 470 { 471 OUT_AS2 (mov, w, %L0); 472 OUT_AS1 (page, __leaf_fp_pop_args_ret); 473 OUT_AS1 (jmp, __leaf_fp_pop_args_ret); 474 epilogue_size += 6; 475 need_ret = 0; 476 } 477 } 478 } 479 } 480 481 if (current_function_pops_args && args_locals_size && need_ret) 482 { 483 operands[0] = GEN_INT (args_locals_size); 484 485 switch (args_locals_size & 0xff) 486 { 487 default: 488 OUT_AS2 (mov, w, %L0); 489 OUT_AS2 (add, spl, w); 490 epilogue_size += 4; 491 /* fall-thru */ 492 493 case 0: 494 break; 495 496 case 1: 497 OUT_AS1 (inc, spl); 498 epilogue_size += 2; 499 } 500 501 switch (args_locals_size & 0xff00) 502 { 503 default: 504 if ((args_locals_size & 0xff) != ((args_locals_size >> 8) & 0xff)) 505 OUT_AS2 (mov, w, %H0); 506 OUT_AS2 (add, sph, w); 507 epilogue_size += 4; 508 /* fall-thru */ 509 510 case 0: 511 break; 512 513 case 0x100: 514 OUT_AS1 (inc, sph); 515 epilogue_size += 2; 516 } 517 } 518 519 if (need_ret) 520 { 521 OUT_AS1 (ret,); 522 epilogue_size += 2; 523 } 524 525 fprintf (file, "/* epilogue end (size=%d) */\n", epilogue_size); 526 commands_in_prologues += prologue_size; 527 commands_in_epilogues += epilogue_size; 528} 529 530/* Return the difference between the registers after the function 531 prologue. 532 533 Stack Frame grows down: 534 535 ARGUMENTS 536 <------ AP ($102:$103) 537 RETURN PC (unless leaf function) 538 SAVEDFP (if needed) 539 <------ FP [HARD_FRAME_POINTER] ($FD:$FE) 540 SAVED REGS 541 <------ VFP [$100:$101] 542 STACK ALLOCATION 543 <------ SP ($6:$7) */ 544int 545ip2k_init_elim_offset (from, to) 546 int from; 547 int to; 548{ 549 int leaf_func_p = leaf_function_p (); 550 int no_saved_pc = leaf_func_p 551 || ip2k_naked_function_p (current_function_decl); 552 int offset; 553 int reg; 554 int reglimit; 555 556 if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM) 557 return get_frame_size () + 1; 558 559 if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM) 560 return (CHAIN_FRAMES ? 2 : 0) + (no_saved_pc ? 0 : 2); 561 562 /* Count all the registers we had to preserve. */ 563 564 reglimit = CHAIN_FRAMES ? REG_FP : (REG_FP + 2); 565 for (offset = 0,reg = 0; reg < reglimit; ++reg) 566 { 567 if ((regs_ever_live[reg] && ! call_used_regs[reg])) 568 { 569 ++offset; 570 } 571 } 572 573 if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM) 574 return -offset; 575 576 if (from == HARD_FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM) 577 /* Add in the stack-local variables. */ 578 return offset + get_frame_size () + 1; 579 580 if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM) 581 /* Add stack-locals plus saved FP and PC. */ 582 return offset + get_frame_size () + 1 583 + (CHAIN_FRAMES ? 2 : 0) + (no_saved_pc ? 0 : 2); 584 585 abort (); /* Unanticipated elimination. */ 586} 587 588/* Return nonzero if X (an RTX) is a legitimate memory address on the target 589 machine for a memory operand of mode MODE. */ 590 591int 592legitimate_address_p (mode, x, strict) 593 enum machine_mode mode; 594 rtx x; 595 int strict; 596{ 597 int off; 598 599 if (GET_CODE (x) == SUBREG) 600 x = SUBREG_REG (x); 601 602 switch (GET_CODE (x)) 603 { 604 case REG: 605 /* IP allows indirection without offset - only okay if 606 we don't require access to multiple bytes. */ 607 if (REGNO (x) == REG_IP) 608 return (GET_MODE_SIZE (mode) == 1) ? 'R' : 0; 609 610 /* We can indirect thru DP or SP register. */ 611 if (strict ? REG_OK_FOR_BASE_STRICT_P (x) 612 : REG_OK_FOR_BASE_NOSTRICT_P (x)) 613 return 'S'; 614 break; 615 616 case PLUS: 617 /* Offsets from DP or SP are legal in the range 0..127 */ 618 { 619 rtx op1, op2; 620 621 op1 = XEXP (x, 0); 622 op2 = XEXP (x, 1); 623 624 if (REG_P (op2) && ! REG_P (op1)) 625 { 626 rtx tmp = op1; 627 op1 = op2; 628 op2 = tmp; 629 } 630 631 /* Don't let anything but R+I thru.. */ 632 if (! REG_P (op1) 633 || REG_P (op2) 634 || GET_CODE (op2) != CONST_INT) 635 return 0; 636 637 switch (REGNO (op1)) 638 { 639 case REG_DP: /* only 0..127 displacement */ 640 case REG_SP: 641 off = 2 * GET_MODE_SIZE (mode); 642 if (! off) 643 off = 1; 644 645 if (INTVAL (op2) < 0 || INTVAL (op2) > (128 - off)) 646 return 0; /* Positive must be small enough that after 647 splitting all pieces are addressed. */ 648 return 'S'; /* Safe displacement. */ 649 650 case REG_IP: 651 if (GET_MODE_SIZE (mode) <= 1 && INTVAL (op2) == 0) 652 return (GET_MODE_SIZE (mode) == 1) ? 'R' : 0; 653 return 0; 654 655 case REG_AP: 656 case REG_FP: 657 case REG_VFP: 658 default: 659 if (strict || ! REG_OK_FOR_BASE_NOSTRICT_P (op1)) 660 return 0; /* Allow until reload. */ 661 662 return 'S'; 663 } 664 } 665 break; 666 667 case CONST: 668 case SYMBOL_REF: 669 /* We always allow references to things in code space. */ 670 return is_regfile_address (x) ? 0 : 'C'; 671 672 case LABEL_REF: 673 return 'L'; 674 675 default: 676 return 0; 677 } 678 679 return 0; 680} 681 682/* Is ADDR mode dependent? */ 683int 684ip2k_mode_dependent_address (addr) 685 rtx addr; 686{ 687 switch (GET_CODE (addr)) 688 { 689 case POST_INC: 690 case POST_DEC: 691 case PRE_INC: 692 case PRE_DEC: 693 return 1; 694 695 case REG: 696 return (REGNO (addr) == REG_IP); /* Can't do IP displaced addresses. */ 697 698 default: 699 return 0; /* Assume no dependency. */ 700 } 701} 702 703/* Attempts to replace X with a valid 704 memory address for an operand of mode MODE. */ 705 706rtx 707legitimize_address (x, oldx, mode, scratch) 708 rtx x; 709 rtx oldx ATTRIBUTE_UNUSED; 710 rtx scratch; 711 enum machine_mode mode ATTRIBUTE_UNUSED; 712{ 713 rtx reg; 714 715 /* You might think that we could split up a symbolic address by 716 adding the HIGH 8 bits and doing a displacement off the dp. But 717 because we only have 7 bits of offset, that doesn't actually 718 help. So only constant displacements are likely to obtain an 719 advantage. */ 720 721 if (GET_CODE (x) == PLUS && REG_P (XEXP (x, 0)) 722 && GET_CODE (XEXP (x, 1)) == CONST_INT 723 && ! CONST_OK_FOR_LETTER_P (INTVAL (XEXP (x, 1)), 'K')) 724 { 725 int offset = INTVAL (XEXP (x, 1)); 726 727 reg = scratch ? scratch : gen_reg_rtx (Pmode); 728 729 emit_insn (gen_rtx_SET (VOIDmode, reg, 730 gen_rtx_PLUS (Pmode, XEXP (x, 0), 731 GEN_INT (offset & 0xffc0)))); 732 x = gen_rtx_PLUS (Pmode, reg, GEN_INT (offset & 0x3f)); 733 } 734 735 return x; /* We don't have any other tricks. */ 736} 737 738/* Determine if X is a 'data' address or a code address. All static 739 data and stack variables reside in data memory. Only code is believed 740 to be in PRAM or FLASH. */ 741int 742is_regfile_address (x) 743 rtx x; 744{ 745 while (1) 746 switch (GET_CODE (x)) 747 { 748 case SYMBOL_REF: 749 return ! SYMBOL_REF_FLAG (x); /* Declared as function. */ 750 case CONST: 751 case PLUS: 752 x = XEXP (x, 0); 753 break; 754 case CONST_INT: 755 case REG: 756 case SUBREG: 757 return 1; 758 case LABEL_REF: 759 return 0; 760 default: 761 return 0; 762 } 763 764 return 0; 765} 766 767/* Output ADDR to FILE as address. */ 768 769void 770print_operand_address (file, addr) 771 FILE *file; 772 rtx addr; 773{ 774 switch (GET_CODE (addr)) 775 { 776 case SUBREG: 777 addr = alter_subreg (&addr); 778 /* fall-thru */ 779 780 case REG: 781 fprintf (file, "(%s)", 782 REGNO (addr) == REG_DP ? "DP" 783 : REGNO (addr) == REG_SP ? "SP" 784 : REGNO (addr) == REG_IP ? "IP" 785 : REGNO (addr) == REG_VFP ? "VFP" /* Should never see this */ 786 : REGNO (addr) == REG_AP ? "AP" /* or this, either. */ 787 : reg_names[REGNO (addr)]); 788 break; 789 790 case PRE_DEC: 791 case POST_INC: 792 abort (); 793 break; 794 795 case CONST: 796 addr = XEXP (addr, 0); 797 print_operand_address (file, XEXP (addr, 0)); 798 fprintf (file, "+"); 799 print_operand_address (file, XEXP (addr, 1)); 800 return; 801 802 case LO_SUM: 803 if (is_regfile_address (XEXP (addr, 1))) 804 fprintf (file, "%%lo8data("); 805 else 806 fprintf (file, "%%lo8insn("); 807 print_operand_address (file, XEXP (addr, 1)); 808 fprintf (file, ")"); 809 print_operand_address (file, XEXP (addr, 0)); 810 break; 811 812 case PLUS: /* Ought to be stack or dp references. */ 813 if (XEXP (addr, 1) == const0_rtx 814 && GET_CODE (XEXP (addr, 0)) == PLUS) 815 { 816 print_operand_address (file, XEXP (addr, 0)); 817 return; 818 } 819 820 if (! REG_P (XEXP (addr, 0)) || REGNO (XEXP (addr, 0)) != REG_IP) 821 print_operand_address (file, XEXP (addr, 1)); /* const */ 822 print_operand_address (file, XEXP (addr, 0)); /* (reg) */ 823 break; 824 825 case HIGH: 826 if (is_regfile_address (XEXP (addr, 0))) 827 fprintf (file, "%%hi8data("); 828 else 829 fprintf (file, "%%hi8insn("); 830 output_addr_const (file, XEXP (addr, 0)); 831 fprintf (file, ")"); 832 break; 833 834 default: 835 output_addr_const (file, addr); 836 } 837} 838 839 840/* Output X as assembler operand to file FILE. */ 841 842void 843print_operand (file, x, code) 844 FILE *file; 845 rtx x; 846 int code; 847{ 848 int abcd = 0; 849 unsigned long value; 850 851 switch (code) 852 { 853 case '<': /* Push */ 854 ip2k_stack_delta++; 855 return; 856 857 case '>': /* Pop */ 858 ip2k_stack_delta--; 859 return; 860 861 case 'A': 862 case 'B': 863 case 'C': 864 case 'D': 865 abcd = code - 'A'; 866 break; 867 868 case 'H': 869 abcd = 0; 870 break; 871 872 case 'L': 873 abcd = 1; 874 break; 875 876 case 'S': 877 case 'T': 878 case 'U': 879 case 'V': 880 case 'W': 881 case 'X': 882 case 'Y': 883 case 'Z': 884 abcd = code - 'S'; 885 886 default: 887 break; 888 } 889 890 if (ip2k_short_operand (x, GET_MODE (x)) 891 && ip2k_address_uses_reg_p (x, REG_SP)) 892 /* An SP-relative address needs to account for interior stack 893 pushes that reload didn't know about when it calculated the 894 stack offset. */ 895 abcd += ip2k_stack_delta; 896 897 switch (GET_CODE (x)) 898 { 899 case SUBREG: 900 x = alter_subreg (&x); 901 /* fall-thru */ 902 903 case REG: 904 fprintf (file, reg_names[true_regnum (x) + abcd]); 905 break; 906 907 case CONST_INT: 908 switch (code) 909 { 910 case 'x': 911 fprintf (file, "$%x", INTVAL (x) & 0xffff); 912 break; 913 914 case 'b': 915 fprintf (file, "%d", INTVAL (x)); /* bit selector */ 916 break; 917 918 case 'e': /* "1 << n" - e.g. "exp" */ 919 fprintf (file, "#%d", 1 << INTVAL (x)); 920 break; 921 922 case 'A': 923 case 'B': 924 case 'C': 925 case 'D': 926 value = INTVAL (x); 927 value >>= 8 * (3 - abcd); 928 value &= 0xff; 929 930 fprintf (file, "#%ld", value); 931 break; 932 933 case 'H': 934 fprintf (file, "#%d", (INTVAL (x) >> 8) & 0xff); 935 break; 936 937 case 'L': 938 fprintf (file, "#%d", INTVAL (x) & 0xff); 939 break; 940 941 case 'S': 942 case 'T': 943 case 'U': 944 case 'V': 945 case 'W': 946 case 'X': 947 case 'Y': 948 case 'Z': 949 value = ((unsigned long long)INTVAL (x)) >> (8 * (7 - abcd)) & 0xff; 950 fprintf (file, "#%ld", value); 951 break; 952 953 default: 954 fprintf (file, "#%d", INTVAL (x)); 955 } 956 break; 957 958 case SYMBOL_REF: 959 case LABEL_REF: 960 case CODE_LABEL: 961 case CONST: 962 switch (code) 963 { 964 case 'A': 965 case 'B': 966 case 'C': 967 case 'D': 968 case 'S': 969 case 'T': 970 case 'U': 971 case 'V': 972 case 'W': 973 case 'X': 974 case 'Y': 975 case 'Z': 976 abort (); /* Probably an error. */ 977 break; 978 979 case 'H': 980 fprintf (file, "#%s(", 981 is_regfile_address (x) ? "%hi8data" 982 : "%hi8insn"); 983 print_operand_address (file, x); 984 fputc (')', file); 985 break; 986 987 case 'L': 988 fprintf (file, "#%s(", 989 is_regfile_address (x) ? "%lo8data" 990 : "%lo8insn"); 991 print_operand_address (file, x); 992 fputc (')', file); 993 break; 994 995 default: 996 print_operand_address (file, x); 997 } 998 break; 999 1000 case MEM: 1001 { 1002 rtx addr = XEXP (x, 0); 1003 1004 if (GET_CODE (addr) == SUBREG) 1005 addr = alter_subreg (&x); 1006 1007 if (CONSTANT_P (addr) && abcd) 1008 { 1009 fputc ('(', file); 1010 print_operand_address (file, addr); 1011 fprintf (file, ")+%d", abcd); 1012 } 1013 else if (abcd) 1014 { 1015 switch (GET_CODE (addr)) 1016 { 1017 case PLUS: 1018 abcd += INTVAL (XEXP (addr, 1)); 1019 1020 /* Worry about (plus (plus (reg DP) (const_int 10)) 1021 (const_int 0)) */ 1022 if (GET_CODE (XEXP (addr, 0)) == PLUS) 1023 { 1024 addr = XEXP (addr, 0); 1025 abcd += INTVAL (XEXP (addr, 1)); 1026 } 1027 1028 fprintf (file, "%d", abcd); 1029 print_operand_address (file, XEXP (addr, 0)); 1030 break; 1031 1032 case REG: 1033 default: 1034 fprintf (file, "%d", abcd); 1035 print_operand_address (file, addr); 1036 } 1037 } 1038 else if (GET_CODE (addr) == REG 1039 && (REGNO (addr) == REG_DP || REGNO (addr) == REG_SP)) 1040 { 1041 fprintf (file, "0"); 1042 print_operand_address (file, addr); 1043 } 1044 else 1045 print_operand_address (file, addr); 1046 } 1047 break; 1048 1049 case CONST_DOUBLE: 1050 /* Is this an integer or a floating point value? */ 1051 if (GET_MODE (x) == VOIDmode) 1052 { 1053 switch (code) 1054 { 1055 case 'S': 1056 case 'T': 1057 case 'U': 1058 case 'V': 1059 value = CONST_DOUBLE_HIGH (x); 1060 value >>= 8 * (3 - abcd); 1061 value &= 0xff; 1062 1063 fprintf (file, "#%ld", value); 1064 break; 1065 1066 case 'W': 1067 case 'X': 1068 case 'Y': 1069 case 'Z': 1070 value = CONST_DOUBLE_LOW (x); 1071 value >>= 8 * (7 - abcd); 1072 value &= 0xff; 1073 1074 fprintf (file, "#%ld", value); 1075 break; 1076 } 1077 1078 } 1079 else 1080 { 1081 REAL_VALUE_TYPE rv; 1082 1083 REAL_VALUE_FROM_CONST_DOUBLE (rv, x); 1084 REAL_VALUE_TO_TARGET_SINGLE (rv, value); 1085 fprintf (file, "0x%lx", value); 1086 } 1087 break; 1088 1089 default: 1090 fatal_insn ("bad operand", x); 1091 } 1092} 1093 1094/* Remember the operands for the compare. */ 1095const char * 1096ip2k_set_compare (x, y) 1097 rtx x; 1098 rtx y; 1099{ 1100 ip2k_compare_operands[0] = x; 1101 ip2k_compare_operands[1] = y; 1102 return ""; 1103} 1104 1105/* Emit the code for sCOND instructions. */ 1106const char * 1107ip2k_gen_sCOND (insn, code, dest) 1108 rtx insn ATTRIBUTE_UNUSED; 1109 enum rtx_code code; 1110 rtx dest; 1111{ 1112#define operands ip2k_compare_operands 1113 enum machine_mode mode; 1114 1115 operands[2] = dest; 1116 1117 mode = GET_MODE (operands[0]); 1118 if ((mode != QImode) && (mode != HImode) 1119 && (mode != SImode) && (mode != DImode)) 1120 mode = GET_MODE (operands[1]); 1121 1122 /* We have a fast path for a specific type of QImode compare. We ought 1123 to extend this for larger cases too but that wins less frequently and 1124 introduces a lot of complexity. */ 1125 if (mode == QImode 1126 && !rtx_equal_p (operands[0], operands[2]) 1127 && !rtx_equal_p (operands[1], operands[2]) 1128 && (! REG_P (operands[2]) 1129 || (ip2k_xexp_not_uses_reg_p (operands[0], REGNO (operands[2]), 1) 1130 && ip2k_xexp_not_uses_reg_p (operands[1], 1131 REGNO (operands[2]), 1)))) 1132 { 1133 OUT_AS1 (clr, %2); 1134 if (immediate_operand (operands[1], QImode) 1135 && ((INTVAL (operands[1]) & 0xff) == 0xff)) 1136 { 1137 if (code == EQ) 1138 OUT_AS2 (incsnz, w, %0); 1139 else 1140 OUT_AS2 (incsz, w, %0); 1141 } 1142 else if (immediate_operand (operands[1], QImode) 1143 && ((INTVAL (operands[1]) & 0xff) == 0x01)) 1144 { 1145 if (code == EQ) 1146 OUT_AS2 (decsnz, w, %0); 1147 else 1148 OUT_AS2 (decsz, w, %0); 1149 } 1150 else if (ip2k_compare_operands[1] == const0_rtx) 1151 { 1152 OUT_AS2 (mov, w, %0); 1153 if (code == EQ) 1154 OUT_AS1 (snz,); 1155 else 1156 OUT_AS1 (sz,); 1157 } 1158 else 1159 { 1160 OUT_AS2 (mov, w, %0); 1161 if (code == EQ) 1162 OUT_AS2 (csne, w, %1); 1163 else 1164 OUT_AS2 (cse, w, %1); 1165 } 1166 OUT_AS1 (inc, %2); 1167 } 1168 else 1169 { 1170 if (ip2k_compare_operands[1] == const0_rtx) 1171 { 1172 switch (mode) 1173 { 1174 case QImode: 1175 OUT_AS2 (mov, w, %0); 1176 break; 1177 1178 case HImode: 1179 OUT_AS2 (mov, w, %H0); 1180 OUT_AS2 (or, w, %L0); 1181 break; 1182 1183 case SImode: 1184 OUT_AS2 (mov, w, %A0); 1185 OUT_AS2 (or, w, %B0); 1186 OUT_AS2 (or, w, %C0); 1187 OUT_AS2 (or, w, %D0); 1188 break; 1189 1190 case DImode: 1191 OUT_AS2 (mov, w, %S0); 1192 OUT_AS2 (or, w, %T0); 1193 OUT_AS2 (or, w, %U0); 1194 OUT_AS2 (or, w, %V0); 1195 OUT_AS2 (or, w, %W0); 1196 OUT_AS2 (or, w, %X0); 1197 OUT_AS2 (or, w, %Y0); 1198 OUT_AS2 (or, w, %Z0); 1199 break; 1200 1201 default: 1202 abort (); 1203 } 1204 } 1205 else 1206 { 1207 switch (mode) 1208 { 1209 case QImode: 1210 OUT_AS2 (mov, w, %1); 1211 OUT_AS2 (cmp, w, %0); 1212 break; 1213 1214 case HImode: 1215 OUT_AS2 (mov, w, %H1); 1216 OUT_AS2 (cmp, w, %H0); 1217 OUT_AS1 (sz,); 1218 OUT_AS1 (page, 2f); 1219 OUT_AS1 (jmp, 2f); 1220 OUT_AS2 (mov, w, %L1); 1221 OUT_AS2 (cmp, w, %L0); 1222 OUT_AS1 (2:,); 1223 break; 1224 1225 case SImode: 1226 if (code == EQ) 1227 { 1228 OUT_AS2 (mov, w, #1); 1229 OUT_AS2 (mov, mulh, w); 1230 } 1231 else 1232 OUT_AS1 (clr, mulh); 1233 OUT_AS2 (mov, w, %A1); 1234 OUT_AS2 (cse, w, %A0); 1235 OUT_AS1 (page, 2f); 1236 OUT_AS1 (jmp, 2f); 1237 OUT_AS2 (mov, w, %B1); 1238 OUT_AS2 (cse, w, %B0); 1239 OUT_AS1 (page, 2f); 1240 OUT_AS1 (jmp, 2f); 1241 OUT_AS2 (mov, w, %C1); 1242 OUT_AS2 (cse, w, %C0); 1243 OUT_AS1 (page, 2f); 1244 OUT_AS1 (jmp, 2f); 1245 OUT_AS2 (mov, w, %D1); 1246 OUT_AS2 (cse, w, %D0); 1247 OUT_AS1 (2:,); 1248 if (code == EQ) 1249 OUT_AS1 (dec, mulh); 1250 else 1251 OUT_AS1 (inc, mulh); 1252 OUT_AS2 (mov, w, mulh); 1253 OUT_AS2 (mov, %2, w); 1254 return ""; 1255 1256 case DImode: 1257 if (code == EQ) 1258 { 1259 OUT_AS2 (mov, w, #1); 1260 OUT_AS2 (mov, mulh, w); 1261 } 1262 else 1263 OUT_AS1 (clr, mulh); 1264 OUT_AS2 (mov, w, %S1); 1265 OUT_AS2 (cse, w, %S0); 1266 OUT_AS1 (page, 2f); 1267 OUT_AS1 (jmp, 2f); 1268 OUT_AS2 (mov, w, %T1); 1269 OUT_AS2 (cse, w, %T0); 1270 OUT_AS1 (page, 2f); 1271 OUT_AS1 (jmp, 2f); 1272 OUT_AS2 (mov, w, %U1); 1273 OUT_AS2 (cse, w, %U0); 1274 OUT_AS1 (page, 2f); 1275 OUT_AS1 (jmp, 2f); 1276 OUT_AS2 (mov, w, %V1); 1277 OUT_AS2 (cse, w, %V0); 1278 OUT_AS1 (page, 2f); 1279 OUT_AS1 (jmp, 2f); 1280 OUT_AS2 (mov, w, %W1); 1281 OUT_AS2 (cse, w, %W0); 1282 OUT_AS1 (page, 2f); 1283 OUT_AS1 (jmp, 2f); 1284 OUT_AS2 (mov, w, %X1); 1285 OUT_AS2 (cse, w, %X0); 1286 OUT_AS1 (page, 2f); 1287 OUT_AS1 (jmp, 2f); 1288 OUT_AS2 (mov, w, %Y1); 1289 OUT_AS2 (cse, w, %Y0); 1290 OUT_AS1 (page, 2f); 1291 OUT_AS1 (jmp, 2f); 1292 OUT_AS2 (mov, w, %Z1); 1293 OUT_AS2 (cse, w, %Z0); 1294 OUT_AS1 (2:,); 1295 if (code == EQ) 1296 OUT_AS1 (dec, mulh); 1297 else 1298 OUT_AS1 (inc, mulh); 1299 OUT_AS2 (mov, w, mulh); 1300 OUT_AS2 (mov, %2, w); 1301 return ""; 1302 1303 default: 1304 abort (); 1305 } 1306 } 1307 OUT_AS2 (mov, w, #0); 1308 if (code == EQ) 1309 OUT_AS1 (snz,); 1310 else 1311 OUT_AS1 (sz,); 1312 OUT_AS1 (inc, wreg); 1313 OUT_AS2 (mov, %2, w); 1314 } 1315 1316 return ""; 1317#undef operands 1318} 1319 1320const char * 1321ip2k_gen_signed_comp_branch (insn, code, label) 1322 rtx insn; 1323 enum rtx_code code; 1324 rtx label; 1325{ 1326#define operands ip2k_compare_operands 1327 enum machine_mode mode; 1328 int can_use_skip = 0; 1329 rtx ninsn; 1330 1331 operands[2] = label; 1332 1333 mode = GET_MODE (operands[0]); 1334 if ((mode != QImode) && (mode != HImode) 1335 && (mode != SImode) && (mode != DImode)) 1336 mode = GET_MODE (operands[1]); 1337 1338 /* Look for situations where we can just skip the next instruction instead 1339 of skipping and then branching! */ 1340 ninsn = next_real_insn (insn); 1341 if (ninsn 1342 && (recog_memoized (ninsn) >= 0) 1343 && get_attr_skip (ninsn) == SKIP_YES) 1344 { 1345 rtx skip_tgt = next_nonnote_insn (next_real_insn (insn)); 1346 1347 /* The first situation is where the target of the jump is one insn 1348 after the jump insn and the insn being jumped is only one machine 1349 opcode long. */ 1350 if (label == skip_tgt) 1351 can_use_skip = 1; 1352 else 1353 { 1354 /* If our skip target is in fact a code label then we ignore the 1355 label and move onto the next useful instruction. Nothing we do 1356 here has any effect on the use of skipping instructions. */ 1357 if (GET_CODE (skip_tgt) == CODE_LABEL) 1358 skip_tgt = next_nonnote_insn (skip_tgt); 1359 1360 /* The second situation is where we have something of the form: 1361 1362 test_condition 1363 skip_conditional 1364 page/jump label 1365 1366 optional_label (this may or may not exist): 1367 skippable_insn 1368 page/jump label 1369 1370 In this case we can eliminate the first "page/jump label". */ 1371 if (GET_CODE (skip_tgt) == JUMP_INSN) 1372 { 1373 rtx set = single_set (skip_tgt); 1374 if (GET_CODE (XEXP (set, 0)) == PC 1375 && GET_CODE (XEXP (set, 1)) == LABEL_REF 1376 && label == JUMP_LABEL (skip_tgt)) 1377 can_use_skip = 2; 1378 } 1379 } 1380 } 1381 1382 /* gcc is a little braindead and does some rather stateful things while 1383 inspecting attributes - we have to put this state back to what it's 1384 supposed to be. */ 1385 extract_constrain_insn_cached (insn); 1386 1387 if (ip2k_compare_operands[1] == const0_rtx) /* These are easier. */ 1388 { 1389 switch (code) 1390 { 1391 case LT: 1392 if (can_use_skip) 1393 { 1394 OUT_AS2 (sb, %0, 7); 1395 } 1396 else 1397 { 1398 OUT_AS2 (snb, %0, 7); 1399 OUT_AS1 (page, %2); 1400 OUT_AS1 (jmp, %2); 1401 } 1402 break; 1403 1404 case GT: 1405 switch (mode) 1406 { 1407 case DImode: 1408 OUT_AS2 (rl, w, %S0); 1409 OUT_AS2 (mov, w, %S0); 1410 OUT_AS2 (or, w, %T0); 1411 OUT_AS2 (or, w, %U0); 1412 OUT_AS2 (or, w, %V0); 1413 OUT_AS2 (or, w, %W0); 1414 OUT_AS2 (or, w, %X0); 1415 OUT_AS2 (or, w, %Y0); 1416 OUT_AS2 (or, w, %Z0); 1417 OUT_AS1 (snz, ); 1418 OUT_AS2 (setb, status, 0); 1419 OUT_AS2 (sb, status, 0); 1420 OUT_AS1 (page, %2); 1421 OUT_AS1 (jmp, %2); 1422 break; 1423 1424 case SImode: 1425 OUT_AS2 (rl, w, %A0); 1426 OUT_AS2 (mov, w, %A0); 1427 OUT_AS2 (or, w, %B0); 1428 OUT_AS2 (or, w, %C0); 1429 OUT_AS2 (or, w, %D0); 1430 OUT_AS1 (snz, ); 1431 OUT_AS2 (setb, status, 0); 1432 OUT_AS2 (sb, status, 0); 1433 OUT_AS1 (page, %2); 1434 OUT_AS1 (jmp, %2); 1435 break; 1436 1437 case HImode: 1438 OUT_AS2 (rl, w, %H0); 1439 OUT_AS2 (mov, w, %H0); 1440 OUT_AS2 (or, w, %L0); 1441 OUT_AS1 (snz, ); 1442 OUT_AS2 (setb, status, 0); 1443 OUT_AS2 (sb, status, 0); 1444 OUT_AS1 (page, %2); 1445 OUT_AS1 (jmp, %2); 1446 break; 1447 1448 case QImode: 1449 OUT_AS2 (mov, w, %0); /* Will just do "sb w, 7". */ 1450 OUT_AS1 (snz, ); 1451 OUT_AS2 (setb, wreg, 7); 1452 OUT_AS2 (sb, wreg, 7); 1453 OUT_AS1 (page, %2); 1454 OUT_AS1 (jmp, %2); 1455 break; 1456 1457 default: 1458 abort (); 1459 } 1460 break; 1461 1462 case LE: 1463 switch (mode) 1464 { 1465 case DImode: 1466 OUT_AS2 (mov, w, %S0); 1467 OUT_AS2 (or, w, %T0); 1468 OUT_AS2 (or, w, %U0); 1469 OUT_AS2 (or, w, %V0); 1470 OUT_AS2 (or, w, %W0); 1471 OUT_AS2 (or, w, %X0); 1472 OUT_AS2 (or, w, %Y0); 1473 OUT_AS2 (or, w, %Z0); /* Z is correct. */ 1474 OUT_AS1 (sz, ); 1475 OUT_AS2 (snb, %S0, 7); 1476 OUT_AS1 (page, %2); 1477 OUT_AS1 (jmp, %2); 1478 break; 1479 1480 case SImode: 1481 OUT_AS2 (mov, w, %A0); 1482 OUT_AS2 (or, w, %B0); 1483 OUT_AS2 (or, w, %C0); 1484 OUT_AS2 (or, w, %D0); /* Z is correct. */ 1485 OUT_AS1 (sz, ); 1486 OUT_AS2 (snb, %A0, 7); 1487 OUT_AS1 (page, %2); 1488 OUT_AS1 (jmp, %2); 1489 break; 1490 1491 case HImode: 1492 OUT_AS2 (mov, w, %H0); 1493 OUT_AS2 (or, w, %L0); 1494 OUT_AS1 (sz, ); 1495 OUT_AS2 (snb, %H0, 7); 1496 OUT_AS1 (page, %2); 1497 OUT_AS1 (jmp, %2); 1498 break; 1499 1500 case QImode: 1501 OUT_AS2 (mov, w, %0); /* Will just do "sb w, 7". */ 1502 OUT_AS1 (sz, ); 1503 OUT_AS2 (snb, wreg, 7); 1504 OUT_AS1 (page, %2); 1505 OUT_AS1 (jmp, %2); 1506 break; 1507 1508 default: 1509 abort (); 1510 } 1511 break; 1512 1513 case GE: 1514 if (can_use_skip) 1515 { 1516 OUT_AS2 (snb, %0, 7); 1517 } 1518 else 1519 { 1520 OUT_AS2 (sb, %0, 7); 1521 OUT_AS1 (page, %2); 1522 OUT_AS1 (jmp, %2); 1523 } 1524 break; 1525 1526 default: 1527 abort (); 1528 } 1529 return ""; 1530 } 1531 1532 /* signed compares are out of line because we can't get 1533 the hardware to compute the overflow for us. */ 1534 1535 switch (mode) 1536 { 1537 case QImode: 1538 OUT_AS1 (push, %1%<); 1539 OUT_AS1 (push, %0%>); 1540 OUT_AS1 (page, __cmpqi2); 1541 OUT_AS1 (call, __cmpqi2); 1542 break; 1543 1544 case HImode: 1545 OUT_AS1 (push, %L1%<); 1546 OUT_AS1 (push, %H1%<); 1547 OUT_AS1 (push, %L0%<); 1548 OUT_AS1 (push, %H0%>%>%>); 1549 OUT_AS1 (page, __cmphi2); 1550 OUT_AS1 (call, __cmphi2); 1551 break; 1552 1553 case SImode: 1554 OUT_AS1 (push, %D1%<); 1555 OUT_AS1 (push, %C1%<); 1556 OUT_AS1 (push, %B1%<); 1557 OUT_AS1 (push, %A1%<); 1558 OUT_AS1 (push, %D0%<); 1559 OUT_AS1 (push, %C0%<); 1560 OUT_AS1 (push, %B0%<); 1561 OUT_AS1 (push, %A0%>%>%>%>%>%>%>); 1562 OUT_AS1 (page, __cmpsi2); 1563 OUT_AS1 (call, __cmpsi2); 1564 break; 1565 1566 case DImode: 1567 if (GET_CODE (operands[0]) == MEM 1568 && true_regnum (XEXP (operands[0], 0)) == REG_DP) 1569 { 1570 OUT_AS1 (push, %Z1%<); 1571 OUT_AS1 (push, %Y1%<); 1572 OUT_AS1 (push, %X1%<); 1573 OUT_AS1 (push, %W1%<); 1574 OUT_AS1 (push, %V1%<); 1575 OUT_AS1 (push, %U1%<); 1576 OUT_AS1 (push, %T1%<); 1577 OUT_AS1 (push, %S1%>%>%>%>%>%>%>); 1578 OUT_AS1 (page, __cmpdi2_dp); 1579 OUT_AS1 (call, __cmpdi2_dp); 1580 } 1581 else 1582 { 1583 OUT_AS1 (push, %Z1%<); 1584 OUT_AS1 (push, %Y1%<); 1585 OUT_AS1 (push, %X1%<); 1586 OUT_AS1 (push, %W1%<); 1587 OUT_AS1 (push, %V1%<); 1588 OUT_AS1 (push, %U1%<); 1589 OUT_AS1 (push, %T1%<); 1590 OUT_AS1 (push, %S1%<); 1591 OUT_AS1 (push, %Z0%<); 1592 OUT_AS1 (push, %Y0%<); 1593 OUT_AS1 (push, %X0%<); 1594 OUT_AS1 (push, %W0%<); 1595 OUT_AS1 (push, %V0%<); 1596 OUT_AS1 (push, %U0%<); 1597 OUT_AS1 (push, %T0%<); 1598 OUT_AS1 (push, %S0%>%>%>%>%>%>%>%>%>%>%>%>%>%>%>); 1599 OUT_AS1 (page, __cmpdi2); 1600 OUT_AS1 (call, __cmpdi2); 1601 } 1602 break; 1603 1604 default: 1605 abort (); 1606 } 1607 1608 switch (code) 1609 { 1610 case LT: 1611 if (can_use_skip) 1612 { 1613 OUT_AS2 (cse, w, #0); 1614 } 1615 else 1616 { 1617 OUT_AS2 (csne, w, #0); 1618 OUT_AS1 (page, %2); 1619 OUT_AS1 (jmp, %2); 1620 } 1621 break; 1622 1623 case GT: 1624 if (can_use_skip) 1625 { 1626 OUT_AS2 (cse, w, #2); 1627 } 1628 else 1629 { 1630 OUT_AS2 (csne, w, #2); 1631 OUT_AS1 (page, %2); 1632 OUT_AS1 (jmp, %2); 1633 } 1634 break; 1635 1636 case LE: 1637 if (can_use_skip) 1638 { 1639 OUT_AS2 (snb, wreg, 1); 1640 } 1641 else 1642 { 1643 OUT_AS2 (sb, wreg, 1); 1644 OUT_AS1 (page, %2); 1645 OUT_AS1 (jmp, %2); 1646 } 1647 break; 1648 1649 case GE: 1650 if (can_use_skip) 1651 { 1652 OUT_AS2 (csne, w, #0); 1653 } 1654 else 1655 { 1656 OUT_AS2 (cse, w, #0); 1657 OUT_AS1 (page, %2); 1658 OUT_AS1 (jmp, %2); 1659 } 1660 break; 1661 1662 default: 1663 abort (); 1664 } 1665 return ""; 1666#undef operands 1667} 1668 1669const char * 1670ip2k_gen_unsigned_comp_branch (insn, code, label) 1671 rtx insn; 1672 enum rtx_code code; 1673 rtx label; 1674{ 1675#define operands ip2k_compare_operands 1676 enum machine_mode mode; 1677 int imm_sub = 0; 1678 int imm_cmp = 0; 1679 int can_use_skip = 0; 1680 rtx ninsn; 1681 HOST_WIDE_INT const_low; 1682 HOST_WIDE_INT const_high; 1683 1684 operands[2] = label; 1685 1686 mode = GET_MODE (operands[0]); 1687 if ((mode != QImode) && (mode != HImode) && (mode != SImode) 1688 && (mode != DImode)) 1689 { 1690 mode = GET_MODE (operands[1]); 1691 } 1692 1693 /* Look for situations where we can just skip the next instruction instead 1694 of skipping and then branching! */ 1695 ninsn = next_real_insn (insn); 1696 if (ninsn 1697 && (recog_memoized (ninsn) >= 0) 1698 && get_attr_skip (ninsn) == SKIP_YES) 1699 { 1700 rtx skip_tgt = next_nonnote_insn (next_real_insn (insn)); 1701 1702 /* The first situation is where the target of the jump is one insn 1703 after the jump insn and the insn being jumped is only one machine 1704 opcode long. */ 1705 if (label == skip_tgt) 1706 can_use_skip = 1; 1707 else 1708 { 1709 /* If our skip target is in fact a code label then we ignore the 1710 label and move onto the next useful instruction. Nothing we do 1711 here has any effect on the use of skipping instructions. */ 1712 if (GET_CODE (skip_tgt) == CODE_LABEL) 1713 skip_tgt = next_nonnote_insn (skip_tgt); 1714 1715 /* The second situation is where we have something of the form: 1716 1717 test_condition 1718 skip_conditional 1719 page/jump label 1720 1721 optional_label (this may or may not exist): 1722 skippable_insn 1723 page/jump label 1724 1725 In this case we can eliminate the first "page/jump label". */ 1726 if (GET_CODE (skip_tgt) == JUMP_INSN) 1727 { 1728 rtx set = single_set (skip_tgt); 1729 if (GET_CODE (XEXP (set, 0)) == PC 1730 && GET_CODE (XEXP (set, 1)) == LABEL_REF 1731 && label == JUMP_LABEL (skip_tgt)) 1732 can_use_skip = 2; 1733 } 1734 } 1735 } 1736 1737 /* gcc is a little braindead and does some rather stateful things while 1738 inspecting attributes - we have to put this state back to what it's 1739 supposed to be. */ 1740 extract_constrain_insn_cached (insn); 1741 1742 if (ip2k_compare_operands[1] == const0_rtx) 1743 { 1744 switch (code) 1745 { 1746 case LEU: 1747 code = EQ; /* Nothing is LTU 0. */ 1748 goto zero; 1749 1750 case GTU: 1751 code = NE; /* Anything nonzero is GTU. */ 1752 /* fall-thru */ 1753 1754 case EQ: 1755 case NE: /* Test all the bits, result in 1756 Z AND WREG. */ 1757 zero: 1758 switch (mode) 1759 { 1760 case DImode: 1761 OUT_AS2 (mov, w, %S0); 1762 OUT_AS2 (or, w, %T0); 1763 OUT_AS2 (or, w, %U0); 1764 OUT_AS2 (or, w, %V0); 1765 OUT_AS2 (or, w, %W0); 1766 OUT_AS2 (or, w, %X0); 1767 OUT_AS2 (or, w, %Y0); 1768 OUT_AS2 (or, w, %Z0); 1769 break; 1770 1771 case SImode: 1772 OUT_AS2 (mov, w, %A0); 1773 OUT_AS2 (or, w, %B0); 1774 OUT_AS2 (or, w, %C0); 1775 OUT_AS2 (or, w, %D0); 1776 break; 1777 1778 case HImode: 1779 OUT_AS2 (mov, w, %H0); 1780 OUT_AS2 (or, w, %L0); 1781 break; 1782 1783 case QImode: 1784 OUT_AS2 (mov, w, %0); 1785 break; 1786 1787 default: 1788 abort (); 1789 } 1790 1791 if (can_use_skip) 1792 { 1793 if (code == EQ) 1794 OUT_AS1 (sz, ); 1795 else 1796 OUT_AS1 (snz, ); 1797 } 1798 else 1799 { 1800 if (code == EQ) 1801 OUT_AS1 (snz,); 1802 else 1803 OUT_AS1 (sz,); 1804 OUT_AS1 (page, %2); 1805 OUT_AS1 (jmp, %2); 1806 } 1807 break; 1808 1809 case GEU: 1810 /* Always succeed. */ 1811 OUT_AS1 (page, %2); 1812 OUT_AS1 (jmp, %2); 1813 break; 1814 1815 case LTU: 1816 /* Always fail. */ 1817 break; 1818 1819 default: 1820 abort (); 1821 } 1822 return ""; 1823 } 1824 1825 /* Look at whether we have a constant as one of our operands. If we do 1826 and it's in the position that we use to subtract from during our 1827 normal optimized comparison concept then we have to shuffle things 1828 around! */ 1829 if (mode != QImode) 1830 { 1831 if ((immediate_operand (operands[1], GET_MODE (operands[1])) 1832 && ((code == LEU) || (code == GTU))) 1833 || (immediate_operand (operands[0], GET_MODE (operands[0])) 1834 && ((code == LTU) || (code == GEU)))) 1835 { 1836 imm_sub = 1; 1837 } 1838 } 1839 1840 /* Same as above - look if we have a constant that we can compare 1841 for equality or non-equality. If we know this then we can look 1842 for common value eliminations. Note that we want to ensure that 1843 any immediate value is operand 1 to simplify the code later! */ 1844 if ((code == EQ) || (code == NE)) 1845 { 1846 imm_cmp = immediate_operand (operands[1], GET_MODE (operands[1])); 1847 if (! imm_cmp) 1848 { 1849 imm_cmp = immediate_operand (operands[0], GET_MODE (operands[0])); 1850 if (imm_cmp) 1851 { 1852 rtx tmp = operands[1]; 1853 operands[1] = operands[0]; 1854 operands[0] = tmp; 1855 } 1856 } 1857 } 1858 1859 switch (mode) 1860 { 1861 case QImode: 1862 switch (code) 1863 { 1864 case EQ: 1865 if (imm_cmp && ((INTVAL (operands[1]) & 0xff) == 0xff)) 1866 OUT_AS2 (incsnz, w, %0); 1867 else if (imm_cmp && ((INTVAL (operands[1]) & 0xff) == 0x01)) 1868 OUT_AS2 (decsnz, w, %0); 1869 else 1870 { 1871 OUT_AS2 (mov, w, %1); 1872 OUT_AS2 (csne, w, %0); 1873 } 1874 OUT_AS1 (page, %2); 1875 OUT_AS1 (jmp, %2); 1876 break; 1877 1878 case NE: 1879 if (imm_cmp && ((INTVAL (operands[1]) & 0xff) == 0xff)) 1880 OUT_AS2 (incsz, w, %0); 1881 else if (imm_cmp && ((INTVAL (operands[1]) & 0xff) == 0x01)) 1882 OUT_AS2 (decsz, w, %0); 1883 else 1884 { 1885 OUT_AS2 (mov, w, %1); 1886 OUT_AS2 (cse, w, %0); 1887 } 1888 OUT_AS1 (page, %2); 1889 OUT_AS1 (jmp, %2); 1890 break; 1891 1892 case GTU: 1893 OUT_AS2 (mov, w, %0); 1894 OUT_AS2 (cmp, w, %1); 1895 OUT_AS1 (sc,); 1896 OUT_AS1 (page, %2); 1897 OUT_AS1 (jmp, %2); 1898 break; 1899 1900 case GEU: 1901 OUT_AS2 (mov, w, %1); 1902 OUT_AS2 (cmp, w, %0); 1903 OUT_AS1 (snc,); 1904 OUT_AS1 (page, %2); 1905 OUT_AS1 (jmp, %2); 1906 break; 1907 1908 case LTU: 1909 OUT_AS2 (mov, w, %1); 1910 OUT_AS2 (cmp, w, %0); 1911 OUT_AS1 (sc,); 1912 OUT_AS1 (page, %2); 1913 OUT_AS1 (jmp, %2); 1914 break; 1915 1916 case LEU: 1917 OUT_AS2 (mov, w, %0); 1918 OUT_AS2 (cmp, w, %1); 1919 OUT_AS1 (snc,); 1920 OUT_AS1 (page, %2); 1921 OUT_AS1 (jmp, %2); 1922 break; 1923 1924 default: 1925 abort (); 1926 } 1927 break; 1928 1929 case HImode: 1930 switch (code) 1931 { 1932 case EQ: 1933 { 1934 unsigned char h = 0, l = 1; 1935 1936 if (imm_cmp) 1937 { 1938 h = (INTVAL (operands[1]) >> 8) & 0xff; 1939 l = INTVAL (operands[1]) & 0xff; 1940 1941 if ((h == 0xff) && (l == 0xff)) 1942 { 1943 /* We should be able to do the following, but the 1944 IP2k simulator doesn't like it and we get a load 1945 of failures in gcc-c-torture. */ 1946 OUT_AS2 (incsnz, w, %L0); 1947 OUT_AS2 (incsz, w, %H0); 1948/* OUT_AS1 (skip,); Should have this */ 1949 OUT_AS1 (page, 1f);/* Shouldn't need this! */ 1950 OUT_AS1 (jmp, 1f); /* Shouldn't need this either. */ 1951 OUT_AS1 (page, %2); 1952 OUT_AS1 (jmp, %2); 1953 OUT_AS1 (1:,); 1954 break; 1955 } 1956 else if (h == 0) 1957 { 1958 if (l == 1) 1959 OUT_AS2 (dec, w, %L0); 1960 else 1961 { 1962 OUT_AS2 (mov, w, %L0); 1963 OUT_AS2 (sub, w, %L1); 1964 } 1965 OUT_AS2 (or, w, %H0); 1966 OUT_AS1 (snz,); 1967 OUT_AS1 (page, %2); 1968 OUT_AS1 (jmp, %2); 1969 break; 1970 } 1971 else if (l == 0) 1972 { 1973 if (h == 1) 1974 OUT_AS2 (dec, w, %H0); 1975 else 1976 { 1977 OUT_AS2 (mov, w, %H0); 1978 OUT_AS2 (sub, w, %H1); 1979 } 1980 OUT_AS2 (or, w, %L0); 1981 OUT_AS1 (snz,); 1982 OUT_AS1 (page, %2); 1983 OUT_AS1 (jmp, %2); 1984 break; 1985 } 1986 } 1987 1988 OUT_AS2 (mov, w, %H1); 1989 OUT_AS2 (cse, w, %H0); 1990 OUT_AS1 (page, 2f); 1991 OUT_AS1 (jmp, 2f); 1992 if (! imm_cmp || (h != l)) 1993 OUT_AS2 (mov, w, %L1); 1994 OUT_AS2 (csne, w, %L0); 1995 OUT_AS1 (page, %2); 1996 OUT_AS1 (jmp, %2); 1997 OUT_AS1 (2:,); 1998 } 1999 break; 2000 2001 case NE: 2002 { 2003 unsigned char h = 0, l = 1; 2004 2005 if (imm_cmp) 2006 { 2007 h = (INTVAL (operands[1]) >> 8) & 0xff; 2008 l = INTVAL (operands[1]) & 0xff; 2009 2010 if ((h == 0xff) && (l == 0xff)) 2011 { 2012 OUT_AS2 (incsnz, w, %L0); 2013 OUT_AS2 (incsz, w, %H0); 2014 OUT_AS1 (page, %2); 2015 OUT_AS1 (jmp, %2); 2016 break; 2017 } 2018 else if (h == 0) 2019 { 2020 if (l == 1) 2021 OUT_AS2 (dec, w, %L0); 2022 else 2023 { 2024 OUT_AS2 (mov, w, %L0); 2025 OUT_AS2 (sub, w, %L1); 2026 } 2027 OUT_AS2 (or, w, %H0); 2028 OUT_AS1 (sz,); 2029 OUT_AS1 (page, %2); 2030 OUT_AS1 (jmp, %2); 2031 break; 2032 } 2033 else if (l == 0) 2034 { 2035 if (h == 1) 2036 OUT_AS2 (dec, w, %H0); 2037 else 2038 { 2039 OUT_AS2 (mov, w, %H0); 2040 OUT_AS2 (sub, w, %H1); 2041 } 2042 OUT_AS2 (or, w, %L0); 2043 OUT_AS1 (sz,); 2044 OUT_AS1 (page, %2); 2045 OUT_AS1 (jmp, %2); 2046 break; 2047 } 2048 } 2049 2050 OUT_AS2 (mov, w, %H1); 2051 if (imm_cmp && (h == l)) 2052 { 2053 OUT_AS2 (csne, w, %H0); 2054 OUT_AS2 (cse, w, %L0); 2055 } 2056 else 2057 { 2058 OUT_AS2 (cse, w, %H0); 2059 OUT_AS1 (page, %2); 2060 OUT_AS1 (jmp, %2); 2061 OUT_AS2 (mov, w, %L1); 2062 OUT_AS2 (cse, w, %L0); 2063 } 2064 OUT_AS1 (page, %2); 2065 OUT_AS1 (jmp, %2); 2066 } 2067 break; 2068 2069 case GTU: 2070 if (imm_sub) 2071 { 2072 /* > 0xffff never suceeds! */ 2073 if ((INTVAL (operands[1]) & 0xffff) != 0xffff) 2074 { 2075 operands[3] = GEN_INT (INTVAL (operands[1]) + 1); 2076 OUT_AS2 (mov, w, %L3); 2077 OUT_AS2 (sub, w, %L0); 2078 OUT_AS2 (mov, w, %H3); 2079 OUT_AS2 (subc, w, %H0); 2080 OUT_AS1 (snc,); 2081 OUT_AS1 (page, %2); 2082 OUT_AS1 (jmp, %2); 2083 } 2084 } 2085 else 2086 { 2087 OUT_AS2 (mov, w, %L0); 2088 OUT_AS2 (sub, w, %L1); 2089 OUT_AS2 (mov, w, %H0); 2090 OUT_AS2 (subc, w, %H1); 2091 OUT_AS1 (sc,); 2092 OUT_AS1 (page, %2); 2093 OUT_AS1 (jmp, %2); 2094 } 2095 break; 2096 2097 case GEU: 2098 if (imm_sub) 2099 { 2100 if (INTVAL (operands[0]) == 0) 2101 { 2102 OUT_AS2 (mov, w, %H1); 2103 OUT_AS2 (or, w, %L1); 2104 OUT_AS1 (snz,); 2105 OUT_AS1 (page, %2); 2106 OUT_AS1 (jmp, %2); 2107 } 2108 else 2109 { 2110 operands[3] = GEN_INT (INTVAL (operands[0]) - 1); 2111 OUT_AS2 (mov, w, %L3); 2112 OUT_AS2 (sub, w, %L1); 2113 OUT_AS2 (mov, w, %H3); 2114 OUT_AS2 (subc, w, %H1); 2115 OUT_AS1 (sc,); 2116 OUT_AS1 (page, %2); 2117 OUT_AS1 (jmp, %2); 2118 } 2119 } 2120 else 2121 { 2122 OUT_AS2 (mov, w, %L1); 2123 OUT_AS2 (sub, w, %L0); 2124 OUT_AS2 (mov, w, %H1); 2125 OUT_AS2 (subc, w, %H0); 2126 OUT_AS1 (snc,); 2127 OUT_AS1 (page, %2); 2128 OUT_AS1 (jmp, %2); 2129 } 2130 break; 2131 2132 case LTU: 2133 if (imm_sub) 2134 { 2135 if (INTVAL (operands[0]) == 0) 2136 { 2137 OUT_AS2 (mov, w, %H1); 2138 OUT_AS2 (or, w, %L1); 2139 OUT_AS1 (sz,); 2140 OUT_AS1 (page, %2); 2141 OUT_AS1 (jmp, %2); 2142 } 2143 else 2144 { 2145 operands[3] = GEN_INT (INTVAL (operands[0]) - 1); 2146 OUT_AS2 (mov, w, %L3); 2147 OUT_AS2 (sub, w, %L1); 2148 OUT_AS2 (mov, w, %H3); 2149 OUT_AS2 (subc, w, %H1); 2150 OUT_AS1 (snc,); 2151 OUT_AS1 (page, %2); 2152 OUT_AS1 (jmp, %2); 2153 } 2154 } 2155 else 2156 { 2157 OUT_AS2 (mov, w, %L1); 2158 OUT_AS2 (sub, w, %L0); 2159 OUT_AS2 (mov, w, %H1); 2160 OUT_AS2 (subc, w, %H0); 2161 OUT_AS1 (sc,); 2162 OUT_AS1 (page, %2); 2163 OUT_AS1 (jmp, %2); 2164 } 2165 break; 2166 2167 case LEU: 2168 if (imm_sub) 2169 { 2170 if ((INTVAL (operands[1]) & 0xffff) == 0xffff) 2171 { 2172 /* <= 0xffff always suceeds. */ 2173 OUT_AS1 (page, %2); 2174 OUT_AS1 (jmp, %2); 2175 } 2176 else 2177 { 2178 operands[3] = GEN_INT (INTVAL (operands[1]) + 1); 2179 OUT_AS2 (mov, w, %L3); 2180 OUT_AS2 (sub, w, %L0); 2181 OUT_AS2 (mov, w, %H3); 2182 OUT_AS2 (subc, w, %H0); 2183 OUT_AS1 (sc,); 2184 OUT_AS1 (page, %2); 2185 OUT_AS1 (jmp, %2); 2186 } 2187 } 2188 else 2189 { 2190 OUT_AS2 (mov, w, %L0); 2191 OUT_AS2 (sub, w, %L1); 2192 OUT_AS2 (mov, w, %H0); 2193 OUT_AS2 (subc, w, %H1); 2194 OUT_AS1 (snc,); 2195 OUT_AS1 (page, %2); 2196 OUT_AS1 (jmp, %2); 2197 } 2198 break; 2199 2200 default: 2201 abort (); 2202 } 2203 break; 2204 2205 case SImode: 2206 switch (code) 2207 { 2208 case EQ: 2209 { 2210 unsigned char a = 0, b = 1, c = 2, d = 3; 2211 2212 if (imm_cmp) 2213 { 2214 a = (INTVAL (operands[1]) >> 24) & 0xff; 2215 b = (INTVAL (operands[1]) >> 16) & 0xff; 2216 c = (INTVAL (operands[1]) >> 8) & 0xff; 2217 d = INTVAL (operands[1]) & 0xff; 2218 } 2219 2220 OUT_AS2 (mov, w, %A1); 2221 if (imm_cmp && (b == a)) 2222 { 2223 OUT_AS2 (csne, w, %A0); 2224 OUT_AS2 (cse, w, %B0); 2225 } 2226 else 2227 { 2228 OUT_AS2 (cse, w, %A0); 2229 OUT_AS1 (page, 2f); 2230 OUT_AS1 (jmp, 2f); 2231 OUT_AS2 (mov, w, %B1); 2232 OUT_AS2 (cse, w, %B0); 2233 } 2234 OUT_AS1 (page, 2f); 2235 OUT_AS1 (jmp, 2f); 2236 if (! imm_cmp || (c != b)) 2237 OUT_AS2 (mov, w, %C1); 2238 OUT_AS2 (cse, w, %C0); 2239 OUT_AS1 (page, 2f); 2240 OUT_AS1 (jmp, 2f); 2241 if (! imm_cmp || (d != c)) 2242 OUT_AS2 (mov, w, %D1); 2243 OUT_AS2 (csne, w, %D0); 2244 OUT_AS1 (page, %2); 2245 OUT_AS1 (jmp, %2); 2246 OUT_AS1 (2:,); 2247 } 2248 break; 2249 2250 case NE: 2251 { 2252 unsigned char a = 0, b = 1, c = 2, d = 3; 2253 2254 if (imm_cmp) 2255 { 2256 a = (INTVAL (operands[1]) >> 24) & 0xff; 2257 b = (INTVAL (operands[1]) >> 16) & 0xff; 2258 c = (INTVAL (operands[1]) >> 8) & 0xff; 2259 d = INTVAL (operands[1]) & 0xff; 2260 } 2261 2262 OUT_AS2 (mov, w, %A1); 2263 if (imm_cmp && (b == a)) 2264 { 2265 OUT_AS2 (csne, w, %A0); 2266 OUT_AS2 (cse, w, %B0); 2267 } 2268 else 2269 { 2270 OUT_AS2 (cse, w, %A0); 2271 OUT_AS1 (page, %2); 2272 OUT_AS1 (jmp, %2); 2273 OUT_AS2 (mov, w, %B1); 2274 OUT_AS2 (cse, w, %B0); 2275 } 2276 OUT_AS1 (page, %2); 2277 OUT_AS1 (jmp, %2); 2278 if (! imm_cmp || (c != b)) 2279 OUT_AS2 (mov, w, %C1); 2280 if (imm_cmp && (d == c)) 2281 { 2282 OUT_AS2 (csne, w, %C0); 2283 OUT_AS2 (cse, w, %D0); 2284 } 2285 else 2286 { 2287 OUT_AS2 (cse, w, %C0); 2288 OUT_AS1 (page, %2); 2289 OUT_AS1 (jmp, %2); 2290 OUT_AS2 (mov, w, %D1); 2291 OUT_AS2 (cse, w, %D0); 2292 } 2293 OUT_AS1 (page, %2); 2294 OUT_AS1 (jmp, %2); 2295 } 2296 break; 2297 2298 case GTU: 2299 if (imm_sub) 2300 { 2301 /* > 0xffffffff never suceeds! */ 2302 if ((unsigned HOST_WIDE_INT)(INTVAL (operands[1]) & 0xffffffff) 2303 != 0xffffffff) 2304 { 2305 operands[3] = GEN_INT (INTVAL (operands[1]) + 1); 2306 OUT_AS2 (mov, w, %D3); 2307 OUT_AS2 (sub, w, %D0); 2308 OUT_AS2 (mov, w, %C3); 2309 OUT_AS2 (subc, w, %C0); 2310 OUT_AS2 (mov, w, %B3); 2311 OUT_AS2 (subc, w, %B0); 2312 OUT_AS2 (mov, w, %A3); 2313 OUT_AS2 (subc, w, %A0); 2314 OUT_AS1 (snc,); 2315 OUT_AS1 (page, %2); 2316 OUT_AS1 (jmp, %2); 2317 } 2318 } 2319 else 2320 { 2321 OUT_AS2 (mov, w, %D0); 2322 OUT_AS2 (sub, w, %D1); 2323 OUT_AS2 (mov, w, %C0); 2324 OUT_AS2 (subc, w, %C1); 2325 OUT_AS2 (mov, w, %B0); 2326 OUT_AS2 (subc, w, %B1); 2327 OUT_AS2 (mov, w, %A0); 2328 OUT_AS2 (subc, w, %A1); 2329 OUT_AS1 (sc,); 2330 OUT_AS1 (page, %2); 2331 OUT_AS1 (jmp, %2); 2332 } 2333 break; 2334 2335 case GEU: 2336 if (imm_sub) 2337 { 2338 if (INTVAL (operands[0]) == 0) 2339 { 2340 OUT_AS2 (mov, w, %A1); 2341 OUT_AS2 (or, w, %B1); 2342 OUT_AS2 (or, w, %C1); 2343 OUT_AS2 (or, w, %D1); 2344 OUT_AS1 (snz,); 2345 OUT_AS1 (page, %2); 2346 OUT_AS1 (jmp, %2); 2347 } 2348 else 2349 { 2350 operands[3] = GEN_INT (INTVAL (operands[0]) - 1); 2351 OUT_AS2 (mov, w, %D3); 2352 OUT_AS2 (sub, w, %D1); 2353 OUT_AS2 (mov, w, %C3); 2354 OUT_AS2 (subc, w, %C1); 2355 OUT_AS2 (mov, w, %B3); 2356 OUT_AS2 (subc, w, %B1); 2357 OUT_AS2 (mov, w, %A3); 2358 OUT_AS2 (subc, w, %A1); 2359 OUT_AS1 (sc,); 2360 OUT_AS1 (page, %2); 2361 OUT_AS1 (jmp, %2); 2362 } 2363 } 2364 else 2365 { 2366 OUT_AS2 (mov, w, %D1); 2367 OUT_AS2 (sub, w, %D0); 2368 OUT_AS2 (mov, w, %C1); 2369 OUT_AS2 (subc, w, %C0); 2370 OUT_AS2 (mov, w, %B1); 2371 OUT_AS2 (subc, w, %B0); 2372 OUT_AS2 (mov, w, %A1); 2373 OUT_AS2 (subc, w, %A0); 2374 OUT_AS1 (snc,); 2375 OUT_AS1 (page, %2); 2376 OUT_AS1 (jmp, %2); 2377 } 2378 break; 2379 2380 case LTU: 2381 if (imm_sub) 2382 { 2383 if (INTVAL (operands[0]) == 0) 2384 { 2385 OUT_AS2 (mov, w, %A1); 2386 OUT_AS2 (or, w, %B1); 2387 OUT_AS2 (or, w, %C1); 2388 OUT_AS2 (or, w, %D1); 2389 OUT_AS1 (sz,); 2390 OUT_AS1 (page, %2); 2391 OUT_AS1 (jmp, %2); 2392 } 2393 else 2394 { 2395 operands[3] = GEN_INT (INTVAL (operands[0]) - 1); 2396 OUT_AS2 (mov, w, %D3); 2397 OUT_AS2 (sub, w, %D1); 2398 OUT_AS2 (mov, w, %C3); 2399 OUT_AS2 (subc, w, %C1); 2400 OUT_AS2 (mov, w, %B3); 2401 OUT_AS2 (subc, w, %B1); 2402 OUT_AS2 (mov, w, %A3); 2403 OUT_AS2 (subc, w, %A1); 2404 OUT_AS1 (snc,); 2405 OUT_AS1 (page, %2); 2406 OUT_AS1 (jmp, %2); 2407 } 2408 } 2409 else 2410 { 2411 OUT_AS2 (mov, w, %D1); 2412 OUT_AS2 (sub, w, %D0); 2413 OUT_AS2 (mov, w, %C1); 2414 OUT_AS2 (subc, w, %C0); 2415 OUT_AS2 (mov, w, %B1); 2416 OUT_AS2 (subc, w, %B0); 2417 OUT_AS2 (mov, w, %A1); 2418 OUT_AS2 (subc, w, %A0); 2419 OUT_AS1 (sc,); 2420 OUT_AS1 (page, %2); 2421 OUT_AS1 (jmp, %2); 2422 } 2423 break; 2424 2425 case LEU: 2426 if (imm_sub) 2427 { 2428 if ((unsigned HOST_WIDE_INT)(INTVAL (operands[1]) & 0xffffffff) 2429 == 0xffffffff) 2430 { 2431 /* <= 0xffffffff always suceeds. */ 2432 OUT_AS1 (page, %2); 2433 OUT_AS1 (jmp, %2); 2434 } 2435 else 2436 { 2437 operands[3] = GEN_INT (INTVAL (operands[1]) + 1); 2438 OUT_AS2 (mov, w, %D3); 2439 OUT_AS2 (sub, w, %D0); 2440 OUT_AS2 (mov, w, %C3); 2441 OUT_AS2 (subc, w, %C0); 2442 OUT_AS2 (mov, w, %B3); 2443 OUT_AS2 (subc, w, %B0); 2444 OUT_AS2 (mov, w, %A3); 2445 OUT_AS2 (subc, w, %A0); 2446 OUT_AS1 (sc,); 2447 OUT_AS1 (page, %2); 2448 OUT_AS1 (jmp, %2); 2449 } 2450 } 2451 else 2452 { 2453 OUT_AS2 (mov, w, %D0); 2454 OUT_AS2 (sub, w, %D1); 2455 OUT_AS2 (mov, w, %C0); 2456 OUT_AS2 (subc, w, %C1); 2457 OUT_AS2 (mov, w, %B0); 2458 OUT_AS2 (subc, w, %B1); 2459 OUT_AS2 (mov, w, %A0); 2460 OUT_AS2 (subc, w, %A1); 2461 OUT_AS1 (snc,); 2462 OUT_AS1 (page, %2); 2463 OUT_AS1 (jmp, %2); 2464 } 2465 break; 2466 2467 default: 2468 abort (); 2469 } 2470 break; 2471 2472 case DImode: 2473 if (GET_CODE (operands[1]) == CONST_INT) 2474 { 2475 const_low = INTVAL (operands[1]); 2476 const_high = (const_low >= 0) - 1; 2477 } 2478 else if (GET_CODE (operands[1]) == CONST_DOUBLE) 2479 { 2480 const_low = CONST_DOUBLE_LOW (operands[1]); 2481 const_high = CONST_DOUBLE_HIGH (operands[1]); 2482 } 2483 switch (code) 2484 { 2485 case EQ: 2486 { 2487 unsigned char s = 0, t = 1, u = 2, v = 3; 2488 unsigned char w = 4, x = 5, y = 6, z = 7; 2489 if (optimize_size) 2490 { 2491 if (GET_CODE (operands[0]) == MEM 2492 && true_regnum (XEXP (operands[0], 0)) == REG_DP) 2493 { 2494 OUT_AS1 (push, %Z1%<); 2495 OUT_AS1 (push, %Y1%<); 2496 OUT_AS1 (push, %X1%<); 2497 OUT_AS1 (push, %W1%<); 2498 OUT_AS1 (push, %V1%<); 2499 OUT_AS1 (push, %U1%<); 2500 OUT_AS1 (push, %T1%<); 2501 OUT_AS1 (push, %S1%>%>%>%>%>%>%>); 2502 OUT_AS1 (page, __cmpdi2_dp); 2503 OUT_AS1 (call, __cmpdi2_dp); 2504 OUT_AS2 (csne, w, #1); 2505 OUT_AS1 (page, %2); 2506 OUT_AS1 (jmp, %2); 2507 } 2508 else 2509 { 2510 OUT_AS1 (push, %Z1%<); 2511 OUT_AS1 (push, %Y1%<); 2512 OUT_AS1 (push, %X1%<); 2513 OUT_AS1 (push, %W1%<); 2514 OUT_AS1 (push, %V1%<); 2515 OUT_AS1 (push, %U1%<); 2516 OUT_AS1 (push, %T1%<); 2517 OUT_AS1 (push, %S1%<); 2518 OUT_AS1 (push, %Z0%<); 2519 OUT_AS1 (push, %Y0%<); 2520 OUT_AS1 (push, %X0%<); 2521 OUT_AS1 (push, %W0%<); 2522 OUT_AS1 (push, %V0%<); 2523 OUT_AS1 (push, %U0%<); 2524 OUT_AS1 (push, %T0%<); 2525 OUT_AS1 (push, %S0%>%>%>%>%>%>%>%>%>%>%>%>%>%>%>); 2526 OUT_AS1 (page, __cmpdi2); 2527 OUT_AS1 (call, __cmpdi2); 2528 OUT_AS2 (csne, w, #1); 2529 OUT_AS1 (page, %2); 2530 OUT_AS1 (jmp, %2); 2531 } 2532 } 2533 else 2534 { 2535 if (imm_cmp) 2536 { 2537 s = (const_high >> 24) & 0xff; 2538 t = (const_high >> 16) & 0xff; 2539 u = (const_high >> 8) & 0xff; 2540 v = const_high & 0xff; 2541 w = (const_low >> 24) & 0xff; 2542 x = (const_low >> 16) & 0xff; 2543 y = (const_low >> 8) & 0xff; 2544 z = const_low & 0xff; 2545 } 2546 2547 OUT_AS2 (mov, w, %S1); 2548 if (imm_cmp && (s == t)) 2549 { 2550 OUT_AS2 (csne, w, %S0); 2551 OUT_AS2 (cse, w, %T0); 2552 } 2553 else 2554 { 2555 OUT_AS2 (cse, w, %S0); 2556 OUT_AS1 (page, 2f); 2557 OUT_AS1 (jmp, 2f); 2558 OUT_AS2 (mov, w, %T1); 2559 OUT_AS2 (cse, w, %T0); 2560 } 2561 OUT_AS1 (page, 2f); 2562 OUT_AS1 (jmp, 2f); 2563 2564 OUT_AS2 (mov, w, %U1); 2565 if (imm_cmp && (u == v)) 2566 { 2567 OUT_AS2 (csne, w, %U0); 2568 OUT_AS2 (cse, w, %V0); 2569 } 2570 else 2571 { 2572 OUT_AS2 (cse, w, %U0); 2573 OUT_AS1 (page, 2f); 2574 OUT_AS1 (jmp, 2f); 2575 OUT_AS2 (mov, w, %V1); 2576 OUT_AS2 (cse, w, %V0); 2577 } 2578 OUT_AS1 (page, 2f); 2579 OUT_AS1 (jmp, 2f); 2580 2581 OUT_AS2 (mov, w, %W1); 2582 if (imm_cmp && (w == x)) 2583 { 2584 OUT_AS2 (csne, w, %W0); 2585 OUT_AS2 (cse, w, %X0); 2586 } 2587 else 2588 { 2589 OUT_AS2 (cse, w, %W0); 2590 OUT_AS1 (page, 2f); 2591 OUT_AS1 (jmp, 2f); 2592 OUT_AS2 (mov, w, %X1); 2593 OUT_AS2 (cse, w, %X0); 2594 } 2595 OUT_AS1 (page, 2f); 2596 OUT_AS1 (jmp, 2f); 2597 2598 if (! imm_cmp || (x != y)) 2599 OUT_AS2 (mov, w, %Y1); 2600 OUT_AS2 (cse, w, %Y0); 2601 OUT_AS1 (page, 2f); 2602 OUT_AS1 (jmp, 2f); 2603 if (! imm_cmp || (z != y)) 2604 OUT_AS2 (mov, w, %Z1); 2605 OUT_AS2 (csne, w, %Z0); 2606 OUT_AS1 (page, %2); 2607 OUT_AS1 (jmp, %2); 2608 OUT_AS1 (2:,); 2609 } 2610 } 2611 break; 2612 2613 case NE: 2614 { 2615 unsigned char s = 0, t = 1, u = 2, v = 3; 2616 unsigned char w = 4, x = 5, y = 6, z = 7; 2617 2618 if (optimize_size) 2619 { 2620 if (GET_CODE (operands[0]) == MEM 2621 && true_regnum (XEXP (operands[0], 0)) == REG_DP) 2622 { 2623 OUT_AS1 (push, %Z1%<); 2624 OUT_AS1 (push, %Y1%<); 2625 OUT_AS1 (push, %X1%<); 2626 OUT_AS1 (push, %W1%<); 2627 OUT_AS1 (push, %V1%<); 2628 OUT_AS1 (push, %U1%<); 2629 OUT_AS1 (push, %T1%<); 2630 OUT_AS1 (push, %S1%>%>%>%>%>%>%>); 2631 OUT_AS1 (page, __cmpdi2_dp); 2632 OUT_AS1 (call, __cmpdi2_dp); 2633 OUT_AS2 (cse, w, #1); 2634 OUT_AS1 (page, %2); 2635 OUT_AS1 (jmp, %2); 2636 } 2637 else 2638 { 2639 OUT_AS1 (push, %Z1%<); 2640 OUT_AS1 (push, %Y1%<); 2641 OUT_AS1 (push, %X1%<); 2642 OUT_AS1 (push, %W1%<); 2643 OUT_AS1 (push, %V1%<); 2644 OUT_AS1 (push, %U1%<); 2645 OUT_AS1 (push, %T1%<); 2646 OUT_AS1 (push, %S1%<); 2647 OUT_AS1 (push, %Z0%<); 2648 OUT_AS1 (push, %Y0%<); 2649 OUT_AS1 (push, %X0%<); 2650 OUT_AS1 (push, %W0%<); 2651 OUT_AS1 (push, %V0%<); 2652 OUT_AS1 (push, %U0%<); 2653 OUT_AS1 (push, %T0%<); 2654 OUT_AS1 (push, %S0%>%>%>%>%>%>%>%>%>%>%>%>%>%>%>); 2655 OUT_AS1 (page, __cmpdi2); 2656 OUT_AS1 (call, __cmpdi2); 2657 OUT_AS2 (cse, w, #1); 2658 OUT_AS1 (page, %2); 2659 OUT_AS1 (jmp, %2); 2660 } 2661 } 2662 else 2663 { 2664 if (imm_cmp) 2665 { 2666 s = (const_high >> 24) & 0xff; 2667 t = (const_high >> 16) & 0xff; 2668 u = (const_high >> 8) & 0xff; 2669 v = const_high & 0xff; 2670 w = (const_low >> 24) & 0xff; 2671 x = (const_low >> 16) & 0xff; 2672 y = (const_low >> 8) & 0xff; 2673 z = const_low & 0xff; 2674 } 2675 2676 OUT_AS2 (mov, w, %S1); 2677 if (imm_cmp && (s == t)) 2678 { 2679 OUT_AS2 (csne, w, %S0); 2680 OUT_AS2 (cse, w, %T0); 2681 } 2682 else 2683 { 2684 OUT_AS2 (cse, w, %S0); 2685 OUT_AS1 (page, %2); 2686 OUT_AS1 (jmp, %2); 2687 OUT_AS2 (mov, w, %T1); 2688 OUT_AS2 (cse, w, %T0); 2689 } 2690 OUT_AS1 (page, %2); 2691 OUT_AS1 (jmp, %2); 2692 2693 OUT_AS2 (mov, w, %U1); 2694 if (imm_cmp && (u == v)) 2695 { 2696 OUT_AS2 (csne, w, %U0); 2697 OUT_AS2 (cse, w, %V0); 2698 } 2699 else 2700 { 2701 OUT_AS2 (cse, w, %U0); 2702 OUT_AS1 (page, %2); 2703 OUT_AS1 (jmp, %2); 2704 OUT_AS2 (mov, w, %V1); 2705 OUT_AS2 (cse, w, %V0); 2706 } 2707 OUT_AS1 (page, %2); 2708 OUT_AS1 (jmp, %2); 2709 2710 OUT_AS2 (mov, w, %W1); 2711 if (imm_cmp && (w == x)) 2712 { 2713 OUT_AS2 (csne, w, %W0); 2714 OUT_AS2 (cse, w, %X0); 2715 } 2716 else 2717 { 2718 OUT_AS2 (cse, w, %W0); 2719 OUT_AS1 (page, %2); 2720 OUT_AS1 (jmp, %2); 2721 OUT_AS2 (mov, w, %X1); 2722 OUT_AS2 (cse, w, %X0); 2723 } 2724 OUT_AS1 (page, %2); 2725 OUT_AS1 (jmp, %2); 2726 2727 if (! imm_cmp || (y != x)) 2728 OUT_AS2 (mov, w, %Y1); 2729 if (imm_cmp && (z == y)) 2730 { 2731 OUT_AS2 (csne, w, %Y0); 2732 OUT_AS2 (cse, w, %Z0); 2733 } 2734 else 2735 { 2736 OUT_AS2 (cse, w, %Y0); 2737 OUT_AS1 (page, %2); 2738 OUT_AS1 (jmp, %2); 2739 OUT_AS2 (mov, w, %Z1); 2740 OUT_AS2 (cse, w, %Z0); 2741 } 2742 OUT_AS1 (page, %2); 2743 OUT_AS1 (jmp, %2); 2744 } 2745 } 2746 break; 2747 2748 case GTU: 2749 if (imm_sub) 2750 { 2751 /* > 0xffffffffffffffff never suceeds! */ 2752 if (((const_high & 0xffffffff) != 0xffffffff) 2753 || ((const_low & 0xffffffff) != 0xffffffff)) 2754 { 2755 operands[3] = GEN_INT (const_low + 1); 2756 operands[4] = GEN_INT (const_high 2757 + (INTVAL (operands[3]) ? 0 : 1)); 2758 OUT_AS2 (mov, w, %D3); 2759 OUT_AS2 (sub, w, %Z0); 2760 OUT_AS2 (mov, w, %C3); 2761 OUT_AS2 (subc, w, %Y0); 2762 OUT_AS2 (mov, w, %B3); 2763 OUT_AS2 (subc, w, %X0); 2764 OUT_AS2 (mov, w, %A3); 2765 OUT_AS2 (subc, w, %W0); 2766 OUT_AS2 (mov, w, %D4); 2767 OUT_AS2 (subc, w, %V0); 2768 OUT_AS2 (mov, w, %C4); 2769 OUT_AS2 (subc, w, %U0); 2770 OUT_AS2 (mov, w, %B4); 2771 OUT_AS2 (subc, w, %T0); 2772 OUT_AS2 (mov, w, %A4); 2773 OUT_AS2 (subc, w, %S0); 2774 OUT_AS1 (snc,); 2775 OUT_AS1 (page, %2); 2776 OUT_AS1 (jmp, %2); 2777 } 2778 } 2779 else 2780 { 2781 OUT_AS2 (mov, w, %Z0); 2782 OUT_AS2 (sub, w, %Z1); 2783 OUT_AS2 (mov, w, %Y0); 2784 OUT_AS2 (subc, w, %Y1); 2785 OUT_AS2 (mov, w, %X0); 2786 OUT_AS2 (subc, w, %X1); 2787 OUT_AS2 (mov, w, %W0); 2788 OUT_AS2 (subc, w, %W1); 2789 OUT_AS2 (mov, w, %V0); 2790 OUT_AS2 (subc, w, %V1); 2791 OUT_AS2 (mov, w, %U0); 2792 OUT_AS2 (subc, w, %U1); 2793 OUT_AS2 (mov, w, %T0); 2794 OUT_AS2 (subc, w, %T1); 2795 OUT_AS2 (mov, w, %S0); 2796 OUT_AS2 (subc, w, %S1); 2797 OUT_AS1 (sc,); 2798 OUT_AS1 (page, %2); 2799 OUT_AS1 (jmp, %2); 2800 } 2801 break; 2802 2803 case GEU: 2804 if (imm_sub) 2805 { 2806 HOST_WIDE_INT const_low0; 2807 HOST_WIDE_INT const_high0; 2808 2809 if (GET_CODE (operands[0]) == CONST_INT) 2810 { 2811 const_low0 = INTVAL (operands[0]); 2812 const_high0 = (const_low >= 0) - 1; 2813 } 2814 else if (GET_CODE (operands[0]) == CONST_DOUBLE) 2815 { 2816 const_low0 = CONST_DOUBLE_LOW (operands[0]); 2817 const_high0 = CONST_DOUBLE_HIGH (operands[0]); 2818 } 2819 2820 if (const_high0 == 0 && const_low0 == 0) 2821 { 2822 OUT_AS2 (mov, w, %S1); 2823 OUT_AS2 (or, w, %T1); 2824 OUT_AS2 (or, w, %U1); 2825 OUT_AS2 (or, w, %V1); 2826 OUT_AS2 (or, w, %W1); 2827 OUT_AS2 (or, w, %X1); 2828 OUT_AS2 (or, w, %Y1); 2829 OUT_AS2 (or, w, %Z1); 2830 OUT_AS1 (snz,); 2831 OUT_AS1 (page, %2); 2832 OUT_AS1 (jmp, %2); 2833 } 2834 else 2835 { 2836 operands[3] = GEN_INT (const_low0 - 1); 2837 operands[4] = GEN_INT (const_high0 - (const_low0 ? 1 : 0)); 2838 OUT_AS2 (mov, w, %D3); 2839 OUT_AS2 (sub, w, %Z1); 2840 OUT_AS2 (mov, w, %C3); 2841 OUT_AS2 (subc, w, %Y1); 2842 OUT_AS2 (mov, w, %B3); 2843 OUT_AS2 (subc, w, %X1); 2844 OUT_AS2 (mov, w, %A3); 2845 OUT_AS2 (subc, w, %W1); 2846 OUT_AS2 (mov, w, %D4); 2847 OUT_AS2 (subc, w, %V1); 2848 OUT_AS2 (mov, w, %C4); 2849 OUT_AS2 (subc, w, %U1); 2850 OUT_AS2 (mov, w, %B4); 2851 OUT_AS2 (subc, w, %T1); 2852 OUT_AS2 (mov, w, %A4); 2853 OUT_AS2 (subc, w, %S1); 2854 OUT_AS1 (sc,); 2855 OUT_AS1 (page, %2); 2856 OUT_AS1 (jmp, %2); 2857 } 2858 } 2859 else 2860 { 2861 OUT_AS2 (mov, w, %Z1); 2862 OUT_AS2 (sub, w, %Z0); 2863 OUT_AS2 (mov, w, %Y1); 2864 OUT_AS2 (subc, w, %Y0); 2865 OUT_AS2 (mov, w, %X1); 2866 OUT_AS2 (subc, w, %X0); 2867 OUT_AS2 (mov, w, %W1); 2868 OUT_AS2 (subc, w, %W0); 2869 OUT_AS2 (mov, w, %V1); 2870 OUT_AS2 (subc, w, %V0); 2871 OUT_AS2 (mov, w, %U1); 2872 OUT_AS2 (subc, w, %U0); 2873 OUT_AS2 (mov, w, %T1); 2874 OUT_AS2 (subc, w, %T0); 2875 OUT_AS2 (mov, w, %S1); 2876 OUT_AS2 (subc, w, %S0); 2877 OUT_AS1 (snc,); 2878 OUT_AS1 (page, %2); 2879 OUT_AS1 (jmp, %2); 2880 } 2881 break; 2882 2883 case LTU: 2884 if (imm_sub) 2885 { 2886 HOST_WIDE_INT const_low0; 2887 HOST_WIDE_INT const_high0; 2888 2889 if (GET_CODE (operands[0]) == CONST_INT) 2890 { 2891 const_low0 = INTVAL (operands[0]); 2892 const_high0 = (const_low >= 0) - 1; 2893 } 2894 else if (GET_CODE (operands[0]) == CONST_DOUBLE) 2895 { 2896 const_low0 = CONST_DOUBLE_LOW (operands[0]); 2897 const_high0 = CONST_DOUBLE_HIGH (operands[0]); 2898 } 2899 2900 if (const_high0 == 0 && const_low0 == 0) 2901 { 2902 OUT_AS2 (mov, w, %S1); 2903 OUT_AS2 (or, w, %T1); 2904 OUT_AS2 (or, w, %U1); 2905 OUT_AS2 (or, w, %V1); 2906 OUT_AS2 (or, w, %W1); 2907 OUT_AS2 (or, w, %X1); 2908 OUT_AS2 (or, w, %Y1); 2909 OUT_AS2 (or, w, %Z1); 2910 OUT_AS1 (sz,); 2911 OUT_AS1 (page, %2); 2912 OUT_AS1 (jmp, %2); 2913 } 2914 else 2915 { 2916 operands[3] = GEN_INT (const_low0 - 1); 2917 operands[4] = GEN_INT (const_high0 - (const_low0 ? 1 : 0)); 2918 OUT_AS2 (mov, w, %D3); 2919 OUT_AS2 (sub, w, %Z1); 2920 OUT_AS2 (mov, w, %C3); 2921 OUT_AS2 (subc, w, %Y1); 2922 OUT_AS2 (mov, w, %B3); 2923 OUT_AS2 (subc, w, %X1); 2924 OUT_AS2 (mov, w, %A3); 2925 OUT_AS2 (subc, w, %W1); 2926 OUT_AS2 (mov, w, %D4); 2927 OUT_AS2 (subc, w, %V1); 2928 OUT_AS2 (mov, w, %C4); 2929 OUT_AS2 (subc, w, %U1); 2930 OUT_AS2 (mov, w, %B4); 2931 OUT_AS2 (subc, w, %T1); 2932 OUT_AS2 (mov, w, %A4); 2933 OUT_AS2 (subc, w, %S1); 2934 OUT_AS1 (snc,); 2935 OUT_AS1 (page, %2); 2936 OUT_AS1 (jmp, %2); 2937 } 2938 } 2939 else 2940 { 2941 OUT_AS2 (mov, w, %Z1); 2942 OUT_AS2 (sub, w, %Z0); 2943 OUT_AS2 (mov, w, %Y1); 2944 OUT_AS2 (subc, w, %Y0); 2945 OUT_AS2 (mov, w, %X1); 2946 OUT_AS2 (subc, w, %X0); 2947 OUT_AS2 (mov, w, %W1); 2948 OUT_AS2 (subc, w, %W0); 2949 OUT_AS2 (mov, w, %V1); 2950 OUT_AS2 (subc, w, %V0); 2951 OUT_AS2 (mov, w, %U1); 2952 OUT_AS2 (subc, w, %U0); 2953 OUT_AS2 (mov, w, %T1); 2954 OUT_AS2 (subc, w, %T0); 2955 OUT_AS2 (mov, w, %S1); 2956 OUT_AS2 (subc, w, %S0); 2957 OUT_AS1 (sc,); 2958 OUT_AS1 (page, %2); 2959 OUT_AS1 (jmp, %2); 2960 } 2961 break; 2962 2963 case LEU: 2964 if (imm_sub) 2965 { 2966 if (((const_high & 0xffffffff) == 0xffffffff) 2967 && ((const_low & 0xffffffff) == 0xffffffff)) 2968 { 2969 /* <= 0xffffffffffffffff always suceeds. */ 2970 OUT_AS1 (page, %2); 2971 OUT_AS1 (jmp, %2); 2972 } 2973 else 2974 { 2975 operands[3] = GEN_INT (const_low + 1); 2976 operands[4] = GEN_INT (const_high 2977 + (INTVAL (operands[3]) ? 0 : 1)); 2978 OUT_AS2 (mov, w, %D3); 2979 OUT_AS2 (sub, w, %Z0); 2980 OUT_AS2 (mov, w, %C3); 2981 OUT_AS2 (subc, w, %Y0); 2982 OUT_AS2 (mov, w, %B3); 2983 OUT_AS2 (subc, w, %X0); 2984 OUT_AS2 (mov, w, %A3); 2985 OUT_AS2 (subc, w, %W0); 2986 OUT_AS2 (mov, w, %D4); 2987 OUT_AS2 (subc, w, %V0); 2988 OUT_AS2 (mov, w, %C4); 2989 OUT_AS2 (subc, w, %U0); 2990 OUT_AS2 (mov, w, %B4); 2991 OUT_AS2 (subc, w, %T0); 2992 OUT_AS2 (mov, w, %A4); 2993 OUT_AS2 (subc, w, %S0); 2994 OUT_AS1 (sc,); 2995 OUT_AS1 (page, %2); 2996 OUT_AS1 (jmp, %2); 2997 } 2998 } 2999 else 3000 { 3001 OUT_AS2 (mov, w, %Z0); 3002 OUT_AS2 (sub, w, %Z1); 3003 OUT_AS2 (mov, w, %Y0); 3004 OUT_AS2 (subc, w, %Y1); 3005 OUT_AS2 (mov, w, %X0); 3006 OUT_AS2 (subc, w, %X1); 3007 OUT_AS2 (mov, w, %W0); 3008 OUT_AS2 (subc, w, %W1); 3009 OUT_AS2 (mov, w, %V0); 3010 OUT_AS2 (subc, w, %V1); 3011 OUT_AS2 (mov, w, %U0); 3012 OUT_AS2 (subc, w, %U1); 3013 OUT_AS2 (mov, w, %T0); 3014 OUT_AS2 (subc, w, %T1); 3015 OUT_AS2 (mov, w, %S0); 3016 OUT_AS2 (subc, w, %S1); 3017 OUT_AS1 (snc,); 3018 OUT_AS1 (page, %2); 3019 OUT_AS1 (jmp, %2); 3020 } 3021 break; 3022 3023 default: 3024 abort (); 3025 } 3026 break; 3027 3028 default: 3029 abort (); 3030 } 3031#undef operands 3032 return ""; 3033} 3034 3035/* Output rtx VALUE as .byte to file FILE. */ 3036 3037void 3038asm_output_char(file, value) 3039 FILE *file; 3040 rtx value; 3041{ 3042 fprintf (file, "\t.byte "); 3043 output_addr_const (file, value); 3044 fprintf (file, "\n"); 3045} 3046 3047 3048/* Output VALUE as .byte to file FILE. */ 3049 3050void 3051asm_output_byte (file,value) 3052 FILE *file; 3053 int value; 3054{ 3055 fprintf (file, "\t.byte 0x%x\n",value & 0xff); 3056} 3057 3058 3059/* Output rtx VALUE as .word to file FILE. */ 3060 3061void 3062asm_output_short (file, value) 3063 FILE *file; 3064 rtx value; 3065{ 3066 fprintf (file, "\t.word "); 3067 output_addr_const (file, (value)); 3068 fprintf (file, "\n"); 3069} 3070 3071 3072/* Output real N to file FILE. */ 3073 3074void 3075asm_output_float (file, n) 3076 FILE *file; 3077 REAL_VALUE_TYPE n; 3078{ 3079 long val; 3080 char dstr[100]; 3081 3082 REAL_VALUE_TO_TARGET_SINGLE (n, val); 3083 real_to_decimal (dstr, &n, sizeof (dstr), 0, 1); 3084 3085 fprintf (file, "\t.long 0x%08lx\t/* %s */\n", val, dstr); 3086} 3087 3088/* Sets section name for declaration DECL. */ 3089 3090void 3091unique_section (decl, reloc) 3092 tree decl; 3093 int reloc ATTRIBUTE_UNUSED; 3094{ 3095 int len; 3096 const char *name; 3097 char *string; 3098 const char *prefix; 3099 name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); 3100 /* Strip off any encoding in name. */ 3101 name = (* targetm.strip_name_encoding) (name); 3102 3103 if (TREE_CODE (decl) == FUNCTION_DECL) 3104 { 3105 if (flag_function_sections) 3106 prefix = ".text."; 3107 else 3108 prefix = ".text"; 3109 } 3110 else 3111 abort (); 3112 3113 if (flag_function_sections) 3114 { 3115 len = strlen (name) + strlen (prefix); 3116 string = alloca (len + 1); 3117 sprintf (string, "%s%s", prefix, name); 3118 DECL_SECTION_NAME (decl) = build_string (len, string); 3119 } 3120} 3121 3122 3123/* Output section name to file FILE. */ 3124 3125void 3126asm_output_section_name(file, decl, name, reloc) 3127 FILE *file; 3128 tree decl ATTRIBUTE_UNUSED; 3129 const char *name; 3130 int reloc ATTRIBUTE_UNUSED; 3131{ 3132 fprintf (file, ".section %s\n", name); 3133} 3134 3135/* Return value is nonzero if pseudos that have been 3136 assigned to registers of class CLASS would likely be spilled 3137 because registers of CLASS are needed for spill registers. */ 3138 3139enum reg_class 3140class_likely_spilled_p(c) 3141 int c; 3142{ 3143 return (c == IP_REGS 3144 || c == IPL_REGS 3145 || c == IPH_REGS 3146 || c == DP_SP_REGS 3147 || c == SP_REGS 3148 || c == DP_REGS 3149 || c == DPL_REGS 3150 || c == DPH_REGS 3151 || c == PTR_REGS); 3152} 3153 3154/* Valid attributes: 3155 progmem - put data to program memory; 3156 naked - don't generate function prologue/epilogue and `ret' command. 3157 3158 Only `progmem' attribute valid for type. */ 3159 3160const struct attribute_spec ip2k_attribute_table[] = 3161{ 3162 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */ 3163 { "progmem", 0, 0, false, false, false, ip2k_handle_progmem_attribute }, 3164 { "naked", 0, 0, true, false, false, ip2k_handle_fndecl_attribute }, 3165 { NULL, 0, 0, false, false, false, NULL } 3166}; 3167 3168/* Handle a "progmem" attribute; arguments as in 3169 struct attribute_spec.handler. */ 3170static tree 3171ip2k_handle_progmem_attribute (node, name, args, flags, no_add_attrs) 3172 tree *node; 3173 tree name; 3174 tree args ATTRIBUTE_UNUSED; 3175 int flags ATTRIBUTE_UNUSED; 3176 bool *no_add_attrs; 3177{ 3178 if (DECL_P (*node)) 3179 { 3180 if (TREE_CODE (*node) == TYPE_DECL) 3181 { 3182 /* This is really a decl attribute, not a type attribute, 3183 but try to handle it for GCC 3.0 backwards compatibility. */ 3184 3185 tree type = TREE_TYPE (*node); 3186 tree attr = tree_cons (name, args, TYPE_ATTRIBUTES (type)); 3187 tree newtype = build_type_attribute_variant (type, attr); 3188 3189 TYPE_MAIN_VARIANT (newtype) = TYPE_MAIN_VARIANT (type); 3190 TREE_TYPE (*node) = newtype; 3191 *no_add_attrs = true; 3192 } 3193 else if (TREE_STATIC (*node) || DECL_EXTERNAL (*node)) 3194 { 3195 if (DECL_INITIAL (*node) == NULL_TREE && !DECL_EXTERNAL (*node)) 3196 { 3197 warning ("only initialized variables can be placed into " 3198 "program memory area"); 3199 *no_add_attrs = true; 3200 } 3201 } 3202 else 3203 { 3204 warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); 3205 *no_add_attrs = true; 3206 } 3207 } 3208 3209 return NULL_TREE; 3210} 3211 3212/* Handle an attribute requiring a FUNCTION_DECL; arguments as in 3213 struct attribute_spec.handler. */ 3214static tree 3215ip2k_handle_fndecl_attribute (node, name, args, flags, no_add_attrs) 3216 tree *node; 3217 tree name; 3218 tree args ATTRIBUTE_UNUSED; 3219 int flags ATTRIBUTE_UNUSED; 3220 bool *no_add_attrs; 3221{ 3222 if (TREE_CODE (*node) != FUNCTION_DECL) 3223 { 3224 warning ("`%s' attribute only applies to functions", 3225 IDENTIFIER_POINTER (name)); 3226 *no_add_attrs = true; 3227 } 3228 3229 return NULL_TREE; 3230} 3231 3232/* Encode section information about tree DECL. */ 3233 3234void 3235encode_section_info (decl, first) 3236 tree decl; 3237 int first ATTRIBUTE_UNUSED; 3238{ 3239 if (! DECL_P (decl)) 3240 return; 3241 3242 if (TREE_CODE (decl) == FUNCTION_DECL) 3243 SYMBOL_REF_FLAG (XEXP (DECL_RTL (decl), 0)) = 1; 3244} 3245 3246/* Outputs to the stdio stream FILE some 3247 appropriate text to go at the start of an assembler file. */ 3248 3249void 3250asm_file_start (file) 3251 FILE *file; 3252{ 3253 output_file_directive (file, main_input_filename); 3254 3255 commands_in_prologues = 0; 3256 commands_in_epilogues = 0; 3257} 3258 3259/* Outputs to the stdio stream FILE some 3260 appropriate text to go at the end of an assembler file. */ 3261 3262void 3263asm_file_end (file) 3264 FILE *file; 3265{ 3266 fprintf 3267 (file, 3268 "/* File %s: prologues %3d, epilogues %3d */\n", 3269 main_input_filename, commands_in_prologues, commands_in_epilogues); 3270} 3271 3272/* Cost functions. */ 3273 3274/* Calculate the cost of X code of the expression in which it is contained, 3275 found in OUTER_CODE. */ 3276 3277int 3278default_rtx_costs (x, code, outer_code) 3279 rtx x; 3280 enum rtx_code code; 3281 enum rtx_code outer_code; 3282{ 3283 enum machine_mode mode = GET_MODE (x); 3284 int extra_cost = 0; 3285 int total; 3286 3287 switch (code) 3288 { 3289 case MEM: 3290 return ip2k_address_cost (XEXP (x, 0)); 3291 3292 case ROTATE: 3293 case ROTATERT: 3294 case ASHIFT: 3295 case LSHIFTRT: 3296 case ASHIFTRT: 3297 if (GET_CODE (XEXP (x, 1)) == CONST_INT) 3298 { 3299 int val = INTVAL (XEXP (x, 1)); 3300 int cost; 3301 3302 /* Shift by const instructions are proportional to 3303 the shift count modulus 8. Note that we increase the mode 3304 size multiplier by 1 to account for clearing the carry flag. */ 3305 cost = COSTS_N_INSNS (abs (val) % 8); 3306 cost += rtx_cost (XEXP (x, 0), code); 3307 cost *= (GET_MODE_SIZE (mode) + 1); 3308 3309 /* Sign-preserving shifts require 2 extra instructions. */ 3310 if (code == ASHIFT) 3311 cost += COSTS_N_INSNS (2); 3312 return cost; 3313 } 3314 total = rtx_cost (XEXP (x, 0), code); 3315 total += COSTS_N_INSNS (GET_MODE_SIZE (mode) * 8); 3316 return total; 3317 3318 case MINUS: 3319 case PLUS: 3320 case AND: 3321 case XOR: 3322 case IOR: 3323 total = rtx_cost (XEXP (x, 0), code) 3324 + rtx_cost (XEXP (x, 1), code); 3325 total += COSTS_N_INSNS (GET_MODE_SIZE (mode) * 3); 3326 return total; 3327 3328 case MOD: 3329 case DIV: 3330 if (mode == QImode) 3331 return COSTS_N_INSNS (20); 3332 if (mode == HImode) 3333 return COSTS_N_INSNS (60); 3334 else if (mode == SImode) 3335 return COSTS_N_INSNS (180); 3336 else 3337 return COSTS_N_INSNS (540); 3338 3339 case MULT: 3340 /* These costs are OK, but should really handle subtle cases 3341 where we're using sign or zero extended args as these are 3342 *much* cheaper than those given below! */ 3343 if (mode == QImode) 3344 return COSTS_N_INSNS (4); 3345 if (mode == HImode) 3346 return COSTS_N_INSNS (12); 3347 if (mode == SImode) 3348 return COSTS_N_INSNS (36); 3349 else 3350 return COSTS_N_INSNS (108); 3351 3352 case NEG: 3353 case SIGN_EXTEND: 3354 extra_cost = COSTS_N_INSNS (GET_MODE_SIZE (mode)); 3355 3356 /* Fall through. */ 3357 case NOT: 3358 case COMPARE: 3359 case ABS: 3360 total = rtx_cost (XEXP (x, 0), code); 3361 return total + extra_cost + COSTS_N_INSNS (GET_MODE_SIZE (mode) * 2); 3362 3363 case TRUNCATE: 3364 case ZERO_EXTEND: 3365 if (outer_code == SET) 3366 return rtx_cost (XEXP (x, 0), code) 3367 + COSTS_N_INSNS (GET_MODE_SIZE (mode) * 3 / 2); 3368 else 3369 return -(COSTS_N_INSNS (GET_MODE_SIZE (mode)) / 2); 3370 3371 case IF_THEN_ELSE: 3372 return rtx_cost (XEXP (x, 0), code) 3373 + COSTS_N_INSNS (2); 3374 3375 case EQ: 3376 case NE: 3377 case LTU: 3378 case GTU: 3379 case LEU: 3380 case GEU: 3381 case LT: 3382 case GT: 3383 case LE: 3384 case GE: 3385 return rtx_cost (XEXP (x, 0), code) 3386 + rtx_cost (XEXP (x, 1), code); 3387 3388 default: 3389 return COSTS_N_INSNS (4); 3390 } 3391} 3392 3393/* Calculate the cost of a memory address. */ 3394 3395int 3396ip2k_address_cost (x) 3397 rtx x; 3398{ 3399 switch (legitimate_address_p (VOIDmode, x, 0)) 3400 { 3401 case 'S': /* Very low cost - (IP), (SP+N) or (DP+N) */ 3402 return 8; 3403 3404 case 'R': /* Indirected through IP. */ 3405 return 8; 3406 3407 case 'L': /* Label references. */ 3408 return 0; 3409 3410 case 'C': /* Constants and symbol references. */ 3411 return 4; 3412 3413 default: 3414 return 1000; /* Must reload. */ 3415 } 3416} 3417 3418/* As part of the machine-dependent reorg we look for opcode sequences where 3419 we do some operation and then move the results back to one of the original 3420 source operands. With working on the source operand directly is probably 3421 much cheaper and the move from this to the original source operand will be 3422 no more expensive than the original move. */ 3423 3424#ifdef IP2K_MD_REORG_PASS 3425static void 3426mdr_resequence_xy_yx (first_insn) 3427 rtx first_insn; 3428{ 3429 rtx insn; 3430 3431 for (insn = first_insn; insn; insn = next_nonnote_insn (insn)) 3432 { 3433 rtx set; 3434 3435 if (GET_CODE (insn) != INSN) 3436 continue; 3437 3438 set = (GET_CODE (PATTERN (insn)) == SET) ? PATTERN (insn) : NULL_RTX; 3439 if (set == NULL_RTX) 3440 continue; 3441 3442 /* Look for operations that tend to be very cheap to run when the source 3443 * and dest args are the same because the IP2022 has opcodes that can 3444 operate on the source directly. If we have to spill through the W 3445 register then we've possibly not got a good case for doing this. */ 3446 if ((GET_CODE (XEXP (set, 0)) == REG 3447 || GET_CODE (XEXP (set, 0)) == MEM) 3448 && (GET_CODE (XEXP (set, 1)) == ASHIFT 3449 || GET_CODE (XEXP (set, 1)) == ASHIFTRT 3450 || GET_CODE (XEXP (set, 1)) == LSHIFTRT 3451 || GET_CODE (XEXP (set, 1)) == XOR 3452 || GET_CODE (XEXP (set, 1)) == IOR 3453 || GET_CODE (XEXP (set, 1)) == AND 3454 || GET_CODE (XEXP (set, 1)) == PLUS 3455 || GET_CODE (XEXP (set, 1)) == MINUS 3456 || GET_CODE (XEXP (set, 1)) == MULT)) 3457 { 3458 rtx set2; 3459 rtx next_insn; 3460 3461 next_insn = next_nonnote_insn (insn); 3462 if (! next_insn) 3463 continue; 3464 3465 if (GET_CODE (next_insn) != INSN) 3466 continue; 3467 3468 set2 = ((GET_CODE (PATTERN (next_insn)) == SET) 3469 ? PATTERN (next_insn) : NULL_RTX); 3470 if (set2 == NULL_RTX) 3471 continue; 3472 3473 if ((GET_CODE (XEXP (XEXP (set, 1), 0)) == REG 3474 || GET_CODE (XEXP (XEXP (set, 1), 0)) == MEM) 3475 && rtx_equal_p (XEXP (set2, 0), XEXP (XEXP (set, 1), 0)) 3476 && rtx_equal_p (XEXP (set2, 1), XEXP (set, 0))) 3477 { 3478 rtx next2_insn; 3479 rtx b_insn; 3480 3481 b_insn = gen_rtx_SET (VOIDmode, 3482 XEXP (XEXP (set, 1), 0), 3483 gen_rtx_fmt_ee (GET_CODE (XEXP (set, 1)), 3484 GET_MODE (XEXP (set, 0)), 3485 XEXP (XEXP (set, 1), 0), 3486 XEXP (XEXP (set, 1), 1))); 3487 3488 emit_insn_before (b_insn, insn); 3489 b_insn = gen_rtx_SET (GET_MODE (XEXP (set, 0)), XEXP (set, 0), 3490 XEXP (XEXP (set, 1), 0)); 3491 next2_insn = emit_insn_before (b_insn, insn); 3492 delete_insn (insn); 3493 delete_insn (next_insn); 3494 insn = next2_insn; 3495 continue; 3496 } 3497 3498 /* Having tried with one operand of the expression, now, if 3499 appropriate, try to do the same thing with the second operand. 3500 Of course there are fewer operations that can match here 3501 because they must be commutative. */ 3502 if (GET_RTX_CLASS (GET_CODE (XEXP (set, 1))) == 'c' 3503 && (GET_CODE (XEXP (XEXP (set, 1), 1)) == REG 3504 || GET_CODE (XEXP (XEXP (set, 1), 1)) == MEM) 3505 && rtx_equal_p (XEXP (set2, 0), XEXP (XEXP (set, 1), 1)) 3506 && rtx_equal_p (XEXP (set2, 1), XEXP (set, 0))) 3507 { 3508 rtx rtx_ee; 3509 rtx next2_insn; 3510 int swap_args; 3511 3512 /* Try to ensure that we put things in a canonical form. */ 3513 swap_args = (GET_CODE (XEXP (XEXP (set, 1), 0)) == REG 3514 || GET_CODE (XEXP (XEXP (set, 1), 0)) == MEM); 3515 rtx_ee = gen_rtx_fmt_ee (GET_CODE (XEXP (set, 1)), 3516 GET_MODE (XEXP (set, 0)), 3517 XEXP (XEXP (set, 1), swap_args ? 1 : 0), 3518 XEXP (XEXP (set, 1), 3519 swap_args ? 0 : 1)); 3520 3521 emit_insn_before (gen_rtx_SET (VOIDmode, 3522 XEXP (XEXP (set, 1), 1), 3523 rtx_ee), 3524 insn); 3525 next2_insn = emit_insn_before (gen_rtx_SET 3526 (GET_MODE (XEXP (set, 0)), 3527 XEXP (set, 0), 3528 XEXP (XEXP (set, 1), 1)), 3529 insn); 3530 delete_insn (insn); 3531 delete_insn (next_insn); 3532 insn = next2_insn; 3533 } 3534 } 3535 } 3536} 3537 3538/* Replace and recurse until we've tried QImode pieces! */ 3539 3540static void 3541mdr_pres_replace_and_recurse (orig, with, insn) 3542 rtx orig; 3543 rtx with; 3544 rtx insn; 3545{ 3546 enum machine_mode new_mode; 3547 3548 validate_replace_rtx (orig, with, insn); 3549 3550 switch (GET_MODE (orig)) 3551 { 3552 case DImode: 3553 case DFmode: 3554 new_mode = SImode; 3555 break; 3556 3557 case SImode: 3558 case SFmode: 3559 new_mode = HImode; 3560 break; 3561 3562 case HImode: 3563 new_mode = QImode; 3564 break; 3565 3566 default: 3567 return; 3568 } 3569 3570 mdr_pres_replace_and_recurse (ip2k_get_low_half (orig, new_mode), 3571 ip2k_get_low_half (with, new_mode), 3572 insn); 3573 mdr_pres_replace_and_recurse (ip2k_get_high_half (orig, new_mode), 3574 ip2k_get_high_half (with, new_mode), 3575 insn); 3576} 3577 3578/* Assist the following function, mdr_propagate_reg_equivs(). */ 3579 3580static void 3581mdr_propagate_reg_equivs_sequence (first_insn, orig, equiv) 3582 rtx first_insn; 3583 rtx orig; 3584 rtx equiv; 3585{ 3586 rtx try_insn; 3587 rtx try_equiv = equiv; 3588 3589 /* First scan the RTL looking for anything else that might clobber what 3590 we're doing. If we find anything then we can't do the replacement. */ 3591 for (try_insn = next_nonnote_insn (first_insn); 3592 try_insn; try_insn = next_nonnote_insn (try_insn)) 3593 { 3594 rtx pattern; 3595 3596 if (GET_CODE (try_insn) != JUMP_INSN && GET_CODE (try_insn) != INSN) 3597 continue; 3598 3599 pattern = PATTERN (try_insn); 3600 if (GET_CODE (pattern) == PARALLEL) 3601 { 3602 int j; 3603 3604 for (j = 0; j < XVECLEN (pattern, 0); j++) 3605 { 3606 rtx px = XVECEXP (pattern, 0, j); 3607 3608 if (GET_CODE (px) == SET) 3609 if (! ip2k_composite_xexp_not_uses_reg_p (XEXP (px, 0), 3610 REGNO (orig), 3611 GET_MODE_SIZE (GET_MODE (orig)))) 3612 return; 3613 } 3614 } 3615 else if (GET_CODE (pattern) == SET) 3616 { 3617 if (! ip2k_composite_xexp_not_uses_reg_p (XEXP (pattern, 0), 3618 REGNO (orig), 3619 GET_MODE_SIZE (GET_MODE (orig)))) 3620 return; 3621 } 3622 } 3623 3624 /* Once we've decided that we're safe to do the replacement then make the 3625 changes. */ 3626 for (try_insn = next_nonnote_insn (first_insn); try_insn; 3627 try_insn = next_nonnote_insn (try_insn)) 3628 { 3629 rtx set; 3630 rtx new_equiv = NULL_RTX; 3631 3632 if (GET_CODE (try_insn) != JUMP_INSN && GET_CODE (try_insn) != INSN) 3633 { 3634 try_equiv = equiv; 3635 continue; 3636 } 3637 3638 set = ((GET_CODE (PATTERN (try_insn)) == SET) 3639 ? PATTERN (try_insn) : NULL_RTX); 3640 if (set == NULL_RTX) 3641 continue; 3642 3643 /* We look for a special case of "push" operations screwing our 3644 register equivalence when it's based on a stack slot. We can 3645 track this one and replace the old equivalence expression with 3646 a new one. */ 3647 if (GET_CODE (XEXP (set, 0)) == MEM 3648 && GET_CODE (XEXP (XEXP (set, 0), 0)) == POST_DEC 3649 && REG_P (XEXP (XEXP (XEXP (set, 0), 0), 0)) 3650 && REGNO (XEXP (XEXP (XEXP (set, 0), 0), 0)) == REG_SP) 3651 { 3652 /* XXX - need to ensure that we can track this without going 3653 out of range! */ 3654 HOST_WIDE_INT disp = (INTVAL (XEXP (XEXP (try_equiv, 0), 1)) 3655 + GET_MODE_SIZE (GET_MODE (XEXP (set, 0)))); 3656 new_equiv = gen_rtx_MEM (GET_MODE (try_equiv), 3657 gen_rtx_PLUS (Pmode, 3658 gen_rtx_REG (HImode, REG_SP), 3659 GEN_INT (disp))); 3660 } 3661 3662 /* The replacement process is somewhat complicated by the fact that we 3663 might be dealing with what were originally subregs and thus we have 3664 to replace parts of our original expression! */ 3665 mdr_pres_replace_and_recurse (orig, try_equiv, try_insn); 3666 3667 if (new_equiv != NULL_RTX) 3668 try_equiv = new_equiv; 3669 } 3670} 3671 3672/* Try propagating register equivalences forwards. It may be that we can 3673 replace a register use with an equivalent expression that already 3674 holds the same value and thus allow one or more register loads to 3675 be eliminated. */ 3676 3677static void 3678mdr_propagate_reg_equivs (first_insn) 3679 rtx first_insn; 3680{ 3681 rtx insn; 3682 rtx set; 3683 3684 for (insn = first_insn; insn; insn = next_nonnote_insn (insn)) 3685 { 3686 if (GET_CODE (insn) != INSN) 3687 continue; 3688 3689 set = (GET_CODE (PATTERN (insn)) == SET) ? PATTERN (insn) : NULL_RTX; 3690 if (set == NULL_RTX) 3691 continue; 3692 3693 /* Have we found a stack slot equivalence for a register? */ 3694 if (REG_P (XEXP (set, 0)) 3695 && REGNO (XEXP (set, 0)) >= 0x88 3696 && GET_CODE (XEXP (set, 1)) == MEM 3697 && GET_CODE (XEXP (XEXP (set, 1), 0)) == PLUS 3698 && REG_P (XEXP (XEXP (XEXP (set, 1), 0), 0)) 3699 && REGNO (XEXP (XEXP (XEXP (set, 1), 0), 0)) == REG_SP 3700 && find_reg_note (insn, REG_EQUIV, NULL_RTX)) 3701 { 3702 mdr_propagate_reg_equivs_sequence (insn, XEXP (set, 0), 3703 XEXP (set, 1)); 3704 } 3705 } 3706} 3707 3708/* Structure used to track jump targets. */ 3709 3710struct dpre_jump_targets 3711{ 3712 int target; /* Is this a jump target? */ 3713 int reach_count; /* Number of ways we can reach this insn. */ 3714 int touch_count; /* Number of times we've touched this 3715 insns during scanning. */ 3716 rtx dp_equiv; /* DP-equivalence at this point. */ 3717}; 3718 3719struct dpre_jump_targets *ip2k_dpre_jump_targets; 3720 3721/* DP equivalence tracking used within DP reload elimination. */ 3722 3723static int 3724track_dp_reload (insn, dp_current, dp_current_ok, modifying) 3725 rtx insn; 3726 rtx *dp_current; 3727 int dp_current_ok; 3728 int modifying; 3729{ 3730 rtx set; 3731 3732 if (GET_CODE (insn) != INSN) 3733 { 3734 *dp_current = NULL_RTX; 3735 return 1; 3736 } 3737 3738 set = (GET_CODE (PATTERN (insn)) == SET) ? PATTERN (insn) : NULL_RTX; 3739 if (set == NULL_RTX) 3740 { 3741 *dp_current = NULL_RTX; 3742 return 1; 3743 } 3744 3745 /* If we're pushing a PLUS or MINUS then it's a win if we can replace 3746 an expression for which DP is equivalent with DP. This happens 3747 surprisingly often when we pass a pointer to a structure embedded 3748 within another structure. */ 3749 if (*dp_current != NULL_RTX 3750 && GET_CODE (XEXP (set, 0)) == MEM 3751 && GET_CODE (XEXP (XEXP (set, 0), 0)) == POST_DEC 3752 && GET_CODE (XEXP (XEXP (XEXP (set, 0), 0), 0)) == REG 3753 && REGNO (XEXP (XEXP (XEXP (set, 0), 0), 0)) == REG_SP 3754 && (GET_CODE (XEXP (set, 1)) == PLUS 3755 || GET_CODE (XEXP (set, 1)) == MINUS) 3756 && GET_CODE (*dp_current) != SYMBOL_REF 3757 && GET_CODE (*dp_current) != LABEL_REF 3758 && GET_CODE (*dp_current) != CONST) 3759 { 3760 if (modifying) 3761 validate_replace_rtx (*dp_current, gen_rtx_REG (HImode, REG_DP), insn); 3762 } 3763 3764 /* Look for DP being modified. If it is, see if it's being changed 3765 to what it already is! */ 3766 if (GET_CODE (XEXP (set, 0)) == REG 3767 && REGNO (XEXP (set, 0)) == REG_DP 3768 && GET_MODE (XEXP (set, 0)) == HImode) 3769 { 3770 /* If this is an equivalence we can delete the new set operation. */ 3771 if (*dp_current != NULL_RTX 3772 && rtx_equal_p (XEXP (set, 1), *dp_current)) 3773 { 3774 if (modifying) 3775 delete_insn (insn); 3776 } 3777 else 3778 { 3779 /* If we've not found an equivalence we can look for a special 3780 case where an operand of the expression that sets DP is 3781 already equivalent to DP and in that circumstance we simplify 3782 by replacing that expression with DP. */ 3783 if (*dp_current != NULL_RTX 3784 && GET_CODE (*dp_current) != SYMBOL_REF 3785 && GET_CODE (*dp_current) != LABEL_REF 3786 && GET_CODE (*dp_current) != CONST 3787 && modifying) 3788 validate_replace_rtx (*dp_current, XEXP (set, 0), insn); 3789 3790 /* Assuming that we're not loading DP from something that uses DP 3791 itself then we mark the new equivalence for DP. If we did match 3792 DP then we can't re-use this one. */ 3793 if (ip2k_xexp_not_uses_reg_p (XEXP (set, 1), REG_DP, 2)) 3794 { 3795 *dp_current = XEXP (set, 1); 3796 return 1; 3797 } 3798 else 3799 { 3800 *dp_current = NULL_RTX; 3801 return 1; 3802 } 3803 } 3804 } 3805 else if (GET_CODE (XEXP (set, 0)) == REG 3806 && (REGNO (XEXP (set, 0)) == REG_DPL 3807 || REGNO (XEXP (set, 0)) == REG_DPH)) 3808 { 3809 /* If we clobber part of DP then we've clobbered any equivalences! */ 3810 *dp_current = NULL_RTX; 3811 return 1; 3812 } 3813 else if (! ip2k_xexp_not_uses_reg_p (XEXP (set, 0), REG_SP, 2) 3814 && *dp_current != NULL_RTX 3815 && !ip2k_xexp_not_uses_reg_p (*dp_current, REG_SP, 2)) 3816 { 3817 /* We look for a special case of "push" operations screwing up the 3818 setting of DP when it's based on the stack. We can track this one 3819 and replace the old expression for DP with a new one. */ 3820 if (GET_CODE (XEXP (set, 0)) == MEM 3821 && GET_CODE (XEXP (XEXP (set, 0), 0)) == POST_DEC 3822 && GET_CODE (XEXP (XEXP (XEXP (set, 0), 0), 0)) == REG 3823 && REGNO (XEXP (XEXP (XEXP (set, 0), 0), 0)) == REG_SP 3824 && GET_CODE (*dp_current) == MEM 3825 && GET_CODE (XEXP (*dp_current, 0)) == PLUS) 3826 { 3827 /* XXX - need to ensure that we can track this without going 3828 out of range! */ 3829 HOST_WIDE_INT disp = (INTVAL (XEXP (XEXP (*dp_current, 0), 1)) 3830 + GET_MODE_SIZE (GET_MODE (XEXP (set, 0)))); 3831 *dp_current = gen_rtx_MEM (HImode, 3832 gen_rtx_PLUS (Pmode, 3833 gen_rtx_REG(HImode, REG_SP), 3834 GEN_INT (disp))); 3835 return 1; 3836 } 3837 3838 /* Now we look for writes to the stack. We can determine if these will 3839 affect the equivalence we're tracking for DP and if not then we can 3840 keep tracking it. */ 3841 if (GET_CODE (XEXP (set, 0)) == MEM 3842 && GET_CODE (*dp_current) == MEM) 3843 { 3844 /* Look at the SP offsets and look for any overlaps. */ 3845 int dp_cur_sp_offs = INTVAL (XEXP (XEXP (*dp_current, 0), 1)); 3846 int set_sp_offs = INTVAL (XEXP (XEXP (XEXP (set, 0), 0), 1)); 3847 3848 if (abs (dp_cur_sp_offs - set_sp_offs) < 2) 3849 { 3850 *dp_current = NULL_RTX; 3851 return 1; 3852 } 3853 } 3854 } 3855 else if (GET_CODE (XEXP (set, 0)) == REG 3856 && *dp_current != NULL_RTX 3857 && !ip2k_xexp_not_uses_reg_p (*dp_current, REGNO (XEXP (set, 0)), 3858 GET_MODE_SIZE (GET_MODE (XEXP (set, 3859 0))))) 3860 { 3861 /* If we've just clobbered all or part of a register reference that we 3862 were sharing for DP then we can't share it any more! */ 3863 *dp_current = NULL_RTX; 3864 } 3865 3866 return dp_current_ok; 3867} 3868 3869/* As part of the machine-dependent reorg we scan loads and reloads of 3870 DP to see where any are redundant. This does happens because we 3871 are able to subsequently transform things in interesting ways. Sometimes 3872 gcc also does unecessary reloads too so we try to eliminate these too. */ 3873 3874static void 3875mdr_try_dp_reload_elim (first_insn) 3876 rtx first_insn; 3877{ 3878 rtx insn; 3879 struct dpre_jump_targets *djt; 3880 rtx dp_current; 3881 int incomplete_scan; 3882 int last_incomplete_scan; 3883 3884 ip2k_dpre_jump_targets 3885 = (struct dpre_jump_targets *) xcalloc (get_max_uid (), 3886 sizeof (struct dpre_jump_targets)); 3887 3888 /* First we scan to build up a list of all CODE_LABEL insns and we work out 3889 how many different ways we can reach them. */ 3890 for (insn = first_insn; insn; insn = next_nonnote_insn (insn)) 3891 { 3892 if (GET_CODE (insn) == CODE_LABEL) 3893 { 3894 djt = &ip2k_dpre_jump_targets[INSN_UID (insn)]; 3895 djt->target = 1; 3896 djt->reach_count = LABEL_NUSES (insn); 3897 djt->touch_count = 0; 3898 djt->dp_equiv = NULL_RTX; 3899 if (! prev_nonnote_insn (insn) 3900 || (prev_nonnote_insn (insn) 3901 && GET_CODE (prev_nonnote_insn (insn)) != BARRIER)) 3902 djt->reach_count++; 3903 } 3904 } 3905 3906 /* Next we scan all of the ways of reaching the code labels to see 3907 what the DP register is equivalent to as we reach them. If we find 3908 that they're the same then we keep noting the matched value. We 3909 iterate around this until we reach a convergence on DP equivalences 3910 at all code labels - we have to be very careful not to be too 3911 optimistic! */ 3912 incomplete_scan = -1; 3913 do 3914 { 3915 int dp_current_ok = 0; 3916 last_incomplete_scan = incomplete_scan; 3917 dp_current = NULL_RTX; 3918 3919 for (insn = first_insn; insn; insn = next_nonnote_insn (insn)) 3920 { 3921 /* If we have a code label then we need to see if we already know 3922 what the equivalence is at this point. If we do then we use it 3923 immediately, but if we don't then we have a special case to track 3924 when we hit a fallthrough-edge (label with no barrier preceding 3925 it). Any other accesses to the label must be from jump insns 3926 and so they're handled elsewhere. */ 3927 if (GET_CODE (insn) == CODE_LABEL) 3928 { 3929 djt = &ip2k_dpre_jump_targets[INSN_UID (insn)]; 3930 3931 /* If we're fully characterized the use the equivalence. */ 3932 if (djt->touch_count == djt->reach_count) 3933 { 3934 dp_current = djt->dp_equiv; 3935 dp_current_ok = 1; 3936 continue; 3937 } 3938 3939 /* If we have a known equivalence for DP as we reach the 3940 fallthrough-edge then track this into the code label. */ 3941 if (dp_current_ok 3942 && (! prev_nonnote_insn (insn) 3943 || (prev_nonnote_insn (insn) 3944 && GET_CODE (prev_nonnote_insn (insn)) != BARRIER))) 3945 { 3946 if (djt->touch_count == 0) 3947 djt->dp_equiv = dp_current; 3948 3949 if (djt->touch_count < djt->reach_count) 3950 { 3951 djt->touch_count++; 3952 if (! rtx_equal_p (djt->dp_equiv, dp_current)) 3953 { 3954 /* When we definitely know that we can't form an 3955 equivalence for DP here we must clobber anything 3956 that we'd started to track too. */ 3957 djt->dp_equiv = NULL_RTX; 3958 dp_current = NULL_RTX; 3959 dp_current_ok = 1; 3960 } 3961 } 3962 } 3963 3964 /* If we've not completely characterized this code label then 3965 be cautious and assume that we don't know what DP is 3966 equivalent to. */ 3967 if (djt->touch_count < djt->reach_count) 3968 { 3969 dp_current = NULL_RTX; 3970 dp_current_ok = 0; 3971 } 3972 3973 continue; 3974 } 3975 3976 /* If we've hit a jump insn then we look for either an address 3977 vector (jump table) or for jump label references. */ 3978 if (GET_CODE (insn) == JUMP_INSN) 3979 { 3980 /* Don't attempt to track here if we don't have a known 3981 equivalence for DP at this point. */ 3982 if (dp_current_ok) 3983 { 3984 rtx pat = PATTERN (insn); 3985 if (GET_CODE (pat) == ADDR_VEC) 3986 { 3987 int i; 3988 int len = XVECLEN (pat, 0); 3989 3990 for (i = 0; i < len; i++) 3991 { 3992 rtx vec_insn = XEXP (XVECEXP (pat, 0, i), 0); 3993 djt = &ip2k_dpre_jump_targets [INSN_UID (vec_insn)]; 3994 3995 if (djt->touch_count == 0) 3996 djt->dp_equiv = dp_current; 3997 3998 if (djt->touch_count < djt->reach_count) 3999 { 4000 djt->touch_count++; 4001 if (! rtx_equal_p (djt->dp_equiv, dp_current)) 4002 djt->dp_equiv = NULL_RTX; 4003 } 4004 } 4005 } 4006 else if (JUMP_LABEL (insn)) 4007 { 4008 rtx j_insn = JUMP_LABEL (insn); 4009 djt = &ip2k_dpre_jump_targets[INSN_UID (j_insn)]; 4010 4011 if (djt->touch_count == 0) 4012 djt->dp_equiv = dp_current; 4013 4014 if (djt->touch_count < djt->reach_count) 4015 { 4016 djt->touch_count++; 4017 if (! rtx_equal_p (djt->dp_equiv, dp_current)) 4018 djt->dp_equiv = NULL_RTX; 4019 } 4020 } 4021 } 4022 4023 continue; 4024 } 4025 4026 /* Anything other than a code labal or jump arrives here. 4027 We try and track DP, but sometimes we might not be able to. */ 4028 dp_current_ok = track_dp_reload (insn, &dp_current, 4029 dp_current_ok, 0); 4030 } 4031 4032 /* When we're looking to see if we've finished we count the number of 4033 paths throught the code labels where we weren't able to definitively 4034 track DP. 4035 This number is used to see if we're converging on a solution. 4036 If this hits zero then we've fully converged, but if this stays the 4037 same as last time then we probably can't make any further 4038 progress. */ 4039 incomplete_scan = 0; 4040 for (insn = first_insn; insn; insn = next_nonnote_insn (insn)) 4041 { 4042 if (GET_CODE (insn) == CODE_LABEL) 4043 { 4044 djt = &ip2k_dpre_jump_targets[INSN_UID (insn)]; 4045 if (djt->touch_count != djt->reach_count) 4046 { 4047 incomplete_scan += (djt->reach_count - djt->touch_count); 4048 djt->dp_equiv = NULL_RTX; 4049 djt->touch_count = 0; 4050 } 4051 } 4052 } 4053 } 4054 while (incomplete_scan && incomplete_scan != last_incomplete_scan); 4055 4056 /* Finally we scan the whole function and run DP elimination. When we hit 4057 a CODE_LABEL we pick up any stored equivalence since we now know that 4058 every path to this point entered with DP holding the same thing! If 4059 we subsequently have a reload that matches then we can eliminate it. */ 4060 dp_current = NULL_RTX; 4061 for (insn = first_insn; insn; insn = next_nonnote_insn (insn)) 4062 { 4063 if (GET_CODE (insn) == JUMP_INSN) 4064 continue; 4065 4066 if (GET_CODE (insn) == CODE_LABEL) 4067 { 4068 djt = &ip2k_dpre_jump_targets[INSN_UID (insn)]; 4069 dp_current = djt->dp_equiv; 4070 continue; 4071 } 4072 4073 track_dp_reload (insn, &dp_current, 1, 1); 4074 } 4075 4076 free (ip2k_dpre_jump_targets); 4077} 4078 4079/* As part of the machine-dependent reorg we look for reloads of DP 4080 that we can move to earlier points within the file. 4081 Moving these out of the way allows more peepholes to match. */ 4082 4083static void 4084mdr_try_move_dp_reload (first_insn) 4085 rtx first_insn; 4086{ 4087 rtx insn; 4088 rtx set; 4089 rtx orig_first; 4090 4091 /* Don't try to match the first instruction because we can't move it 4092 anyway. */ 4093 orig_first = first_insn; 4094 first_insn = next_nonnote_insn (first_insn); 4095 4096 for (insn = first_insn; insn; insn = next_nonnote_insn (insn)) 4097 { 4098 if (GET_CODE (insn) != INSN) 4099 continue; 4100 4101 set = (GET_CODE (PATTERN (insn)) == SET) ? PATTERN (insn) : NULL_RTX; 4102 if (set == NULL_RTX) 4103 continue; 4104 4105 /* Look for DP being loaded. When we find this we start a rewind 4106 scan looking for possible positions to move this to. */ 4107 if (GET_CODE (XEXP (set, 0)) == REG 4108 && REGNO (XEXP (set, 0)) == REG_DP 4109 && GET_MODE (XEXP (set, 0)) == HImode) 4110 { 4111 int try_again; 4112 rtx try_insn = insn; 4113 4114 do 4115 { 4116 rtx rewind; 4117 rtx check; 4118 4119 try_again = 0; 4120 4121 /* For now we do the *really* simple version of things and only 4122 attempt to move the load of DP if it's very safe to do so. */ 4123 rewind = prev_nonnote_insn (try_insn); 4124 if (rewind != orig_first && rewind != NULL_RTX 4125 && GET_CODE (rewind) == INSN) 4126 { 4127 check = ((GET_CODE (PATTERN (rewind)) == SET) 4128 ? PATTERN (rewind) : NULL_RTX); 4129 if (check != NULL_RTX 4130 && ip2k_composite_xexp_not_uses_cc0_p (XEXP (check, 0)) 4131 && ip2k_composite_xexp_not_uses_cc0_p (XEXP (check, 1))) 4132 { 4133 if (GET_CODE (XEXP (check, 0)) == REG 4134 && REGNO (XEXP (check, 0)) != REG_DPH 4135 && REGNO (XEXP (check, 0)) != REG_DPL 4136 && (ip2k_composite_xexp_not_uses_reg_p 4137 (XEXP (check, 1), REG_DP, 2)) 4138 && (ip2k_composite_xexp_not_uses_reg_p 4139 (XEXP (set, 1), 4140 REGNO (XEXP (check, 0)), 4141 GET_MODE_SIZE (GET_MODE (XEXP (check, 0)))))) 4142 { 4143 emit_insn_before (set, rewind); 4144 if (try_insn == insn) 4145 insn = prev_nonnote_insn (insn); 4146 delete_insn (try_insn); 4147 try_insn = prev_nonnote_insn (rewind); 4148 try_again = 1; 4149 } 4150 else if (GET_CODE (XEXP (set, 1)) == REG 4151 && ip2k_composite_xexp_not_uses_reg_p (XEXP (check, 1), REG_DP, 2) 4152 && ip2k_composite_xexp_not_uses_reg_p (XEXP (check, 0), REG_DP, 2) 4153 && ip2k_composite_xexp_not_uses_reg_p (XEXP (check, 0), REGNO (XEXP (set, 1)), 4154 GET_MODE_SIZE (GET_MODE (XEXP (set, 1))))) 4155 { 4156 emit_insn_before (set, rewind); 4157 if (try_insn == insn) 4158 insn = prev_nonnote_insn (insn); 4159 delete_insn (try_insn); 4160 try_insn = prev_nonnote_insn (rewind); 4161 try_again = 1; 4162 } 4163 } 4164 } 4165 } 4166 while (try_again && try_insn); 4167 } 4168 } 4169} 4170#endif /* IP2K_MD_REORG_PASS */ 4171 4172/* Look to see if the expression, x, can have any stack references offset by 4173 a fixed constant, offset. If it definitely can then returns nonzero. */ 4174 4175static int 4176ip2k_check_can_adjust_stack_ref (x, offset) 4177 rtx x; 4178 int offset; 4179{ 4180 if (GET_RTX_CLASS (GET_CODE (x)) == '2' 4181 || GET_RTX_CLASS (GET_CODE (x)) == 'c') 4182 return (ip2k_check_can_adjust_stack_ref (XEXP (x, 0), offset) 4183 && ip2k_check_can_adjust_stack_ref (XEXP (x, 1), offset)); 4184 4185 if (GET_RTX_CLASS (GET_CODE (x)) == '1') 4186 return ip2k_check_can_adjust_stack_ref (XEXP (x, 0), offset); 4187 4188 switch (GET_CODE (x)) 4189 { 4190 case REG: 4191 return (REGNO (x) != REG_SPH && REGNO (x) != REG_SPL); 4192 4193 case MEM: 4194 if (GET_CODE (XEXP (x, 0)) != PLUS) 4195 return 1; 4196 4197 if (GET_CODE (XEXP (XEXP (x, 0), 0)) != REG) 4198 return 1; 4199 4200 if (REGNO (XEXP (XEXP (x, 0), 0)) != REG_SP) 4201 return 1; 4202 4203 /* We can't allow this if the adjustment will create an 4204 invalid address. */ 4205 return (INTVAL (XEXP (XEXP (x, 0), 1)) 4206 + offset <= (128 - 2 * GET_MODE_SIZE (GET_MODE (x)))); 4207 4208 case CONST: 4209 case CONST_INT: 4210 case CONST_DOUBLE: 4211 case SYMBOL_REF: 4212 case LABEL_REF: 4213 return 1; 4214 4215 default: 4216 return 0; 4217 } 4218} 4219 4220/* Adjusts all of the stack references in the expression pointed to by x by 4221 a fixed offset. */ 4222 4223static void 4224ip2k_adjust_stack_ref (x, offset) 4225 rtx *x; 4226 int offset; 4227{ 4228 if (GET_RTX_CLASS (GET_CODE (*x)) == '2' 4229 || GET_RTX_CLASS (GET_CODE (*x)) == 'c') 4230 { 4231 ip2k_adjust_stack_ref (&XEXP (*x, 0), offset); 4232 ip2k_adjust_stack_ref (&XEXP (*x, 1), offset); 4233 return; 4234 } 4235 4236 if (GET_RTX_CLASS (GET_CODE (*x)) == '1') 4237 { 4238 ip2k_adjust_stack_ref (&XEXP (*x, 0), offset); 4239 return; 4240 } 4241 4242 switch (GET_CODE (*x)) 4243 { 4244 case MEM: 4245 if (GET_CODE (XEXP (*x, 0)) != PLUS) 4246 return; 4247 4248 if (GET_CODE (XEXP (XEXP (*x, 0), 0)) != REG) 4249 return; 4250 4251 if (REGNO (XEXP (XEXP (*x, 0), 0)) != REG_SP) 4252 return; 4253 4254 *x = copy_rtx (*x); 4255 XEXP (XEXP (*x, 0), 1) = GEN_INT (INTVAL (XEXP (XEXP (*x, 0), 1)) 4256 + offset); 4257 break; 4258 4259 default: 4260 break; 4261 } 4262} 4263 4264#ifdef IP2K_MD_REORG_PASS 4265/* As part of the machine-dependent reorg we look to move push instructions 4266 to earlier points within the file. Moving these out of the way allows more 4267 peepholes to match. */ 4268 4269static void 4270mdr_try_move_pushes (first_insn) 4271 rtx first_insn; 4272{ 4273 rtx insn; 4274 rtx set; 4275 rtx orig_first; 4276 4277 /* Don't try to match the first instruction because we can't move 4278 it anyway. */ 4279 orig_first = first_insn; 4280 first_insn = next_nonnote_insn (first_insn); 4281 4282 for (insn = first_insn; insn; insn = next_nonnote_insn (insn)) 4283 { 4284 if (GET_CODE (insn) != INSN) 4285 continue; 4286 4287 set = (GET_CODE (PATTERN (insn)) == SET) ? PATTERN (insn) : NULL_RTX; 4288 if (set == NULL_RTX) 4289 continue; 4290 4291 /* Have we found a push instruction? */ 4292 if (GET_CODE (XEXP (set, 0)) == MEM 4293 && GET_CODE (XEXP (XEXP (set, 0), 0)) == POST_DEC 4294 && GET_CODE (XEXP (XEXP (XEXP (set, 0), 0), 0)) == REG 4295 && REGNO (XEXP (XEXP (XEXP (set, 0), 0), 0)) == REG_SP 4296 && GET_CODE (XEXP (set, 1)) == REG) 4297 { 4298 rtx try_insn = insn; 4299 unsigned int regno = REGNO (XEXP (set, 1)); 4300 int reg_range = GET_MODE_SIZE (GET_MODE (XEXP (set, 1))); 4301 4302 while (1) 4303 { 4304 rtx rewind; 4305 rtx check; 4306 4307 rewind = prev_nonnote_insn (try_insn); 4308 if (rewind == orig_first || rewind == NULL_RTX 4309 || GET_CODE (rewind) != INSN) 4310 break; 4311 4312 check = (GET_CODE (PATTERN (rewind)) == SET) ? PATTERN (rewind) : NULL_RTX; 4313 if (check == NULL_RTX) 4314 break; 4315 4316 if (! ip2k_check_can_adjust_stack_ref (XEXP (check, 0), 4317 reg_range) 4318 || ! ip2k_check_can_adjust_stack_ref (XEXP (check, 1), 4319 reg_range)) 4320 break; 4321 4322 /* If we've hit another push instruction we can't go any 4323 further. */ 4324 if (GET_CODE (XEXP (check, 0)) == MEM 4325 && GET_CODE (XEXP (XEXP (check, 0), 0)) == POST_DEC 4326 && GET_CODE (XEXP (XEXP (XEXP (check, 0), 0), 0)) == REG 4327 && REGNO (XEXP (XEXP (XEXP (check, 0), 0), 0)) == REG_SP) 4328 break; 4329 4330 /* If this is a register move then check that it doesn't clobber 4331 SP or any part of the instruction we're trying to move. */ 4332 if (GET_CODE (XEXP (check, 0)) == REG) 4333 { 4334 unsigned int check_reg = REGNO (XEXP (check, 0)); 4335 int check_reg_range = GET_MODE_SIZE (GET_MODE (XEXP (check, 4336 0))); 4337 4338 /* If we have a special case where what we want to push is 4339 being loaded by this "clobbering" insn then we can just 4340 push what is being used to load us and then do the load. 4341 This may seem a little odd, but we may subsequently be 4342 able to merge the load with another instruction as it 4343 may only be used once now! Note though that we 4344 specifically don't try this if the expression being 4345 loaded is an HImode MEM using IP. */ 4346 if (check_reg == regno 4347 && check_reg_range == reg_range 4348 && ((GET_CODE (XEXP (check, 1)) == REG 4349 || (GET_CODE (XEXP (check, 1)) == MEM 4350 && (GET_MODE (XEXP (check, 1)) != HImode 4351 || ip2k_xexp_not_uses_reg_for_mem (XEXP (check, 1), REG_IP)))))) 4352 { 4353 switch (check_reg_range) 4354 { 4355 case 1: 4356 emit_insn_before (gen_movqi (XEXP (set, 0), 4357 XEXP (check, 1)), 4358 rewind); 4359 delete_insn (try_insn); 4360 break; 4361 4362 case 2: 4363 emit_insn_before (gen_movhi (XEXP (set, 0), 4364 XEXP (check, 1)), 4365 rewind); 4366 delete_insn (try_insn); 4367 break; 4368 4369 case 4: 4370 emit_insn_before (gen_movsi (XEXP (set, 0), 4371 XEXP (check, 1)), 4372 rewind); 4373 delete_insn (try_insn); 4374 break; 4375 4376 case 8: 4377 emit_insn_before (gen_movdi (XEXP (set, 0), 4378 XEXP (check, 1)), 4379 rewind); 4380 delete_insn (try_insn); 4381 break; 4382 } 4383 4384 ip2k_adjust_stack_ref (&XEXP (check, 0), reg_range); 4385 ip2k_adjust_stack_ref (&XEXP (check, 1), reg_range); 4386 try_insn = prev_nonnote_insn (rewind); 4387 /* XXX - should be a continue? */ 4388 break; 4389 } 4390 4391 if ((check_reg == REG_SPL) 4392 || (check_reg == REG_SPH) 4393 || (((regno <= check_reg) 4394 && (regno + reg_range - 1) >= check_reg) 4395 || ((regno <= (check_reg + check_reg_range - 1)) 4396 && ((regno + reg_range - 1) 4397 >= (check_reg + check_reg_range - 1))))) 4398 break; 4399 } 4400 4401 emit_insn_before (set, rewind); 4402 delete_insn (try_insn); 4403 ip2k_adjust_stack_ref (&XEXP (check, 0), reg_range); 4404 ip2k_adjust_stack_ref (&XEXP (check, 1), reg_range); 4405 try_insn = prev_nonnote_insn (rewind); 4406 } 4407 } 4408 } 4409} 4410 4411/* Assist the following function, mdr_try_propagate_clr(). */ 4412 4413static void 4414mdr_try_propagate_clr_sequence (first_insn, regno) 4415 rtx first_insn; 4416 unsigned int regno; 4417{ 4418 rtx try_insn; 4419 4420 for (try_insn = next_nonnote_insn (first_insn); try_insn; 4421 try_insn = next_nonnote_insn (try_insn)) 4422 { 4423 rtx new_insn = NULL_RTX; 4424 rtx set2; 4425 4426 if (GET_CODE (try_insn) == JUMP_INSN) 4427 continue; 4428 4429 if (GET_CODE (try_insn) != INSN) 4430 break; 4431 4432 set2 = ((GET_CODE (PATTERN (try_insn)) == SET) 4433 ? PATTERN (try_insn) : NULL_RTX); 4434 if (set2 == NULL_RTX) 4435 continue; 4436 4437 if (GET_CODE (XEXP (set2, 1)) == AND 4438 && ((GET_CODE (XEXP (XEXP (set2, 1), 0)) == REG 4439 && REGNO (XEXP (XEXP (set2, 1), 0)) == regno) 4440 || (GET_CODE (XEXP (XEXP (set2, 1), 1)) == REG 4441 && REGNO (XEXP (XEXP (set2, 1), 1)) == regno))) 4442 { 4443 rtx remove_insn = try_insn; 4444 try_insn = emit_insn_before (gen_rtx_SET (QImode, XEXP (set2, 0), 4445 const0_rtx), try_insn); 4446 delete_insn (remove_insn); 4447 } 4448 else if (GET_CODE (XEXP (set2, 1)) == IOR 4449 && GET_CODE (XEXP (XEXP (set2, 1), 0)) == REG 4450 && REGNO (XEXP (XEXP (set2, 1), 0)) == regno) 4451 { 4452 rtx remove_insn = try_insn; 4453 try_insn = emit_insn_before (gen_rtx_SET (QImode, XEXP (set2, 0), 4454 XEXP (XEXP (set2, 1), 1)), 4455 try_insn); 4456 delete_insn (remove_insn); 4457 } 4458 else if (GET_CODE (XEXP (set2, 1)) == IOR 4459 && GET_CODE (XEXP (XEXP (set2, 1), 1)) == REG 4460 && REGNO (XEXP (XEXP (set2, 1), 1)) == regno) 4461 { 4462 rtx remove_insn = try_insn; 4463 try_insn = emit_insn_before (gen_rtx_SET (QImode, XEXP (set2, 0), 4464 XEXP (XEXP (set2, 1), 0)), 4465 try_insn); 4466 delete_insn (remove_insn); 4467 } 4468 else if (GET_CODE (XEXP (set2, 1)) == XOR 4469 && GET_CODE (XEXP (XEXP (set2, 1), 0)) == REG 4470 && REGNO (XEXP (XEXP (set2, 1), 0)) == regno) 4471 { 4472 rtx remove_insn = try_insn; 4473 try_insn = emit_insn_before (gen_rtx_SET (QImode, XEXP (set2, 0), 4474 XEXP (XEXP (set2, 1), 1)), 4475 try_insn); 4476 delete_insn (remove_insn); 4477 } 4478 else if (GET_CODE (XEXP (set2, 1)) == XOR 4479 && GET_CODE (XEXP (XEXP (set2, 1), 1)) == REG 4480 && REGNO (XEXP (XEXP (set2, 1), 1)) == regno) 4481 { 4482 rtx remove_insn = try_insn; 4483 try_insn = emit_insn_before (gen_rtx_SET (QImode, XEXP (set2, 0), 4484 XEXP (XEXP (set2, 1), 0)), 4485 try_insn); 4486 delete_insn (remove_insn); 4487 } 4488 4489 if (GET_CODE (XEXP (set2, 0)) == REG) 4490 { 4491 int reg2_range = GET_MODE_SIZE (GET_MODE (XEXP (set2, 0))); 4492 unsigned int regno2 = REGNO (XEXP (set2, 0)); 4493 4494 if (reg2_range == 1 4495 && regno == regno2 4496 && GET_CODE (XEXP (set2, 1)) == CONST_INT) 4497 { 4498 int iv = INTVAL (XEXP (set2, 1)); 4499 if (iv == 0xff) 4500 iv = -1; 4501 if (iv == 1 || iv == -1) 4502 { 4503 new_insn = gen_rtx_SET (QImode, XEXP (set2, 0), 4504 gen_rtx_PLUS (QImode, XEXP (set2, 0), 4505 GEN_INT (iv))); 4506 new_insn = emit_insn_before (new_insn, try_insn); 4507 delete_insn (try_insn); 4508 try_insn = new_insn; 4509 } 4510 break; 4511 } 4512 4513 if ((regno >= regno2) && (regno <= regno2 + reg2_range - 1)) 4514 break; 4515 4516 if (GET_CODE (XEXP (set2, 1)) == REG 4517 && REGNO (XEXP (set2, 1)) == regno) 4518 { 4519 new_insn = emit_insn_before (gen_rtx_SET (QImode, 4520 XEXP (set2, 0), 4521 const0_rtx), 4522 try_insn); 4523 delete_insn (try_insn); 4524 try_insn = new_insn; 4525 } 4526 } 4527 4528 if (GET_CODE (XEXP (set2, 0)) == CC0) 4529 { 4530 if (GET_CODE (XEXP (set2, 1)) == REG 4531 && GET_MODE_SIZE (GET_MODE (XEXP (set2, 1))) == 2 4532 && REGNO (XEXP (set2, 1)) == regno) 4533 { 4534 new_insn = gen_rtx_SET (VOIDmode, gen_rtx (CC0, VOIDmode), 4535 gen_rtx_REG(QImode, regno + 1)); 4536 new_insn = emit_insn_before (new_insn, try_insn); 4537 } 4538 else if (GET_CODE (XEXP (set2, 1)) == COMPARE 4539 && GET_CODE (XEXP (XEXP (set2, 1), 0)) == REG 4540 && GET_MODE_SIZE (GET_MODE (XEXP (XEXP (set2, 1), 0))) == 2 4541 && REGNO (XEXP (XEXP (set2, 1), 0)) == regno 4542 && GET_CODE (XEXP (XEXP (set2, 1), 1)) == CONST_INT 4543 && INTVAL (XEXP (XEXP (set2, 1), 1)) >= 0 4544 && INTVAL (XEXP (XEXP (set2, 1), 1)) < 256) 4545 { 4546 new_insn = gen_rtx_SET (VOIDmode, cc0_rtx, 4547 gen_rtx_COMPARE(QImode, 4548 gen_rtx_REG (QImode, 4549 regno + 1), 4550 XEXP (XEXP (set2, 1), 4551 1))); 4552 new_insn = emit_insn_before (new_insn, try_insn); 4553 } 4554 4555 /* If we have inserted a replacement for a CC0 setter operation 4556 then we need to delete the old one. */ 4557 if (new_insn != NULL_RTX) 4558 { 4559 delete_insn (try_insn); 4560 try_insn = new_insn; 4561 4562 /* Now as we know that we have just done an unsigned compare 4563 (remember we were zero-extended by the clr!) we also know 4564 that we don't need a signed jump insn. If we find that 4565 our next isns is a signed jump then make it unsigned! */ 4566 if (GET_CODE (next_nonnote_insn (try_insn)) == JUMP_INSN) 4567 { 4568 rtx set3; 4569 4570 try_insn = next_nonnote_insn (try_insn); 4571 set3 = ((GET_CODE (PATTERN (try_insn)) == SET) 4572 ? PATTERN (try_insn) : NULL_RTX); 4573 if (set3 == NULL_RTX) 4574 continue; 4575 4576 /* If we discover that our jump target is only accessible 4577 from here then we can continue our "clr" propagation to 4578 it too! */ 4579 if (LABEL_NUSES (JUMP_LABEL (try_insn)) == 1) 4580 mdr_try_propagate_clr_sequence (JUMP_LABEL (try_insn), 4581 regno); 4582 4583 if (GET_CODE (XEXP (set3, 0)) == PC 4584 && GET_CODE (XEXP (set3, 1)) == IF_THEN_ELSE 4585 && (GET_CODE (XEXP (XEXP (set3, 1), 0)) == GT 4586 || GET_CODE (XEXP (XEXP (set3, 1), 0)) == GE 4587 || GET_CODE (XEXP (XEXP (set3, 1), 0)) == LT 4588 || GET_CODE (XEXP (XEXP (set3, 1), 0)) == LE) 4589 && GET_CODE (XEXP (XEXP (XEXP (set3, 1), 0), 0)) == CC0 4590 && (GET_CODE (XEXP (XEXP (XEXP (set3, 1), 0), 1)) 4591 == CONST_INT) 4592 && GET_CODE (XEXP (XEXP (set3, 1), 1)) == LABEL_REF 4593 && GET_CODE (XEXP (XEXP (set3, 1), 2)) == PC) 4594 { 4595 enum rtx_code code; 4596 rtx new_if; 4597 rtx cmp; 4598 4599 /* Replace our old conditional jump with a new one that 4600 does the unsigned form of what was previously a 4601 signed comparison. */ 4602 code = GET_CODE (XEXP (XEXP (set3, 1), 0)); 4603 cmp = gen_rtx_fmt_ee ((code == GT 4604 ? GTU 4605 : (code == GE 4606 ? GEU 4607 : (code == LT ? LTU : LEU))), 4608 VOIDmode, 4609 XEXP (XEXP (XEXP (set3, 1), 0), 0), 4610 XEXP (XEXP (XEXP (set3, 1), 0), 4611 1)); 4612 new_if 4613 = gen_rtx_SET (GET_MODE (set3), 4614 pc_rtx, 4615 gen_rtx_IF_THEN_ELSE 4616 (GET_MODE (XEXP (set3, 1)), cmp, 4617 XEXP (XEXP (set3, 1), 1), 4618 XEXP (XEXP (set3, 1), 2))); 4619 new_insn = emit_jump_insn_before (new_if, try_insn); 4620 LABEL_NUSES (JUMP_LABEL (try_insn))++; 4621 delete_insn (try_insn); 4622 try_insn = new_insn; 4623 } 4624 } 4625 } 4626 } 4627 else if (GET_CODE (XEXP (set2, 1)) == PLUS 4628 && GET_CODE (XEXP (XEXP (set2, 1), 0)) == REG 4629 && GET_MODE_SIZE (GET_MODE (XEXP (XEXP (set2, 1), 0))) == 2 4630 && REGNO (XEXP (XEXP (set2, 1), 0)) == regno 4631 && (GET_CODE (XEXP (XEXP (set2, 1), 1)) == REG 4632 || GET_CODE (XEXP (XEXP (set2, 1), 1)) == MEM 4633 || GET_CODE (XEXP (XEXP (set2, 1), 1)) == CONST_INT 4634 || GET_CODE (XEXP (XEXP (set2, 1), 1)) == CONST 4635 || GET_CODE (XEXP (XEXP (set2, 1), 1)) == SYMBOL_REF)) 4636 { 4637 rtx extend = gen_rtx_ZERO_EXTEND (HImode, 4638 gen_rtx_REG (QImode, regno + 1)); 4639 new_insn = gen_rtx_SET (HImode, XEXP (set2, 0), 4640 gen_rtx_PLUS (HImode, extend, 4641 XEXP (XEXP (set2, 1), 1))); 4642 new_insn = emit_insn_before (new_insn, try_insn); 4643 delete_insn (try_insn); 4644 try_insn = new_insn; 4645 } 4646 else if (GET_CODE (XEXP (set2, 1)) == PLUS 4647 && GET_CODE (XEXP (XEXP (set2, 1), 1)) == REG 4648 && GET_MODE_SIZE (GET_MODE (XEXP (XEXP (set2, 1), 1))) == 2 4649 && REGNO (XEXP (XEXP (set2, 1), 1)) == regno 4650 && (GET_CODE (XEXP (XEXP (set2, 1), 0)) == REG 4651 || GET_CODE (XEXP (XEXP (set2, 1), 0)) == MEM 4652 || GET_CODE (XEXP (XEXP (set2, 1), 0)) == CONST_INT 4653 || GET_CODE (XEXP (XEXP (set2, 1), 0)) == CONST 4654 || GET_CODE (XEXP (XEXP (set2, 1), 0)) == SYMBOL_REF)) 4655 { 4656 rtx t_src = gen_rtx_PLUS (HImode, 4657 gen_rtx_ZERO_EXTEND (HImode, 4658 gen_rtx_REG (QImode, 4659 regno 4660 + 1)), 4661 XEXP (XEXP (set2, 1), 0)); 4662 new_insn = emit_insn_before (gen_rtx_SET (HImode, XEXP (set2, 0), 4663 t_src), 4664 try_insn); 4665 delete_insn (try_insn); 4666 try_insn = new_insn; 4667 } 4668 } 4669} 4670 4671/* One of the things that can quite often happen with an 8-bit CPU is that 4672 we end up clearing the MSByte of a 16-bit value. Unfortunately, all too 4673 often gcc doesn't have any way to realize that only half of the value is 4674 useful and ends up doing more work than it should. We scan for such 4675 occurrences here, track them and reduce compare operations to a smaller 4676 size where possible. 4677 4678 Note that this is somewhat different to move propagation as we may 4679 actually change some instruction patterns when we're doing this whereas 4680 move propagation is just about doing a search and replace. */ 4681 4682static void 4683mdr_try_propagate_clr (first_insn) 4684 rtx first_insn; 4685{ 4686 rtx insn; 4687 rtx set; 4688 4689 for (insn = first_insn; insn; insn = next_nonnote_insn (insn)) 4690 { 4691 if (GET_CODE (insn) != INSN) 4692 continue; 4693 4694 set = (GET_CODE (PATTERN (insn)) == SET) ? PATTERN (insn) : NULL_RTX; 4695 if (set == NULL_RTX) 4696 continue; 4697 4698 /* Have we found a "clr" instruction? */ 4699 if (GET_CODE (XEXP (set, 0)) == REG 4700 && GET_CODE (XEXP (set, 1)) == CONST_INT 4701 && GET_MODE_SIZE (GET_MODE (XEXP (set, 0))) == 1 4702 && INTVAL (XEXP (set, 1)) == 0) 4703 { 4704 mdr_try_propagate_clr_sequence (insn, REGNO (XEXP (set, 0))); 4705 } 4706 } 4707} 4708#endif /* IP2K_MD_REORG_PASS */ 4709 4710/* Look to see if the expression, x, does not make any memory references 4711 via the specified register. This is very conservative and only returns 4712 nonzero if we definitely don't have such a memory ref. */ 4713 4714static int 4715ip2k_xexp_not_uses_reg_for_mem (x, regno) 4716 rtx x; 4717 unsigned int regno; 4718{ 4719 if (regno & 1) 4720 regno &= 0xfffffffe; 4721 4722 if (GET_RTX_CLASS (GET_CODE (x)) == 'b') 4723 return (ip2k_xexp_not_uses_reg_for_mem (XEXP (x, 0), regno) 4724 && ip2k_xexp_not_uses_reg_for_mem (XEXP (x, 1), regno) 4725 && ip2k_xexp_not_uses_reg_for_mem (XEXP (x, 2), regno)); 4726 4727 if (GET_RTX_CLASS (GET_CODE (x)) == '2' 4728 || GET_RTX_CLASS (GET_CODE (x)) == 'c' 4729 || GET_RTX_CLASS (GET_CODE (x)) == '<') 4730 return (ip2k_xexp_not_uses_reg_for_mem (XEXP (x, 0), regno) 4731 && ip2k_xexp_not_uses_reg_for_mem (XEXP (x, 1), regno)); 4732 4733 if (GET_RTX_CLASS (GET_CODE (x)) == '1' 4734 || GET_RTX_CLASS (GET_CODE (x)) == '3') 4735 return ip2k_xexp_not_uses_reg_for_mem (XEXP (x, 0), regno); 4736 4737 switch (GET_CODE (x)) 4738 { 4739 case REG: 4740 return 1; 4741 4742 case MEM: 4743 if ((GET_CODE (XEXP (x, 0)) == PLUS 4744 && GET_CODE (XEXP (XEXP (x, 0), 0)) == REG 4745 && REGNO (XEXP (XEXP (x, 0), 0)) == regno) 4746 || (GET_CODE (XEXP (x, 0)) == REG 4747 && REGNO (XEXP (x, 0)) == regno)) 4748 return 0; 4749 else 4750 return 1; 4751 4752 case CONST: 4753 case CONST_INT: 4754 case CONST_DOUBLE: 4755 case SYMBOL_REF: 4756 case LABEL_REF: 4757 case CC0: 4758 case PC: 4759 return 1; 4760 4761 default: 4762 return 0; 4763 } 4764} 4765 4766#ifdef IP2K_MD_REORG_PASS 4767/* Assist the following function, mdr_try_propagate_move(). */ 4768 4769static void 4770mdr_try_propagate_move_sequence (first_insn, orig, equiv) 4771 rtx first_insn; 4772 rtx orig; 4773 rtx equiv; 4774{ 4775 rtx try_insn; 4776 4777 for (try_insn = next_nonnote_insn (first_insn); try_insn; 4778 try_insn = next_nonnote_insn (try_insn)) 4779 { 4780 rtx set; 4781 int range; 4782 rtx new_equiv = NULL_RTX; 4783 4784 if (GET_CODE (try_insn) != JUMP_INSN && GET_CODE (try_insn) != INSN) 4785 break; 4786 4787 set = single_set (try_insn); 4788 if (set == NULL_RTX) 4789 break; 4790 4791 range = MAX (GET_MODE_SIZE (GET_MODE (equiv)), 4792 GET_MODE_SIZE (GET_MODE (XEXP (set, 0)))); 4793 4794 if (GET_CODE (equiv) == REG 4795 && REGNO (equiv) == REG_W 4796 && (recog_memoized (try_insn) < 0 4797 || get_attr_clobberw (try_insn) != CLOBBERW_NO) 4798 && (! (GET_CODE (XEXP (set, 0)) == REG 4799 && REGNO (XEXP (set, 0)) == REG_W 4800 && rtx_equal_p (XEXP (set, 1), orig)))) 4801 break; 4802 else if (GET_CODE (XEXP (set, 0)) == REG 4803 && (REGNO (XEXP (set, 0)) == REG_SP 4804 || ! ip2k_xexp_not_uses_reg_p (equiv, REGNO (XEXP (set, 0)), 4805 range) 4806 || ! ip2k_xexp_not_uses_reg_p (orig, REGNO (XEXP (set, 0)), 4807 range)) 4808 && ! rtx_equal_p (equiv, XEXP (set, 0)) 4809 && ! rtx_equal_p (orig, XEXP (set, 0))) 4810 break; 4811 else if (GET_CODE (orig) == REG 4812 && (REGNO (orig) == REG_IPL 4813 || REGNO (orig) == REG_IPH 4814 || REGNO (orig) == REG_DPL 4815 || REGNO (orig) == REG_DPH) 4816 && (! ip2k_xexp_not_uses_reg_for_mem (XEXP (set, 0), 4817 REGNO (orig)) 4818 || ! ip2k_xexp_not_uses_reg_for_mem (XEXP (set, 1), 4819 REGNO (orig)))) 4820 break; 4821 else if (GET_CODE (XEXP (set, 0)) == MEM 4822 && GET_CODE (equiv) == MEM) 4823 { 4824 if (! ip2k_xexp_not_uses_reg_p (equiv, REG_SP, 2)) 4825 { 4826 if (! ip2k_xexp_not_uses_reg_p (XEXP (set, 0), REG_SP, 2)) 4827 { 4828 /* We look for a special case of "push" operations screwing 4829 our register equivalence when it's based on a stack slot. 4830 We can track this one and replace the old equivalence 4831 expression with a new one. */ 4832 if (GET_CODE (XEXP (XEXP (set, 0), 0)) == POST_DEC 4833 && GET_CODE (XEXP (XEXP (XEXP (set, 0), 0), 0)) == REG 4834 && REGNO (XEXP (XEXP (XEXP (set, 0), 0), 0)) == REG_SP 4835 && GET_CODE (XEXP (equiv, 0)) == PLUS 4836 && REGNO (XEXP (XEXP (equiv, 0), 0)) == REG_SP) 4837 { 4838 int md_size = GET_MODE_SIZE (GET_MODE (XEXP (set, 0))); 4839 int new_sp_offs = INTVAL (XEXP (XEXP (equiv, 0), 1)) 4840 + md_size; 4841 4842 /* Don't allow an invalid stack pointer offset to be 4843 created. */ 4844 if (new_sp_offs > (128 - 2 * md_size)) 4845 break; 4846 4847 new_equiv 4848 = gen_rtx_MEM (GET_MODE (equiv), 4849 gen_rtx_PLUS (Pmode, 4850 gen_rtx_REG (HImode , 4851 REG_SP), 4852 GEN_INT (new_sp_offs))); 4853 } 4854 else if (! rtx_equal_p (equiv, XEXP (set, 0))) 4855 { 4856 /* Look at the SP offsets and look for any overlaps. */ 4857 int equiv_offs = GET_CODE (XEXP (equiv, 0)) == PLUS 4858 ? INTVAL (XEXP (XEXP (equiv, 0), 1)) 4859 : 0; 4860 int set_offs 4861 = (GET_CODE (XEXP (XEXP (set, 0), 0)) == PLUS 4862 ? INTVAL (XEXP (XEXP (XEXP (set, 0), 0), 1)) 4863 : 0); 4864 4865 if (abs (equiv_offs - set_offs) < range) 4866 break; 4867 } 4868 } 4869 } 4870 4871 if (! ip2k_xexp_not_uses_reg_p (equiv, REG_IP, 2)) 4872 break; 4873 4874 if (! ip2k_xexp_not_uses_reg_p (XEXP (set, 0), REG_DP, 2) 4875 && ! ip2k_xexp_not_uses_reg_p (equiv, REG_DP, 2) 4876 && ! rtx_equal_p (equiv, XEXP (set, 0))) 4877 { 4878 /* Look at the DP offsets and look for any overlaps. */ 4879 int equiv_offs = GET_CODE (XEXP (equiv, 0)) == PLUS 4880 ? INTVAL (XEXP (XEXP (equiv, 0), 1)) 4881 : 0; 4882 int set_offs = GET_CODE (XEXP (XEXP (set, 0), 0)) == PLUS 4883 ? INTVAL (XEXP (XEXP (XEXP (set, 0), 0), 1)) 4884 : 0; 4885 4886 if (abs (equiv_offs - set_offs) < range) 4887 break; 4888 } 4889 } 4890 4891 validate_replace_rtx_subexp (orig, equiv, try_insn, &XEXP (set, 1)); 4892 4893 if (rtx_equal_p (equiv, XEXP (set, 0)) 4894 || rtx_equal_p (orig, XEXP (set, 0))) 4895 break; 4896 4897 if (new_equiv != NULL_RTX) 4898 equiv = new_equiv; 4899 } 4900} 4901 4902/* Try propagating move instructions forwards. It may be that we can 4903 replace a register use with an equivalent expression that already 4904 holds the same value and thus allow one or more register loads to 4905 be eliminated. */ 4906 4907static void 4908mdr_try_propagate_move (first_insn) 4909 rtx first_insn; 4910{ 4911 rtx insn; 4912 rtx set; 4913 4914 for (insn = first_insn; insn; insn = next_nonnote_insn (insn)) 4915 { 4916 if (GET_CODE (insn) != INSN) 4917 continue; 4918 4919 set = (GET_CODE (PATTERN (insn)) == SET) ? PATTERN (insn) : NULL_RTX; 4920 if (set == NULL_RTX) 4921 continue; 4922 4923 /* Have we found a simple move instruction? */ 4924 if (GET_CODE (XEXP (set, 0)) == REG 4925 && (REGNO (XEXP (set, 0)) >= 0x80 4926 || REGNO (XEXP (set, 0)) == REG_DPL 4927 || REGNO (XEXP (set, 0)) == REG_DPH 4928 || REGNO (XEXP (set, 0)) == REG_IPL 4929 || REGNO (XEXP (set, 0)) == REG_IPH) 4930 && ((GET_CODE (XEXP (set, 1)) == REG 4931 && REGNO (XEXP (set, 1)) != REG_SP 4932 && ip2k_xexp_not_uses_reg_p (XEXP (set, 0), 4933 REGNO (XEXP (set, 1)), 4934 GET_MODE_SIZE (GET_MODE (XEXP (set, 4935 0))))) 4936 || (GET_CODE (XEXP (set, 1)) == MEM 4937 && (ip2k_xexp_not_uses_reg_p (XEXP (set, 1), REG_IP, 2) 4938 || GET_MODE (XEXP (set, 1)) == QImode) 4939 && ((REGNO (XEXP (set, 0)) != REG_DPH 4940 && REGNO (XEXP (set, 0)) != REG_DPL) 4941 || ip2k_xexp_not_uses_reg_p (XEXP (set, 1), REG_DP, 2))) 4942 || (GET_CODE (XEXP (set, 1)) == CONST_INT 4943 && (GET_MODE (XEXP (set, 0)) != QImode 4944 || INTVAL (XEXP (set, 1)) != 0)) 4945 || GET_CODE (XEXP (set, 1)) == CONST_DOUBLE 4946 || GET_CODE (XEXP (set, 1)) == CONST 4947 || GET_CODE (XEXP (set, 1)) == SYMBOL_REF)) 4948 { 4949 mdr_try_propagate_move_sequence (insn, XEXP (set, 0), XEXP (set, 1)); 4950 } 4951 } 4952} 4953 4954/* Try to remove redundant instructions. */ 4955 4956static void 4957mdr_try_remove_redundant_insns (first_insn) 4958 rtx first_insn; 4959{ 4960 rtx insn; 4961 4962 for (insn = first_insn; insn; insn = next_nonnote_insn (insn)) 4963 { 4964 rtx set; 4965 enum machine_mode mode; 4966 int md_size; 4967 HOST_WIDE_INT pattern; 4968 int i; 4969 4970 if (GET_CODE (insn) != INSN) 4971 continue; 4972 4973 if (GET_CODE (PATTERN (insn)) == CONST_INT) 4974 { 4975 /* We've found a dummy expression. */ 4976 rtx remove_insn = insn; 4977 insn = prev_nonnote_insn (insn); 4978 delete_insn (remove_insn); 4979 continue; 4980 } 4981 4982 set = (GET_CODE (PATTERN (insn)) == SET) ? PATTERN (insn) : NULL_RTX; 4983 if (set == NULL_RTX) 4984 continue; 4985 4986 mode = GET_MODE (XEXP (set, 0)); 4987 md_size = GET_MODE_SIZE (mode); 4988 if ((md_size < 1) || (md_size > 4)) 4989 continue; 4990 4991 pattern = 0; 4992 for (i = 0; i < md_size; i++) 4993 { 4994 pattern <<= 8; 4995 pattern |= 0xff; 4996 } 4997 4998 if ((GET_CODE (XEXP (set, 1)) == AND 4999 && GET_CODE (XEXP (XEXP (set, 1), 1)) == CONST_INT 5000 && INTVAL (XEXP (XEXP (set, 1), 1)) == pattern) 5001 || ((GET_CODE (XEXP (set, 1)) == IOR 5002 || GET_CODE (XEXP (set, 1)) == XOR) 5003 && GET_CODE (XEXP (XEXP (set, 1), 1)) == CONST_INT 5004 && INTVAL (XEXP (XEXP (set, 1), 1)) == 0x00)) 5005 { 5006 /* We've found an AND with all 1's, an XOR with all 0's or an 5007 IOR with 0's. */ 5008 rtx remove_insn = insn; 5009 5010 /* Is it completely redundant or should it become a move insn? */ 5011 if (! rtx_equal_p (XEXP (set, 0), XEXP (XEXP (set, 1), 0))) 5012 { 5013 emit_insn_before (gen_rtx_SET (mode, 5014 XEXP (set, 0), 5015 XEXP (XEXP (set, 1), 0)), 5016 insn); 5017 } 5018 5019 insn = prev_nonnote_insn(insn); 5020 delete_insn (remove_insn); 5021 } 5022 else if (GET_CODE (XEXP (set, 1)) == AND 5023 && GET_CODE (XEXP (XEXP (set, 1), 1)) == CONST_INT 5024 && INTVAL (XEXP (XEXP (set, 1), 1)) == 0) 5025 { 5026 /* We've found an AND with all 0's. */ 5027 rtx remove_insn = insn; 5028 insn = emit_insn_before (gen_rtx_SET (mode, 5029 XEXP (set, 0), 5030 XEXP (XEXP (set, 1), 1)), 5031 insn); 5032 delete_insn (remove_insn); 5033 } 5034 } 5035} 5036 5037/* Structure used to track jump targets. */ 5038 5039struct we_jump_targets 5040{ 5041 int target; /* Is this a jump target? */ 5042 int reach_count; /* Number of ways we can reach this insn. */ 5043 int touch_count; /* Number of times we've touched this insn 5044 during scanning. */ 5045 rtx w_equiv; /* WREG-equivalence at this point. */ 5046}; 5047 5048struct we_jump_targets *ip2k_we_jump_targets; 5049 5050/* WREG equivalence tracking used within DP reload elimination. */ 5051 5052static int 5053track_w_reload (insn, w_current, w_current_ok, modifying) 5054 rtx insn; 5055 rtx *w_current; 5056 int w_current_ok; 5057 int modifying; 5058{ 5059 rtx set; 5060 5061 if (GET_CODE (insn) != INSN) 5062 { 5063 *w_current = NULL_RTX; 5064 return 1; 5065 } 5066 5067 set = (GET_CODE (PATTERN (insn)) == SET) ? PATTERN (insn) : NULL_RTX; 5068 if (set == NULL_RTX) 5069 { 5070 *w_current = NULL_RTX; 5071 return 1; 5072 } 5073 5074 /* Look for W being modified. If it is, see if it's being changed 5075 to what it already is! */ 5076 if (GET_CODE (XEXP (set, 0)) == REG 5077 && REGNO (XEXP (set, 0)) == REG_W 5078 && GET_MODE (XEXP (set, 0)) == QImode) 5079 { 5080 /* If this is an equivalence we can delete the new set operation. */ 5081 if (*w_current != NULL_RTX 5082 && rtx_equal_p (XEXP (set, 1), *w_current)) 5083 { 5084 if (modifying) 5085 delete_insn (insn); 5086 } 5087 else 5088 { 5089 *w_current = XEXP (set, 1); 5090 return 1; 5091 } 5092 } 5093 else if (recog_memoized (insn) < 0 5094 || get_attr_clobberw (insn) != CLOBBERW_NO) 5095 { 5096 /* If we clobber W then we've clobbered any equivalences ! */ 5097 *w_current = NULL_RTX; 5098 return 1; 5099 } 5100 else if (! ip2k_xexp_not_uses_reg_p (XEXP (set, 0), REG_SP, 2) 5101 && *w_current != NULL_RTX 5102 && !ip2k_xexp_not_uses_reg_p (*w_current, REG_SP, 2)) 5103 { 5104 /* We look for a special case of "push" operations screwing up the 5105 setting of DP when it's based on the stack. We can track this one 5106 and replace the old expression for DP with a new one. */ 5107 if (GET_CODE (XEXP (set, 0)) == MEM 5108 && GET_CODE (XEXP (XEXP (set, 0), 0)) == POST_DEC 5109 && GET_CODE (XEXP (XEXP (XEXP (set, 0), 0), 0)) == REG 5110 && REGNO (XEXP (XEXP (XEXP (set, 0), 0), 0)) == REG_SP 5111 && GET_CODE (*w_current) == MEM 5112 && GET_CODE (XEXP (*w_current, 0)) == PLUS) 5113 { 5114 /* XXX - need to ensure that we can track this without going 5115 out of range! */ 5116 rtx val = GEN_INT (INTVAL (XEXP (XEXP (*w_current, 0), 1)) 5117 + GET_MODE_SIZE (GET_MODE (XEXP (set, 0)))); 5118 *w_current 5119 = gen_rtx_MEM (HImode, gen_rtx_PLUS (Pmode, 5120 gen_rtx_REG(HImode, REG_SP), 5121 val)); 5122 return 1; 5123 } 5124 } 5125 else if (GET_CODE (XEXP (set, 0)) == REG 5126 && *w_current != NULL_RTX 5127 && !ip2k_xexp_not_uses_reg_p (*w_current, REGNO (XEXP (set, 0)), 5128 GET_MODE_SIZE (GET_MODE (XEXP (set 5129 , 0))))) 5130 { 5131 /* If we've just clobbered all or part of a register reference that we 5132 were sharing for W then we can't share it any more! */ 5133 *w_current = NULL_RTX; 5134 } 5135 5136 return w_current_ok; 5137} 5138 5139/* As part of the machine-dependent reorg we scan moves into w and track them 5140 to see where any are redundant. */ 5141 5142static void 5143mdr_try_wreg_elim (first_insn) 5144 rtx first_insn; 5145{ 5146 rtx insn; 5147 struct we_jump_targets *wjt; 5148 rtx w_current; 5149 int incomplete_scan; 5150 int last_incomplete_scan; 5151 5152 ip2k_we_jump_targets 5153 = (struct we_jump_targets *) xcalloc (get_max_uid (), 5154 sizeof (struct we_jump_targets)); 5155 5156 /* First we scan to build up a list of all CODE_LABEL insns and we work out 5157 how many different ways we can reach them. */ 5158 for (insn = first_insn; insn; insn = next_nonnote_insn (insn)) 5159 { 5160 if (GET_CODE (insn) == CODE_LABEL) 5161 { 5162 wjt = &ip2k_we_jump_targets[INSN_UID (insn)]; 5163 wjt->target = 1; 5164 wjt->reach_count = LABEL_NUSES (insn); 5165 wjt->touch_count = 0; 5166 wjt->w_equiv = NULL_RTX; 5167 if (! prev_nonnote_insn (insn) 5168 || (prev_nonnote_insn (insn) 5169 && GET_CODE (prev_nonnote_insn (insn)) != BARRIER)) 5170 wjt->reach_count++; 5171 } 5172 } 5173 5174 /* Next we scan all of the ways of reaching the code labels to see 5175 what the WREG register is equivalent to as we reach them. If we find 5176 that they're the same then we keep noting the matched value. We 5177 iterate around this until we reach a convergence on WREG equivalences 5178 at all code labels - we have to be very careful not to be too 5179 optimistic! */ 5180 incomplete_scan = -1; 5181 do 5182 { 5183 int w_current_ok = 0; 5184 last_incomplete_scan = incomplete_scan; 5185 w_current = NULL_RTX; 5186 5187 for (insn = first_insn; insn; insn = next_nonnote_insn (insn)) 5188 { 5189 /* If we have a code label then we need to see if we already know 5190 what the equivalence is at this point. If we do then we use it 5191 immediately, but if we don't then we have a special case to track 5192 when we hit a fallthrough-edge (label with no barrier preceding 5193 it). Any other accesses to the label must be from jump insns 5194 and so they're handled elsewhere. */ 5195 if (GET_CODE (insn) == CODE_LABEL) 5196 { 5197 wjt = &ip2k_we_jump_targets[INSN_UID (insn)]; 5198 5199 /* If we're fully characterized the use the equivalence. */ 5200 if (wjt->touch_count == wjt->reach_count) 5201 { 5202 w_current = wjt->w_equiv; 5203 w_current_ok = 1; 5204 continue; 5205 } 5206 5207 /* If we have a known equivalence for WREG as we reach the 5208 fallthrough-edge then track this into the code label. */ 5209 if (w_current_ok 5210 && (! prev_nonnote_insn (insn) 5211 || (prev_nonnote_insn (insn) 5212 && GET_CODE (prev_nonnote_insn (insn)) != BARRIER))) 5213 { 5214 if (wjt->touch_count == 0) 5215 wjt->w_equiv = w_current; 5216 5217 if (wjt->touch_count < wjt->reach_count) 5218 { 5219 wjt->touch_count++; 5220 if (! rtx_equal_p (wjt->w_equiv, w_current)) 5221 { 5222 /* When we definitely know that we can't form an 5223 equivalence for WREG here we must clobber anything 5224 that we'd started to track too. */ 5225 wjt->w_equiv = NULL_RTX; 5226 w_current = NULL_RTX; 5227 w_current_ok = 1; 5228 } 5229 } 5230 } 5231 5232 /* If we've not completely characterized this code label then 5233 be cautious and assume that we don't know what WREG is 5234 equivalent to. */ 5235 if (wjt->touch_count < wjt->reach_count) 5236 { 5237 w_current = NULL_RTX; 5238 w_current_ok = 0; 5239 } 5240 5241 continue; 5242 } 5243 5244 /* If we've hit a jump insn then we look for either an address 5245 vector (jump table) or for jump label references. */ 5246 if (GET_CODE (insn) == JUMP_INSN) 5247 { 5248 /* Don't attempt to track here if we don't have a known 5249 equivalence for WREG at this point. */ 5250 if (w_current_ok) 5251 { 5252 if (JUMP_LABEL (insn)) 5253 { 5254 wjt 5255 = &ip2k_we_jump_targets[INSN_UID (JUMP_LABEL (insn))]; 5256 5257 if (wjt->touch_count == 0) 5258 wjt->w_equiv = w_current; 5259 5260 if (wjt->touch_count < wjt->reach_count) 5261 { 5262 wjt->touch_count++; 5263 if (! rtx_equal_p (wjt->w_equiv, w_current)) 5264 wjt->w_equiv = NULL_RTX; 5265 } 5266 } 5267 } 5268 5269 continue; 5270 } 5271 5272 /* Anything other than a code labal or jump arrives here. We try and 5273 track WREG, but sometimes we might not be able to. */ 5274 w_current_ok = track_w_reload (insn, &w_current, w_current_ok, 0); 5275 } 5276 5277 /* When we're looking to see if we've finished we count the number of 5278 paths throught the code labels where we weren't able to definitively 5279 track WREG. This number is used to see if we're converging on a 5280 solution. 5281 If this hits zero then we've fully converged, but if this stays the 5282 same as last time then we probably can't make any further 5283 progress. */ 5284 incomplete_scan = 0; 5285 for (insn = first_insn; insn; insn = next_nonnote_insn (insn)) 5286 { 5287 if (GET_CODE (insn) == CODE_LABEL) 5288 { 5289 wjt = &ip2k_we_jump_targets[INSN_UID (insn)]; 5290 if (wjt->touch_count != wjt->reach_count) 5291 { 5292 incomplete_scan += (wjt->reach_count - wjt->touch_count); 5293 wjt->w_equiv = NULL_RTX; 5294 wjt->touch_count = 0; 5295 } 5296 } 5297 } 5298 } 5299 while (incomplete_scan && incomplete_scan != last_incomplete_scan); 5300 5301 /* Finally we scan the whole function and run WREG elimination. When we hit 5302 a CODE_LABEL we pick up any stored equivalence since we now know that 5303 every path to this point entered with WREG holding the same thing! If 5304 we subsequently have a reload that matches then we can eliminate it. */ 5305 w_current = NULL_RTX; 5306 for (insn = first_insn; insn; insn = next_nonnote_insn (insn)) 5307 { 5308 if (GET_CODE (insn) == JUMP_INSN) 5309 continue; 5310 5311 if (GET_CODE (insn) == CODE_LABEL) 5312 { 5313 wjt = &ip2k_we_jump_targets[INSN_UID (insn)]; 5314 w_current = wjt->w_equiv; 5315 continue; 5316 } 5317 5318 track_w_reload (insn, &w_current, 1, 1); 5319 } 5320 5321 free (ip2k_we_jump_targets); 5322} 5323#endif /* IP2K_MD_REORG_PASS */ 5324 5325/* We perform a lot of untangling of the RTL within the reorg pass since 5326 the IP2k requires some really bizarre (and really undesireable) things 5327 to happen in order to guarantee not aborting. This pass causes several 5328 earlier passes to be re-run as it progressively transforms things, 5329 making the subsequent runs continue to win. */ 5330 5331void 5332machine_dependent_reorg (first_insn) 5333 rtx first_insn ATTRIBUTE_UNUSED; 5334{ 5335#ifdef IP2K_MD_REORG_PASS 5336 rtx insn, set; 5337#endif 5338 5339 CC_STATUS_INIT; 5340 5341 if (optimize == 0) 5342 { 5343 ip2k_reorg_completed = 1; 5344 ip2k_reorg_split_dimode = 1; 5345 ip2k_reorg_split_simode = 1; 5346 ip2k_reorg_split_himode = 1; 5347 ip2k_reorg_split_qimode = 1; 5348 ip2k_reorg_merge_qimode = 1; 5349 return; 5350 } 5351#ifndef IP2K_MD_REORG_PASS 5352 ip2k_reorg_completed = 1; 5353 ip2k_reorg_split_dimode = 1; 5354 ip2k_reorg_split_simode = 1; 5355 ip2k_reorg_split_himode = 1; 5356 ip2k_reorg_split_qimode = 1; 5357 ip2k_reorg_merge_qimode = 1; 5358#else 5359 /* All optimizations below must be debugged and enabled one by one. 5360 All of them commented now because of abort in GCC core. */ 5361 5362 ip2k_reorg_in_progress = 1; 5363 5364 /* Look for size effects of earlier optimizations - in particular look for 5365 situations where we're saying "use" a register on one hand but immediately 5366 tagging it as "REG_DEAD" at the same time! Seems like a bug in core-gcc 5367 somewhere really but this is what we have to live with! */ 5368 for (insn = first_insn; insn; insn = NEXT_INSN (insn)) 5369 { 5370 rtx body; 5371 5372 if (GET_CODE (insn) == CODE_LABEL 5373 || GET_CODE (insn) == NOTE 5374 || GET_CODE (insn) == BARRIER) 5375 continue; 5376 5377 if (GET_RTX_CLASS (GET_CODE (insn)) != 'i') 5378 continue; 5379 5380 body = PATTERN (insn); 5381 if (GET_CODE (body) == USE) 5382 if (GET_CODE (XEXP (body, 0)) == REG) 5383 { 5384 int reg; 5385 5386 reg = REGNO (XEXP (body, 0)); 5387 if (find_regno_note (insn, REG_DEAD, reg)) 5388 { 5389 delete_insn (insn); 5390 } 5391 } 5392 } 5393 5394 /* There's a good chance that since we last did CSE that we've rearranged 5395 things in such a way that another go will win. Do so now! */ 5396 reload_cse_regs (first_insn); 5397 find_basic_blocks (first_insn, max_reg_num (), 0); 5398 life_analysis (first_insn, 0, PROP_REG_INFO | PROP_DEATH_NOTES); 5399 5400 /* Look for where absurd things are happening with DP. */ 5401 mdr_try_dp_reload_elim (first_insn); 5402 5403 ip2k_reorg_in_progress = 0; 5404 ip2k_reorg_completed = 1; 5405 5406 split_all_insns (0); 5407 5408 reload_cse_regs (first_insn); 5409 find_basic_blocks (first_insn, max_reg_num (), 0); 5410 life_analysis (first_insn, 0, PROP_REG_INFO | PROP_DEATH_NOTES); 5411 if (flag_peephole2) 5412 peephole2_optimize (NULL); 5413 5414 mdr_resequence_xy_yx (first_insn); 5415 mdr_propagate_reg_equivs (first_insn); 5416 5417 /* Look for redundant set instructions. These can occur when we split 5418 instruction patterns and end up with the second half merging with 5419 or being replaced by something that clobbers the first half. */ 5420 for (insn = first_insn; insn; insn = next_nonnote_insn (insn)) 5421 { 5422 if (GET_CODE (insn) == INSN) 5423 { 5424 set = (GET_CODE (PATTERN (insn)) == SET) ? PATTERN (insn) : NULL_RTX; 5425 if ((set != NULL_RTX) 5426 && (GET_CODE (XEXP (set, 0)) == REG) 5427 && (GET_MODE (XEXP (set, 0)) == QImode) 5428 && (find_regno_note (insn, REG_UNUSED, REGNO (XEXP (set, 0))))) 5429 delete_insn (insn); 5430 } 5431 } 5432 5433 mdr_try_move_dp_reload (first_insn); 5434 mdr_try_move_pushes (first_insn); 5435 5436 find_basic_blocks (first_insn, max_reg_num (), 0); 5437 life_analysis (first_insn, 0, PROP_FINAL); 5438 5439 mdr_try_propagate_move (first_insn); 5440 mdr_resequence_xy_yx (first_insn); 5441 5442 ip2k_reorg_split_dimode = 1; 5443 split_all_insns (0); 5444 5445 mdr_try_remove_redundant_insns (first_insn); 5446 5447 mdr_try_propagate_move (first_insn); 5448 5449 reload_cse_regs (first_insn); 5450 find_basic_blocks (first_insn, max_reg_num (), 0); 5451 life_analysis (first_insn, 0, PROP_FINAL); 5452 if (flag_peephole2) 5453 peephole2_optimize (NULL); 5454 5455 mdr_try_propagate_move (first_insn); 5456 5457 find_basic_blocks (first_insn, max_reg_num (), 0); 5458 life_analysis (first_insn, 0, PROP_FINAL); 5459 5460 ip2k_reorg_split_simode = 1; 5461 split_all_insns (0); 5462 5463 mdr_try_remove_redundant_insns (first_insn); 5464 5465 mdr_try_propagate_move (first_insn); 5466 5467 reload_cse_regs (first_insn); 5468 find_basic_blocks (first_insn, max_reg_num (), 0); 5469 life_analysis (first_insn, 0, PROP_FINAL); 5470 if (flag_peephole2) 5471 peephole2_optimize (NULL); 5472 5473 mdr_try_propagate_move (first_insn); 5474 5475 find_basic_blocks (first_insn, max_reg_num (), 0); 5476 life_analysis (first_insn, 0, PROP_FINAL); 5477 5478 ip2k_reorg_split_himode = 1; 5479 ip2k_reorg_merge_qimode = 1; 5480 split_all_insns (0); 5481 5482 mdr_try_remove_redundant_insns (first_insn); 5483 mdr_try_propagate_clr (first_insn); 5484 mdr_try_propagate_move (first_insn); 5485 5486 mdr_try_dp_reload_elim (first_insn); 5487 mdr_try_move_dp_reload (first_insn); 5488 5489 rebuild_jump_labels (first_insn); 5490 5491 /* Call to jump_optimize (...) was here, but now I removed it. */ 5492 5493 find_basic_blocks (first_insn, max_reg_num (), 0); 5494 life_analysis (first_insn, 0, PROP_FINAL); 5495 if (flag_peephole2) 5496 peephole2_optimize (NULL); 5497 5498 mdr_try_propagate_move (first_insn); 5499 5500 find_basic_blocks (first_insn, max_reg_num (), 0); 5501 life_analysis (first_insn, 0, PROP_FINAL); 5502 mdr_try_remove_redundant_insns (first_insn); 5503 5504 mdr_try_propagate_clr (first_insn); 5505 mdr_try_propagate_move (first_insn); 5506 5507 find_basic_blocks (first_insn, max_reg_num (), 0); 5508 life_analysis (first_insn, 0, PROP_FINAL); 5509 5510 ip2k_reorg_split_qimode = 1; 5511 split_all_insns (0); 5512 5513 mdr_try_wreg_elim (first_insn); 5514 mdr_try_propagate_move (first_insn); 5515 5516 find_basic_blocks (first_insn, max_reg_num (), 0); 5517 life_analysis (first_insn, 0, PROP_FINAL); 5518#endif 5519} 5520 5521/* Returns a bit position if mask contains only a single bit. Returns -1 if 5522 there were zero or more than one set bits. */ 5523int 5524find_one_set_bit_p (mask) 5525 HOST_WIDE_INT mask; 5526{ 5527 int i; 5528 unsigned HOST_WIDE_INT n = mask; 5529 for (i = 0; i < 32; i++) 5530 { 5531 if (n & 0x80000000UL) 5532 { 5533 if (n & 0x7fffffffUL) 5534 return -1; 5535 else 5536 return 31 - i; 5537 } 5538 n <<= 1; 5539 } 5540 return -1; 5541} 5542 5543/* Returns a bit position if mask contains only a single clear bit. 5544 Returns -1 if there were zero or more than one clear bits. */ 5545int 5546find_one_clear_bit_p (mask) 5547 HOST_WIDE_INT mask; 5548{ 5549 int i; 5550 unsigned HOST_WIDE_INT n = mask; 5551 for (i = 0; i < 32; i++) 5552 { 5553 if ((n & 0x80000000UL) == 0UL) 5554 { 5555 if ((n & 0x7fffffffUL) != 0x7fffffffUL) 5556 return -1; 5557 else 5558 return 31 - i; 5559 } 5560 n <<= 1; 5561 n |= 1; 5562 } 5563 return -1; 5564} 5565 5566 5567/* Split a move into two smaller pieces. 5568 MODE indicates the reduced mode. OPERANDS[0] is the original destination 5569 OPERANDS[1] is the original src. The new destinations are 5570 OPERANDS[2] and OPERANDS[4], while the new sources are OPERANDS[3] 5571 and OPERANDS[5]. */ 5572 5573void 5574ip2k_split_words (nmode, omode, operands) 5575 enum machine_mode nmode; 5576 enum machine_mode omode; 5577 rtx *operands; 5578{ 5579 rtx dl, dh; /* src/dest pieces. */ 5580 rtx sl, sh; 5581 int move_high_first = 0; /* Assume no overlap. */ 5582 int pushflag = 0; 5583 5584 switch (GET_CODE (operands[0])) /* DEST */ 5585 { 5586 case SUBREG: 5587 case REG: 5588 if ((GET_CODE (operands[1]) == REG 5589 || GET_CODE (operands[1]) == SUBREG) 5590 && (true_regnum (operands[0]) <= true_regnum (operands[1]) 5591 || (true_regnum (operands[1]) 5592 + GET_MODE_SIZE (omode) - 1 < true_regnum (operands[0])))) 5593 move_high_first = 1; 5594 5595 if (GET_CODE (operands[0]) == SUBREG) 5596 { 5597 dl = simplify_gen_subreg (nmode, operands[0], omode, 5598 GET_MODE_SIZE (nmode)); 5599 dh = simplify_gen_subreg (nmode, operands[0], omode, 0); 5600 } 5601 else if (GET_CODE (operands[0]) == REG && ! IS_PSEUDO_P (operands[0])) 5602 { 5603 int r = REGNO (operands[0]); 5604 dh = gen_rtx_REG (nmode, r); 5605 dl = gen_rtx_REG (nmode, r + HARD_REGNO_NREGS (r, nmode)); 5606 } 5607 else 5608 { 5609 dh = gen_rtx_SUBREG (nmode, operands[0], 0); 5610 dl = gen_rtx_SUBREG (nmode, operands[0], GET_MODE_SIZE (nmode)); 5611 } 5612 break; 5613 5614 case MEM: 5615 switch (GET_CODE (XEXP (operands[0], 0))) 5616 { 5617 case POST_INC: 5618 abort (); 5619 case POST_DEC: 5620 dl = dh = gen_rtx_MEM (nmode, XEXP (operands[0], 0)); 5621 pushflag = 1; 5622 break; 5623 default: 5624 dl = change_address (operands[0], nmode, 5625 plus_constant (XEXP (operands[0], 0), 5626 GET_MODE_SIZE (nmode))); 5627 dh = gen_rtx_MEM (nmode, XEXP (operands[0], 0)); 5628 } 5629 break; 5630 default: 5631 abort (); 5632 } 5633 5634 switch (GET_CODE (operands[1])) 5635 { 5636 case REG: 5637 if (! IS_PSEUDO_P (operands[1])) 5638 { 5639 int r = REGNO (operands[1]); 5640 5641 sh = gen_rtx_REG (nmode, r); 5642 sl = gen_rtx_REG (nmode, r + HARD_REGNO_NREGS (r, nmode)); 5643 } 5644 else 5645 { 5646 sh = gen_rtx_SUBREG (nmode, operands[1], 0); 5647 sl = gen_rtx_SUBREG (nmode, operands[1], GET_MODE_SIZE (nmode)); 5648 } 5649 break; 5650 5651 case CONST_DOUBLE: 5652 if (operands[1] == const0_rtx) 5653 sh = sl = const0_rtx; 5654 else 5655 { 5656 if (GET_MODE (operands[0]) != DImode) 5657 { 5658 REAL_VALUE_TYPE rv; 5659 long value; 5660 5661 REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[1]); 5662 REAL_VALUE_TO_TARGET_SINGLE (rv, value); 5663 5664 sh = gen_int_mode ((value >> 16) & 0xffff, nmode); 5665 sl = gen_int_mode (value & 0xffff, nmode); 5666 } 5667 else 5668 { 5669 sh = gen_int_mode (CONST_DOUBLE_HIGH (operands[1]), nmode); 5670 sl = gen_int_mode (CONST_DOUBLE_LOW (operands[1]), nmode); 5671 } 5672 } 5673 break; 5674 5675 case CONST_INT: 5676 if (operands[1] == const0_rtx) 5677 sh = sl = const0_rtx; 5678 else 5679 { 5680 int val = INTVAL (operands[1]); 5681 int vl, vh; 5682 5683 switch (nmode) 5684 { 5685 case QImode: 5686 vh = (val >> 8) & 0xff; 5687 vl = val & 0xff; 5688 break; 5689 5690 case HImode: 5691 vh = (val >> 16) & 0xffff; 5692 vl = val & 0xffff; 5693 break; 5694 5695 case SImode: 5696 if (val < 0) /* sign extend */ 5697 vh = -1; 5698 else 5699 vh = 0; 5700 vl = val; /* Give low 32 bits back. */ 5701 break; 5702 5703 default: 5704 abort (); 5705 } 5706 5707 sl = gen_int_mode (vl, nmode); 5708 sh = gen_int_mode (vh, nmode); 5709 } 5710 break; 5711 5712 case SUBREG: 5713 sl = simplify_gen_subreg (nmode, operands[1], omode, 5714 GET_MODE_SIZE (nmode)); 5715 sh = simplify_gen_subreg (nmode, operands[1], omode, 0); 5716 break; 5717 5718 case MEM: 5719 switch (GET_CODE (XEXP (operands[1], 0))) 5720 { 5721 case POST_DEC: 5722 case POST_INC: 5723 abort (); 5724 break; 5725 5726 default: 5727 /* Worry about splitting stack pushes. */ 5728 if (pushflag && ip2k_address_uses_reg_p (operands[1], REG_SP)) 5729 sl = sh = change_address (operands[1], nmode, 5730 plus_constant (XEXP (operands[1], 0), 5731 GET_MODE_SIZE (nmode))); 5732 else 5733 { 5734 sl = change_address (operands[1], nmode, 5735 plus_constant (XEXP (operands[1], 0), 5736 GET_MODE_SIZE (nmode))); 5737 sh = gen_rtx_MEM (nmode, XEXP (operands[1], 0)); 5738 } 5739 } 5740 break; 5741 5742 default: 5743 abort (); 5744 } 5745 5746 if (move_high_first) 5747 { 5748 operands[2] = dh; 5749 operands[3] = sh; 5750 operands[4] = dl; 5751 operands[5] = sl; 5752 } 5753 else 5754 { 5755 operands[2] = dl; 5756 operands[3] = sl; 5757 operands[4] = dh; 5758 operands[5] = sh; 5759 } 5760 return; 5761} 5762 5763/* Get the low half of an operand. */ 5764rtx 5765ip2k_get_low_half (x, mode) 5766 rtx x; 5767 enum machine_mode mode; 5768{ 5769 switch (GET_CODE (x)) 5770 { 5771 case REG: 5772 if (! IS_PSEUDO_P (x)) 5773 { 5774 unsigned int r = REGNO (x); 5775 5776 return gen_rtx_REG (mode, r + HARD_REGNO_NREGS (r, mode)); 5777 } 5778 else 5779 { 5780 return gen_rtx_SUBREG (mode, x, GET_MODE_SIZE (mode)); 5781 } 5782 break; 5783 5784 case CONST_DOUBLE: 5785 if (x == const0_rtx) 5786 return const0_rtx; 5787 else 5788 { 5789 if (mode != SImode) 5790 { 5791 REAL_VALUE_TYPE rv; 5792 long value; 5793 5794 REAL_VALUE_FROM_CONST_DOUBLE (rv, x); 5795 REAL_VALUE_TO_TARGET_SINGLE (rv, value); 5796 5797 return gen_int_mode (value & 0xffff, mode); 5798 } 5799 else 5800 return gen_int_mode (CONST_DOUBLE_LOW (x), mode); 5801 } 5802 break; 5803 5804 case CONST_INT: 5805 if (x == const0_rtx) 5806 return const0_rtx; 5807 else 5808 { 5809 int val = INTVAL (x); 5810 int vl, vh; 5811 5812 switch (mode) 5813 { 5814 case QImode: 5815 vh = (val >> 8) & 0xff; 5816 vl = val & 0xff; 5817 break; 5818 5819 case HImode: 5820 vh = (val >> 16) & 0xffff; 5821 vl = val & 0xffff; 5822 break; 5823 5824 case SImode: 5825 if (val < 0) /* sign extend */ 5826 vh = -1; 5827 else 5828 vh = 0; 5829 vl = val; /* Give low 32 bits back. */ 5830 break; 5831 5832 default: 5833 abort (); 5834 } 5835 5836 return gen_int_mode (vl, mode); 5837 } 5838 break; 5839 5840 case SUBREG: 5841 return simplify_gen_subreg (mode, x, GET_MODE (x), GET_MODE_SIZE (mode)); 5842 5843 case MEM: 5844 switch (GET_CODE (XEXP (x, 0))) 5845 { 5846 case POST_DEC: 5847 case POST_INC: 5848 abort (); 5849 break; 5850 5851 default: 5852 return change_address (x, mode, 5853 plus_constant (XEXP (x, 0), 5854 GET_MODE_SIZE (mode))); 5855 } 5856 break; 5857 5858 default: 5859 abort (); 5860 } 5861 return NULL_RTX; 5862} 5863 5864/* Get the high half of an operand. */ 5865rtx 5866ip2k_get_high_half (x, mode) 5867 rtx x; 5868 enum machine_mode mode; 5869{ 5870 switch (GET_CODE (x)) 5871 { 5872 case REG: 5873 if (! IS_PSEUDO_P (x)) 5874 { 5875 unsigned int r = REGNO (x); 5876 5877 return gen_rtx_REG (mode, r); 5878 } 5879 else 5880 { 5881 return gen_rtx_SUBREG (mode, x, 0); 5882 } 5883 break; 5884 5885 case CONST_DOUBLE: 5886 if (x == const0_rtx) 5887 return const0_rtx; 5888 else 5889 { 5890 if (mode != SImode) 5891 { 5892 REAL_VALUE_TYPE rv; 5893 long value; 5894 5895 REAL_VALUE_FROM_CONST_DOUBLE (rv, x); 5896 REAL_VALUE_TO_TARGET_SINGLE (rv, value); 5897 5898 return gen_int_mode ((value >> 16) & 0xffff, mode); 5899 } 5900 else 5901 return gen_int_mode (CONST_DOUBLE_HIGH (x), mode); 5902 } 5903 break; 5904 5905 case CONST_INT: 5906 if (x == const0_rtx) 5907 return const0_rtx; 5908 else 5909 { 5910 int val = INTVAL (x); 5911 int vl, vh; 5912 5913 switch (mode) 5914 { 5915 case QImode: 5916 vh = (val >> 8) & 0xff; 5917 vl = val & 0xff; 5918 break; 5919 5920 case HImode: 5921 vh = (val >> 16) & 0xffff; 5922 vl = val & 0xffff; 5923 break; 5924 5925 case SImode: 5926 if (val < 0) /* sign extend */ 5927 vh = -1; 5928 else 5929 vh = 0; 5930 vl = val; /* Give low 32 bits back. */ 5931 break; 5932 5933 default: 5934 abort (); 5935 } 5936 5937 return gen_int_mode (vh, mode); 5938 } 5939 break; 5940 5941 case SUBREG: 5942 return simplify_gen_subreg (mode, x, GET_MODE (x), 0); 5943 break; 5944 5945 case MEM: 5946 switch (GET_CODE (XEXP (x, 0))) 5947 { 5948 case POST_DEC: 5949 case POST_INC: 5950 abort (); 5951 break; 5952 5953 default: 5954 return change_address (x, mode, plus_constant (XEXP (x, 0), 0)); 5955 } 5956 break; 5957 5958 default: 5959 abort (); 5960 } 5961 return NULL_RTX; 5962} 5963 5964/* Does address X use register R. Only valid for REG_SP, REG_DP, REG_IP 5965 or REG_FP. */ 5966 5967int 5968ip2k_address_uses_reg_p (x, r) 5969 rtx x; 5970 unsigned int r; 5971{ 5972 if (GET_CODE (x) != MEM) 5973 return 0; 5974 5975 x = XEXP (x, 0); 5976 5977 while (1) 5978 switch (GET_CODE (x)) 5979 { 5980 case POST_DEC: 5981 case POST_INC: 5982 case PRE_DEC: 5983 case PRE_INC: 5984 x = XEXP (x, 0); 5985 break; 5986 5987 case PLUS: 5988 if (ip2k_address_uses_reg_p (XEXP (x, 1), r)) 5989 return 1; 5990 5991 x = XEXP (x, 0); 5992 break; 5993 5994 case SUBREG: 5995 /* Ignore subwords. */ 5996 x = SUBREG_REG (x); 5997 break; 5998 5999 case REG: 6000 /* Have to consider that r might be LSB of a pointer reg. */ 6001 return ((REGNO (x) == r) || (REGNO (x) == (r - 1))) ? 1 : 0; 6002 6003 case MEM: 6004 /* We might be looking at a (mem:BLK (mem (...))) */ 6005 x = XEXP (x, 0); 6006 break; 6007 6008 default: 6009 return 0; 6010 }; 6011} 6012 6013/* Does the queried XEXP not use a particular register? If we're certain 6014 that it doesn't then we return TRUE otherwise we assume FALSE. */ 6015 6016int 6017ip2k_xexp_not_uses_reg_p (x, r, rsz) 6018 rtx x; 6019 unsigned int r; 6020 int rsz; 6021{ 6022 switch (GET_CODE (x)) 6023 { 6024 case REG: 6025 { 6026 int msz = GET_MODE_SIZE (GET_MODE (x)); 6027 6028 return (((REGNO (x) + msz - 1) < r) 6029 || (REGNO (x) > (r + rsz - 1))); 6030 } 6031 6032 case MEM: 6033 return !ip2k_address_uses_reg_p (x, r); 6034 6035 case LABEL_REF: 6036 case SYMBOL_REF: 6037 case CONST: 6038 case CONST_INT: 6039 case CONST_DOUBLE: 6040 case CC0: 6041 case PC: 6042 return 1; 6043 6044 default: 6045 return 0; 6046 } 6047} 6048 6049/* Does the queried XEXP not use a particular register? If we're certain 6050 that it doesn't then we return TRUE otherwise we assume FALSE. */ 6051 6052int 6053ip2k_composite_xexp_not_uses_reg_p (x, r, rsz) 6054 rtx x; 6055 unsigned int r; 6056 int rsz; 6057{ 6058 if (GET_RTX_CLASS (GET_CODE (x)) == 'b') 6059 return (ip2k_composite_xexp_not_uses_reg_p (XEXP (x, 0), r, rsz) 6060 && ip2k_composite_xexp_not_uses_reg_p (XEXP (x, 1), r, rsz) 6061 && ip2k_composite_xexp_not_uses_reg_p (XEXP (x, 2), r, rsz)); 6062 6063 if (GET_RTX_CLASS (GET_CODE (x)) == '2' 6064 || GET_RTX_CLASS (GET_CODE (x)) == 'c' 6065 || GET_RTX_CLASS (GET_CODE (x)) == '<') 6066 return (ip2k_composite_xexp_not_uses_reg_p (XEXP (x, 0), r, rsz) 6067 && ip2k_composite_xexp_not_uses_reg_p (XEXP (x, 1), r, rsz)); 6068 6069 if (GET_RTX_CLASS (GET_CODE (x)) == '1' 6070 || GET_RTX_CLASS (GET_CODE (x)) == '3') 6071 return ip2k_composite_xexp_not_uses_reg_p (XEXP (x, 0), r, rsz); 6072 6073 return ip2k_xexp_not_uses_reg_p (x, r, rsz); 6074} 6075 6076/* Does the queried XEXP not use CC0? If we're certain that 6077 it doesn't then we return TRUE otherwise we assume FALSE. */ 6078 6079int 6080ip2k_composite_xexp_not_uses_cc0_p (x) 6081 rtx x; 6082{ 6083 if (GET_RTX_CLASS (GET_CODE (x)) == 'b') 6084 return (ip2k_composite_xexp_not_uses_cc0_p (XEXP (x, 0)) 6085 && ip2k_composite_xexp_not_uses_cc0_p (XEXP (x, 1)) 6086 && ip2k_composite_xexp_not_uses_cc0_p (XEXP (x, 2))); 6087 6088 if (GET_RTX_CLASS (GET_CODE (x)) == '2' 6089 || GET_RTX_CLASS (GET_CODE (x)) == 'c' 6090 || GET_RTX_CLASS (GET_CODE (x)) == '<') 6091 return (ip2k_composite_xexp_not_uses_cc0_p (XEXP (x, 0)) 6092 && ip2k_composite_xexp_not_uses_cc0_p (XEXP (x, 1))); 6093 6094 if (GET_RTX_CLASS (GET_CODE (x)) == '1' 6095 || GET_RTX_CLASS (GET_CODE (x)) == '3') 6096 return ip2k_composite_xexp_not_uses_cc0_p (XEXP (x, 0)); 6097 6098 return GET_CODE (x) != CC0; 6099} 6100 6101int 6102ip2k_split_dest_operand (x, mode) 6103 rtx x; 6104 enum machine_mode mode; 6105{ 6106 return nonimmediate_operand (x, mode) || push_operand (x, mode); 6107} 6108 6109int 6110ip2k_nonptr_operand (x, mode) 6111 rtx x; 6112 enum machine_mode mode; 6113{ 6114 return register_operand (x, mode) && !ip2k_ptr_operand (x, mode); 6115} 6116 6117/* Is X a reference to IP or DP or SP? */ 6118 6119int 6120ip2k_ptr_operand (x, mode) 6121 rtx x; 6122 enum machine_mode mode; 6123 6124{ 6125 if (GET_CODE (x) == SUBREG) 6126 x = SUBREG_REG (x); 6127 6128 return (REG_P (x) 6129 && (mode == HImode || mode == VOIDmode) 6130 && (REGNO (x) == REG_IP 6131 || REGNO (x) == REG_DP 6132 || REGNO (x) == REG_SP)); 6133} 6134 6135int 6136ip2k_sp_operand (x, mode) 6137 rtx x; 6138 enum machine_mode mode ATTRIBUTE_UNUSED; 6139 6140{ 6141 return REG_P (x) && REGNO (x) == REG_SP; 6142} 6143 6144int 6145ip2k_ip_operand (x, mode) 6146 rtx x; 6147 enum machine_mode mode; 6148 6149{ 6150 if (GET_CODE (x) != MEM) 6151 return 0; 6152 6153 x = XEXP (x, 0); 6154 6155 if (GET_CODE (x) == PLUS && XEXP (x, 1) == const0_rtx) 6156 x = XEXP (x, 0); 6157 6158 if (! REG_P (x)) 6159 return 0; 6160 6161 if (GET_MODE_SIZE (mode) > 1) 6162 return 0; /* Can't access offset bytes. */ 6163 6164 return REGNO (x) == REG_IP; 6165} 6166 6167/* Is X a memory address suitable for SP or DP relative addressing? */ 6168int 6169ip2k_short_operand (x, mode) 6170 rtx x; 6171 enum machine_mode mode; 6172{ 6173 int r; 6174 unsigned int offs = 0; 6175 6176 if (! memory_operand (x, mode)) 6177 return 0; /* Got to be a memory address. */ 6178 6179 x = XEXP (x, 0); 6180 switch (GET_CODE (x)) 6181 { 6182 default: 6183 return 0; 6184 6185 case PLUS: 6186 if (! REG_P (XEXP (x, 0)) 6187 || GET_CODE (XEXP (x, 1)) != CONST_INT) 6188 return 0; 6189 6190 offs = INTVAL (XEXP (x, 1)); 6191 6192 if (128 <= offs) 6193 return 0; 6194 6195 x = XEXP (x, 0); 6196 6197 /* fall thru */ 6198 6199 case REG: 6200 if (IS_PSEUDO_P (x)) 6201 return 0; /* Optimistic - doesn't work. */ 6202 6203 r = REGNO (x); 6204 6205 /* For 'S' constraint, we presume that no IP adjustment 6206 simulation is performed - so only QI mode allows IP to be a 6207 short offset address. All other IP references must be 6208 handled by 'R' constraints. */ 6209 if (r == REG_IP && offs == 0 && GET_MODE_SIZE (mode) <= 1) 6210 return 1; 6211 6212 return (r == REG_SP || r == REG_DP); 6213 } 6214} 6215 6216int 6217ip2k_nonsp_reg_operand (x, mode) 6218 rtx x; 6219 enum machine_mode mode ATTRIBUTE_UNUSED; 6220{ 6221 if (GET_CODE (x) == SUBREG) 6222 x = SUBREG_REG (x); 6223 6224 return (REG_P (x) && REGNO (x) != REG_SP); 6225} 6226 6227int 6228ip2k_gen_operand (x, mode) 6229 rtx x; 6230 enum machine_mode mode; 6231{ 6232 return ip2k_short_operand (x, mode) 6233 || (GET_CODE (x) == SUBREG 6234 && REG_P (SUBREG_REG (x))) 6235 || (ip2k_nonsp_reg_operand (x, mode)); 6236} 6237 6238int 6239ip2k_extra_constraint (x, c) 6240 rtx x; 6241 int c; 6242{ 6243 switch (c) 6244 { 6245 case 'S': /* Allow offset in stack frame... */ 6246 return ip2k_short_operand (x, GET_MODE (x)); 6247 6248 case 'R': 6249 return ip2k_ip_operand (x, GET_MODE (x)); 6250 6251 case 'T': /* Constant int or .data address. */ 6252 return CONSTANT_P (x) && is_regfile_address (x); 6253 6254 default: 6255 return 0; 6256 } 6257} 6258 6259int 6260ip2k_unary_operator (op, mode) 6261 rtx op; 6262 enum machine_mode mode; 6263{ 6264 return ((mode == VOIDmode || GET_MODE (op) == mode) 6265 && GET_RTX_CLASS (GET_CODE (op)) == '1'); 6266} 6267 6268int 6269ip2k_binary_operator (op, mode) 6270 rtx op; 6271 enum machine_mode mode; 6272{ 6273 return ((mode == VOIDmode || GET_MODE (op) == mode) 6274 && (GET_RTX_CLASS (GET_CODE (op)) == 'c' 6275 || GET_RTX_CLASS (GET_CODE (op)) == '2')); 6276} 6277 6278int 6279ip2k_symbol_ref_operand (op, mode) 6280 rtx op; 6281 enum machine_mode mode ATTRIBUTE_UNUSED; 6282{ 6283 /* We define an IP2k symbol ref to be either a direct reference or one 6284 with a constant offset. */ 6285 return (GET_CODE (op) == SYMBOL_REF) 6286 || (GET_CODE (op) == CONST 6287 && GET_CODE (XEXP (op, 0)) == PLUS 6288 && GET_CODE (XEXP (XEXP (op, 0), 0)) == SYMBOL_REF); 6289} 6290 6291int 6292ip2k_signed_comparison_operator (op, mode) 6293 rtx op; 6294 enum machine_mode mode; 6295{ 6296 return (comparison_operator (op, mode) 6297 && signed_condition (GET_CODE (op)) == GET_CODE (op)); 6298} 6299 6300int 6301ip2k_unsigned_comparison_operator (op, mode) 6302 rtx op; 6303 enum machine_mode mode; 6304{ 6305 return (comparison_operator (op, mode) 6306 && unsigned_condition (GET_CODE (op)) == GET_CODE (op)); 6307} 6308