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