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