|
|
1.1 root 1: /* Subroutines for insn-output.c for SPUR. Adapted from routines for
2: the Motorola 68000 family.
3: Copyright (C) 1988, 1991 Free Software Foundation, Inc.
4:
5: This file is part of GNU CC.
6:
7: GNU CC is free software; you can redistribute it and/or modify
8: it under the terms of the GNU General Public License as published by
9: the Free Software Foundation; either version 2, or (at your option)
10: any later version.
11:
12: GNU CC is distributed in the hope that it will be useful,
13: but WITHOUT ANY WARRANTY; without even the implied warranty of
14: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15: GNU General Public License for more details.
16:
17: You should have received a copy of the GNU General Public License
18: along with GNU CC; see the file COPYING. If not, write to
1.1.1.2 ! root 19: the Free Software Foundation, 59 Temple Place - Suite 330,
! 20: Boston, MA 02111-1307, USA. */
1.1 root 21:
22: #include "config.h"
23: #include "rtl.h"
24: #include "regs.h"
25: #include "hard-reg-set.h"
26: #include "real.h"
27: #include "insn-config.h"
28: #include "conditions.h"
29: #include "insn-flags.h"
30: #include "output.h"
31: #include "insn-attr.h"
32:
33: static rtx find_addr_reg ();
34:
35: char *
36: output_compare (operands, opcode, exchange_opcode,
37: neg_opcode, neg_exchange_opcode)
38: rtx *operands;
39: char *opcode;
40: char *exchange_opcode;
41: char *neg_opcode;
42: char *neg_exchange_opcode;
43: {
44: static char buf[100];
45: operands[2] = operands[0];
46: if (GET_CODE (cc_prev_status.value1) == CONST_INT)
47: {
48: operands[1] = cc_prev_status.value1;
49: operands[0] = cc_prev_status.value2;
50: opcode = exchange_opcode, neg_opcode = neg_exchange_opcode;
51: }
52: else
53: {
54: operands[0] = cc_prev_status.value1;
55: operands[1] = cc_prev_status.value2;
56: }
57: if (TARGET_LONG_JUMPS)
58: sprintf (buf,
59: "cmp_br_delayed %s,%%0,%%1,1f\n\tnop\n\tjump %%l2\n\tnop\n1:",
60: neg_opcode);
61: else
62: sprintf (buf, "cmp_br_delayed %s,%%0,%%1,%%l2\n\tnop", opcode);
63: return buf;
64: }
65:
66: /* Return the best assembler insn template
67: for moving operands[1] into operands[0] as a fullword. */
68:
69: static char *
70: singlemove_string (operands)
71: rtx *operands;
72: {
73: if (GET_CODE (operands[0]) == MEM)
74: return "st_32 %r1,%0";
75: if (GET_CODE (operands[1]) == MEM)
76: return "ld_32 %0,%1\n\tnop";
77: if (GET_CODE (operands[1]) == REG)
78: return "add_nt %0,%1,$0";
79: return "add_nt %0,r0,%1";
80: }
81:
82: /* Output assembler code to perform a doubleword move insn
83: with operands OPERANDS. */
84:
85: char *
86: output_move_double (operands)
87: rtx *operands;
88: {
89: enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
90: rtx latehalf[2];
91: rtx addreg0 = 0, addreg1 = 0;
92:
93: /* First classify both operands. */
94:
95: if (REG_P (operands[0]))
96: optype0 = REGOP;
97: else if (offsettable_memref_p (operands[0]))
98: optype0 = OFFSOP;
99: else if (GET_CODE (operands[0]) == MEM)
100: optype0 = MEMOP;
101: else
102: optype0 = RNDOP;
103:
104: if (REG_P (operands[1]))
105: optype1 = REGOP;
106: else if (CONSTANT_P (operands[1]))
107: optype1 = CNSTOP;
108: else if (offsettable_memref_p (operands[1]))
109: optype1 = OFFSOP;
110: else if (GET_CODE (operands[1]) == MEM)
111: optype1 = MEMOP;
112: else
113: optype1 = RNDOP;
114:
115: /* Check for the cases that the operand constraints are not
116: supposed to allow to happen. Abort if we get one,
117: because generating code for these cases is painful. */
118:
119: if (optype0 == RNDOP || optype1 == RNDOP)
120: abort ();
121:
122: /* If an operand is an unoffsettable memory ref, find a register
123: we can increment temporarily to make it refer to the second word. */
124:
125: if (optype0 == MEMOP)
126: addreg0 = find_addr_reg (XEXP (operands[0], 0));
127:
128: if (optype1 == MEMOP)
129: addreg1 = find_addr_reg (XEXP (operands[1], 0));
130:
131: /* Ok, we can do one word at a time.
132: Normally we do the low-numbered word first,
133: but if either operand is autodecrementing then we
134: do the high-numbered word first.
135:
136: In either case, set up in LATEHALF the operands to use
137: for the high-numbered word and in some cases alter the
138: operands in OPERANDS to be suitable for the low-numbered word. */
139:
140: if (optype0 == REGOP)
141: latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
142: else if (optype0 == OFFSOP)
143: latehalf[0] = adj_offsettable_operand (operands[0], 4);
144: else
145: latehalf[0] = operands[0];
146:
147: if (optype1 == REGOP)
148: latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
149: else if (optype1 == OFFSOP)
150: latehalf[1] = adj_offsettable_operand (operands[1], 4);
151: else if (optype1 == CNSTOP)
152: {
153: if (GET_CODE (operands[1]) == CONST_DOUBLE)
154: {
155: latehalf[1] = gen_rtx (CONST_INT, VOIDmode,
156: CONST_DOUBLE_HIGH (operands[1]));
157: operands[1] = gen_rtx (CONST_INT, VOIDmode,
158: CONST_DOUBLE_LOW (operands[1]));
159: }
160: else if (CONSTANT_P (operands[1]))
161: latehalf[1] = const0_rtx;
162: }
163: else
164: latehalf[1] = operands[1];
165:
166: /* If the first move would clobber the source of the second one,
167: do them in the other order. This happens only for registers;
168: such overlap can't happen in memory unless the user explicitly
169: sets it up, and that is an undefined circumstance. */
170:
171: if (optype0 == REGOP && optype1 == REGOP
172: && REGNO (operands[0]) == REGNO (latehalf[1]))
173: {
174: /* Make any unoffsettable addresses point at high-numbered word. */
175: if (addreg0)
176: output_asm_insn ("add_nt %0,%0,$4", &addreg0);
177: if (addreg1)
178: output_asm_insn ("add_nt %0,%0,$4", &addreg1);
179:
180: /* Do that word. */
181: output_asm_insn (singlemove_string (latehalf), latehalf);
182:
183: /* Undo the adds we just did. */
184: if (addreg0)
185: output_asm_insn ("add_nt %0,%0,$-4", &addreg0);
186: if (addreg1)
187: output_asm_insn ("add_nt %0,%0,$-4", &addreg0);
188:
189: /* Do low-numbered word. */
190: return singlemove_string (operands);
191: }
192:
193: /* Normal case: do the two words, low-numbered first. */
194:
195: output_asm_insn (singlemove_string (operands), operands);
196:
197: /* Make any unoffsettable addresses point at high-numbered word. */
198: if (addreg0)
199: output_asm_insn ("add_nt %0,%0,$4", &addreg0);
200: if (addreg1)
201: output_asm_insn ("add_nt %0,%0,$4", &addreg1);
202:
203: /* Do that word. */
204: output_asm_insn (singlemove_string (latehalf), latehalf);
205:
206: /* Undo the adds we just did. */
207: if (addreg0)
208: output_asm_insn ("add_nt %0,%0,$-4", &addreg0);
209: if (addreg1)
210: output_asm_insn ("add_nt %0,%0,$-4", &addreg1);
211:
212: return "";
213: }
214:
215: static char *
216: output_fp_move_double (operands)
217: rtx *operands;
218: {
219: if (FP_REG_P (operands[0]))
220: {
221: if (FP_REG_P (operands[1]))
222: return "fmov %0,%1";
223: if (GET_CODE (operands[1]) == REG)
224: {
225: rtx xoperands[2];
226: int offset = - get_frame_size () - 8;
227: xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
228: xoperands[0] = gen_rtx (CONST_INT, VOIDmode, offset + 4);
229: output_asm_insn ("st_32 %1,r25,%0", xoperands);
230: xoperands[1] = operands[1];
231: xoperands[0] = gen_rtx (CONST_INT, VOIDmode, offset);
232: output_asm_insn ("st_32 %1,r25,%0", xoperands);
233: xoperands[1] = operands[0];
234: output_asm_insn ("ld_dbl %1,r25,%0\n\tnop", xoperands);
235: return "";
236: }
237: return "ld_dbl %0,%1\n\tnop";
238: }
239: else if (FP_REG_P (operands[1]))
240: {
241: if (GET_CODE (operands[0]) == REG)
242: {
243: rtx xoperands[2];
244: int offset = - get_frame_size () - 8;
245: xoperands[0] = gen_rtx (CONST_INT, VOIDmode, offset);
246: xoperands[1] = operands[1];
247: output_asm_insn ("st_dbl %1,r25,%0", xoperands);
248: xoperands[1] = operands[0];
249: output_asm_insn ("ld_32 %1,r25,%0\n\tnop", xoperands);
250: xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
251: xoperands[0] = gen_rtx (CONST_INT, VOIDmode, offset + 4);
252: output_asm_insn ("ld_32 %1,r25,%0\n\tnop", xoperands);
253: return "";
254: }
255: return "st_dbl %1,%0";
256: }
257: }
258:
259: /* Return a REG that occurs in ADDR with coefficient 1.
260: ADDR can be effectively incremented by incrementing REG. */
261:
262: static rtx
263: find_addr_reg (addr)
264: rtx addr;
265: {
266: while (GET_CODE (addr) == PLUS)
267: {
268: if (GET_CODE (XEXP (addr, 0)) == REG)
269: addr = XEXP (addr, 0);
270: else if (GET_CODE (XEXP (addr, 1)) == REG)
271: addr = XEXP (addr, 1);
272: else if (CONSTANT_P (XEXP (addr, 0)))
273: addr = XEXP (addr, 1);
274: else if (CONSTANT_P (XEXP (addr, 1)))
275: addr = XEXP (addr, 0);
276: else
277: abort ();
278: }
279: if (GET_CODE (addr) == REG)
280: return addr;
281: abort ();
282: }
283:
284: /* Generate code to add a large integer constant to register, reg, storing
285: * the result in a register, target. Offset must be 27-bit signed quantity */
286:
287: static char *
288: output_add_large_offset (target, reg, offset)
289: rtx target, reg;
290: int offset;
291: {
292: rtx operands[3];
293: int high, n, i;
294: operands[0] = target, operands[1] = reg;
295:
296: for (high = offset, n = 0;
297: (unsigned) (high + 0x2000) >= 0x4000;
298: high >>= 1, n += 1)
299: ;
300: operands[2] = gen_rtx (CONST_INT, VOIDmode, high);
301: output_asm_insn ("add_nt r2,r0,%2", operands);
302: i = n;
303: while (i >= 3)
304: output_asm_insn ("sll r2,r2,$3", operands), i -= 3;
305: if (i == 2)
306: output_asm_insn ("sll r2,r2,$2", operands);
307: else if (i == 1)
308: output_asm_insn ("sll r2,r2,$1", operands);
309: output_asm_insn ("add_nt %0,r2,%1", operands);
310: if (offset - (high << n) != 0)
311: {
312: operands[2] = gen_rtx (CONST_INT, VOIDmode, offset - (high << n));
313: output_asm_insn ("add_nt %0,%0,%2", operands);
314: }
315: return "";
316: }
317:
318: /* Additional TESTFN for matching. Like immediate_operand, but matches big
319: * constants */
320:
321: int
322: big_immediate_operand (op, mode)
323: rtx op;
324: enum machine_mode mode;
325: {
326: return (GET_CODE (op) == CONST_INT);
327: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.