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