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