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