|
|
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 distributed in the hope that it will be useful, ! 7: but WITHOUT ANY WARRANTY. No author or distributor ! 8: accepts responsibility to anyone for the consequences of using it ! 9: or for whether it serves any particular purpose or works at all, ! 10: unless he says so in writing. Refer to the GNU CC General Public ! 11: License for full details. ! 12: ! 13: Everyone is granted permission to copy, modify and redistribute ! 14: GNU CC, but only under the conditions described in the ! 15: GNU CC General Public License. A copy of this license is ! 16: supposed to have been given to you along with GNU CC so you ! 17: can know your rights and responsibilities. It should be in a ! 18: file named COPYING. Among other things, the copyright notice ! 19: and this notice must be preserved on all copies. */ ! 20: ! 21: ! 22: /* Some output-actions in m68k.md need these. */ ! 23: #include <stdio.h> ! 24: extern FILE *asm_out_file; ! 25: ! 26: static rtx find_addr_reg (); ! 27: ! 28: char * ! 29: output_btst (operands, countop, dataop, insn, signpos) ! 30: rtx *operands; ! 31: rtx countop, dataop; ! 32: rtx insn; ! 33: int signpos; ! 34: { ! 35: operands[0] = countop; ! 36: operands[1] = dataop; ! 37: if (GET_CODE (countop) == CONST_INT) ! 38: { ! 39: register int count = INTVAL (countop); ! 40: if (count == signpos) ! 41: cc_status.flags = CC_NOT_POSITIVE | CC_Z_IN_NOT_N; ! 42: else ! 43: cc_status.flags = CC_NOT_NEGATIVE | CC_Z_IN_NOT_N; ! 44: ! 45: if (count == 31 ! 46: && next_insn_tests_no_inequality (insn)) ! 47: return "tst%.l %1"; ! 48: if (count == 15 ! 49: && next_insn_tests_no_inequality (insn)) ! 50: return "tst%.w %1"; ! 51: if (count == 7 ! 52: && next_insn_tests_no_inequality (insn)) ! 53: return "tst%.b %1"; ! 54: ! 55: cc_status.flags = CC_NOT_NEGATIVE; ! 56: } ! 57: return "btst %0,%1"; ! 58: } ! 59: ! 60: /* Return the best assembler insn template ! 61: for moving operands[1] into operands[0] as a fullword. */ ! 62: ! 63: static char * ! 64: singlemove_string (operands) ! 65: rtx *operands; ! 66: { ! 67: if (operands[1] != const0_rtx) ! 68: return "move%.l %1,%0"; ! 69: if (! ADDRESS_REG_P (operands[0])) ! 70: return "clr%.l %0"; ! 71: return "sub%.l %0,%0"; ! 72: } ! 73: ! 74: /* Output assembler code to perform a doubleword move insn ! 75: with operands OPERANDS. */ ! 76: ! 77: char * ! 78: output_move_double (operands) ! 79: rtx *operands; ! 80: { ! 81: enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1; ! 82: rtx latehalf[2]; ! 83: rtx addreg0 = 0, addreg1 = 0; ! 84: ! 85: /* First classify both operands. */ ! 86: ! 87: if (REG_P (operands[0])) ! 88: optype0 = REGOP; ! 89: else if (offsetable_memref_p (operands[0])) ! 90: optype0 = OFFSOP; ! 91: else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC) ! 92: optype0 = POPOP; ! 93: else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC) ! 94: optype0 = PUSHOP; ! 95: else if (GET_CODE (operands[0]) == MEM) ! 96: optype0 = MEMOP; ! 97: else ! 98: optype0 = RNDOP; ! 99: ! 100: if (REG_P (operands[1])) ! 101: optype1 = REGOP; ! 102: else if (CONSTANT_P (operands[1]) ! 103: || GET_CODE (operands[1]) == CONST_DOUBLE) ! 104: optype1 = CNSTOP; ! 105: else if (offsetable_memref_p (operands[1])) ! 106: optype1 = OFFSOP; ! 107: else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC) ! 108: optype1 = POPOP; ! 109: else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC) ! 110: optype1 = PUSHOP; ! 111: else if (GET_CODE (operands[1]) == MEM) ! 112: optype1 = MEMOP; ! 113: else ! 114: optype1 = RNDOP; ! 115: ! 116: /* Check for the cases that the operand constraints are not ! 117: supposed to allow to happen. Abort if we get one, ! 118: because generating code for these cases is painful. */ ! 119: ! 120: if (optype0 == RNDOP || optype1 == RNDOP) ! 121: abort (); ! 122: ! 123: /* If one operand is decrementing and one is incrementing ! 124: decrement the former register explicitly ! 125: and change that operand into ordinary indexing. */ ! 126: ! 127: if (optype0 == PUSHOP && optype1 == POPOP) ! 128: { ! 129: operands[0] = XEXP (XEXP (operands[0], 0), 0); ! 130: output_asm_insn ("subq%.l %#8,%0", operands); ! 131: operands[0] = gen_rtx (MEM, DImode, operands[0]); ! 132: optype0 = OFFSOP; ! 133: } ! 134: if (optype0 == POPOP && optype1 == PUSHOP) ! 135: { ! 136: operands[1] = XEXP (XEXP (operands[1], 0), 0); ! 137: output_asm_insn ("subq%.l %#8,%1", operands); ! 138: operands[1] = gen_rtx (MEM, DImode, operands[1]); ! 139: optype1 = OFFSOP; ! 140: } ! 141: ! 142: /* If an operand is an unoffsettable memory ref, find a register ! 143: we can increment temporarily to make it refer to the second word. */ ! 144: ! 145: if (optype0 == MEMOP) ! 146: addreg0 = find_addr_reg (operands[0]); ! 147: ! 148: if (optype1 == MEMOP) ! 149: addreg1 = find_addr_reg (operands[1]); ! 150: ! 151: /* Ok, we can do one word at a time. ! 152: Normally we do the low-numbered word first, ! 153: but if either operand is autodecrementing then we ! 154: do the high-numbered word first. ! 155: ! 156: In either case, set up in LATEHALF the operands to use ! 157: for the high-numbered word and in some cases alter the ! 158: operands in OPERANDS to be suitable for the low-numbered word. */ ! 159: ! 160: if (optype0 == REGOP) ! 161: latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); ! 162: else if (optype0 == OFFSOP) ! 163: latehalf[0] = adj_offsetable_operand (operands[0], 4); ! 164: else ! 165: latehalf[0] = operands[0]; ! 166: ! 167: if (optype1 == REGOP) ! 168: latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); ! 169: else if (optype1 == OFFSOP) ! 170: latehalf[1] = adj_offsetable_operand (operands[1], 4); ! 171: else if (optype1 == CNSTOP) ! 172: { ! 173: if (CONSTANT_P (operands[1])) ! 174: latehalf[1] = const0_rtx; ! 175: else if (GET_CODE (operands[1]) == CONST_DOUBLE) ! 176: { ! 177: latehalf[1] = gen_rtx (CONST_INT, VOIDmode, XINT (operands[1], 1)); ! 178: operands[1] = gen_rtx (CONST_INT, VOIDmode, XINT (operands[1], 0)); ! 179: } ! 180: } ! 181: else ! 182: latehalf[1] = operands[1]; ! 183: ! 184: /* If insn is effectively movd N(sp),-(sp) then we will do the ! 185: high word first. We should use the adjusted operand 1 (which is N+4(sp)) ! 186: for the low word as well, to compensate for the first decrement of sp. */ ! 187: if (optype0 == PUSHOP ! 188: && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM ! 189: && reg_mentioned_p (XEXP (XEXP (operands[0], 0), 0), operands[1])) ! 190: operands[1] = latehalf[1]; ! 191: ! 192: /* If one or both operands autodecrementing, ! 193: do the two words, high-numbered first. */ ! 194: ! 195: /* Likewise, the first move would clobber the source of the second one, ! 196: do them in the other order. This happens only for registers; ! 197: such overlap can't happen in memory unless the user explicitly ! 198: sets it up, and that is an undefined circumstance. */ ! 199: ! 200: if (optype0 == PUSHOP || optype1 == PUSHOP ! 201: || (optype0 == REGOP && optype1 == REGOP ! 202: && REGNO (operands[0]) == REGNO (latehalf[1]))) ! 203: { ! 204: /* Make any unoffsetable addresses point at high-numbered word. */ ! 205: if (addreg0) ! 206: output_asm_insn ("addql %#4,%0", &addreg0); ! 207: if (addreg1) ! 208: output_asm_insn ("addql %#4,%0", &addreg1); ! 209: ! 210: /* Do that word. */ ! 211: output_asm_insn (singlemove_string (latehalf), latehalf); ! 212: ! 213: /* Undo the adds we just did. */ ! 214: if (addreg0) ! 215: output_asm_insn ("subql %#4,%0", &addreg0); ! 216: if (addreg1) ! 217: output_asm_insn ("subql %#4,%0", &addreg1); ! 218: ! 219: /* Do low-numbered word. */ ! 220: return singlemove_string (operands); ! 221: } ! 222: ! 223: /* Normal case: do the two words, low-numbered first. */ ! 224: ! 225: output_asm_insn (singlemove_string (operands), operands); ! 226: ! 227: /* Make any unoffsetable addresses point at high-numbered word. */ ! 228: if (addreg0) ! 229: output_asm_insn ("addql %#4,%0", &addreg0); ! 230: if (addreg1) ! 231: output_asm_insn ("addql %#4,%0", &addreg1); ! 232: ! 233: /* Do that word. */ ! 234: output_asm_insn (singlemove_string (latehalf), latehalf); ! 235: ! 236: /* Undo the adds we just did. */ ! 237: if (addreg0) ! 238: output_asm_insn ("subql %#4,%0", &addreg0); ! 239: if (addreg1) ! 240: output_asm_insn ("subql %#4,%0", &addreg1); ! 241: ! 242: return ""; ! 243: } ! 244: ! 245: /* Return a REG that occurs in ADDR with coefficient 1. ! 246: ADDR can be effectively incremented by incrementing REG. */ ! 247: ! 248: static rtx ! 249: find_addr_reg (addr) ! 250: rtx addr; ! 251: { ! 252: while (GET_CODE (addr) == PLUS) ! 253: { ! 254: if (GET_CODE (XEXP (addr, 0)) == REG) ! 255: addr = XEXP (addr, 0); ! 256: if (GET_CODE (XEXP (addr, 1)) == REG) ! 257: addr = XEXP (addr, 1); ! 258: if (CONSTANT_P (XEXP (addr, 0))) ! 259: addr = XEXP (addr, 1); ! 260: if (CONSTANT_P (XEXP (addr, 1))) ! 261: addr = XEXP (addr, 0); ! 262: } ! 263: if (GET_CODE (addr) == REG) ! 264: return addr; ! 265: return 0; ! 266: } ! 267: ! 268: char * ! 269: output_move_const_double (operands) ! 270: rtx *operands; ! 271: { ! 272: int code = standard_68881_constant_p (operands[1]); ! 273: ! 274: if (code != 0) ! 275: { ! 276: static char buf[40]; ! 277: ! 278: sprintf (buf, "fmovecr %%#0x%x,%%0", code & 0xff); ! 279: return buf; ! 280: } ! 281: return "fmove%.d %1,%0"; ! 282: } ! 283: ! 284: char * ! 285: output_move_const_single (operands) ! 286: rtx *operands; ! 287: { ! 288: int code = standard_68881_constant_p (operands[1]); ! 289: ! 290: if (code != 0) ! 291: { ! 292: static char buf[40]; ! 293: ! 294: sprintf (buf, "fmovecr %%#0x%x,%%0", code & 0xff); ! 295: return buf; ! 296: } ! 297: return "fmove%.s %f1,%0"; ! 298: } ! 299: ! 300: /* Return nonzero if X, a CONST_DOUBLE, has a value that we can get ! 301: from the "fmovecr" instruction. ! 302: The value, anded with 0xff, gives the code to use in fmovecr ! 303: to get the desired constant. */ ! 304: ! 305: int ! 306: standard_68881_constant_p (x) ! 307: rtx x; ! 308: { ! 309: union {double d; int i[2];} u; ! 310: register double d; ! 311: u.i[0] = XINT (x, 0); ! 312: u.i[1] = XINT (x, 1); ! 313: d = u.d; ! 314: ! 315: if (d == 0) ! 316: return 0x0f; ! 317: /* Note: there are various other constants available ! 318: but it is a nuisance to put in their values here. */ ! 319: if (d == 1) ! 320: return 0x32; ! 321: if (d == 10) ! 322: return 0x33; ! 323: if (d == 100) ! 324: return 0x34; ! 325: if (d == 10000) ! 326: return 0x35; ! 327: if (d == 1e8) ! 328: return 0x36; ! 329: if (GET_MODE (x) == SFmode) ! 330: return 0; ! 331: if (d == 1e16) ! 332: return 0x37; ! 333: /* larger powers of ten in the constants ram are not used ! 334: because they are not equal to a `double' C constant. */ ! 335: return 0; ! 336: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.