|
|
1.1 ! root 1: /* Subroutines for insn-output.c for Motorola 68000 family. ! 2: Copyright (C) 1988 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: static rtx find_addr_reg (); ! 22: ! 23: char * ! 24: output_compare (operands, opcode, exchange_opcode) ! 25: rtx *operands; ! 26: char *opcode; ! 27: char *exchange_opcode; ! 28: { ! 29: static char buf[40]; ! 30: operands[2] = operands[0]; ! 31: if (GET_CODE (cc_prev_status.value1) == CONST_INT) ! 32: { ! 33: operands[1] = cc_prev_status.value1; ! 34: operands[0] = cc_prev_status.value2; ! 35: opcode = exchange_opcode; ! 36: } ! 37: else ! 38: { ! 39: operands[0] = cc_prev_status.value1; ! 40: operands[1] = cc_prev_status.value2; ! 41: } ! 42: sprintf (buf, "cmp_br_delayed %s,%%0,%%1,%%l2\n\tnop", opcode); ! 43: return buf; ! 44: } ! 45: ! 46: /* Return the best assembler insn template ! 47: for moving operands[1] into operands[0] as a fullword. */ ! 48: ! 49: static char * ! 50: singlemove_string (operands) ! 51: rtx *operands; ! 52: { ! 53: if (GET_CODE (operands[0]) == MEM) ! 54: return "st_32 %r1,%0"; ! 55: if (GET_CODE (operands[1]) == MEM) ! 56: return "ld_32 %0,%1\n\tnop"; ! 57: return "add_nt %0,r0,%1"; ! 58: } ! 59: ! 60: /* Output assembler code to perform a doubleword move insn ! 61: with operands OPERANDS. */ ! 62: ! 63: char * ! 64: output_move_double (operands) ! 65: rtx *operands; ! 66: { ! 67: enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1; ! 68: rtx latehalf[2]; ! 69: rtx addreg0 = 0, addreg1 = 0; ! 70: ! 71: /* First classify both operands. */ ! 72: ! 73: if (REG_P (operands[0])) ! 74: optype0 = REGOP; ! 75: else if (offsetable_memref_p (operands[0])) ! 76: optype0 = OFFSOP; ! 77: else if (GET_CODE (operands[0]) == MEM) ! 78: optype0 = MEMOP; ! 79: else ! 80: optype0 = RNDOP; ! 81: ! 82: if (REG_P (operands[1])) ! 83: optype1 = REGOP; ! 84: else if (CONSTANT_P (operands[1]) ! 85: || GET_CODE (operands[1]) == CONST_DOUBLE) ! 86: optype1 = CNSTOP; ! 87: else if (offsetable_memref_p (operands[1])) ! 88: optype1 = OFFSOP; ! 89: else if (GET_CODE (operands[1]) == MEM) ! 90: optype0 = MEMOP; ! 91: else ! 92: optype1 = RNDOP; ! 93: ! 94: /* Check for the cases that the operand constraints are not ! 95: supposed to allow to happen. Abort if we get one, ! 96: because generating code for these cases is painful. */ ! 97: ! 98: if (optype0 == RNDOP || optype1 == RNDOP) ! 99: abort (); ! 100: ! 101: /* If an operand is an unoffsettable memory ref, find a register ! 102: we can increment temporarily to make it refer to the second word. */ ! 103: ! 104: if (optype0 == MEMOP) ! 105: addreg0 = find_addr_reg (operands[0]); ! 106: ! 107: if (optype1 == MEMOP) ! 108: addreg1 = find_addr_reg (operands[1]); ! 109: ! 110: /* Ok, we can do one word at a time. ! 111: Normally we do the low-numbered word first, ! 112: but if either operand is autodecrementing then we ! 113: do the high-numbered word first. ! 114: ! 115: In either case, set up in LATEHALF the operands to use ! 116: for the high-numbered word and in some cases alter the ! 117: operands in OPERANDS to be suitable for the low-numbered word. */ ! 118: ! 119: if (optype0 == REGOP) ! 120: latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); ! 121: else if (optype0 == OFFSOP) ! 122: latehalf[0] = adj_offsetable_operand (operands[0], 4); ! 123: else ! 124: latehalf[0] = operands[0]; ! 125: ! 126: if (optype1 == REGOP) ! 127: latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); ! 128: else if (optype1 == OFFSOP) ! 129: latehalf[1] = adj_offsetable_operand (operands[1], 4); ! 130: else if (optype1 == CNSTOP) ! 131: { ! 132: if (CONSTANT_P (operands[1])) ! 133: latehalf[1] = const0_rtx; ! 134: else if (GET_CODE (operands[1]) == CONST_DOUBLE) ! 135: { ! 136: latehalf[1] = gen_rtx (CONST_INT, VOIDmode, XINT (operands[1], 1)); ! 137: operands[1] = gen_rtx (CONST_INT, VOIDmode, XINT (operands[1], 0)); ! 138: } ! 139: } ! 140: else ! 141: latehalf[1] = operands[1]; ! 142: ! 143: /* If the first move would clobber the source of the second one, ! 144: do them in the other order. This happens only for registers; ! 145: such overlap can't happen in memory unless the user explicitly ! 146: sets it up, and that is an undefined circumstance. */ ! 147: ! 148: if (optype0 == REGOP && optype1 == REGOP ! 149: && REGNO (operands[0]) == REGNO (latehalf[1])) ! 150: { ! 151: /* Make any unoffsetable addresses point at high-numbered word. */ ! 152: if (addreg0) ! 153: output_asm_insn ("add_nt %0,%0,$4", &addreg0); ! 154: if (addreg1) ! 155: output_asm_insn ("add_nt %0,%0,$4", &addreg1); ! 156: ! 157: /* Do that word. */ ! 158: output_asm_insn (singlemove_string (latehalf), latehalf); ! 159: ! 160: /* Undo the adds we just did. */ ! 161: if (addreg0) ! 162: output_asm_insn ("add_nt %0,%0,$-4", &addreg0); ! 163: if (addreg1) ! 164: output_asm_insn ("add_nt %0,%0,$-4", &addreg0); ! 165: ! 166: /* Do low-numbered word. */ ! 167: return singlemove_string (operands); ! 168: } ! 169: ! 170: /* Normal case: do the two words, low-numbered first. */ ! 171: ! 172: output_asm_insn (singlemove_string (operands), operands); ! 173: ! 174: /* Make any unoffsetable addresses point at high-numbered word. */ ! 175: if (addreg0) ! 176: output_asm_insn ("add_nt %0,%0,$4", &addreg0); ! 177: if (addreg1) ! 178: output_asm_insn ("add_nt %0,%0,$4", &addreg1); ! 179: ! 180: /* Do that word. */ ! 181: output_asm_insn (singlemove_string (latehalf), latehalf); ! 182: ! 183: /* Undo the adds we just did. */ ! 184: if (addreg0) ! 185: output_asm_insn ("add_nt %0,%0,$-4", &addreg0); ! 186: if (addreg1) ! 187: output_asm_insn ("add_nt %0,%0,$-4", &addreg1); ! 188: ! 189: return ""; ! 190: } ! 191: ! 192: static char * ! 193: output_fp_move_double (operands) ! 194: rtx *operands; ! 195: { ! 196: if (FP_REG_P (operands[0])) ! 197: { ! 198: if (FP_REG_P (operands[1])) ! 199: return "fmov %0,%1"; ! 200: if (GET_CODE (operands[1]) == REG) ! 201: { ! 202: rtx xoperands[2]; ! 203: int offset = - get_frame_size () - 8; ! 204: xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); ! 205: xoperands[0] = gen_rtx (CONST_INT, VOIDmode, offset + 4); ! 206: output_asm_insn ("st_32 %1,r25,%0", xoperands); ! 207: xoperands[1] = operands[1]; ! 208: xoperands[0] = gen_rtx (CONST_INT, VOIDmode, offset); ! 209: output_asm_insn ("st_32 %1,r25,%0", xoperands); ! 210: xoperands[1] = operands[0]; ! 211: output_asm_insn ("ld_dbl %1,r25,%0\n\tnop", xoperands); ! 212: return ""; ! 213: } ! 214: return "ld_dbl %0,%1\n\tnop"; ! 215: } ! 216: else if (FP_REG_P (operands[1])) ! 217: { ! 218: if (GET_CODE (operands[0]) == REG) ! 219: { ! 220: rtx xoperands[2]; ! 221: int offset = - get_frame_size () - 8; ! 222: xoperands[0] = gen_rtx (CONST_INT, VOIDmode, offset); ! 223: xoperands[1] = operands[1]; ! 224: output_asm_insn ("st_dbl %1,r25,%0", xoperands); ! 225: xoperands[1] = operands[0]; ! 226: output_asm_insn ("ld_32 %1,r25,%0\n\tnop", xoperands); ! 227: xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); ! 228: xoperands[0] = gen_rtx (CONST_INT, VOIDmode, offset + 4); ! 229: output_asm_insn ("ld_32 %1,r25,%0\n\tnop", xoperands); ! 230: return ""; ! 231: } ! 232: return "st_dbl %1,%0"; ! 233: } ! 234: } ! 235: ! 236: /* Return a REG that occurs in ADDR with coefficient 1. ! 237: ADDR can be effectively incremented by incrementing REG. */ ! 238: ! 239: static rtx ! 240: find_addr_reg (addr) ! 241: rtx addr; ! 242: { ! 243: while (GET_CODE (addr) == PLUS) ! 244: { ! 245: if (GET_CODE (XEXP (addr, 0)) == REG) ! 246: addr = XEXP (addr, 0); ! 247: if (GET_CODE (XEXP (addr, 1)) == REG) ! 248: addr = XEXP (addr, 1); ! 249: if (CONSTANT_P (XEXP (addr, 0))) ! 250: addr = XEXP (addr, 1); ! 251: if (CONSTANT_P (XEXP (addr, 1))) ! 252: addr = XEXP (addr, 0); ! 253: } ! 254: if (GET_CODE (addr) == REG) ! 255: return addr; ! 256: return 0; ! 257: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.