|
|
1.1 root 1: /* Subroutines for insn-output.c for Motorola 68000 family. 1.1.1.4 ! root 2: Copyright (C) 1987, 1993, 1994, 1995 Free Software Foundation, Inc. 1.1 root 3: 4: This file is part of GNU CC. 5: 6: GNU CC is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: GNU CC is distributed in the hope that it will be useful, 12: but WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14: GNU General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU CC; see the file COPYING. If not, write to 1.1.1.4 ! root 18: the Free Software Foundation, 59 Temple Place - Suite 330, ! 19: Boston, MA 02111-1307, USA. */ 1.1 root 20: 21: 22: /* Some output-actions in m68k.md need these. */ 23: #include <stdio.h> 24: #include "config.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: 35: /* Needed for use_return_insn. */ 36: #include "flags.h" 37: 38: #ifdef SUPPORT_SUN_FPA 39: 40: /* Index into this array by (register number >> 3) to find the 41: smallest class which contains that register. */ 42: enum reg_class regno_reg_class[] 43: = { DATA_REGS, ADDR_REGS, FP_REGS, 44: LO_FPA_REGS, LO_FPA_REGS, FPA_REGS, FPA_REGS }; 45: 46: #endif /* defined SUPPORT_SUN_FPA */ 47: 48: /* This flag is used to communicate between movhi and ASM_OUTPUT_CASE_END, 49: if SGS_SWITCH_TABLE. */ 50: int switch_table_difference_label_flag; 51: 52: static rtx find_addr_reg (); 53: rtx legitimize_pic_address (); 54: 55: 56: /* Emit a (use pic_offset_table_rtx) if we used PIC relocation in the 57: function at any time during the compilation process. In the future 58: we should try and eliminate the USE if we can easily determine that 59: all PIC references were deleted from the current function. That would 60: save an address register */ 61: 1.1.1.2 root 62: void 1.1 root 63: finalize_pic () 64: { 65: if (flag_pic && current_function_uses_pic_offset_table) 1.1.1.4 ! root 66: { ! 67: rtx insn = gen_rtx (USE, VOIDmode, pic_offset_table_rtx); ! 68: emit_insn_after (insn, get_insns ()); ! 69: emit_insn (insn); ! 70: } 1.1 root 71: } 72: 73: 74: /* This function generates the assembly code for function entry. 75: STREAM is a stdio stream to output the code to. 76: SIZE is an int: how many units of temporary storage to allocate. 77: Refer to the array `regs_ever_live' to determine which registers 78: to save; `regs_ever_live[I]' is nonzero if register number I 79: is ever used in the function. This function is responsible for 80: knowing which registers should not be saved even if used. */ 81: 82: 83: /* Note that the order of the bit mask for fmovem is the opposite 84: of the order for movem! */ 85: 86: 87: void 88: output_function_prologue (stream, size) 89: FILE *stream; 90: int size; 91: { 92: register int regno; 93: register int mask = 0; 94: int num_saved_regs = 0; 95: extern char call_used_regs[]; 96: int fsize = (size + 3) & -4; 97: 98: 99: if (frame_pointer_needed) 100: { 1.1.1.3 root 101: if (fsize == 0 && TARGET_68040) 102: { 103: /* on the 68040, pea + move is faster than link.w 0 */ 104: #ifdef MOTOROLA 105: asm_fprintf (stream, "\tpea (%s)\n\tmove.l %s,%s\n", 106: reg_names[FRAME_POINTER_REGNUM], reg_names[STACK_POINTER_REGNUM], 107: reg_names[FRAME_POINTER_REGNUM]); 108: #else 109: asm_fprintf (stream, "\tpea %s@\n\tmovel %s,%s\n", 110: reg_names[FRAME_POINTER_REGNUM], reg_names[STACK_POINTER_REGNUM], 111: reg_names[FRAME_POINTER_REGNUM]); 112: #endif 113: } 114: else if (fsize < 0x8000) 1.1 root 115: { 116: #ifdef MOTOROLA 117: asm_fprintf (stream, "\tlink.w %s,%0I%d\n", 118: reg_names[FRAME_POINTER_REGNUM], -fsize); 119: #else 120: asm_fprintf (stream, "\tlink %s,%0I%d\n", 121: reg_names[FRAME_POINTER_REGNUM], -fsize); 122: #endif 123: } 124: else if (TARGET_68020) 125: { 126: #ifdef MOTOROLA 127: asm_fprintf (stream, "\tlink.l %s,%0I%d\n", 128: reg_names[FRAME_POINTER_REGNUM], -fsize); 129: #else 130: asm_fprintf (stream, "\tlink %s,%0I%d\n", 131: reg_names[FRAME_POINTER_REGNUM], -fsize); 132: #endif 133: } 134: else 135: { 1.1.1.3 root 136: /* Adding negative number is faster on the 68040. */ 1.1 root 137: #ifdef MOTOROLA 138: asm_fprintf (stream, "\tlink.w %s,%0I0\n\tadd.l %0I%d,%Rsp\n", 139: reg_names[FRAME_POINTER_REGNUM], -fsize); 140: #else 141: asm_fprintf (stream, "\tlink %s,%0I0\n\taddl %0I%d,%Rsp\n", 142: reg_names[FRAME_POINTER_REGNUM], -fsize); 143: #endif 144: } 145: } 146: else if (fsize) 147: { 148: /* Adding negative number is faster on the 68040. */ 149: if (fsize + 4 < 0x8000) 150: { 1.1.1.3 root 151: /* asm_fprintf() cannot handle %. */ 1.1 root 152: #ifdef MOTOROLA 153: asm_fprintf (stream, "\tadd.w %0I%d,%Rsp\n", - (fsize + 4)); 154: #else 155: asm_fprintf (stream, "\taddw %0I%d,%Rsp\n", - (fsize + 4)); 156: #endif 157: } 158: else 159: { 1.1.1.3 root 160: /* asm_fprintf() cannot handle %. */ 1.1 root 161: #ifdef MOTOROLA 162: asm_fprintf (stream, "\tadd.l %0I%d,%Rsp\n", - (fsize + 4)); 163: #else 164: asm_fprintf (stream, "\taddl %0I%d,%Rsp\n", - (fsize + 4)); 165: #endif 166: } 167: } 168: #ifdef SUPPORT_SUN_FPA 169: for (regno = 24; regno < 56; regno++) 170: if (regs_ever_live[regno] && ! call_used_regs[regno]) 171: { 172: #ifdef MOTOROLA 173: asm_fprintf (stream, "\tfpmovd %s,-(%Rsp)\n", 174: reg_names[regno]); 175: #else 176: asm_fprintf (stream, "\tfpmoved %s,%Rsp@-\n", 177: reg_names[regno]); 178: #endif 179: } 180: #endif 181: for (regno = 16; regno < 24; regno++) 182: if (regs_ever_live[regno] && ! call_used_regs[regno]) 183: mask |= 1 << (regno - 16); 184: if ((mask & 0xff) != 0) 185: { 186: #ifdef MOTOROLA 187: asm_fprintf (stream, "\tfmovm %0I0x%x,-(%Rsp)\n", mask & 0xff); 188: #else 189: asm_fprintf (stream, "\tfmovem %0I0x%x,%Rsp@-\n", mask & 0xff); 190: #endif 191: } 192: mask = 0; 193: for (regno = 0; regno < 16; regno++) 194: if (regs_ever_live[regno] && ! call_used_regs[regno]) 195: { 196: mask |= 1 << (15 - regno); 197: num_saved_regs++; 198: } 199: if (frame_pointer_needed) 200: { 201: mask &= ~ (1 << (15 - FRAME_POINTER_REGNUM)); 202: num_saved_regs--; 203: } 204: 205: #if NEED_PROBE 206: fprintf (stream, "\ttstl sp@(%d)\n", NEED_PROBE - num_saved_regs * 4); 207: #endif 208: 209: if (num_saved_regs <= 2) 210: { 211: /* Store each separately in the same order moveml uses. 212: Using two movel instructions instead of a single moveml 213: is about 15% faster for the 68020 and 68030 at no expense 214: in code size */ 215: 216: int i; 217: 218: /* Undo the work from above. */ 219: for (i = 0; i< 16; i++) 220: if (mask & (1 << i)) 221: asm_fprintf (stream, 222: #ifdef MOTOROLA 223: "\t%Omove.l %s,-(%Rsp)\n", 224: #else 225: "\tmovel %s,%Rsp@-\n", 226: #endif 227: reg_names[15 - i]); 228: } 229: else if (mask) 230: { 231: #ifdef MOTOROLA 232: asm_fprintf (stream, "\tmovm.l %0I0x%x,-(%Rsp)\n", mask); 233: #else 234: asm_fprintf (stream, "\tmoveml %0I0x%x,%Rsp@-\n", mask); 235: #endif 236: } 237: if (flag_pic && current_function_uses_pic_offset_table) 238: { 239: #ifdef MOTOROLA 240: asm_fprintf (stream, "\t%Olea (%Rpc, %U_GLOBAL_OFFSET_TABLE_@GOTPC), %s\n", 241: reg_names[PIC_OFFSET_TABLE_REGNUM]); 242: #else 243: asm_fprintf (stream, "\tmovel %0I__GLOBAL_OFFSET_TABLE_, %s\n", 244: reg_names[PIC_OFFSET_TABLE_REGNUM]); 245: asm_fprintf (stream, "\tlea %Rpc@(0,%s:l),%s\n", 246: reg_names[PIC_OFFSET_TABLE_REGNUM], 247: reg_names[PIC_OFFSET_TABLE_REGNUM]); 248: #endif 249: } 250: } 251: 252: /* Return true if this function's epilogue can be output as RTL. */ 253: 254: int 255: use_return_insn () 256: { 257: int regno; 258: 259: if (!reload_completed || frame_pointer_needed || get_frame_size () != 0) 260: return 0; 261: 262: /* Copied from output_function_epilogue (). We should probably create a 263: separate layout routine to perform the common work. */ 264: 265: for (regno = 0 ; regno < FIRST_PSEUDO_REGISTER ; regno++) 266: if (regs_ever_live[regno] && ! call_used_regs[regno]) 267: return 0; 268: 269: return 1; 270: } 271: 272: /* This function generates the assembly code for function exit, 273: on machines that need it. Args are same as for FUNCTION_PROLOGUE. 274: 275: The function epilogue should not depend on the current stack pointer! 276: It should use the frame pointer only, if there is a frame pointer. 277: This is mandatory because of alloca; we also take advantage of it to 278: omit stack adjustments before returning. */ 279: 280: void 281: output_function_epilogue (stream, size) 282: FILE *stream; 283: int size; 284: { 285: register int regno; 286: register int mask, fmask; 287: register int nregs; 288: int offset, foffset, fpoffset; 289: extern char call_used_regs[]; 290: int fsize = (size + 3) & -4; 291: int big = 0; 292: rtx insn = get_last_insn (); 293: 294: /* If the last insn was a BARRIER, we don't have to write any code. */ 295: if (GET_CODE (insn) == NOTE) 296: insn = prev_nonnote_insn (insn); 297: if (insn && GET_CODE (insn) == BARRIER) 298: { 299: /* Output just a no-op so that debuggers don't get confused 300: about which function the pc is in at this address. */ 301: asm_fprintf (stream, "\tnop\n"); 302: return; 303: } 304: 305: #ifdef FUNCTION_EXTRA_EPILOGUE 306: FUNCTION_EXTRA_EPILOGUE (stream, size); 307: #endif 308: nregs = 0; fmask = 0; fpoffset = 0; 309: #ifdef SUPPORT_SUN_FPA 310: for (regno = 24 ; regno < 56 ; regno++) 311: if (regs_ever_live[regno] && ! call_used_regs[regno]) 312: nregs++; 313: fpoffset = nregs * 8; 314: #endif 315: nregs = 0; 316: for (regno = 16; regno < 24; regno++) 317: if (regs_ever_live[regno] && ! call_used_regs[regno]) 318: { 319: nregs++; 320: fmask |= 1 << (23 - regno); 321: } 322: foffset = fpoffset + nregs * 12; 323: nregs = 0; mask = 0; 324: if (frame_pointer_needed) 325: regs_ever_live[FRAME_POINTER_REGNUM] = 0; 326: for (regno = 0; regno < 16; regno++) 327: if (regs_ever_live[regno] && ! call_used_regs[regno]) 328: { 329: nregs++; 330: mask |= 1 << regno; 331: } 332: offset = foffset + nregs * 4; 333: if (offset + fsize >= 0x8000 334: && frame_pointer_needed 335: && (mask || fmask || fpoffset)) 336: { 337: #ifdef MOTOROLA 1.1.1.3 root 338: asm_fprintf (stream, "\t%Omove.l %0I%d,%Ra1\n", -fsize); 1.1 root 339: #else 1.1.1.3 root 340: asm_fprintf (stream, "\tmovel %0I%d,%Ra1\n", -fsize); 1.1 root 341: #endif 342: fsize = 0, big = 1; 343: } 344: if (nregs <= 2) 345: { 346: /* Restore each separately in the same order moveml does. 347: Using two movel instructions instead of a single moveml 348: is about 15% faster for the 68020 and 68030 at no expense 349: in code size. */ 350: 351: int i; 352: 353: /* Undo the work from above. */ 354: for (i = 0; i< 16; i++) 355: if (mask & (1 << i)) 356: { 357: if (big) 358: { 359: #ifdef MOTOROLA 1.1.1.3 root 360: asm_fprintf (stream, "\t%Omove.l -%d(%s,%Ra1.l),%s\n", 1.1 root 361: offset + fsize, 362: reg_names[FRAME_POINTER_REGNUM], 363: reg_names[i]); 364: #else 1.1.1.3 root 365: asm_fprintf (stream, "\tmovel %s@(-%d,%Ra1:l),%s\n", 1.1 root 366: reg_names[FRAME_POINTER_REGNUM], 367: offset + fsize, reg_names[i]); 368: #endif 369: } 370: else if (! frame_pointer_needed) 371: { 372: #ifdef MOTOROLA 373: asm_fprintf (stream, "\t%Omove.l (%Rsp)+,%s\n", 374: reg_names[i]); 375: #else 376: asm_fprintf (stream, "\tmovel %Rsp@+,%s\n", 377: reg_names[i]); 378: #endif 379: } 380: else 381: { 382: #ifdef MOTOROLA 383: asm_fprintf (stream, "\t%Omove.l -%d(%s),%s\n", 384: offset + fsize, 385: reg_names[FRAME_POINTER_REGNUM], 386: reg_names[i]); 387: #else 388: asm_fprintf (stream, "\tmovel %s@(-%d),%s\n", 389: reg_names[FRAME_POINTER_REGNUM], 390: offset + fsize, reg_names[i]); 391: #endif 392: } 393: offset = offset - 4; 394: } 395: } 396: else if (mask) 397: { 398: if (big) 399: { 400: #ifdef MOTOROLA 1.1.1.3 root 401: asm_fprintf (stream, "\tmovm.l -%d(%s,%Ra1.l),%0I0x%x\n", 1.1 root 402: offset + fsize, 403: reg_names[FRAME_POINTER_REGNUM], 404: mask); 405: #else 1.1.1.3 root 406: asm_fprintf (stream, "\tmoveml %s@(-%d,%Ra1:l),%0I0x%x\n", 1.1 root 407: reg_names[FRAME_POINTER_REGNUM], 408: offset + fsize, mask); 409: #endif 410: } 411: else if (! frame_pointer_needed) 412: { 413: #ifdef MOTOROLA 414: asm_fprintf (stream, "\tmovm.l (%Rsp)+,%0I0x%x\n", mask); 415: #else 416: asm_fprintf (stream, "\tmoveml %Rsp@+,%0I0x%x\n", mask); 417: #endif 418: } 419: else 420: { 421: #ifdef MOTOROLA 422: asm_fprintf (stream, "\tmovm.l -%d(%s),%0I0x%x\n", 423: offset + fsize, 424: reg_names[FRAME_POINTER_REGNUM], 425: mask); 426: #else 427: asm_fprintf (stream, "\tmoveml %s@(-%d),%0I0x%x\n", 428: reg_names[FRAME_POINTER_REGNUM], 429: offset + fsize, mask); 430: #endif 431: } 432: } 433: if (fmask) 434: { 435: if (big) 436: { 437: #ifdef MOTOROLA 1.1.1.3 root 438: asm_fprintf (stream, "\tfmovm -%d(%s,%Ra1.l),%0I0x%x\n", 1.1 root 439: foffset + fsize, 440: reg_names[FRAME_POINTER_REGNUM], 441: fmask); 442: #else 1.1.1.3 root 443: asm_fprintf (stream, "\tfmovem %s@(-%d,%Ra1:l),%0I0x%x\n", 1.1 root 444: reg_names[FRAME_POINTER_REGNUM], 445: foffset + fsize, fmask); 446: #endif 447: } 448: else if (! frame_pointer_needed) 449: { 450: #ifdef MOTOROLA 451: asm_fprintf (stream, "\tfmovm (%Rsp)+,%0I0x%x\n", fmask); 452: #else 453: asm_fprintf (stream, "\tfmovem %Rsp@+,%0I0x%x\n", fmask); 454: #endif 455: } 456: else 457: { 458: #ifdef MOTOROLA 459: asm_fprintf (stream, "\tfmovm -%d(%s),%0I0x%x\n", 460: foffset + fsize, 461: reg_names[FRAME_POINTER_REGNUM], 462: fmask); 463: #else 464: asm_fprintf (stream, "\tfmovem %s@(-%d),%0I0x%x\n", 465: reg_names[FRAME_POINTER_REGNUM], 466: foffset + fsize, fmask); 467: #endif 468: } 469: } 470: if (fpoffset != 0) 471: for (regno = 55; regno >= 24; regno--) 472: if (regs_ever_live[regno] && ! call_used_regs[regno]) 473: { 474: if (big) 475: { 476: #ifdef MOTOROLA 1.1.1.3 root 477: asm_fprintf (stream, "\tfpmovd -%d(%s,%Ra1.l), %s\n", 1.1 root 478: fpoffset + fsize, 479: reg_names[FRAME_POINTER_REGNUM], 480: reg_names[regno]); 481: #else 1.1.1.3 root 482: asm_fprintf (stream, "\tfpmoved %s@(-%d,%Ra1:l), %s\n", 1.1 root 483: reg_names[FRAME_POINTER_REGNUM], 484: fpoffset + fsize, reg_names[regno]); 485: #endif 486: } 487: else if (! frame_pointer_needed) 488: { 489: #ifdef MOTOROLA 490: asm_fprintf (stream, "\tfpmovd (%Rsp)+,%s\n", 491: reg_names[regno]); 492: #else 493: asm_fprintf (stream, "\tfpmoved %Rsp@+, %s\n", 494: reg_names[regno]); 495: #endif 496: } 497: else 498: { 499: #ifdef MOTOROLA 500: asm_fprintf (stream, "\tfpmovd -%d(%s), %s\n", 501: fpoffset + fsize, 502: reg_names[FRAME_POINTER_REGNUM], 503: reg_names[regno]); 504: #else 505: asm_fprintf (stream, "\tfpmoved %s@(-%d), %s\n", 506: reg_names[FRAME_POINTER_REGNUM], 507: fpoffset + fsize, reg_names[regno]); 508: #endif 509: } 510: fpoffset -= 8; 511: } 512: if (frame_pointer_needed) 513: fprintf (stream, "\tunlk %s\n", 514: reg_names[FRAME_POINTER_REGNUM]); 515: else if (fsize) 516: { 517: if (fsize + 4 < 0x8000) 518: { 1.1.1.3 root 519: /* asm_fprintf() cannot handle %. */ 1.1 root 520: #ifdef MOTOROLA 521: asm_fprintf (stream, "\tadd.w %0I%d,%Rsp\n", fsize + 4); 522: #else 523: asm_fprintf (stream, "\taddw %0I%d,%Rsp\n", fsize + 4); 524: #endif 525: } 526: else 527: { 1.1.1.3 root 528: /* asm_fprintf() cannot handle %. */ 1.1 root 529: #ifdef MOTOROLA 530: asm_fprintf (stream, "\tadd.l %0I%d,%Rsp\n", fsize + 4); 531: #else 532: asm_fprintf (stream, "\taddl %0I%d,%Rsp\n", fsize + 4); 533: #endif 534: } 535: } 536: if (current_function_pops_args) 537: asm_fprintf (stream, "\trtd %0I%d\n", current_function_pops_args); 538: else 539: fprintf (stream, "\trts\n"); 540: } 541: 542: /* Similar to general_operand, but exclude stack_pointer_rtx. */ 543: 544: int 545: not_sp_operand (op, mode) 546: register rtx op; 547: enum machine_mode mode; 548: { 549: return op != stack_pointer_rtx && general_operand (op, mode); 550: } 551: 552: /* Return TRUE if X is a valid comparison operator for the dbcc 553: instruction. 554: 555: Note it rejects floating point comparison operators. 556: (In the future we could use Fdbcc). 557: 558: It also rejects some comparisons when CC_NO_OVERFLOW is set. */ 559: 560: int 561: valid_dbcc_comparison_p (x, mode) 562: rtx x; 563: enum machine_mode mode; 564: { 565: /* We could add support for these in the future */ 566: if (cc_prev_status.flags & CC_IN_68881) 567: return 0; 568: 569: switch (GET_CODE (x)) 570: { 571: 572: case EQ: case NE: case GTU: case LTU: 573: case GEU: case LEU: 574: return 1; 575: 576: /* Reject some when CC_NO_OVERFLOW is set. This may be over 577: conservative */ 578: case GT: case LT: case GE: case LE: 579: return ! (cc_prev_status.flags & CC_NO_OVERFLOW); 580: default: 581: return 0; 582: } 583: } 584: 585: /* Output a dbCC; jCC sequence. Note we do not handle the 586: floating point version of this sequence (Fdbcc). We also 587: do not handle alternative conditions when CC_NO_OVERFLOW is 588: set. It is assumed that valid_dbcc_comparison_p will kick 589: those out before we get here. */ 590: 591: output_dbcc_and_branch (operands) 592: rtx *operands; 593: { 594: 595: switch (GET_CODE (operands[3])) 596: { 597: case EQ: 598: #ifdef MOTOROLA 599: output_asm_insn ("dbeq %0,%l1\n\tjbeq %l2", operands); 600: #else 601: output_asm_insn ("dbeq %0,%l1\n\tjeq %l2", operands); 602: #endif 603: break; 604: 605: case NE: 606: #ifdef MOTOROLA 607: output_asm_insn ("dbne %0,%l1\n\tjbne %l2", operands); 608: #else 609: output_asm_insn ("dbne %0,%l1\n\tjne %l2", operands); 610: #endif 611: break; 612: 613: case GT: 614: #ifdef MOTOROLA 615: output_asm_insn ("dbgt %0,%l1\n\tjbgt %l2", operands); 616: #else 617: output_asm_insn ("dbgt %0,%l1\n\tjgt %l2", operands); 618: #endif 619: break; 620: 621: case GTU: 622: #ifdef MOTOROLA 623: output_asm_insn ("dbhi %0,%l1\n\tjbhi %l2", operands); 624: #else 625: output_asm_insn ("dbhi %0,%l1\n\tjhi %l2", operands); 626: #endif 627: break; 628: 629: case LT: 630: #ifdef MOTOROLA 631: output_asm_insn ("dblt %0,%l1\n\tjblt %l2", operands); 632: #else 633: output_asm_insn ("dblt %0,%l1\n\tjlt %l2", operands); 634: #endif 635: break; 636: 637: case LTU: 638: #ifdef MOTOROLA 639: output_asm_insn ("dbcs %0,%l1\n\tjbcs %l2", operands); 640: #else 641: output_asm_insn ("dbcs %0,%l1\n\tjcs %l2", operands); 642: #endif 643: break; 644: 645: case GE: 646: #ifdef MOTOROLA 647: output_asm_insn ("dbge %0,%l1\n\tjbge %l2", operands); 648: #else 649: output_asm_insn ("dbge %0,%l1\n\tjge %l2", operands); 650: #endif 651: break; 652: 653: case GEU: 654: #ifdef MOTOROLA 655: output_asm_insn ("dbcc %0,%l1\n\tjbcc %l2", operands); 656: #else 657: output_asm_insn ("dbcc %0,%l1\n\tjcc %l2", operands); 658: #endif 659: break; 660: 661: case LE: 662: #ifdef MOTOROLA 663: output_asm_insn ("dble %0,%l1\n\tjble %l2", operands); 664: #else 665: output_asm_insn ("dble %0,%l1\n\tjle %l2", operands); 666: #endif 667: break; 668: 669: case LEU: 670: #ifdef MOTOROLA 671: output_asm_insn ("dbls %0,%l1\n\tjbls %l2", operands); 672: #else 673: output_asm_insn ("dbls %0,%l1\n\tjls %l2", operands); 674: #endif 675: break; 676: 677: default: 678: abort (); 679: } 680: 681: /* If the decrement is to be done in SImode, then we have 682: to compensate for the fact that dbcc decrements in HImode. */ 683: switch (GET_MODE (operands[0])) 684: { 685: case SImode: 686: #ifdef MOTOROLA 687: output_asm_insn ("clr%.w %0\n\tsubq%.l %#1,%0\n\tjbpl %l1", operands); 688: #else 689: output_asm_insn ("clr%.w %0\n\tsubq%.l %#1,%0\n\tjpl %l1", operands); 690: #endif 691: break; 692: 693: case HImode: 694: break; 695: 696: default: 697: abort (); 698: } 699: } 700: 701: char * 1.1.1.4 ! root 702: output_scc_di(op, operand1, operand2, dest) ! 703: rtx op; ! 704: rtx operand1; ! 705: rtx operand2; ! 706: rtx dest; ! 707: { ! 708: rtx loperands[7]; ! 709: enum rtx_code op_code = GET_CODE (op); ! 710: ! 711: /* The m68k cmp.l instruction requires operand1 to be a reg as used ! 712: below. Swap the operands and change the op if these requirements ! 713: are not fulfilled. */ ! 714: if (GET_CODE (operand2) == REG && GET_CODE (operand1) != REG) ! 715: { ! 716: rtx tmp = operand1; ! 717: ! 718: operand1 = operand2; ! 719: operand2 = tmp; ! 720: op_code = swap_condition (op_code); ! 721: } ! 722: loperands[0] = operand1; ! 723: if (GET_CODE (operand1) == REG) ! 724: loperands[1] = gen_rtx (REG, SImode, REGNO (operand1) + 1); ! 725: else ! 726: loperands[1] = adj_offsettable_operand (operand1, 4); ! 727: if (operand2 != const0_rtx) ! 728: { ! 729: loperands[2] = operand2; ! 730: if (GET_CODE (operand2) == REG) ! 731: loperands[3] = gen_rtx (REG, SImode, REGNO (operand2) + 1); ! 732: else ! 733: loperands[3] = adj_offsettable_operand (operand2, 4); ! 734: } ! 735: loperands[4] = gen_label_rtx(); ! 736: if (operand2 != const0_rtx) ! 737: #ifdef MOTOROLA ! 738: #ifdef SGS_CMP_ORDER ! 739: output_asm_insn ("cmp%.l %0,%2\n\tjbne %l4\n\tcmp%.l %1,%3", loperands); ! 740: #else ! 741: output_asm_insn ("cmp%.l %2,%0\n\tjbne %l4\n\tcmp%.l %3,%1", loperands); ! 742: #endif ! 743: #else ! 744: #ifdef SGS_CMP_ORDER ! 745: output_asm_insn ("cmp%.l %0,%2\n\tjne %l4\n\tcmp%.l %1,%3", loperands); ! 746: #else ! 747: output_asm_insn ("cmp%.l %2,%0\n\tjne %l4\n\tcmp%.l %3,%1", loperands); ! 748: #endif ! 749: #endif ! 750: else ! 751: #ifdef MOTOROLA ! 752: output_asm_insn ("tst%.l %0\n\tjbne %l4\n\ttst%.l %1", loperands); ! 753: #else ! 754: output_asm_insn ("tst%.l %0\n\tjne %l4\n\ttst%.l %1", loperands); ! 755: #endif ! 756: loperands[5] = dest; ! 757: ! 758: switch (op_code) ! 759: { ! 760: case EQ: ! 761: ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", ! 762: CODE_LABEL_NUMBER (loperands[4])); ! 763: output_asm_insn ("seq %5", loperands); ! 764: break; ! 765: ! 766: case NE: ! 767: ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", ! 768: CODE_LABEL_NUMBER (loperands[4])); ! 769: output_asm_insn ("sne %5", loperands); ! 770: break; ! 771: ! 772: case GT: ! 773: loperands[6] = gen_label_rtx(); ! 774: #ifdef MOTOROLA ! 775: output_asm_insn ("shi %5\n\tjbra %l6", loperands); ! 776: #else ! 777: output_asm_insn ("shi %5\n\tjra %l6", loperands); ! 778: #endif ! 779: ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", ! 780: CODE_LABEL_NUMBER (loperands[4])); ! 781: output_asm_insn ("sgt %5", loperands); ! 782: ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", ! 783: CODE_LABEL_NUMBER (loperands[6])); ! 784: break; ! 785: ! 786: case GTU: ! 787: ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", ! 788: CODE_LABEL_NUMBER (loperands[4])); ! 789: output_asm_insn ("shi %5", loperands); ! 790: break; ! 791: ! 792: case LT: ! 793: loperands[6] = gen_label_rtx(); ! 794: #ifdef MOTOROLA ! 795: output_asm_insn ("scs %5\n\tjbra %l6", loperands); ! 796: #else ! 797: output_asm_insn ("scs %5\n\tjra %l6", loperands); ! 798: #endif ! 799: ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", ! 800: CODE_LABEL_NUMBER (loperands[4])); ! 801: output_asm_insn ("slt %5", loperands); ! 802: ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", ! 803: CODE_LABEL_NUMBER (loperands[6])); ! 804: break; ! 805: ! 806: case LTU: ! 807: ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", ! 808: CODE_LABEL_NUMBER (loperands[4])); ! 809: output_asm_insn ("scs %5", loperands); ! 810: break; ! 811: ! 812: case GE: ! 813: loperands[6] = gen_label_rtx(); ! 814: #ifdef MOTOROLA ! 815: output_asm_insn ("scc %5\n\tjbra %l6", loperands); ! 816: #else ! 817: output_asm_insn ("scc %5\n\tjra %l6", loperands); ! 818: #endif ! 819: ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", ! 820: CODE_LABEL_NUMBER (loperands[4])); ! 821: output_asm_insn ("sge %5", loperands); ! 822: ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", ! 823: CODE_LABEL_NUMBER (loperands[6])); ! 824: break; ! 825: ! 826: case GEU: ! 827: ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", ! 828: CODE_LABEL_NUMBER (loperands[4])); ! 829: output_asm_insn ("scc %5", loperands); ! 830: break; ! 831: ! 832: case LE: ! 833: loperands[6] = gen_label_rtx(); ! 834: #ifdef MOTOROLA ! 835: output_asm_insn ("sls %5\n\tjbra %l6", loperands); ! 836: #else ! 837: output_asm_insn ("sls %5\n\tjra %l6", loperands); ! 838: #endif ! 839: ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", ! 840: CODE_LABEL_NUMBER (loperands[4])); ! 841: output_asm_insn ("sle %5", loperands); ! 842: ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", ! 843: CODE_LABEL_NUMBER (loperands[6])); ! 844: break; ! 845: ! 846: case LEU: ! 847: ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", ! 848: CODE_LABEL_NUMBER (loperands[4])); ! 849: output_asm_insn ("sls %5", loperands); ! 850: break; ! 851: ! 852: default: ! 853: abort (); ! 854: } ! 855: return ""; ! 856: } ! 857: ! 858: char * 1.1 root 859: output_btst (operands, countop, dataop, insn, signpos) 860: rtx *operands; 861: rtx countop, dataop; 862: rtx insn; 863: int signpos; 864: { 865: operands[0] = countop; 866: operands[1] = dataop; 867: 868: if (GET_CODE (countop) == CONST_INT) 869: { 870: register int count = INTVAL (countop); 871: /* If COUNT is bigger than size of storage unit in use, 872: advance to the containing unit of same size. */ 873: if (count > signpos) 874: { 875: int offset = (count & ~signpos) / 8; 876: count = count & signpos; 877: operands[1] = dataop = adj_offsettable_operand (dataop, offset); 878: } 879: if (count == signpos) 880: cc_status.flags = CC_NOT_POSITIVE | CC_Z_IN_NOT_N; 881: else 882: cc_status.flags = CC_NOT_NEGATIVE | CC_Z_IN_NOT_N; 883: 884: /* These three statements used to use next_insns_test_no... 885: but it appears that this should do the same job. */ 886: if (count == 31 887: && next_insn_tests_no_inequality (insn)) 888: return "tst%.l %1"; 889: if (count == 15 890: && next_insn_tests_no_inequality (insn)) 891: return "tst%.w %1"; 892: if (count == 7 893: && next_insn_tests_no_inequality (insn)) 894: return "tst%.b %1"; 895: 896: cc_status.flags = CC_NOT_NEGATIVE; 897: } 898: return "btst %0,%1"; 899: } 900: 901: /* Returns 1 if OP is either a symbol reference or a sum of a symbol 902: reference and a constant. */ 903: 904: int 905: symbolic_operand (op, mode) 906: register rtx op; 907: enum machine_mode mode; 908: { 909: switch (GET_CODE (op)) 910: { 911: case SYMBOL_REF: 912: case LABEL_REF: 913: return 1; 914: 915: case CONST: 916: op = XEXP (op, 0); 917: return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF 918: || GET_CODE (XEXP (op, 0)) == LABEL_REF) 919: && GET_CODE (XEXP (op, 1)) == CONST_INT); 920: 921: #if 0 /* Deleted, with corresponding change in m68k.h, 922: so as to fit the specs. No CONST_DOUBLE is ever symbolic. */ 923: case CONST_DOUBLE: 924: return GET_MODE (op) == mode; 925: #endif 926: 927: default: 928: return 0; 929: } 930: } 1.1.1.4 ! root 931: ! 932: /* Check for sign_extend or zero_extend. Used for bit-count operands. */ ! 933: ! 934: int ! 935: extend_operator(x, mode) ! 936: rtx x; ! 937: enum machine_mode mode; ! 938: { ! 939: if (mode != VOIDmode && GET_MODE(x) != mode) ! 940: return 0; ! 941: switch (GET_CODE(x)) ! 942: { ! 943: case SIGN_EXTEND : ! 944: case ZERO_EXTEND : ! 945: return 1; ! 946: default : ! 947: return 0; ! 948: } ! 949: } 1.1 root 950: 951: 952: /* Legitimize PIC addresses. If the address is already 953: position-independent, we return ORIG. Newly generated 954: position-independent addresses go to REG. If we need more 955: than one register, we lose. 956: 957: An address is legitimized by making an indirect reference 958: through the Global Offset Table with the name of the symbol 959: used as an offset. 960: 961: The assembler and linker are responsible for placing the 962: address of the symbol in the GOT. The function prologue 963: is responsible for initializing a5 to the starting address 964: of the GOT. 965: 966: The assembler is also responsible for translating a symbol name 967: into a constant displacement from the start of the GOT. 968: 969: A quick example may make things a little clearer: 970: 971: When not generating PIC code to store the value 12345 into _foo 972: we would generate the following code: 973: 974: movel #12345, _foo 975: 976: When generating PIC two transformations are made. First, the compiler 977: loads the address of foo into a register. So the first transformation makes: 978: 979: lea _foo, a0 980: movel #12345, a0@ 981: 982: The code in movsi will intercept the lea instruction and call this 983: routine which will transform the instructions into: 984: 985: movel a5@(_foo:w), a0 986: movel #12345, a0@ 987: 988: 989: That (in a nutshell) is how *all* symbol and label references are 990: handled. */ 991: 992: rtx 993: legitimize_pic_address (orig, mode, reg) 994: rtx orig, reg; 995: enum machine_mode mode; 996: { 997: rtx pic_ref = orig; 998: 999: /* First handle a simple SYMBOL_REF or LABEL_REF */ 1000: if (GET_CODE (orig) == SYMBOL_REF || GET_CODE (orig) == LABEL_REF) 1001: { 1002: if (reg == 0) 1003: abort (); 1004: 1005: pic_ref = gen_rtx (MEM, Pmode, 1006: gen_rtx (PLUS, Pmode, 1007: pic_offset_table_rtx, orig)); 1008: current_function_uses_pic_offset_table = 1; 1009: RTX_UNCHANGING_P (pic_ref) = 1; 1010: emit_move_insn (reg, pic_ref); 1011: return reg; 1012: } 1013: else if (GET_CODE (orig) == CONST) 1014: { 1015: rtx base, offset; 1016: 1017: /* Make sure this is CONST has not already been legitimized */ 1018: if (GET_CODE (XEXP (orig, 0)) == PLUS 1019: && XEXP (XEXP (orig, 0), 0) == pic_offset_table_rtx) 1020: return orig; 1021: 1022: if (reg == 0) 1023: abort (); 1024: 1025: /* legitimize both operands of the PLUS */ 1026: if (GET_CODE (XEXP (orig, 0)) == PLUS) 1027: { 1028: base = legitimize_pic_address (XEXP (XEXP (orig, 0), 0), Pmode, reg); 1029: orig = legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode, 1030: base == reg ? 0 : reg); 1031: } 1032: else abort (); 1033: 1034: if (GET_CODE (orig) == CONST_INT) 1035: return plus_constant_for_output (base, INTVAL (orig)); 1036: pic_ref = gen_rtx (PLUS, Pmode, base, orig); 1037: /* Likewise, should we set special REG_NOTEs here? */ 1038: } 1039: return pic_ref; 1040: } 1041: 1042: 1.1.1.4 ! root 1043: typedef enum { MOVL, SWAP, NEGW, NOTW, NOTB, MOVQ } CONST_METHOD; ! 1044: ! 1045: use_movq (i) ! 1046: int i; ! 1047: { ! 1048: return (i >= -128 && i <= 127); ! 1049: } ! 1050: ! 1051: CONST_METHOD ! 1052: const_method (constant) ! 1053: rtx constant; ! 1054: { ! 1055: int i; ! 1056: unsigned u; ! 1057: ! 1058: i = INTVAL (constant); ! 1059: if (use_movq (i)) ! 1060: return MOVQ; ! 1061: /* if -256 < N < 256 but N is not in range for a moveq ! 1062: N^ff will be, so use moveq #N^ff, dreg; not.b dreg. */ ! 1063: if (use_movq (i ^ 0xff)) ! 1064: return NOTB; ! 1065: /* Likewise, try with not.w */ ! 1066: if (use_movq (i ^ 0xffff)) ! 1067: return NOTW; ! 1068: /* This is the only value where neg.w is useful */ ! 1069: if (i == -65408) ! 1070: return NEGW; ! 1071: /* Try also with swap */ ! 1072: u = i; ! 1073: if (use_movq ((u >> 16) | (u << 16))) ! 1074: return SWAP; ! 1075: /* Otherwise, use move.l */ ! 1076: return MOVL; ! 1077: } ! 1078: ! 1079: const_int_cost (constant) ! 1080: rtx constant; ! 1081: { ! 1082: switch (const_method (constant)) ! 1083: { ! 1084: case MOVQ : ! 1085: /* Constants between -128 and 127 are cheap due to moveq */ ! 1086: return 0; ! 1087: case NOTB : ! 1088: case NOTW : ! 1089: case NEGW : ! 1090: case SWAP : ! 1091: /* Constants easily generated by moveq + not.b/not.w/neg.w/swap */ ! 1092: return 1; ! 1093: case MOVL : ! 1094: return 2; ! 1095: default : ! 1096: abort (); ! 1097: } ! 1098: } ! 1099: ! 1100: char * ! 1101: output_move_const_into_data_reg (operands) ! 1102: rtx *operands; ! 1103: { ! 1104: int i; ! 1105: ! 1106: i = INTVAL (operands[1]); ! 1107: switch (const_method (operands[1])) ! 1108: { ! 1109: case MOVQ : ! 1110: #if defined (MOTOROLA) && !defined (CRDS) ! 1111: return "moveq%.l %1,%0"; ! 1112: #else ! 1113: return "moveq %1,%0"; ! 1114: #endif ! 1115: case NOTB : ! 1116: operands[1] = gen_rtx (CONST_INT, VOIDmode, i ^ 0xff); ! 1117: #if defined (MOTOROLA) && !defined (CRDS) ! 1118: return "moveq%.l %1,%0\n\tnot%.b %0"; ! 1119: #else ! 1120: return "moveq %1,%0\n\tnot%.b %0"; ! 1121: #endif ! 1122: case NOTW : ! 1123: operands[1] = gen_rtx (CONST_INT, VOIDmode, i ^ 0xffff); ! 1124: #if defined (MOTOROLA) && !defined (CRDS) ! 1125: return "moveq%.l %1,%0\n\tnot%.w %0"; ! 1126: #else ! 1127: return "moveq %1,%0\n\tnot%.w %0"; ! 1128: #endif ! 1129: case NEGW : ! 1130: #if defined (MOTOROLA) && !defined (CRDS) ! 1131: return "moveq%.l %#-128,%0\n\tneg%.w %0"; ! 1132: #else ! 1133: return "moveq %#-128,%0\n\tneg%.w %0"; ! 1134: #endif ! 1135: case SWAP : ! 1136: { ! 1137: unsigned u = i; ! 1138: ! 1139: operands[1] = gen_rtx (CONST_INT, VOIDmode, (u << 16) | (u >> 16)); ! 1140: #if defined (MOTOROLA) && !defined (CRDS) ! 1141: return "moveq%.l %1,%0\n\tswap %0"; ! 1142: #else ! 1143: return "moveq %1,%0\n\tswap %0"; ! 1144: #endif ! 1145: } ! 1146: case MOVL : ! 1147: return "move%.l %1,%0"; ! 1148: default : ! 1149: abort (); ! 1150: } ! 1151: } ! 1152: 1.1 root 1153: /* Return the best assembler insn template 1154: for moving operands[1] into operands[0] as a fullword. */ 1155: 1156: static char * 1157: singlemove_string (operands) 1158: rtx *operands; 1159: { 1160: #ifdef SUPPORT_SUN_FPA 1161: if (FPA_REG_P (operands[0]) || FPA_REG_P (operands[1])) 1162: return "fpmoves %1,%0"; 1163: #endif 1164: if (DATA_REG_P (operands[0]) 1.1.1.4 ! root 1165: && GET_CODE (operands[1]) == CONST_INT) ! 1166: return output_move_const_into_data_reg (operands); 1.1 root 1167: if (operands[1] != const0_rtx) 1168: return "move%.l %1,%0"; 1169: if (! ADDRESS_REG_P (operands[0])) 1170: return "clr%.l %0"; 1171: return "sub%.l %0,%0"; 1172: } 1173: 1174: 1175: /* Output assembler code to perform a doubleword move insn 1176: with operands OPERANDS. */ 1177: 1178: char * 1179: output_move_double (operands) 1180: rtx *operands; 1181: { 1182: enum 1183: { 1184: REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP 1185: } optype0, optype1; 1186: rtx latehalf[2]; 1187: rtx middlehalf[2]; 1.1.1.2 root 1188: rtx xops[2]; 1.1 root 1189: rtx addreg0 = 0, addreg1 = 0; 1.1.1.2 root 1190: int dest_overlapped_low = 0; 1.1 root 1191: int size = GET_MODE_SIZE (GET_MODE (operands[0])); 1192: 1193: middlehalf[0] = 0; 1194: middlehalf[1] = 0; 1195: 1196: /* First classify both operands. */ 1197: 1198: if (REG_P (operands[0])) 1199: optype0 = REGOP; 1200: else if (offsettable_memref_p (operands[0])) 1201: optype0 = OFFSOP; 1202: else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC) 1203: optype0 = POPOP; 1204: else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC) 1205: optype0 = PUSHOP; 1206: else if (GET_CODE (operands[0]) == MEM) 1207: optype0 = MEMOP; 1208: else 1209: optype0 = RNDOP; 1210: 1211: if (REG_P (operands[1])) 1212: optype1 = REGOP; 1213: else if (CONSTANT_P (operands[1])) 1214: optype1 = CNSTOP; 1215: else if (offsettable_memref_p (operands[1])) 1216: optype1 = OFFSOP; 1217: else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC) 1218: optype1 = POPOP; 1219: else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC) 1220: optype1 = PUSHOP; 1221: else if (GET_CODE (operands[1]) == MEM) 1222: optype1 = MEMOP; 1223: else 1224: optype1 = RNDOP; 1225: 1226: /* Check for the cases that the operand constraints are not 1227: supposed to allow to happen. Abort if we get one, 1228: because generating code for these cases is painful. */ 1229: 1230: if (optype0 == RNDOP || optype1 == RNDOP) 1231: abort (); 1232: 1233: /* If one operand is decrementing and one is incrementing 1234: decrement the former register explicitly 1235: and change that operand into ordinary indexing. */ 1236: 1237: if (optype0 == PUSHOP && optype1 == POPOP) 1238: { 1239: operands[0] = XEXP (XEXP (operands[0], 0), 0); 1240: if (size == 12) 1241: output_asm_insn ("sub%.l %#12,%0", operands); 1242: else 1243: output_asm_insn ("subq%.l %#8,%0", operands); 1244: if (GET_MODE (operands[1]) == XFmode) 1245: operands[0] = gen_rtx (MEM, XFmode, operands[0]); 1246: else if (GET_MODE (operands[0]) == DFmode) 1247: operands[0] = gen_rtx (MEM, DFmode, operands[0]); 1248: else 1249: operands[0] = gen_rtx (MEM, DImode, operands[0]); 1250: optype0 = OFFSOP; 1251: } 1252: if (optype0 == POPOP && optype1 == PUSHOP) 1253: { 1254: operands[1] = XEXP (XEXP (operands[1], 0), 0); 1255: if (size == 12) 1256: output_asm_insn ("sub%.l %#12,%1", operands); 1257: else 1258: output_asm_insn ("subq%.l %#8,%1", operands); 1259: if (GET_MODE (operands[1]) == XFmode) 1260: operands[1] = gen_rtx (MEM, XFmode, operands[1]); 1261: else if (GET_MODE (operands[1]) == DFmode) 1262: operands[1] = gen_rtx (MEM, DFmode, operands[1]); 1263: else 1264: operands[1] = gen_rtx (MEM, DImode, operands[1]); 1265: optype1 = OFFSOP; 1266: } 1267: 1268: /* If an operand is an unoffsettable memory ref, find a register 1269: we can increment temporarily to make it refer to the second word. */ 1270: 1271: if (optype0 == MEMOP) 1272: addreg0 = find_addr_reg (XEXP (operands[0], 0)); 1273: 1274: if (optype1 == MEMOP) 1275: addreg1 = find_addr_reg (XEXP (operands[1], 0)); 1276: 1277: /* Ok, we can do one word at a time. 1278: Normally we do the low-numbered word first, 1279: but if either operand is autodecrementing then we 1280: do the high-numbered word first. 1281: 1282: In either case, set up in LATEHALF the operands to use 1283: for the high-numbered word and in some cases alter the 1284: operands in OPERANDS to be suitable for the low-numbered word. */ 1285: 1286: if (size == 12) 1287: { 1288: if (optype0 == REGOP) 1289: { 1290: latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 2); 1291: middlehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); 1292: } 1293: else if (optype0 == OFFSOP) 1294: { 1295: middlehalf[0] = adj_offsettable_operand (operands[0], 4); 1296: latehalf[0] = adj_offsettable_operand (operands[0], size - 4); 1297: } 1298: else 1299: { 1300: middlehalf[0] = operands[0]; 1301: latehalf[0] = operands[0]; 1302: } 1303: 1304: if (optype1 == REGOP) 1305: { 1306: latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 2); 1307: middlehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); 1308: } 1309: else if (optype1 == OFFSOP) 1310: { 1311: middlehalf[1] = adj_offsettable_operand (operands[1], 4); 1312: latehalf[1] = adj_offsettable_operand (operands[1], size - 4); 1313: } 1314: else if (optype1 == CNSTOP) 1315: { 1316: if (GET_CODE (operands[1]) == CONST_DOUBLE) 1317: { 1318: REAL_VALUE_TYPE r; 1319: long l[3]; 1320: 1321: REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]); 1322: REAL_VALUE_TO_TARGET_LONG_DOUBLE (r, l); 1323: operands[1] = GEN_INT (l[0]); 1324: middlehalf[1] = GEN_INT (l[1]); 1325: latehalf[1] = GEN_INT (l[2]); 1326: } 1327: else if (CONSTANT_P (operands[1])) 1328: { 1329: /* actually, no non-CONST_DOUBLE constant should ever 1330: appear here. */ 1331: abort (); 1332: if (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) < 0) 1333: latehalf[1] = constm1_rtx; 1334: else 1335: latehalf[1] = const0_rtx; 1336: } 1337: } 1338: else 1339: { 1340: middlehalf[1] = operands[1]; 1341: latehalf[1] = operands[1]; 1342: } 1343: } 1344: else 1345: /* size is not 12: */ 1346: { 1347: if (optype0 == REGOP) 1348: latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); 1349: else if (optype0 == OFFSOP) 1350: latehalf[0] = adj_offsettable_operand (operands[0], size - 4); 1351: else 1352: latehalf[0] = operands[0]; 1353: 1354: if (optype1 == REGOP) 1355: latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); 1356: else if (optype1 == OFFSOP) 1357: latehalf[1] = adj_offsettable_operand (operands[1], size - 4); 1358: else if (optype1 == CNSTOP) 1359: split_double (operands[1], &operands[1], &latehalf[1]); 1360: else 1361: latehalf[1] = operands[1]; 1362: } 1363: 1364: /* If insn is effectively movd N(sp),-(sp) then we will do the 1365: high word first. We should use the adjusted operand 1 (which is N+4(sp)) 1366: for the low word as well, to compensate for the first decrement of sp. */ 1367: if (optype0 == PUSHOP 1368: && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM 1369: && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1])) 1.1.1.2 root 1370: operands[1] = middlehalf[1] = latehalf[1]; 1371: 1372: /* For (set (reg:DI N) (mem:DI ... (reg:SI N) ...)), 1373: if the upper part of reg N does not appear in the MEM, arrange to 1374: emit the move late-half first. Otherwise, compute the MEM address 1375: into the upper part of N and use that as a pointer to the memory 1376: operand. */ 1377: if (optype0 == REGOP 1378: && (optype1 == OFFSOP || optype1 == MEMOP)) 1379: { 1380: rtx testlow = gen_rtx (REG, SImode, REGNO (operands[0])); 1381: 1382: if (reg_overlap_mentioned_p (testlow, XEXP (operands[1], 0)) 1383: && reg_overlap_mentioned_p (latehalf[0], XEXP (operands[1], 0))) 1384: { 1385: /* If both halves of dest are used in the src memory address, 1386: compute the address into latehalf of dest. 1387: Note that this can't happen if the dest is two data regs. */ 1388: compadr: 1389: xops[0] = latehalf[0]; 1390: xops[1] = XEXP (operands[1], 0); 1391: output_asm_insn ("lea %a1,%0", xops); 1392: if( GET_MODE (operands[1]) == XFmode ) 1393: { 1394: operands[1] = gen_rtx (MEM, XFmode, latehalf[0]); 1395: middlehalf[1] = adj_offsettable_operand (operands[1], size-8); 1396: latehalf[1] = adj_offsettable_operand (operands[1], size-4); 1397: } 1398: else 1399: { 1400: operands[1] = gen_rtx (MEM, DImode, latehalf[0]); 1401: latehalf[1] = adj_offsettable_operand (operands[1], size-4); 1402: } 1403: } 1404: else if (size == 12 1405: && reg_overlap_mentioned_p (middlehalf[0], 1406: XEXP (operands[1], 0))) 1407: { 1408: /* Check for two regs used by both source and dest. 1409: Note that this can't happen if the dest is all data regs. 1410: It can happen if the dest is d6, d7, a0. 1411: But in that case, latehalf is an addr reg, so 1412: the code at compadr does ok. */ 1413: 1414: if (reg_overlap_mentioned_p (testlow, XEXP (operands[1], 0)) 1415: || reg_overlap_mentioned_p (latehalf[0], XEXP (operands[1], 0))) 1416: goto compadr; 1417: 1418: /* JRV says this can't happen: */ 1419: if (addreg0 || addreg1) 1420: abort (); 1421: 1422: /* Only the middle reg conflicts; simply put it last. */ 1423: output_asm_insn (singlemove_string (operands), operands); 1424: output_asm_insn (singlemove_string (latehalf), latehalf); 1425: output_asm_insn (singlemove_string (middlehalf), middlehalf); 1426: return ""; 1427: } 1428: else if (reg_overlap_mentioned_p (testlow, XEXP (operands[1], 0))) 1429: /* If the low half of dest is mentioned in the source memory 1430: address, the arrange to emit the move late half first. */ 1431: dest_overlapped_low = 1; 1432: } 1.1 root 1433: 1434: /* If one or both operands autodecrementing, 1435: do the two words, high-numbered first. */ 1436: 1437: /* Likewise, the first move would clobber the source of the second one, 1438: do them in the other order. This happens only for registers; 1439: such overlap can't happen in memory unless the user explicitly 1440: sets it up, and that is an undefined circumstance. */ 1441: 1442: if (optype0 == PUSHOP || optype1 == PUSHOP 1443: || (optype0 == REGOP && optype1 == REGOP 1444: && ((middlehalf[1] && REGNO (operands[0]) == REGNO (middlehalf[1])) 1.1.1.2 root 1445: || REGNO (operands[0]) == REGNO (latehalf[1]))) 1446: || dest_overlapped_low) 1.1 root 1447: { 1448: /* Make any unoffsettable addresses point at high-numbered word. */ 1449: if (addreg0) 1450: { 1451: if (size == 12) 1.1.1.3 root 1452: output_asm_insn ("addq%.l %#8,%0", &addreg0); 1.1 root 1453: else 1.1.1.3 root 1454: output_asm_insn ("addq%.l %#4,%0", &addreg0); 1.1 root 1455: } 1456: if (addreg1) 1457: { 1458: if (size == 12) 1.1.1.3 root 1459: output_asm_insn ("addq%.l %#8,%0", &addreg1); 1.1 root 1460: else 1.1.1.3 root 1461: output_asm_insn ("addq%.l %#4,%0", &addreg1); 1.1 root 1462: } 1463: 1464: /* Do that word. */ 1465: output_asm_insn (singlemove_string (latehalf), latehalf); 1466: 1467: /* Undo the adds we just did. */ 1468: if (addreg0) 1.1.1.3 root 1469: output_asm_insn ("subq%.l %#4,%0", &addreg0); 1.1 root 1470: if (addreg1) 1.1.1.3 root 1471: output_asm_insn ("subq%.l %#4,%0", &addreg1); 1.1 root 1472: 1473: if (size == 12) 1474: { 1475: output_asm_insn (singlemove_string (middlehalf), middlehalf); 1476: if (addreg0) 1.1.1.3 root 1477: output_asm_insn ("subq%.l %#4,%0", &addreg0); 1.1 root 1478: if (addreg1) 1.1.1.3 root 1479: output_asm_insn ("subq%.l %#4,%0", &addreg1); 1.1 root 1480: } 1481: 1482: /* Do low-numbered word. */ 1483: return singlemove_string (operands); 1484: } 1485: 1486: /* Normal case: do the two words, low-numbered first. */ 1487: 1488: output_asm_insn (singlemove_string (operands), operands); 1489: 1490: /* Do the middle one of the three words for long double */ 1491: if (size == 12) 1492: { 1493: if (addreg0) 1.1.1.3 root 1494: output_asm_insn ("addq%.l %#4,%0", &addreg0); 1.1 root 1495: if (addreg1) 1.1.1.3 root 1496: output_asm_insn ("addq%.l %#4,%0", &addreg1); 1.1 root 1497: 1498: output_asm_insn (singlemove_string (middlehalf), middlehalf); 1499: } 1500: 1501: /* Make any unoffsettable addresses point at high-numbered word. */ 1502: if (addreg0) 1.1.1.3 root 1503: output_asm_insn ("addq%.l %#4,%0", &addreg0); 1.1 root 1504: if (addreg1) 1.1.1.3 root 1505: output_asm_insn ("addq%.l %#4,%0", &addreg1); 1.1 root 1506: 1507: /* Do that word. */ 1508: output_asm_insn (singlemove_string (latehalf), latehalf); 1509: 1510: /* Undo the adds we just did. */ 1511: if (addreg0) 1512: { 1513: if (size == 12) 1.1.1.3 root 1514: output_asm_insn ("subq%.l %#8,%0", &addreg0); 1.1 root 1515: else 1.1.1.3 root 1516: output_asm_insn ("subq%.l %#4,%0", &addreg0); 1.1 root 1517: } 1518: if (addreg1) 1519: { 1520: if (size == 12) 1.1.1.3 root 1521: output_asm_insn ("subq%.l %#8,%0", &addreg1); 1.1 root 1522: else 1.1.1.3 root 1523: output_asm_insn ("subq%.l %#4,%0", &addreg1); 1.1 root 1524: } 1525: 1526: return ""; 1527: } 1528: 1529: /* Return a REG that occurs in ADDR with coefficient 1. 1530: ADDR can be effectively incremented by incrementing REG. */ 1531: 1532: static rtx 1533: find_addr_reg (addr) 1534: rtx addr; 1535: { 1536: while (GET_CODE (addr) == PLUS) 1537: { 1538: if (GET_CODE (XEXP (addr, 0)) == REG) 1539: addr = XEXP (addr, 0); 1540: else if (GET_CODE (XEXP (addr, 1)) == REG) 1541: addr = XEXP (addr, 1); 1542: else if (CONSTANT_P (XEXP (addr, 0))) 1543: addr = XEXP (addr, 1); 1544: else if (CONSTANT_P (XEXP (addr, 1))) 1545: addr = XEXP (addr, 0); 1546: else 1547: abort (); 1548: } 1549: if (GET_CODE (addr) == REG) 1550: return addr; 1551: abort (); 1552: } 1553: 1554: /* Store in cc_status the expressions that the condition codes will 1555: describe after execution of an instruction whose pattern is EXP. 1556: Do not alter them if the instruction would not alter the cc's. */ 1557: 1558: /* On the 68000, all the insns to store in an address register fail to 1559: set the cc's. However, in some cases these instructions can make it 1560: possibly invalid to use the saved cc's. In those cases we clear out 1561: some or all of the saved cc's so they won't be used. */ 1562: 1563: notice_update_cc (exp, insn) 1564: rtx exp; 1565: rtx insn; 1566: { 1567: /* If the cc is being set from the fpa and the expression is not an 1568: explicit floating point test instruction (which has code to deal with 1569: this), reinit the CC. */ 1570: if (((cc_status.value1 && FPA_REG_P (cc_status.value1)) 1571: || (cc_status.value2 && FPA_REG_P (cc_status.value2))) 1572: && !(GET_CODE (exp) == PARALLEL 1573: && GET_CODE (XVECEXP (exp, 0, 0)) == SET 1574: && XEXP (XVECEXP (exp, 0, 0), 0) == cc0_rtx)) 1575: { 1576: CC_STATUS_INIT; 1577: } 1578: else if (GET_CODE (exp) == SET) 1579: { 1580: if (GET_CODE (SET_SRC (exp)) == CALL) 1581: { 1582: CC_STATUS_INIT; 1583: } 1584: else if (ADDRESS_REG_P (SET_DEST (exp))) 1585: { 1586: if (cc_status.value1 1587: && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value1)) 1588: cc_status.value1 = 0; 1589: if (cc_status.value2 1590: && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value2)) 1591: cc_status.value2 = 0; 1592: } 1593: else if (!FP_REG_P (SET_DEST (exp)) 1594: && SET_DEST (exp) != cc0_rtx 1595: && (FP_REG_P (SET_SRC (exp)) 1596: || GET_CODE (SET_SRC (exp)) == FIX 1597: || GET_CODE (SET_SRC (exp)) == FLOAT_TRUNCATE 1598: || GET_CODE (SET_SRC (exp)) == FLOAT_EXTEND)) 1599: { 1600: CC_STATUS_INIT; 1601: } 1602: /* A pair of move insns doesn't produce a useful overall cc. */ 1603: else if (!FP_REG_P (SET_DEST (exp)) 1604: && !FP_REG_P (SET_SRC (exp)) 1605: && GET_MODE_SIZE (GET_MODE (SET_SRC (exp))) > 4 1606: && (GET_CODE (SET_SRC (exp)) == REG 1607: || GET_CODE (SET_SRC (exp)) == MEM 1608: || GET_CODE (SET_SRC (exp)) == CONST_DOUBLE)) 1609: { 1610: CC_STATUS_INIT; 1611: } 1612: else if (GET_CODE (SET_SRC (exp)) == CALL) 1613: { 1614: CC_STATUS_INIT; 1615: } 1616: else if (XEXP (exp, 0) != pc_rtx) 1617: { 1618: cc_status.flags = 0; 1619: cc_status.value1 = XEXP (exp, 0); 1620: cc_status.value2 = XEXP (exp, 1); 1621: } 1622: } 1623: else if (GET_CODE (exp) == PARALLEL 1624: && GET_CODE (XVECEXP (exp, 0, 0)) == SET) 1625: { 1626: if (ADDRESS_REG_P (XEXP (XVECEXP (exp, 0, 0), 0))) 1627: CC_STATUS_INIT; 1628: else if (XEXP (XVECEXP (exp, 0, 0), 0) != pc_rtx) 1629: { 1630: cc_status.flags = 0; 1631: cc_status.value1 = XEXP (XVECEXP (exp, 0, 0), 0); 1632: cc_status.value2 = XEXP (XVECEXP (exp, 0, 0), 1); 1633: } 1634: } 1635: else 1636: CC_STATUS_INIT; 1637: if (cc_status.value2 != 0 1638: && ADDRESS_REG_P (cc_status.value2) 1639: && GET_MODE (cc_status.value2) == QImode) 1640: CC_STATUS_INIT; 1641: if (cc_status.value2 != 0 1642: && !(cc_status.value1 && FPA_REG_P (cc_status.value1))) 1643: switch (GET_CODE (cc_status.value2)) 1644: { 1645: case PLUS: case MINUS: case MULT: 1646: case DIV: case UDIV: case MOD: case UMOD: case NEG: 1.1.1.3 root 1647: case ASHIFT: case ASHIFTRT: case LSHIFTRT: 1.1 root 1648: case ROTATE: case ROTATERT: 1649: if (GET_MODE (cc_status.value2) != VOIDmode) 1650: cc_status.flags |= CC_NO_OVERFLOW; 1651: break; 1652: case ZERO_EXTEND: 1653: /* (SET r1 (ZERO_EXTEND r2)) on this machine 1654: ends with a move insn moving r2 in r2's mode. 1655: Thus, the cc's are set for r2. 1656: This can set N bit spuriously. */ 1657: cc_status.flags |= CC_NOT_NEGATIVE; 1658: } 1659: if (cc_status.value1 && GET_CODE (cc_status.value1) == REG 1660: && cc_status.value2 1661: && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2)) 1662: cc_status.value2 = 0; 1663: if (((cc_status.value1 && FP_REG_P (cc_status.value1)) 1664: || (cc_status.value2 && FP_REG_P (cc_status.value2))) 1665: && !((cc_status.value1 && FPA_REG_P (cc_status.value1)) 1666: || (cc_status.value2 && FPA_REG_P (cc_status.value2)))) 1667: cc_status.flags = CC_IN_68881; 1668: } 1669: 1670: char * 1671: output_move_const_double (operands) 1672: rtx *operands; 1673: { 1674: #ifdef SUPPORT_SUN_FPA 1675: if (TARGET_FPA && FPA_REG_P (operands[0])) 1676: { 1677: int code = standard_sun_fpa_constant_p (operands[1]); 1678: 1679: if (code != 0) 1680: { 1681: static char buf[40]; 1682: 1683: sprintf (buf, "fpmove%%.d %%%%%d,%%0", code & 0x1ff); 1684: return buf; 1685: } 1686: return "fpmove%.d %1,%0"; 1687: } 1688: else 1689: #endif 1690: { 1691: int code = standard_68881_constant_p (operands[1]); 1692: 1693: if (code != 0) 1694: { 1695: static char buf[40]; 1696: 1697: sprintf (buf, "fmovecr %%#0x%x,%%0", code & 0xff); 1698: return buf; 1699: } 1700: return "fmove%.d %1,%0"; 1701: } 1702: } 1703: 1704: char * 1705: output_move_const_single (operands) 1706: rtx *operands; 1707: { 1708: #ifdef SUPPORT_SUN_FPA 1709: if (TARGET_FPA) 1710: { 1711: int code = standard_sun_fpa_constant_p (operands[1]); 1712: 1713: if (code != 0) 1714: { 1715: static char buf[40]; 1716: 1717: sprintf (buf, "fpmove%%.s %%%%%d,%%0", code & 0x1ff); 1718: return buf; 1719: } 1720: return "fpmove%.s %1,%0"; 1721: } 1722: else 1723: #endif /* defined SUPPORT_SUN_FPA */ 1724: { 1725: int code = standard_68881_constant_p (operands[1]); 1726: 1727: if (code != 0) 1728: { 1729: static char buf[40]; 1730: 1731: sprintf (buf, "fmovecr %%#0x%x,%%0", code & 0xff); 1732: return buf; 1733: } 1734: return "fmove%.s %f1,%0"; 1735: } 1736: } 1737: 1738: /* Return nonzero if X, a CONST_DOUBLE, has a value that we can get 1739: from the "fmovecr" instruction. 1740: The value, anded with 0xff, gives the code to use in fmovecr 1741: to get the desired constant. */ 1742: 1743: /* This code has been fixed for cross-compilation. */ 1744: 1745: static int inited_68881_table = 0; 1746: 1747: char *strings_68881[7] = { 1748: "0.0", 1749: "1.0", 1750: "10.0", 1751: "100.0", 1752: "10000.0", 1753: "1e8", 1754: "1e16" 1755: }; 1756: 1757: int codes_68881[7] = { 1758: 0x0f, 1759: 0x32, 1760: 0x33, 1761: 0x34, 1762: 0x35, 1763: 0x36, 1764: 0x37 1765: }; 1766: 1767: REAL_VALUE_TYPE values_68881[7]; 1768: 1769: /* Set up values_68881 array by converting the decimal values 1770: strings_68881 to binary. */ 1771: 1772: void 1773: init_68881_table () 1774: { 1775: int i; 1776: REAL_VALUE_TYPE r; 1777: enum machine_mode mode; 1778: 1779: mode = DFmode; 1780: for (i = 0; i < 7; i++) 1781: { 1782: if (i == 6) 1783: mode = SFmode; 1784: r = REAL_VALUE_ATOF (strings_68881[i], mode); 1785: values_68881[i] = r; 1786: } 1787: inited_68881_table = 1; 1788: } 1789: 1790: int 1791: standard_68881_constant_p (x) 1792: rtx x; 1793: { 1794: REAL_VALUE_TYPE r; 1795: int i; 1796: enum machine_mode mode; 1797: 1.1.1.3 root 1798: #ifdef NO_ASM_FMOVECR 1799: return 0; 1800: #endif 1801: 1.1 root 1802: /* fmovecr must be emulated on the 68040, so it shouldn't be used at all. */ 1803: if (TARGET_68040) 1804: return 0; 1805: 1806: #ifndef REAL_ARITHMETIC 1807: #if HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT 1808: if (! flag_pretend_float) 1809: return 0; 1810: #endif 1811: #endif 1812: 1813: if (! inited_68881_table) 1814: init_68881_table (); 1815: 1816: REAL_VALUE_FROM_CONST_DOUBLE (r, x); 1817: 1818: for (i = 0; i < 6; i++) 1819: { 1820: if (REAL_VALUES_EQUAL (r, values_68881[i])) 1821: return (codes_68881[i]); 1822: } 1823: 1824: if (GET_MODE (x) == SFmode) 1825: return 0; 1826: 1827: if (REAL_VALUES_EQUAL (r, values_68881[6])) 1828: return (codes_68881[6]); 1829: 1830: /* larger powers of ten in the constants ram are not used 1831: because they are not equal to a `double' C constant. */ 1832: return 0; 1833: } 1834: 1835: /* If X is a floating-point constant, return the logarithm of X base 2, 1836: or 0 if X is not a power of 2. */ 1837: 1838: int 1839: floating_exact_log2 (x) 1840: rtx x; 1841: { 1842: REAL_VALUE_TYPE r, r1; 1843: int i; 1844: 1845: #ifndef REAL_ARITHMETIC 1846: #if HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT 1847: if (! flag_pretend_float) 1848: return 0; 1849: #endif 1850: #endif 1851: 1852: REAL_VALUE_FROM_CONST_DOUBLE (r, x); 1853: 1854: if (REAL_VALUES_LESS (r, dconst0)) 1855: return 0; 1856: 1857: r1 = dconst1; 1858: i = 0; 1859: while (REAL_VALUES_LESS (r1, r)) 1860: { 1861: r1 = REAL_VALUE_LDEXP (dconst1, i); 1862: if (REAL_VALUES_EQUAL (r1, r)) 1863: return i; 1864: i = i + 1; 1865: } 1866: return 0; 1867: } 1868: 1869: #ifdef SUPPORT_SUN_FPA 1870: /* Return nonzero if X, a CONST_DOUBLE, has a value that we can get 1871: from the Sun FPA's constant RAM. 1872: The value returned, anded with 0x1ff, gives the code to use in fpmove 1873: to get the desired constant. */ 1874: 1875: static int inited_FPA_table = 0; 1876: 1877: char *strings_FPA[38] = { 1878: /* small rationals */ 1879: "0.0", 1880: "1.0", 1881: "0.5", 1882: "-1.0", 1883: "2.0", 1884: "3.0", 1885: "4.0", 1886: "8.0", 1887: "0.25", 1888: "0.125", 1889: "10.0", 1890: "-0.5", 1891: /* Decimal equivalents of double precision values */ 1892: "2.718281828459045091", /* D_E */ 1893: "6.283185307179586477", /* 2 pi */ 1894: "3.141592653589793116", /* D_PI */ 1895: "1.570796326794896619", /* pi/2 */ 1896: "1.414213562373095145", /* D_SQRT2 */ 1897: "0.7071067811865475244", /* 1/sqrt(2) */ 1898: "-1.570796326794896619", /* -pi/2 */ 1899: "1.442695040888963387", /* D_LOG2ofE */ 1900: "3.321928024887362182", /* D_LOG2of10 */ 1901: "0.6931471805599452862", /* D_LOGEof2 */ 1902: "2.302585092994045901", /* D_LOGEof10 */ 1903: "0.3010299956639811980", /* D_LOG10of2 */ 1904: "0.4342944819032518167", /* D_LOG10ofE */ 1905: /* Decimal equivalents of single precision values */ 1906: "2.718281745910644531", /* S_E */ 1907: "6.283185307179586477", /* 2 pi */ 1908: "3.141592741012573242", /* S_PI */ 1909: "1.570796326794896619", /* pi/2 */ 1910: "1.414213538169860840", /* S_SQRT2 */ 1911: "0.7071067811865475244", /* 1/sqrt(2) */ 1912: "-1.570796326794896619", /* -pi/2 */ 1913: "1.442695021629333496", /* S_LOG2ofE */ 1914: "3.321928024291992188", /* S_LOG2of10 */ 1915: "0.6931471824645996094", /* S_LOGEof2 */ 1916: "2.302585124969482442", /* S_LOGEof10 */ 1917: "0.3010300099849700928", /* S_LOG10of2 */ 1918: "0.4342944920063018799", /* S_LOG10ofE */ 1919: }; 1920: 1921: 1922: int codes_FPA[38] = { 1923: /* small rationals */ 1924: 0x200, 1925: 0xe, 1926: 0xf, 1927: 0x10, 1928: 0x11, 1929: 0xb1, 1930: 0x12, 1931: 0x13, 1932: 0x15, 1933: 0x16, 1934: 0x17, 1935: 0x2e, 1936: /* double precision */ 1937: 0x8, 1938: 0x9, 1939: 0xa, 1940: 0xb, 1941: 0xc, 1942: 0xd, 1943: 0x27, 1944: 0x28, 1945: 0x29, 1946: 0x2a, 1947: 0x2b, 1948: 0x2c, 1949: 0x2d, 1950: /* single precision */ 1951: 0x8, 1952: 0x9, 1953: 0xa, 1954: 0xb, 1955: 0xc, 1956: 0xd, 1957: 0x27, 1958: 0x28, 1959: 0x29, 1960: 0x2a, 1961: 0x2b, 1962: 0x2c, 1963: 0x2d 1964: }; 1965: 1966: REAL_VALUE_TYPE values_FPA[38]; 1967: 1968: /* This code has been fixed for cross-compilation. */ 1969: 1970: void 1971: init_FPA_table () 1972: { 1973: enum machine_mode mode; 1974: int i; 1975: REAL_VALUE_TYPE r; 1976: 1977: mode = DFmode; 1978: for (i = 0; i < 38; i++) 1979: { 1980: if (i == 25) 1981: mode = SFmode; 1982: r = REAL_VALUE_ATOF (strings_FPA[i], mode); 1983: values_FPA[i] = r; 1984: } 1985: inited_FPA_table = 1; 1986: } 1987: 1988: 1989: int 1990: standard_sun_fpa_constant_p (x) 1991: rtx x; 1992: { 1993: REAL_VALUE_TYPE r; 1994: int i; 1995: 1996: #ifndef REAL_ARITHMETIC 1997: #if HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT 1998: if (! flag_pretend_float) 1999: return 0; 2000: #endif 2001: #endif 2002: 2003: if (! inited_FPA_table) 2004: init_FPA_table (); 2005: 2006: REAL_VALUE_FROM_CONST_DOUBLE (r, x); 2007: 2008: for (i=0; i<12; i++) 2009: { 2010: if (REAL_VALUES_EQUAL (r, values_FPA[i])) 2011: return (codes_FPA[i]); 2012: } 2013: 2014: if (GET_MODE (x) == SFmode) 2015: { 2016: for (i=25; i<38; i++) 2017: { 2018: if (REAL_VALUES_EQUAL (r, values_FPA[i])) 2019: return (codes_FPA[i]); 2020: } 2021: } 2022: else 2023: { 2024: for (i=12; i<25; i++) 2025: { 2026: if (REAL_VALUES_EQUAL (r, values_FPA[i])) 2027: return (codes_FPA[i]); 2028: } 2029: } 2030: return 0x0; 2031: } 2032: #endif /* define SUPPORT_SUN_FPA */ 2033: 2034: /* A C compound statement to output to stdio stream STREAM the 2035: assembler syntax for an instruction operand X. X is an RTL 2036: expression. 2037: 2038: CODE is a value that can be used to specify one of several ways 2039: of printing the operand. It is used when identical operands 2040: must be printed differently depending on the context. CODE 2041: comes from the `%' specification that was used to request 2042: printing of the operand. If the specification was just `%DIGIT' 2043: then CODE is 0; if the specification was `%LTR DIGIT' then CODE 2044: is the ASCII code for LTR. 2045: 2046: If X is a register, this macro should print the register's name. 2047: The names can be found in an array `reg_names' whose type is 2048: `char *[]'. `reg_names' is initialized from `REGISTER_NAMES'. 2049: 2050: When the machine description has a specification `%PUNCT' (a `%' 2051: followed by a punctuation character), this macro is called with 2052: a null pointer for X and the punctuation character for CODE. 2053: 2054: The m68k specific codes are: 2055: 2056: '.' for dot needed in Motorola-style opcode names. 2057: '-' for an operand pushing on the stack: 2058: sp@-, -(sp) or -(%sp) depending on the style of syntax. 2059: '+' for an operand pushing on the stack: 2060: sp@+, (sp)+ or (%sp)+ depending on the style of syntax. 2061: '@' for a reference to the top word on the stack: 2062: sp@, (sp) or (%sp) depending on the style of syntax. 2063: '#' for an immediate operand prefix (# in MIT and Motorola syntax 2064: but & in SGS syntax). 2065: '!' for the cc register (used in an `and to cc' insn). 2066: '$' for the letter `s' in an op code, but only on the 68040. 2067: '&' for the letter `d' in an op code, but only on the 68040. 2068: '/' for register prefix needed by longlong.h. 2069: 2070: 'b' for byte insn (no effect, on the Sun; this is for the ISI). 2071: 'd' to force memory addressing to be absolute, not relative. 2072: 'f' for float insn (print a CONST_DOUBLE as a float rather than in hex) 2073: 'w' for FPA insn (print a CONST_DOUBLE as a SunFPA constant rather 2074: than directly). Second part of 'y' below. 2075: 'x' for float insn (print a CONST_DOUBLE as a float rather than in hex), 2076: or print pair of registers as rx:ry. 2077: 'y' for a FPA insn (print pair of registers as rx:ry). This also outputs 2078: CONST_DOUBLE's as SunFPA constant RAM registers if 2079: possible, so it should not be used except for the SunFPA. 2080: 2081: */ 2082: 2083: void 2084: print_operand (file, op, letter) 2085: FILE *file; /* file to write to */ 2086: rtx op; /* operand to print */ 2087: int letter; /* %<letter> or 0 */ 2088: { 2089: int i; 2090: 2091: if (letter == '.') 2092: { 2093: #ifdef MOTOROLA 2094: asm_fprintf (file, "."); 2095: #endif 2096: } 2097: else if (letter == '#') 2098: { 2099: asm_fprintf (file, "%0I"); 2100: } 2101: else if (letter == '-') 2102: { 2103: #ifdef MOTOROLA 2104: asm_fprintf (file, "-(%Rsp)"); 2105: #else 2106: asm_fprintf (file, "%Rsp@-"); 2107: #endif 2108: } 2109: else if (letter == '+') 2110: { 2111: #ifdef MOTOROLA 2112: asm_fprintf (file, "(%Rsp)+"); 2113: #else 2114: asm_fprintf (file, "%Rsp@+"); 2115: #endif 2116: } 2117: else if (letter == '@') 2118: { 2119: #ifdef MOTOROLA 2120: asm_fprintf (file, "(%Rsp)"); 2121: #else 2122: asm_fprintf (file, "%Rsp@"); 2123: #endif 2124: } 2125: else if (letter == '!') 2126: { 2127: asm_fprintf (file, "%Rfpcr"); 2128: } 2129: else if (letter == '$') 2130: { 2131: if (TARGET_68040_ONLY) 2132: { 2133: fprintf (file, "s"); 2134: } 2135: } 2136: else if (letter == '&') 2137: { 2138: if (TARGET_68040_ONLY) 2139: { 2140: fprintf (file, "d"); 2141: } 2142: } 2143: else if (letter == '/') 2144: { 2145: asm_fprintf (file, "%R"); 2146: } 2147: else if (GET_CODE (op) == REG) 2148: { 1.1.1.3 root 2149: #ifdef SUPPORT_SUN_FPA 1.1 root 2150: if (REGNO (op) < 16 2151: && (letter == 'y' || letter == 'x') 2152: && GET_MODE (op) == DFmode) 2153: { 2154: fprintf (file, "%s:%s", reg_names[REGNO (op)], 2155: reg_names[REGNO (op)+1]); 2156: } 2157: else 1.1.1.3 root 2158: #endif 1.1 root 2159: { 1.1.1.4 ! root 2160: if (letter == 'R') ! 2161: /* Print out the second register name of a register pair. ! 2162: I.e., R (6) => 7. */ ! 2163: fputs (reg_names[REGNO (op) + 1], file); ! 2164: else ! 2165: fputs (reg_names[REGNO (op)], file); 1.1 root 2166: } 2167: } 2168: else if (GET_CODE (op) == MEM) 2169: { 2170: output_address (XEXP (op, 0)); 2171: if (letter == 'd' && ! TARGET_68020 2172: && CONSTANT_ADDRESS_P (XEXP (op, 0)) 2173: && !(GET_CODE (XEXP (op, 0)) == CONST_INT 2174: && INTVAL (XEXP (op, 0)) < 0x8000 2175: && INTVAL (XEXP (op, 0)) >= -0x8000)) 2176: { 2177: fprintf (file, ":l"); 2178: } 2179: } 2180: #ifdef SUPPORT_SUN_FPA 2181: else if ((letter == 'y' || letter == 'w') 2182: && GET_CODE (op) == CONST_DOUBLE 2183: && (i = standard_sun_fpa_constant_p (op))) 2184: { 2185: fprintf (file, "%%%d", i & 0x1ff); 2186: } 2187: #endif 2188: else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == SFmode) 2189: { 2190: REAL_VALUE_TYPE r; 2191: REAL_VALUE_FROM_CONST_DOUBLE (r, op); 2192: ASM_OUTPUT_FLOAT_OPERAND (letter, file, r); 2193: } 2194: else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == XFmode) 2195: { 2196: REAL_VALUE_TYPE r; 2197: REAL_VALUE_FROM_CONST_DOUBLE (r, op); 2198: ASM_OUTPUT_LONG_DOUBLE_OPERAND (file, r); 2199: } 2200: else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == DFmode) 2201: { 2202: REAL_VALUE_TYPE r; 2203: REAL_VALUE_FROM_CONST_DOUBLE (r, op); 2204: ASM_OUTPUT_DOUBLE_OPERAND (file, r); 2205: } 2206: else 2207: { 2208: asm_fprintf (file, "%0I"); output_addr_const (file, op); 2209: } 2210: } 2211: 2212: 2213: /* A C compound statement to output to stdio stream STREAM the 2214: assembler syntax for an instruction operand that is a memory 2215: reference whose address is ADDR. ADDR is an RTL expression. 2216: 2217: Note that this contains a kludge that knows that the only reason 2218: we have an address (plus (label_ref...) (reg...)) when not generating 2219: PIC code is in the insn before a tablejump, and we know that m68k.md 2220: generates a label LInnn: on such an insn. 2221: 2222: It is possible for PIC to generate a (plus (label_ref...) (reg...)) 2223: and we handle that just like we would a (plus (symbol_ref...) (reg...)). 2224: 2225: Some SGS assemblers have a bug such that "Lnnn-LInnn-2.b(pc,d0.l*2)" 2226: fails to assemble. Luckily "Lnnn(pc,d0.l*2)" produces the results 2227: we want. This difference can be accommodated by using an assembler 2228: define such "LDnnn" to be either "Lnnn-LInnn-2.b", "Lnnn", or any other 2229: string, as necessary. This is accomplished via the ASM_OUTPUT_CASE_END 2230: macro. See m68k/sgs.h for an example; for versions without the bug. 1.1.1.3 root 2231: Some assemblers refuse all the above solutions. The workaround is to 2232: emit "K(pc,d0.l*2)" with K being a small constant known to give the 2233: right behaviour. 1.1 root 2234: 2235: They also do not like things like "pea 1.w", so we simple leave off 2236: the .w on small constants. 2237: 2238: This routine is responsible for distinguishing between -fpic and -fPIC 2239: style relocations in an address. When generating -fpic code the 2240: offset is output in word mode (eg movel a5@(_foo:w), a0). When generating 2241: -fPIC code the offset is output in long mode (eg movel a5@(_foo:l), a0) */ 2242: 1.1.1.3 root 2243: #ifndef ASM_OUTPUT_CASE_FETCH 2244: #ifdef MOTOROLA 2245: #ifdef SGS 2246: #define ASM_OUTPUT_CASE_FETCH(file, labelno, regname)\ 2247: asm_fprintf (file, "%LLD%d(%Rpc,%s.", labelno, regname) 2248: #else 2249: #define ASM_OUTPUT_CASE_FETCH(file, labelno, regname)\ 2250: asm_fprintf (file, "%LL%d-%LLI%d.b(%Rpc,%s.", labelno, labelno, regname) 2251: #endif 2252: #else 2253: #define ASM_OUTPUT_CASE_FETCH(file, labelno, regname)\ 2254: asm_fprintf (file, "%Rpc@(%LL%d-%LLI%d-2:b,%s:", labelno, labelno, regname) 2255: #endif 2256: #endif /* ASM_OUTPUT_CASE_FETCH */ 2257: 1.1 root 2258: void 2259: print_operand_address (file, addr) 2260: FILE *file; 2261: rtx addr; 2262: { 2263: register rtx reg1, reg2, breg, ireg; 2264: rtx offset; 2265: 2266: switch (GET_CODE (addr)) 2267: { 2268: case REG: 2269: #ifdef MOTOROLA 2270: fprintf (file, "(%s)", reg_names[REGNO (addr)]); 2271: #else 2272: fprintf (file, "%s@", reg_names[REGNO (addr)]); 2273: #endif 2274: break; 2275: case PRE_DEC: 2276: #ifdef MOTOROLA 2277: fprintf (file, "-(%s)", reg_names[REGNO (XEXP (addr, 0))]); 2278: #else 2279: fprintf (file, "%s@-", reg_names[REGNO (XEXP (addr, 0))]); 2280: #endif 2281: break; 2282: case POST_INC: 2283: #ifdef MOTOROLA 2284: fprintf (file, "(%s)+", reg_names[REGNO (XEXP (addr, 0))]); 2285: #else 2286: fprintf (file, "%s@+", reg_names[REGNO (XEXP (addr, 0))]); 2287: #endif 2288: break; 2289: case PLUS: 2290: reg1 = reg2 = ireg = breg = offset = 0; 2291: if (CONSTANT_ADDRESS_P (XEXP (addr, 0))) 2292: { 2293: offset = XEXP (addr, 0); 2294: addr = XEXP (addr, 1); 2295: } 2296: else if (CONSTANT_ADDRESS_P (XEXP (addr, 1))) 2297: { 2298: offset = XEXP (addr, 1); 2299: addr = XEXP (addr, 0); 2300: } 2301: if (GET_CODE (addr) != PLUS) 2302: { 2303: ; 2304: } 2305: else if (GET_CODE (XEXP (addr, 0)) == SIGN_EXTEND) 2306: { 2307: reg1 = XEXP (addr, 0); 2308: addr = XEXP (addr, 1); 2309: } 2310: else if (GET_CODE (XEXP (addr, 1)) == SIGN_EXTEND) 2311: { 2312: reg1 = XEXP (addr, 1); 2313: addr = XEXP (addr, 0); 2314: } 2315: else if (GET_CODE (XEXP (addr, 0)) == MULT) 2316: { 2317: reg1 = XEXP (addr, 0); 2318: addr = XEXP (addr, 1); 2319: } 2320: else if (GET_CODE (XEXP (addr, 1)) == MULT) 2321: { 2322: reg1 = XEXP (addr, 1); 2323: addr = XEXP (addr, 0); 2324: } 2325: else if (GET_CODE (XEXP (addr, 0)) == REG) 2326: { 2327: reg1 = XEXP (addr, 0); 2328: addr = XEXP (addr, 1); 2329: } 2330: else if (GET_CODE (XEXP (addr, 1)) == REG) 2331: { 2332: reg1 = XEXP (addr, 1); 2333: addr = XEXP (addr, 0); 2334: } 2335: if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT 2336: || GET_CODE (addr) == SIGN_EXTEND) 2337: { 2338: if (reg1 == 0) 2339: { 2340: reg1 = addr; 2341: } 2342: else 2343: { 2344: reg2 = addr; 2345: } 2346: addr = 0; 2347: } 2348: #if 0 /* for OLD_INDEXING */ 2349: else if (GET_CODE (addr) == PLUS) 2350: { 2351: if (GET_CODE (XEXP (addr, 0)) == REG) 2352: { 2353: reg2 = XEXP (addr, 0); 2354: addr = XEXP (addr, 1); 2355: } 2356: else if (GET_CODE (XEXP (addr, 1)) == REG) 2357: { 2358: reg2 = XEXP (addr, 1); 2359: addr = XEXP (addr, 0); 2360: } 2361: } 2362: #endif 2363: if (offset != 0) 2364: { 2365: if (addr != 0) 2366: { 2367: abort (); 2368: } 2369: addr = offset; 2370: } 2371: if ((reg1 && (GET_CODE (reg1) == SIGN_EXTEND 2372: || GET_CODE (reg1) == MULT)) 2373: || (reg2 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg2)))) 2374: { 2375: breg = reg2; 2376: ireg = reg1; 2377: } 2378: else if (reg1 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg1))) 2379: { 2380: breg = reg1; 2381: ireg = reg2; 2382: } 2383: if (ireg != 0 && breg == 0 && GET_CODE (addr) == LABEL_REF 2384: && ! (flag_pic && ireg == pic_offset_table_rtx)) 2385: { 2386: int scale = 1; 2387: if (GET_CODE (ireg) == MULT) 2388: { 2389: scale = INTVAL (XEXP (ireg, 1)); 2390: ireg = XEXP (ireg, 0); 2391: } 2392: if (GET_CODE (ireg) == SIGN_EXTEND) 2393: { 1.1.1.3 root 2394: ASM_OUTPUT_CASE_FETCH (file, 1.1 root 2395: CODE_LABEL_NUMBER (XEXP (addr, 0)), 2396: reg_names[REGNO (XEXP (ireg, 0))]); 1.1.1.3 root 2397: fprintf (file, "w"); 1.1 root 2398: } 2399: else 2400: { 1.1.1.3 root 2401: ASM_OUTPUT_CASE_FETCH (file, 1.1 root 2402: CODE_LABEL_NUMBER (XEXP (addr, 0)), 2403: reg_names[REGNO (ireg)]); 1.1.1.3 root 2404: fprintf (file, "l"); 1.1 root 2405: } 2406: if (scale != 1) 2407: { 2408: #ifdef MOTOROLA 2409: fprintf (file, "*%d", scale); 2410: #else 2411: fprintf (file, ":%d", scale); 2412: #endif 2413: } 2414: putc (')', file); 2415: break; 2416: } 2417: if (breg != 0 && ireg == 0 && GET_CODE (addr) == LABEL_REF 2418: && ! (flag_pic && breg == pic_offset_table_rtx)) 2419: { 1.1.1.3 root 2420: ASM_OUTPUT_CASE_FETCH (file, 1.1 root 2421: CODE_LABEL_NUMBER (XEXP (addr, 0)), 2422: reg_names[REGNO (breg)]); 1.1.1.3 root 2423: fprintf (file, "l)"); 1.1 root 2424: break; 2425: } 2426: if (ireg != 0 || breg != 0) 2427: { 2428: int scale = 1; 2429: if (breg == 0) 2430: { 2431: abort (); 2432: } 2433: if (! flag_pic && addr && GET_CODE (addr) == LABEL_REF) 2434: { 2435: abort (); 2436: } 2437: #ifdef MOTOROLA 2438: if (addr != 0) 2439: { 2440: output_addr_const (file, addr); 2441: if (flag_pic && (breg == pic_offset_table_rtx)) 2442: fprintf (file, "@GOT"); 2443: } 2444: fprintf (file, "(%s", reg_names[REGNO (breg)]); 2445: if (ireg != 0) 2446: { 2447: putc (',', file); 2448: } 2449: #else 2450: fprintf (file, "%s@(", reg_names[REGNO (breg)]); 2451: if (addr != 0) 2452: { 2453: output_addr_const (file, addr); 2454: if ((flag_pic == 1) && (breg == pic_offset_table_rtx)) 2455: fprintf (file, ":w"); 2456: if ((flag_pic == 2) && (breg == pic_offset_table_rtx)) 2457: fprintf (file, ":l"); 2458: } 2459: if (addr != 0 && ireg != 0) 2460: { 2461: putc (',', file); 2462: } 2463: #endif 2464: if (ireg != 0 && GET_CODE (ireg) == MULT) 2465: { 2466: scale = INTVAL (XEXP (ireg, 1)); 2467: ireg = XEXP (ireg, 0); 2468: } 2469: if (ireg != 0 && GET_CODE (ireg) == SIGN_EXTEND) 2470: { 2471: #ifdef MOTOROLA 2472: fprintf (file, "%s.w", reg_names[REGNO (XEXP (ireg, 0))]); 2473: #else 2474: fprintf (file, "%s:w", reg_names[REGNO (XEXP (ireg, 0))]); 2475: #endif 2476: } 2477: else if (ireg != 0) 2478: { 2479: #ifdef MOTOROLA 2480: fprintf (file, "%s.l", reg_names[REGNO (ireg)]); 2481: #else 2482: fprintf (file, "%s:l", reg_names[REGNO (ireg)]); 2483: #endif 2484: } 2485: if (scale != 1) 2486: { 2487: #ifdef MOTOROLA 2488: fprintf (file, "*%d", scale); 2489: #else 2490: fprintf (file, ":%d", scale); 2491: #endif 2492: } 2493: putc (')', file); 2494: break; 2495: } 2496: else if (reg1 != 0 && GET_CODE (addr) == LABEL_REF 2497: && ! (flag_pic && reg1 == pic_offset_table_rtx)) 2498: { 1.1.1.3 root 2499: ASM_OUTPUT_CASE_FETCH (file, 1.1 root 2500: CODE_LABEL_NUMBER (XEXP (addr, 0)), 2501: reg_names[REGNO (reg1)]); 1.1.1.3 root 2502: fprintf (file, "l)"); 1.1 root 2503: break; 2504: } 2505: /* FALL-THROUGH (is this really what we want? */ 2506: default: 2507: if (GET_CODE (addr) == CONST_INT 2508: && INTVAL (addr) < 0x8000 2509: && INTVAL (addr) >= -0x8000) 2510: { 2511: #ifdef MOTOROLA 2512: #ifdef SGS 2513: /* Many SGS assemblers croak on size specifiers for constants. */ 2514: fprintf (file, "%d", INTVAL (addr)); 2515: #else 2516: fprintf (file, "%d.w", INTVAL (addr)); 2517: #endif 2518: #else 2519: fprintf (file, "%d:w", INTVAL (addr)); 2520: #endif 2521: } 2522: else 2523: { 2524: output_addr_const (file, addr); 2525: } 2526: break; 2527: } 2528: } 2529: 2530: /* Check for cases where a clr insns can be omitted from code using 2531: strict_low_part sets. For example, the second clrl here is not needed: 2532: clrl d0; movw a0@+,d0; use d0; clrl d0; movw a0@+; use d0; ... 2533: 2534: MODE is the mode of this STRICT_LOW_PART set. FIRST_INSN is the clear 2535: insn we are checking for redundancy. TARGET is the register set by the 2536: clear insn. */ 2537: 2538: int 2539: strict_low_part_peephole_ok (mode, first_insn, target) 2540: enum machine_mode mode; 2541: rtx first_insn; 2542: rtx target; 2543: { 2544: rtx p; 2545: 2546: p = prev_nonnote_insn (first_insn); 2547: 2548: while (p) 2549: { 2550: /* If it isn't an insn, then give up. */ 2551: if (GET_CODE (p) != INSN) 2552: return 0; 2553: 2554: if (reg_set_p (target, p)) 2555: { 2556: rtx set = single_set (p); 2557: rtx dest; 2558: 2559: /* If it isn't an easy to recognize insn, then give up. */ 2560: if (! set) 2561: return 0; 2562: 2563: dest = SET_DEST (set); 2564: 2565: /* If this sets the entire target register to zero, then our 2566: first_insn is redundant. */ 2567: if (rtx_equal_p (dest, target) 2568: && SET_SRC (set) == const0_rtx) 2569: return 1; 2570: else if (GET_CODE (dest) == STRICT_LOW_PART 2571: && GET_CODE (XEXP (dest, 0)) == REG 2572: && REGNO (XEXP (dest, 0)) == REGNO (target) 2573: && (GET_MODE_SIZE (GET_MODE (XEXP (dest, 0))) 2574: <= GET_MODE_SIZE (mode))) 2575: /* This is a strict low part set which modifies less than 2576: we are using, so it is safe. */ 2577: ; 2578: else 2579: return 0; 2580: } 2581: 2582: p = prev_nonnote_insn (p); 2583: 2584: } 2585: 2586: return 0; 2587: } 1.1.1.4 ! root 2588: ! 2589: /* Accept integer operands in the range 0..0xffffffff. We have to check the ! 2590: range carefully since this predicate is used in DImode contexts. Also, we ! 2591: need some extra crud to make it work when hosted on 64-bit machines. */ ! 2592: ! 2593: int ! 2594: const_uint32_operand (op, mode) ! 2595: rtx op; ! 2596: enum machine_mode mode; ! 2597: { ! 2598: #if HOST_BITS_PER_WIDE_INT > 32 ! 2599: /* All allowed constants will fit a CONST_INT. */ ! 2600: return (GET_CODE (op) == CONST_INT ! 2601: && (INTVAL (op) >= 0 && INTVAL (op) <= 0xffffffffL)); ! 2602: #else ! 2603: return ((GET_CODE (op) == CONST_INT && INTVAL (op) >= 0) ! 2604: || (GET_CODE (op) == CONST_DOUBLE && CONST_DOUBLE_HIGH (op) == 0)); ! 2605: #endif ! 2606: } ! 2607: ! 2608: /* Accept integer operands in the range -0x80000000..0x7fffffff. We have ! 2609: to check the range carefully since this predicate is used in DImode ! 2610: contexts. */ ! 2611: ! 2612: int ! 2613: const_sint32_operand (op, mode) ! 2614: rtx op; ! 2615: enum machine_mode mode; ! 2616: { ! 2617: /* All allowed constants will fit a CONST_INT. */ ! 2618: return (GET_CODE (op) == CONST_INT ! 2619: && (INTVAL (op) >= (-0x7fffffff - 1) && INTVAL (op) <= 0x7fffffff)); ! 2620: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.