(TARGET_CPU_arm*, TARGET_CPU_strongarm*, TARGET_CPU_generic):
[official-gcc.git] / gcc / config / fx80 / fx80.c
bloba87be41e5e8d9bc0b49424923c002c887c2edaf5
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)
9 any later version.
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. */
23 #include <stdio.h>
24 #include "config.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"
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 ();
42 char *
43 output_btst (operands, countop, dataop, insn, signpos)
44 rtx *operands;
45 rtx countop, dataop;
46 rtx insn;
47 int signpos;
49 operands[0] = countop;
50 operands[1] = dataop;
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. */
57 if (count > signpos)
59 int offset = (count & ~signpos) / 8;
60 count = count & signpos;
61 operands[1] = dataop = adj_offsettable_operand (dataop, offset);
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;
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";
80 cc_status.flags = CC_NOT_NEGATIVE;
82 return "btst %0,%1";
85 /* Return the best assembler insn template
86 for moving operands[1] into operands[0] as a fullword. */
88 static char *
89 singlemove_string (operands)
90 rtx *operands;
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";
99 /* Output assembler code to perform a doubleword move insn
100 with operands OPERANDS. */
102 char *
103 output_move_double (operands)
104 rtx *operands;
106 enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
107 rtx latehalf[2];
108 rtx addreg0 = 0, addreg1 = 0;
110 /* First classify both operands. */
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;
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;
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)
145 abort ();
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]);
156 optype0 = OFFSOP;
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]);
163 optype1 = OFFSOP;
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);
188 else
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;
205 else
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. */
229 if (addreg0)
230 output_asm_insn ("addql %#4,%0", &addreg0);
231 if (addreg1)
232 output_asm_insn ("addql %#4,%0", &addreg1);
234 /* Do that word. */
235 output_asm_insn (singlemove_string (latehalf), latehalf);
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);
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. */
252 if (addreg0)
253 output_asm_insn ("addql %#4,%0", &addreg0);
254 if (addreg1)
255 output_asm_insn ("addql %#4,%0", &addreg1);
257 /* Do that word. */
258 output_asm_insn (singlemove_string (latehalf), latehalf);
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);
266 return "";
269 /* Return a REG that occurs in ADDR with coefficient 1.
270 ADDR can be effectively incremented by incrementing REG. */
272 static rtx
273 find_addr_reg (addr)
274 rtx addr;
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);
286 else
287 abort ();
289 if (GET_CODE (addr) == REG)
290 return addr;
291 abort ();
295 standard_SunFPA_constant_p (x)
296 rtx x;
298 return( 0 );