1 /* Subroutines for insn-output.c for Alliant FX computers.
2 Copyright (C) 1989,1991 Free Software Foundation, Inc.
4 This file is part of GNU CC.
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)
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.
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. */
22 /* Some output-actions in alliant.md need these. */
27 #include "hard-reg-set.h"
29 #include "insn-config.h"
30 #include "conditions.h"
31 #include "insn-flags.h"
33 #include "insn-attr.h"
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
};
40 static rtx
find_addr_reg ();
43 output_btst (operands
, countop
, dataop
, insn
, signpos
)
49 operands
[0] = countop
;
52 if (GET_CODE (countop
) == CONST_INT
)
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. */
59 int offset
= (count
& ~signpos
) / 8;
60 count
= count
& signpos
;
61 operands
[1] = dataop
= adj_offsettable_operand (dataop
, offset
);
64 cc_status
.flags
= CC_NOT_POSITIVE
| CC_Z_IN_NOT_N
;
66 cc_status
.flags
= CC_NOT_NEGATIVE
| CC_Z_IN_NOT_N
;
68 /* These three statements used to use next_insns_test_no...
69 but it appears that this should do the same job. */
71 && next_insn_tests_no_inequality (insn
))
74 && next_insn_tests_no_inequality (insn
))
77 && next_insn_tests_no_inequality (insn
))
80 cc_status
.flags
= CC_NOT_NEGATIVE
;
85 /* Return the best assembler insn template
86 for moving operands[1] into operands[0] as a fullword. */
89 singlemove_string (operands
)
92 if (operands
[1] != const0_rtx
)
93 return "mov%.l %1,%0";
94 if (! ADDRESS_REG_P (operands
[0]))
96 return "sub%.l %0,%0";
99 /* Output assembler code to perform a doubleword move insn
100 with operands OPERANDS. */
103 output_move_double (operands
)
106 enum { REGOP
, OFFSOP
, MEMOP
, PUSHOP
, POPOP
, CNSTOP
, RNDOP
} optype0
, optype1
;
108 rtx addreg0
= 0, addreg1
= 0;
110 /* First classify both operands. */
112 if (REG_P (operands
[0]))
114 else if (offsettable_memref_p (operands
[0]))
116 else if (GET_CODE (XEXP (operands
[0], 0)) == POST_INC
)
118 else if (GET_CODE (XEXP (operands
[0], 0)) == PRE_DEC
)
120 else if (GET_CODE (operands
[0]) == MEM
)
125 if (REG_P (operands
[1]))
127 else if (CONSTANT_P (operands
[1]))
129 else if (offsettable_memref_p (operands
[1]))
131 else if (GET_CODE (XEXP (operands
[1], 0)) == POST_INC
)
133 else if (GET_CODE (XEXP (operands
[1], 0)) == PRE_DEC
)
135 else if (GET_CODE (operands
[1]) == MEM
)
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. */
144 if (optype0
== RNDOP
|| optype1
== RNDOP
)
147 /* If one operand is decrementing and one is incrementing
148 decrement the former register explicitly
149 and change that operand into ordinary indexing. */
151 if (optype0
== PUSHOP
&& optype1
== POPOP
)
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]);
158 if (optype0
== POPOP
&& optype1
== PUSHOP
)
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]);
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. */
169 if (optype0
== MEMOP
)
170 addreg0
= find_addr_reg (XEXP (operands
[0], 0));
172 if (optype1
== MEMOP
)
173 addreg1
= find_addr_reg (XEXP (operands
[1], 0));
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.
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. */
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);
189 latehalf
[0] = operands
[0];
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
)
197 if (GET_CODE (operands
[1]) == CONST_DOUBLE
)
198 split_double (operands
[1], &operands
[1], &latehalf
[1]);
199 else if (CONSTANT_P (operands
[1]))
201 latehalf
[1] = operands
[1];
202 operands
[1] = const0_rtx
;
206 latehalf
[1] = operands
[1];
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];
216 /* If one or both operands autodecrementing,
217 do the two words, high-numbered first. */
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. */
224 if (optype0
== PUSHOP
|| optype1
== PUSHOP
225 || (optype0
== REGOP
&& optype1
== REGOP
226 && REGNO (operands
[0]) == REGNO (latehalf
[1])))
228 /* Make any unoffsettable addresses point at high-numbered word. */
230 output_asm_insn ("addql %#4,%0", &addreg0
);
232 output_asm_insn ("addql %#4,%0", &addreg1
);
235 output_asm_insn (singlemove_string (latehalf
), latehalf
);
237 /* Undo the adds we just did. */
239 output_asm_insn ("subql %#4,%0", &addreg0
);
241 output_asm_insn ("subql %#4,%0", &addreg1
);
243 /* Do low-numbered word. */
244 return singlemove_string (operands
);
247 /* Normal case: do the two words, low-numbered first. */
249 output_asm_insn (singlemove_string (operands
), operands
);
251 /* Make any unoffsettable addresses point at high-numbered word. */
253 output_asm_insn ("addql %#4,%0", &addreg0
);
255 output_asm_insn ("addql %#4,%0", &addreg1
);
258 output_asm_insn (singlemove_string (latehalf
), latehalf
);
260 /* Undo the adds we just did. */
262 output_asm_insn ("subql %#4,%0", &addreg0
);
264 output_asm_insn ("subql %#4,%0", &addreg1
);
269 /* Return a REG that occurs in ADDR with coefficient 1.
270 ADDR can be effectively incremented by incrementing REG. */
276 while (GET_CODE (addr
) == PLUS
)
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);
289 if (GET_CODE (addr
) == REG
)
295 standard_SunFPA_constant_p (x
)