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