|
|
1.1 ! root 1: /* Subroutines for insn-output.c for SPUR. Adapted from routines for ! 2: the Motorola 68000 family. ! 3: Copyright (C) 1988 Free Software Foundation, Inc. ! 4: ! 5: This file is part of GNU CC. ! 6: ! 7: GNU CC is free software; you can redistribute it and/or modify ! 8: it under the terms of the GNU General Public License as published by ! 9: the Free Software Foundation; either version 1, or (at your option) ! 10: any later version. ! 11: ! 12: GNU CC is distributed in the hope that it will be useful, ! 13: but WITHOUT ANY WARRANTY; without even the implied warranty of ! 14: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! 15: GNU General Public License for more details. ! 16: ! 17: You should have received a copy of the GNU General Public License ! 18: along with GNU CC; see the file COPYING. If not, write to ! 19: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ ! 20: ! 21: static rtx find_addr_reg (); ! 22: ! 23: char * ! 24: output_compare (operands, opcode, exchange_opcode, ! 25: neg_opcode, neg_exchange_opcode) ! 26: rtx *operands; ! 27: char *opcode; ! 28: char *exchange_opcode; ! 29: char *neg_opcode; ! 30: char *neg_exchange_opcode; ! 31: { ! 32: static char buf[100]; ! 33: operands[2] = operands[0]; ! 34: if (GET_CODE (cc_prev_status.value1) == CONST_INT) ! 35: { ! 36: operands[1] = cc_prev_status.value1; ! 37: operands[0] = cc_prev_status.value2; ! 38: opcode = exchange_opcode, neg_opcode = neg_exchange_opcode; ! 39: } ! 40: else ! 41: { ! 42: operands[0] = cc_prev_status.value1; ! 43: operands[1] = cc_prev_status.value2; ! 44: } ! 45: if (TARGET_LONG_JUMPS) ! 46: sprintf (buf, ! 47: "cmp_br_delayed %s,%%0,%%1,1f\n\tnop\n\tjump %%l2\n\tnop\n1:", ! 48: neg_opcode); ! 49: else ! 50: sprintf (buf, "cmp_br_delayed %s,%%0,%%1,%%l2\n\tnop", opcode); ! 51: return buf; ! 52: } ! 53: ! 54: /* Return the best assembler insn template ! 55: for moving operands[1] into operands[0] as a fullword. */ ! 56: ! 57: static char * ! 58: singlemove_string (operands) ! 59: rtx *operands; ! 60: { ! 61: if (GET_CODE (operands[0]) == MEM) ! 62: return "st_32 %r1,%0"; ! 63: if (GET_CODE (operands[1]) == MEM) ! 64: return "ld_32 %0,%1\n\tnop"; ! 65: if (GET_CODE (operands[1]) == REG) ! 66: return "add_nt %0,%1,$0"; ! 67: return "add_nt %0,r0,%1"; ! 68: } ! 69: ! 70: /* Output assembler code to perform a doubleword move insn ! 71: with operands OPERANDS. */ ! 72: ! 73: char * ! 74: output_move_double (operands) ! 75: rtx *operands; ! 76: { ! 77: enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1; ! 78: rtx latehalf[2]; ! 79: rtx addreg0 = 0, addreg1 = 0; ! 80: ! 81: /* First classify both operands. */ ! 82: ! 83: if (REG_P (operands[0])) ! 84: optype0 = REGOP; ! 85: else if (offsettable_memref_p (operands[0])) ! 86: optype0 = OFFSOP; ! 87: else if (GET_CODE (operands[0]) == MEM) ! 88: optype0 = MEMOP; ! 89: else ! 90: optype0 = RNDOP; ! 91: ! 92: if (REG_P (operands[1])) ! 93: optype1 = REGOP; ! 94: else if (CONSTANT_P (operands[1]) ! 95: || GET_CODE (operands[1]) == CONST_DOUBLE) ! 96: optype1 = CNSTOP; ! 97: else if (offsettable_memref_p (operands[1])) ! 98: optype1 = OFFSOP; ! 99: else if (GET_CODE (operands[1]) == MEM) ! 100: optype1 = MEMOP; ! 101: else ! 102: optype1 = RNDOP; ! 103: ! 104: /* Check for the cases that the operand constraints are not ! 105: supposed to allow to happen. Abort if we get one, ! 106: because generating code for these cases is painful. */ ! 107: ! 108: if (optype0 == RNDOP || optype1 == RNDOP) ! 109: abort (); ! 110: ! 111: /* If an operand is an unoffsettable memory ref, find a register ! 112: we can increment temporarily to make it refer to the second word. */ ! 113: ! 114: if (optype0 == MEMOP) ! 115: addreg0 = find_addr_reg (XEXP (operands[0], 0)); ! 116: ! 117: if (optype1 == MEMOP) ! 118: addreg1 = find_addr_reg (XEXP (operands[1], 0)); ! 119: ! 120: /* Ok, we can do one word at a time. ! 121: Normally we do the low-numbered word first, ! 122: but if either operand is autodecrementing then we ! 123: do the high-numbered word first. ! 124: ! 125: In either case, set up in LATEHALF the operands to use ! 126: for the high-numbered word and in some cases alter the ! 127: operands in OPERANDS to be suitable for the low-numbered word. */ ! 128: ! 129: if (optype0 == REGOP) ! 130: latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); ! 131: else if (optype0 == OFFSOP) ! 132: latehalf[0] = adj_offsettable_operand (operands[0], 4); ! 133: else ! 134: latehalf[0] = operands[0]; ! 135: ! 136: if (optype1 == REGOP) ! 137: latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); ! 138: else if (optype1 == OFFSOP) ! 139: latehalf[1] = adj_offsettable_operand (operands[1], 4); ! 140: else if (optype1 == CNSTOP) ! 141: { ! 142: if (CONSTANT_P (operands[1])) ! 143: latehalf[1] = const0_rtx; ! 144: else if (GET_CODE (operands[1]) == CONST_DOUBLE) ! 145: { ! 146: latehalf[1] = gen_rtx (CONST_INT, VOIDmode, ! 147: CONST_DOUBLE_HIGH (operands[1])); ! 148: operands[1] = gen_rtx (CONST_INT, VOIDmode, ! 149: CONST_DOUBLE_LOW (operands[1])); ! 150: } ! 151: } ! 152: else ! 153: latehalf[1] = operands[1]; ! 154: ! 155: /* If the first move would clobber the source of the second one, ! 156: do them in the other order. This happens only for registers; ! 157: such overlap can't happen in memory unless the user explicitly ! 158: sets it up, and that is an undefined circumstance. */ ! 159: ! 160: if (optype0 == REGOP && optype1 == REGOP ! 161: && REGNO (operands[0]) == REGNO (latehalf[1])) ! 162: { ! 163: /* Make any unoffsettable addresses point at high-numbered word. */ ! 164: if (addreg0) ! 165: output_asm_insn ("add_nt %0,%0,$4", &addreg0); ! 166: if (addreg1) ! 167: output_asm_insn ("add_nt %0,%0,$4", &addreg1); ! 168: ! 169: /* Do that word. */ ! 170: output_asm_insn (singlemove_string (latehalf), latehalf); ! 171: ! 172: /* Undo the adds we just did. */ ! 173: if (addreg0) ! 174: output_asm_insn ("add_nt %0,%0,$-4", &addreg0); ! 175: if (addreg1) ! 176: output_asm_insn ("add_nt %0,%0,$-4", &addreg0); ! 177: ! 178: /* Do low-numbered word. */ ! 179: return singlemove_string (operands); ! 180: } ! 181: ! 182: /* Normal case: do the two words, low-numbered first. */ ! 183: ! 184: output_asm_insn (singlemove_string (operands), operands); ! 185: ! 186: /* Make any unoffsettable addresses point at high-numbered word. */ ! 187: if (addreg0) ! 188: output_asm_insn ("add_nt %0,%0,$4", &addreg0); ! 189: if (addreg1) ! 190: output_asm_insn ("add_nt %0,%0,$4", &addreg1); ! 191: ! 192: /* Do that word. */ ! 193: output_asm_insn (singlemove_string (latehalf), latehalf); ! 194: ! 195: /* Undo the adds we just did. */ ! 196: if (addreg0) ! 197: output_asm_insn ("add_nt %0,%0,$-4", &addreg0); ! 198: if (addreg1) ! 199: output_asm_insn ("add_nt %0,%0,$-4", &addreg1); ! 200: ! 201: return ""; ! 202: } ! 203: ! 204: static char * ! 205: output_fp_move_double (operands) ! 206: rtx *operands; ! 207: { ! 208: if (FP_REG_P (operands[0])) ! 209: { ! 210: if (FP_REG_P (operands[1])) ! 211: return "fmov %0,%1"; ! 212: if (GET_CODE (operands[1]) == REG) ! 213: { ! 214: rtx xoperands[2]; ! 215: int offset = - get_frame_size () - 8; ! 216: xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); ! 217: xoperands[0] = gen_rtx (CONST_INT, VOIDmode, offset + 4); ! 218: output_asm_insn ("st_32 %1,r25,%0", xoperands); ! 219: xoperands[1] = operands[1]; ! 220: xoperands[0] = gen_rtx (CONST_INT, VOIDmode, offset); ! 221: output_asm_insn ("st_32 %1,r25,%0", xoperands); ! 222: xoperands[1] = operands[0]; ! 223: output_asm_insn ("ld_dbl %1,r25,%0\n\tnop", xoperands); ! 224: return ""; ! 225: } ! 226: return "ld_dbl %0,%1\n\tnop"; ! 227: } ! 228: else if (FP_REG_P (operands[1])) ! 229: { ! 230: if (GET_CODE (operands[0]) == REG) ! 231: { ! 232: rtx xoperands[2]; ! 233: int offset = - get_frame_size () - 8; ! 234: xoperands[0] = gen_rtx (CONST_INT, VOIDmode, offset); ! 235: xoperands[1] = operands[1]; ! 236: output_asm_insn ("st_dbl %1,r25,%0", xoperands); ! 237: xoperands[1] = operands[0]; ! 238: output_asm_insn ("ld_32 %1,r25,%0\n\tnop", xoperands); ! 239: xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); ! 240: xoperands[0] = gen_rtx (CONST_INT, VOIDmode, offset + 4); ! 241: output_asm_insn ("ld_32 %1,r25,%0\n\tnop", xoperands); ! 242: return ""; ! 243: } ! 244: return "st_dbl %1,%0"; ! 245: } ! 246: } ! 247: ! 248: /* Return a REG that occurs in ADDR with coefficient 1. ! 249: ADDR can be effectively incremented by incrementing REG. */ ! 250: ! 251: static rtx ! 252: find_addr_reg (addr) ! 253: rtx addr; ! 254: { ! 255: while (GET_CODE (addr) == PLUS) ! 256: { ! 257: if (GET_CODE (XEXP (addr, 0)) == REG) ! 258: addr = XEXP (addr, 0); ! 259: else if (GET_CODE (XEXP (addr, 1)) == REG) ! 260: addr = XEXP (addr, 1); ! 261: else if (CONSTANT_P (XEXP (addr, 0))) ! 262: addr = XEXP (addr, 1); ! 263: else if (CONSTANT_P (XEXP (addr, 1))) ! 264: addr = XEXP (addr, 0); ! 265: else ! 266: abort (); ! 267: } ! 268: if (GET_CODE (addr) == REG) ! 269: return addr; ! 270: abort (); ! 271: } ! 272: ! 273: /* Generate code to add a large integer constant to register, reg, storing ! 274: * the result in a register, target. Offset must be 27-bit signed quantity */ ! 275: ! 276: static char * ! 277: output_add_large_offset (target, reg, offset) ! 278: rtx target, reg; ! 279: int offset; ! 280: { ! 281: rtx operands[3]; ! 282: int high, n, i; ! 283: operands[0] = target, operands[1] = reg; ! 284: ! 285: for (high = offset, n = 0; ! 286: (unsigned) (high + 0x2000) >= 0x4000; ! 287: high >>= 1, n += 1) ! 288: ; ! 289: operands[2] = gen_rtx (CONST_INT, VOIDmode, high); ! 290: output_asm_insn ("add_nt r2,r0,%2", operands); ! 291: i = n; ! 292: while (i >= 3) ! 293: output_asm_insn ("sll r2,r2,$3", operands), i -= 3; ! 294: if (i == 2) ! 295: output_asm_insn ("sll r2,r2,$2", operands); ! 296: else if (i == 1) ! 297: output_asm_insn ("sll r2,r2,$1", operands); ! 298: output_asm_insn ("add_nt %0,r2,%1", operands); ! 299: if (offset - (high << n) != 0) ! 300: { ! 301: operands[2] = gen_rtx (CONST_INT, VOIDmode, offset - (high << n)); ! 302: output_asm_insn ("add_nt %0,%0,%2", operands); ! 303: } ! 304: return ""; ! 305: } ! 306: ! 307: /* Additional TESTFN for matching. Like immediate_operand, but matches big ! 308: * constants */ ! 309: ! 310: int ! 311: big_immediate_operand (op, mode) ! 312: rtx op; ! 313: enum machine_mode mode; ! 314: { ! 315: return (GET_CODE (op) == CONST_INT); ! 316: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.