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