|
|
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 1, 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: extern FILE *asm_out_file; ! 24: ! 25: /* Index into this array by (register number >> 3) to find the ! 26: smallest class which contains that register. */ ! 27: enum reg_class regno_reg_class[] ! 28: = { DATA_REGS, ADDR_REGS, FP_REGS, ! 29: LO_FPA_REGS, LO_FPA_REGS, FPA_REGS, FPA_REGS }; ! 30: ! 31: static rtx find_addr_reg (); ! 32: ! 33: char * ! 34: output_btst (operands, countop, dataop, insn, signpos) ! 35: rtx *operands; ! 36: rtx countop, dataop; ! 37: rtx insn; ! 38: int signpos; ! 39: { ! 40: operands[0] = countop; ! 41: operands[1] = dataop; ! 42: ! 43: if (GET_CODE (countop) == CONST_INT) ! 44: { ! 45: register int count = INTVAL (countop); ! 46: /* If COUNT is bigger than size of storage unit in use, ! 47: advance to the containing unit of same size. */ ! 48: if (count > signpos) ! 49: { ! 50: int offset = (count & ~signpos) / 8; ! 51: count = count & signpos; ! 52: operands[1] = dataop = adj_offsettable_operand (dataop, offset); ! 53: } ! 54: if (count == signpos) ! 55: cc_status.flags = CC_NOT_POSITIVE | CC_Z_IN_NOT_N; ! 56: else ! 57: cc_status.flags = CC_NOT_NEGATIVE | CC_Z_IN_NOT_N; ! 58: ! 59: if (count == 31 ! 60: && next_insns_test_no_inequality (insn)) ! 61: return "tst%.l %1"; ! 62: if (count == 15 ! 63: && next_insns_test_no_inequality (insn)) ! 64: return "tst%.w %1"; ! 65: if (count == 7 ! 66: && next_insns_test_no_inequality (insn)) ! 67: return "tst%.b %1"; ! 68: ! 69: cc_status.flags = CC_NOT_NEGATIVE; ! 70: } ! 71: return "btst %0,%1"; ! 72: } ! 73: ! 74: /* Return the best assembler insn template ! 75: for moving operands[1] into operands[0] as a fullword. */ ! 76: ! 77: static char * ! 78: singlemove_string (operands) ! 79: rtx *operands; ! 80: { ! 81: if (FPA_REG_P (operands[0]) || FPA_REG_P (operands[1])) ! 82: return "fpmoves %1,%0"; ! 83: if (operands[1] != const0_rtx) ! 84: return "move%.l %1,%0"; ! 85: if (! ADDRESS_REG_P (operands[0])) ! 86: return "clr%.l %0"; ! 87: return "sub%.l %0,%0"; ! 88: } ! 89: ! 90: /* Output assembler code to perform a doubleword move insn ! 91: with operands OPERANDS. */ ! 92: ! 93: char * ! 94: output_move_double (operands) ! 95: rtx *operands; ! 96: { ! 97: enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1; ! 98: rtx latehalf[2]; ! 99: rtx addreg0 = 0, addreg1 = 0; ! 100: ! 101: /* First classify both operands. */ ! 102: ! 103: if (REG_P (operands[0])) ! 104: optype0 = REGOP; ! 105: else if (offsettable_memref_p (operands[0])) ! 106: optype0 = OFFSOP; ! 107: else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC) ! 108: optype0 = POPOP; ! 109: else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC) ! 110: optype0 = PUSHOP; ! 111: else if (GET_CODE (operands[0]) == MEM) ! 112: optype0 = MEMOP; ! 113: else ! 114: optype0 = RNDOP; ! 115: ! 116: if (REG_P (operands[1])) ! 117: optype1 = REGOP; ! 118: else if (CONSTANT_P (operands[1]) ! 119: || GET_CODE (operands[1]) == CONST_DOUBLE) ! 120: optype1 = CNSTOP; ! 121: else if (offsettable_memref_p (operands[1])) ! 122: optype1 = OFFSOP; ! 123: else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC) ! 124: optype1 = POPOP; ! 125: else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC) ! 126: optype1 = PUSHOP; ! 127: else if (GET_CODE (operands[1]) == MEM) ! 128: optype1 = MEMOP; ! 129: else ! 130: optype1 = RNDOP; ! 131: ! 132: /* Check for the cases that the operand constraints are not ! 133: supposed to allow to happen. Abort if we get one, ! 134: because generating code for these cases is painful. */ ! 135: ! 136: if (optype0 == RNDOP || optype1 == RNDOP) ! 137: abort (); ! 138: ! 139: /* If one operand is decrementing and one is incrementing ! 140: decrement the former register explicitly ! 141: and change that operand into ordinary indexing. */ ! 142: ! 143: if (optype0 == PUSHOP && optype1 == POPOP) ! 144: { ! 145: operands[0] = XEXP (XEXP (operands[0], 0), 0); ! 146: output_asm_insn ("subq%.l %#8,%0", operands); ! 147: operands[0] = gen_rtx (MEM, DImode, operands[0]); ! 148: optype0 = OFFSOP; ! 149: } ! 150: if (optype0 == POPOP && optype1 == PUSHOP) ! 151: { ! 152: operands[1] = XEXP (XEXP (operands[1], 0), 0); ! 153: output_asm_insn ("subq%.l %#8,%1", operands); ! 154: operands[1] = gen_rtx (MEM, DImode, operands[1]); ! 155: optype1 = OFFSOP; ! 156: } ! 157: ! 158: /* If an operand is an unoffsettable memory ref, find a register ! 159: we can increment temporarily to make it refer to the second word. */ ! 160: ! 161: if (optype0 == MEMOP) ! 162: addreg0 = find_addr_reg (XEXP (operands[0], 0)); ! 163: ! 164: if (optype1 == MEMOP) ! 165: addreg1 = find_addr_reg (XEXP (operands[1], 0)); ! 166: ! 167: /* Ok, we can do one word at a time. ! 168: Normally we do the low-numbered word first, ! 169: but if either operand is autodecrementing then we ! 170: do the high-numbered word first. ! 171: ! 172: In either case, set up in LATEHALF the operands to use ! 173: for the high-numbered word and in some cases alter the ! 174: operands in OPERANDS to be suitable for the low-numbered word. */ ! 175: ! 176: if (optype0 == REGOP) ! 177: latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); ! 178: else if (optype0 == OFFSOP) ! 179: latehalf[0] = adj_offsettable_operand (operands[0], 4); ! 180: else ! 181: latehalf[0] = operands[0]; ! 182: ! 183: if (optype1 == REGOP) ! 184: latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); ! 185: else if (optype1 == OFFSOP) ! 186: latehalf[1] = adj_offsettable_operand (operands[1], 4); ! 187: else if (optype1 == CNSTOP) ! 188: { ! 189: if (CONSTANT_P (operands[1])) ! 190: latehalf[1] = const0_rtx; ! 191: else if (GET_CODE (operands[1]) == CONST_DOUBLE) ! 192: { ! 193: latehalf[1] = gen_rtx (CONST_INT, VOIDmode, ! 194: CONST_DOUBLE_HIGH (operands[1])); ! 195: operands[1] = gen_rtx (CONST_INT, VOIDmode, ! 196: CONST_DOUBLE_LOW (operands[1])); ! 197: } ! 198: } ! 199: else ! 200: latehalf[1] = operands[1]; ! 201: ! 202: /* If insn is effectively movd N(sp),-(sp) then we will do the ! 203: high word first. We should use the adjusted operand 1 (which is N+4(sp)) ! 204: for the low word as well, to compensate for the first decrement of sp. */ ! 205: if (optype0 == PUSHOP ! 206: && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM ! 207: && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1])) ! 208: operands[1] = latehalf[1]; ! 209: ! 210: /* If one or both operands autodecrementing, ! 211: do the two words, high-numbered first. */ ! 212: ! 213: /* Likewise, the first move would clobber the source of the second one, ! 214: do them in the other order. This happens only for registers; ! 215: such overlap can't happen in memory unless the user explicitly ! 216: sets it up, and that is an undefined circumstance. */ ! 217: ! 218: if (optype0 == PUSHOP || optype1 == PUSHOP ! 219: || (optype0 == REGOP && optype1 == REGOP ! 220: && REGNO (operands[0]) == REGNO (latehalf[1]))) ! 221: { ! 222: /* Make any unoffsettable addresses point at high-numbered word. */ ! 223: if (addreg0) ! 224: output_asm_insn ("addql %#4,%0", &addreg0); ! 225: if (addreg1) ! 226: output_asm_insn ("addql %#4,%0", &addreg1); ! 227: ! 228: /* Do that word. */ ! 229: output_asm_insn (singlemove_string (latehalf), latehalf); ! 230: ! 231: /* Undo the adds we just did. */ ! 232: if (addreg0) ! 233: output_asm_insn ("subql %#4,%0", &addreg0); ! 234: if (addreg1) ! 235: output_asm_insn ("subql %#4,%0", &addreg1); ! 236: ! 237: /* Do low-numbered word. */ ! 238: return singlemove_string (operands); ! 239: } ! 240: ! 241: /* Normal case: do the two words, low-numbered first. */ ! 242: ! 243: output_asm_insn (singlemove_string (operands), operands); ! 244: ! 245: /* Make any unoffsettable addresses point at high-numbered word. */ ! 246: if (addreg0) ! 247: output_asm_insn ("addql %#4,%0", &addreg0); ! 248: if (addreg1) ! 249: output_asm_insn ("addql %#4,%0", &addreg1); ! 250: ! 251: /* Do that word. */ ! 252: output_asm_insn (singlemove_string (latehalf), latehalf); ! 253: ! 254: /* Undo the adds we just did. */ ! 255: if (addreg0) ! 256: output_asm_insn ("subql %#4,%0", &addreg0); ! 257: if (addreg1) ! 258: output_asm_insn ("subql %#4,%0", &addreg1); ! 259: ! 260: return ""; ! 261: } ! 262: ! 263: /* Return a REG that occurs in ADDR with coefficient 1. ! 264: ADDR can be effectively incremented by incrementing REG. */ ! 265: ! 266: static rtx ! 267: find_addr_reg (addr) ! 268: rtx addr; ! 269: { ! 270: while (GET_CODE (addr) == PLUS) ! 271: { ! 272: if (GET_CODE (XEXP (addr, 0)) == REG) ! 273: addr = XEXP (addr, 0); ! 274: else if (GET_CODE (XEXP (addr, 1)) == REG) ! 275: addr = XEXP (addr, 1); ! 276: else if (CONSTANT_P (XEXP (addr, 0))) ! 277: addr = XEXP (addr, 1); ! 278: else if (CONSTANT_P (XEXP (addr, 1))) ! 279: addr = XEXP (addr, 0); ! 280: else ! 281: abort (); ! 282: } ! 283: if (GET_CODE (addr) == REG) ! 284: return addr; ! 285: abort (); ! 286: } ! 287: ! 288: char * ! 289: output_move_const_double (operands) ! 290: rtx *operands; ! 291: { ! 292: if (TARGET_FPA && FPA_REG_P(operands[0])) ! 293: { ! 294: int code = standard_sun_fpa_constant_p (operands[1]); ! 295: ! 296: if (code != 0) ! 297: { ! 298: static char buf[40]; ! 299: ! 300: sprintf (buf, "fpmove%%.d %%%%%d,%%0", code & 0x1ff); ! 301: return buf; ! 302: } ! 303: return "fpmove%.d %1,%0"; ! 304: } ! 305: else ! 306: { ! 307: int code = standard_68881_constant_p (operands[1]); ! 308: ! 309: if (code != 0) ! 310: { ! 311: static char buf[40]; ! 312: ! 313: sprintf (buf, "fmovecr %%#0x%x,%%0", code & 0xff); ! 314: return buf; ! 315: } ! 316: return "fmove%.d %1,%0"; ! 317: } ! 318: } ! 319: ! 320: char * ! 321: output_move_const_single (operands) ! 322: rtx *operands; ! 323: { ! 324: if (TARGET_FPA) ! 325: { ! 326: int code = standard_sun_fpa_constant_p (operands[1]); ! 327: ! 328: if (code != 0) ! 329: { ! 330: static char buf[40]; ! 331: ! 332: sprintf (buf, "fpmove%%.s %%%%%d,%%0", code & 0x1ff); ! 333: return buf; ! 334: } ! 335: return "fpmove%.s %1,%0"; ! 336: } ! 337: else ! 338: { ! 339: int code = standard_68881_constant_p (operands[1]); ! 340: ! 341: if (code != 0) ! 342: { ! 343: static char buf[40]; ! 344: ! 345: sprintf (buf, "fmovecr %%#0x%x,%%0", code & 0xff); ! 346: return buf; ! 347: } ! 348: return "fmove%.s %f1,%0"; ! 349: } ! 350: } ! 351: ! 352: /* Return nonzero if X, a CONST_DOUBLE, has a value that we can get ! 353: from the "fmovecr" instruction. ! 354: The value, anded with 0xff, gives the code to use in fmovecr ! 355: to get the desired constant. */ ! 356: ! 357: int ! 358: standard_68881_constant_p (x) ! 359: rtx x; ! 360: { ! 361: union {double d; int i[2];} u; ! 362: register double d; ! 363: u.i[0] = CONST_DOUBLE_LOW (x); ! 364: u.i[1] = CONST_DOUBLE_HIGH (x); ! 365: d = u.d; ! 366: ! 367: if (d == 0) ! 368: return 0x0f; ! 369: /* Note: there are various other constants available ! 370: but it is a nuisance to put in their values here. */ ! 371: if (d == 1) ! 372: return 0x32; ! 373: if (d == 10) ! 374: return 0x33; ! 375: if (d == 100) ! 376: return 0x34; ! 377: if (d == 10000) ! 378: return 0x35; ! 379: if (d == 1e8) ! 380: return 0x36; ! 381: if (GET_MODE (x) == SFmode) ! 382: return 0; ! 383: if (d == 1e16) ! 384: return 0x37; ! 385: /* larger powers of ten in the constants ram are not used ! 386: because they are not equal to a `double' C constant. */ ! 387: return 0; ! 388: } ! 389: ! 390: /* Return nonzero if X, a CONST_DOUBLE, has a value that we can get ! 391: from the Sun FPA's constant RAM. ! 392: The value returned, anded with 0x1ff, gives the code to use in fpmove ! 393: to get the desired constant. */ ! 394: #define S_E (2.718281745910644531) ! 395: #define D_E (2.718281828459045091) ! 396: #define S_PI (3.141592741012573242) ! 397: #define D_PI (3.141592653589793116) ! 398: #define S_SQRT2 (1.414213538169860840) ! 399: #define D_SQRT2 (1.414213562373095145) ! 400: #define S_LOG2ofE (1.442695021629333496) ! 401: #define D_LOG2ofE (1.442695040888963387) ! 402: #define S_LOG2of10 (3.321928024291992188) ! 403: #define D_LOG2of10 (3.321928024887362182) ! 404: #define S_LOGEof2 (0.6931471824645996094) ! 405: #define D_LOGEof2 (0.6931471805599452862) ! 406: #define S_LOGEof10 (2.302585124969482442) ! 407: #define D_LOGEof10 (2.302585092994045901) ! 408: #define S_LOG10of2 (0.3010300099849700928) ! 409: #define D_LOG10of2 (0.3010299956639811980) ! 410: #define S_LOG10ofE (0.4342944920063018799) ! 411: #define D_LOG10ofE (0.4342944819032518167) ! 412: ! 413: int ! 414: standard_sun_fpa_constant_p (x) ! 415: rtx x; ! 416: { ! 417: union {double d; int i[2];} u; ! 418: register double d; ! 419: u.i[0] = CONST_DOUBLE_LOW (x); ! 420: u.i[1] = CONST_DOUBLE_HIGH (x); ! 421: d = u.d; ! 422: ! 423: if (d == 0.0) ! 424: return 0x200; /* 0 once 0x1ff is anded with it */ ! 425: if (d == 1.0) ! 426: return 0xe; ! 427: if (d == 0.5) ! 428: return 0xf; ! 429: if (d == -1.0) ! 430: return 0x10; ! 431: if (d == 2.0) ! 432: return 0x11; ! 433: if (d == 3.0) ! 434: return 0xB1; ! 435: if (d == 4.0) ! 436: return 0x12; ! 437: if (d == 8.0) ! 438: return 0x13; ! 439: if (d == 0.25) ! 440: return 0x15; ! 441: if (d == 0.125) ! 442: return 0x16; ! 443: if (d == 10.0) ! 444: return 0x17; ! 445: if (d == -(1.0/2.0)) ! 446: return 0x2E; ! 447: ! 448: /* ! 449: * Stuff that looks different if it's single or double ! 450: */ ! 451: if (GET_MODE(x) == SFmode) ! 452: { ! 453: if (d == S_E) ! 454: return 0x8; ! 455: if (d == (2*S_PI)) ! 456: return 0x9; ! 457: if (d == S_PI) ! 458: return 0xA; ! 459: if (d == (S_PI / 2.0)) ! 460: return 0xB; ! 461: if (d == S_SQRT2) ! 462: return 0xC; ! 463: if (d == (1.0 / S_SQRT2)) ! 464: return 0xD; ! 465: /* Large powers of 10 in the constant ! 466: ram are not used because they are ! 467: not equal to a C double constant */ ! 468: if (d == -(S_PI / 2.0)) ! 469: return 0x27; ! 470: if (d == S_LOG2ofE) ! 471: return 0x28; ! 472: if (d == S_LOG2of10) ! 473: return 0x29; ! 474: if (d == S_LOGEof2) ! 475: return 0x2A; ! 476: if (d == S_LOGEof10) ! 477: return 0x2B; ! 478: if (d == S_LOG10of2) ! 479: return 0x2C; ! 480: if (d == S_LOG10ofE) ! 481: return 0x2D; ! 482: } ! 483: else ! 484: { ! 485: if (d == D_E) ! 486: return 0x8; ! 487: if (d == (2*D_PI)) ! 488: return 0x9; ! 489: if (d == D_PI) ! 490: return 0xA; ! 491: if (d == (D_PI / 2.0)) ! 492: return 0xB; ! 493: if (d == D_SQRT2) ! 494: return 0xC; ! 495: if (d == (1.0 / D_SQRT2)) ! 496: return 0xD; ! 497: /* Large powers of 10 in the constant ! 498: ram are not used because they are ! 499: not equal to a C double constant */ ! 500: if (d == -(D_PI / 2.0)) ! 501: return 0x27; ! 502: if (d == D_LOG2ofE) ! 503: return 0x28; ! 504: if (d == D_LOG2of10) ! 505: return 0x29; ! 506: if (d == D_LOGEof2) ! 507: return 0x2A; ! 508: if (d == D_LOGEof10) ! 509: return 0x2B; ! 510: if (d == D_LOG10of2) ! 511: return 0x2C; ! 512: if (d == D_LOG10ofE) ! 513: return 0x2D; ! 514: } ! 515: return 0x0; ! 516: } ! 517: ! 518: #undef S_E ! 519: #undef D_E ! 520: #undef S_PI ! 521: #undef D_PI ! 522: #undef S_SQRT2 ! 523: #undef D_SQRT2 ! 524: #undef S_LOG2ofE ! 525: #undef D_LOG2ofE ! 526: #undef S_LOG2of10 ! 527: #undef D_LOG2of10 ! 528: #undef S_LOGEof2 ! 529: #undef D_LOGEof2 ! 530: #undef S_LOGEof10 ! 531: #undef D_LOGEof10 ! 532: #undef S_LOG10of2 ! 533: #undef D_LOG10of2 ! 534: #undef S_LOG10ofE ! 535: #undef D_LOG10ofE
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.