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