|
|
1.1 ! root 1: /* Subroutines for insn-output.c for Alliant FX computers. ! 2: Copyright (C) 1989,1991 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 alliant.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: /* Index into this array by (register number >> 3) to find the ! 35: smallest class which contains that register. */ ! 36: enum reg_class regno_reg_class[] ! 37: = { DATA_REGS, ADDR_REGS, FP_REGS }; ! 38: ! 39: static rtx find_addr_reg (); ! 40: ! 41: char * ! 42: output_btst (operands, countop, dataop, insn, signpos) ! 43: rtx *operands; ! 44: rtx countop, dataop; ! 45: rtx insn; ! 46: int signpos; ! 47: { ! 48: operands[0] = countop; ! 49: operands[1] = dataop; ! 50: ! 51: if (GET_CODE (countop) == CONST_INT) ! 52: { ! 53: register int count = INTVAL (countop); ! 54: /* If COUNT is bigger than size of storage unit in use, ! 55: advance to the containing unit of same size. */ ! 56: if (count > signpos) ! 57: { ! 58: int offset = (count & ~signpos) / 8; ! 59: count = count & signpos; ! 60: operands[1] = dataop = adj_offsettable_operand (dataop, offset); ! 61: } ! 62: if (count == signpos) ! 63: cc_status.flags = CC_NOT_POSITIVE | CC_Z_IN_NOT_N; ! 64: else ! 65: cc_status.flags = CC_NOT_NEGATIVE | CC_Z_IN_NOT_N; ! 66: ! 67: /* These three statements used to use next_insns_test_no... ! 68: but it appears that this should do the same job. */ ! 69: if (count == 31 ! 70: && next_insn_tests_no_inequality (insn)) ! 71: return "tst%.l %1"; ! 72: if (count == 15 ! 73: && next_insn_tests_no_inequality (insn)) ! 74: return "tst%.w %1"; ! 75: if (count == 7 ! 76: && next_insn_tests_no_inequality (insn)) ! 77: return "tst%.b %1"; ! 78: ! 79: cc_status.flags = CC_NOT_NEGATIVE; ! 80: } ! 81: return "btst %0,%1"; ! 82: } ! 83: ! 84: /* Return the best assembler insn template ! 85: for moving operands[1] into operands[0] as a fullword. */ ! 86: ! 87: static char * ! 88: singlemove_string (operands) ! 89: rtx *operands; ! 90: { ! 91: if (operands[1] != const0_rtx) ! 92: return "mov%.l %1,%0"; ! 93: if (! ADDRESS_REG_P (operands[0])) ! 94: return "clr%.l %0"; ! 95: return "sub%.l %0,%0"; ! 96: } ! 97: ! 98: /* Output assembler code to perform a doubleword move insn ! 99: with operands OPERANDS. */ ! 100: ! 101: char * ! 102: output_move_double (operands) ! 103: rtx *operands; ! 104: { ! 105: enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1; ! 106: rtx latehalf[2]; ! 107: rtx addreg0 = 0, addreg1 = 0; ! 108: ! 109: /* First classify both operands. */ ! 110: ! 111: if (REG_P (operands[0])) ! 112: optype0 = REGOP; ! 113: else if (offsettable_memref_p (operands[0])) ! 114: optype0 = OFFSOP; ! 115: else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC) ! 116: optype0 = POPOP; ! 117: else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC) ! 118: optype0 = PUSHOP; ! 119: else if (GET_CODE (operands[0]) == MEM) ! 120: optype0 = MEMOP; ! 121: else ! 122: optype0 = RNDOP; ! 123: ! 124: if (REG_P (operands[1])) ! 125: optype1 = REGOP; ! 126: else if (CONSTANT_P (operands[1])) ! 127: optype1 = CNSTOP; ! 128: else if (offsettable_memref_p (operands[1])) ! 129: optype1 = OFFSOP; ! 130: else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC) ! 131: optype1 = POPOP; ! 132: else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC) ! 133: optype1 = PUSHOP; ! 134: else if (GET_CODE (operands[1]) == MEM) ! 135: optype1 = MEMOP; ! 136: else ! 137: optype1 = RNDOP; ! 138: ! 139: /* Check for the cases that the operand constraints are not ! 140: supposed to allow to happen. Abort if we get one, ! 141: because generating code for these cases is painful. */ ! 142: ! 143: if (optype0 == RNDOP || optype1 == RNDOP) ! 144: abort (); ! 145: ! 146: /* If one operand is decrementing and one is incrementing ! 147: decrement the former register explicitly ! 148: and change that operand into ordinary indexing. */ ! 149: ! 150: if (optype0 == PUSHOP && optype1 == POPOP) ! 151: { ! 152: operands[0] = XEXP (XEXP (operands[0], 0), 0); ! 153: output_asm_insn ("subq%.l %#8,%0", operands); ! 154: operands[0] = gen_rtx (MEM, DImode, operands[0]); ! 155: optype0 = OFFSOP; ! 156: } ! 157: if (optype0 == POPOP && optype1 == PUSHOP) ! 158: { ! 159: operands[1] = XEXP (XEXP (operands[1], 0), 0); ! 160: output_asm_insn ("subq%.l %#8,%1", operands); ! 161: operands[1] = gen_rtx (MEM, DImode, operands[1]); ! 162: optype1 = OFFSOP; ! 163: } ! 164: ! 165: /* If an operand is an unoffsettable memory ref, find a register ! 166: we can increment temporarily to make it refer to the second word. */ ! 167: ! 168: if (optype0 == MEMOP) ! 169: addreg0 = find_addr_reg (XEXP (operands[0], 0)); ! 170: ! 171: if (optype1 == MEMOP) ! 172: addreg1 = find_addr_reg (XEXP (operands[1], 0)); ! 173: ! 174: /* Ok, we can do one word at a time. ! 175: Normally we do the low-numbered word first, ! 176: but if either operand is autodecrementing then we ! 177: do the high-numbered word first. ! 178: ! 179: In either case, set up in LATEHALF the operands to use ! 180: for the high-numbered word and in some cases alter the ! 181: operands in OPERANDS to be suitable for the low-numbered word. */ ! 182: ! 183: if (optype0 == REGOP) ! 184: latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); ! 185: else if (optype0 == OFFSOP) ! 186: latehalf[0] = adj_offsettable_operand (operands[0], 4); ! 187: else ! 188: latehalf[0] = operands[0]; ! 189: ! 190: if (optype1 == REGOP) ! 191: latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); ! 192: else if (optype1 == OFFSOP) ! 193: latehalf[1] = adj_offsettable_operand (operands[1], 4); ! 194: else if (optype1 == CNSTOP) ! 195: { ! 196: if (GET_CODE (operands[1]) == CONST_DOUBLE) ! 197: split_double (operands[1], &operands[1], &latehalf[1]); ! 198: else if (CONSTANT_P (operands[1])) ! 199: { ! 200: latehalf[1] = operands[1]; ! 201: operands[1] = const0_rtx; ! 202: } ! 203: } ! 204: else ! 205: latehalf[1] = operands[1]; ! 206: ! 207: /* If insn is effectively movd N(sp),-(sp) then we will do the ! 208: high word first. We should use the adjusted operand 1 (which is N+4(sp)) ! 209: for the low word as well, to compensate for the first decrement of sp. */ ! 210: if (optype0 == PUSHOP ! 211: && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM ! 212: && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1])) ! 213: operands[1] = latehalf[1]; ! 214: ! 215: /* If one or both operands autodecrementing, ! 216: do the two words, high-numbered first. */ ! 217: ! 218: /* Likewise, the first move would clobber the source of the second one, ! 219: do them in the other order. This happens only for registers; ! 220: such overlap can't happen in memory unless the user explicitly ! 221: sets it up, and that is an undefined circumstance. */ ! 222: ! 223: if (optype0 == PUSHOP || optype1 == PUSHOP ! 224: || (optype0 == REGOP && optype1 == REGOP ! 225: && REGNO (operands[0]) == REGNO (latehalf[1]))) ! 226: { ! 227: /* Make any unoffsettable 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: /* Do low-numbered word. */ ! 243: return singlemove_string (operands); ! 244: } ! 245: ! 246: /* Normal case: do the two words, low-numbered first. */ ! 247: ! 248: output_asm_insn (singlemove_string (operands), operands); ! 249: ! 250: /* Make any unoffsettable addresses point at high-numbered word. */ ! 251: if (addreg0) ! 252: output_asm_insn ("addql %#4,%0", &addreg0); ! 253: if (addreg1) ! 254: output_asm_insn ("addql %#4,%0", &addreg1); ! 255: ! 256: /* Do that word. */ ! 257: output_asm_insn (singlemove_string (latehalf), latehalf); ! 258: ! 259: /* Undo the adds we just did. */ ! 260: if (addreg0) ! 261: output_asm_insn ("subql %#4,%0", &addreg0); ! 262: if (addreg1) ! 263: output_asm_insn ("subql %#4,%0", &addreg1); ! 264: ! 265: return ""; ! 266: } ! 267: ! 268: /* Return a REG that occurs in ADDR with coefficient 1. ! 269: ADDR can be effectively incremented by incrementing REG. */ ! 270: ! 271: static rtx ! 272: find_addr_reg (addr) ! 273: rtx addr; ! 274: { ! 275: while (GET_CODE (addr) == PLUS) ! 276: { ! 277: if (GET_CODE (XEXP (addr, 0)) == REG) ! 278: addr = XEXP (addr, 0); ! 279: else if (GET_CODE (XEXP (addr, 1)) == REG) ! 280: addr = XEXP (addr, 1); ! 281: else if (CONSTANT_P (XEXP (addr, 0))) ! 282: addr = XEXP (addr, 1); ! 283: else if (CONSTANT_P (XEXP (addr, 1))) ! 284: addr = XEXP (addr, 0); ! 285: else ! 286: abort (); ! 287: } ! 288: if (GET_CODE (addr) == REG) ! 289: return addr; ! 290: abort (); ! 291: } ! 292: ! 293: int ! 294: standard_SunFPA_constant_p (x) ! 295: rtx x; ! 296: { ! 297: return( 0 ); ! 298: } ! 299:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.