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