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, 59 Temple Place - Suite 330, |
---|
19 | Boston, MA 02111-1307, USA. */ |
---|
20 | |
---|
21 | |
---|
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" |
---|
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 | |
---|