|
|
1.1 root 1: /* Subroutines for insn-output.c for Motorola 68000 family.
2: Copyright (C) 1988 Free Software Foundation, Inc.
3:
4: This file is part of GNU CC.
5:
6: GNU CC is distributed in the hope that it will be useful,
7: but WITHOUT ANY WARRANTY. No author or distributor
8: accepts responsibility to anyone for the consequences of using it
9: or for whether it serves any particular purpose or works at all,
10: unless he says so in writing. Refer to the GNU CC General Public
11: License for full details.
12:
13: Everyone is granted permission to copy, modify and redistribute
14: GNU CC, but only under the conditions described in the
15: GNU CC General Public License. A copy of this license is
16: supposed to have been given to you along with GNU CC so you
17: can know your rights and responsibilities. It should be in a
18: file named COPYING. Among other things, the copyright notice
19: and this notice must be preserved on all copies. */
20:
21: static rtx find_addr_reg ();
22:
23: char *
24: output_compare (operands, opcode, exchange_opcode)
25: rtx *operands;
26: char *opcode;
27: char *exchange_opcode;
28: {
29: static char buf[40];
30: operands[2] = operands[0];
31: if (GET_CODE (cc_prev_status.value1) == CONST_INT)
32: {
33: operands[1] = cc_prev_status.value1;
34: operands[0] = cc_prev_status.value2;
35: opcode = exchange_opcode;
36: }
37: else
38: {
39: operands[0] = cc_prev_status.value1;
40: operands[1] = cc_prev_status.value2;
41: }
42: sprintf (buf, "cmp_br_delayed %s,%%0,%%1,%%l2\n\tnop", opcode);
43: return buf;
44: }
45:
46: /* Return the best assembler insn template
47: for moving operands[1] into operands[0] as a fullword. */
48:
49: static char *
50: singlemove_string (operands)
51: rtx *operands;
52: {
53: if (GET_CODE (operands[0]) == MEM)
54: return "st_32 %r1,%0";
55: if (GET_CODE (operands[1]) == MEM)
56: return "ld_32 %0,%1\n\tnop";
57: return "add_nt %0,r0,%1";
58: }
59:
60: /* Output assembler code to perform a doubleword move insn
61: with operands OPERANDS. */
62:
63: char *
64: output_move_double (operands)
65: rtx *operands;
66: {
67: enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
68: rtx latehalf[2];
69: rtx addreg0 = 0, addreg1 = 0;
70:
71: /* First classify both operands. */
72:
73: if (REG_P (operands[0]))
74: optype0 = REGOP;
75: else if (offsetable_memref_p (operands[0]))
76: optype0 = OFFSOP;
77: else if (GET_CODE (operands[0]) == MEM)
78: optype0 = MEMOP;
79: else
80: optype0 = RNDOP;
81:
82: if (REG_P (operands[1]))
83: optype1 = REGOP;
84: else if (CONSTANT_P (operands[1])
85: || GET_CODE (operands[1]) == CONST_DOUBLE)
86: optype1 = CNSTOP;
87: else if (offsetable_memref_p (operands[1]))
88: optype1 = OFFSOP;
89: else if (GET_CODE (operands[1]) == MEM)
90: optype0 = MEMOP;
91: else
92: optype1 = RNDOP;
93:
94: /* Check for the cases that the operand constraints are not
95: supposed to allow to happen. Abort if we get one,
96: because generating code for these cases is painful. */
97:
98: if (optype0 == RNDOP || optype1 == RNDOP)
99: abort ();
100:
101: /* If an operand is an unoffsettable memory ref, find a register
102: we can increment temporarily to make it refer to the second word. */
103:
104: if (optype0 == MEMOP)
105: addreg0 = find_addr_reg (operands[0]);
106:
107: if (optype1 == MEMOP)
108: addreg1 = find_addr_reg (operands[1]);
109:
110: /* Ok, we can do one word at a time.
111: Normally we do the low-numbered word first,
112: but if either operand is autodecrementing then we
113: do the high-numbered word first.
114:
115: In either case, set up in LATEHALF the operands to use
116: for the high-numbered word and in some cases alter the
117: operands in OPERANDS to be suitable for the low-numbered word. */
118:
119: if (optype0 == REGOP)
120: latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
121: else if (optype0 == OFFSOP)
122: latehalf[0] = adj_offsetable_operand (operands[0], 4);
123: else
124: latehalf[0] = operands[0];
125:
126: if (optype1 == REGOP)
127: latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
128: else if (optype1 == OFFSOP)
129: latehalf[1] = adj_offsetable_operand (operands[1], 4);
130: else if (optype1 == CNSTOP)
131: {
132: if (CONSTANT_P (operands[1]))
133: latehalf[1] = const0_rtx;
134: else if (GET_CODE (operands[1]) == CONST_DOUBLE)
135: {
136: latehalf[1] = gen_rtx (CONST_INT, VOIDmode, XINT (operands[1], 1));
137: operands[1] = gen_rtx (CONST_INT, VOIDmode, XINT (operands[1], 0));
138: }
139: }
140: else
141: latehalf[1] = operands[1];
142:
143: /* If the first move would clobber the source of the second one,
144: do them in the other order. This happens only for registers;
145: such overlap can't happen in memory unless the user explicitly
146: sets it up, and that is an undefined circumstance. */
147:
148: if (optype0 == REGOP && optype1 == REGOP
149: && REGNO (operands[0]) == REGNO (latehalf[1]))
150: {
151: /* Make any unoffsetable addresses point at high-numbered word. */
152: if (addreg0)
153: output_asm_insn ("add_nt %0,%0,$4", &addreg0);
154: if (addreg1)
155: output_asm_insn ("add_nt %0,%0,$4", &addreg1);
156:
157: /* Do that word. */
158: output_asm_insn (singlemove_string (latehalf), latehalf);
159:
160: /* Undo the adds we just did. */
161: if (addreg0)
162: output_asm_insn ("add_nt %0,%0,$-4", &addreg0);
163: if (addreg1)
164: output_asm_insn ("add_nt %0,%0,$-4", &addreg0);
165:
166: /* Do low-numbered word. */
167: return singlemove_string (operands);
168: }
169:
170: /* Normal case: do the two words, low-numbered first. */
171:
172: output_asm_insn (singlemove_string (operands), operands);
173:
174: /* Make any unoffsetable 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", &addreg1);
188:
189: return "";
190: }
191:
192: static char *
193: output_fp_move_double (operands)
194: rtx *operands;
195: {
196: if (FP_REG_P (operands[0]))
197: {
198: if (FP_REG_P (operands[1]))
199: return "fmov %0,%1";
200: if (GET_CODE (operands[1]) == REG)
201: {
202: rtx xoperands[2];
203: int offset = - get_frame_size () - 8;
204: xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
205: xoperands[0] = gen_rtx (CONST_INT, VOIDmode, offset + 4);
206: output_asm_insn ("st_32 %1,r25,%0", xoperands);
207: xoperands[1] = operands[1];
208: xoperands[0] = gen_rtx (CONST_INT, VOIDmode, offset);
209: output_asm_insn ("st_32 %1,r25,%0", xoperands);
210: xoperands[1] = operands[0];
211: output_asm_insn ("ld_dbl %1,r25,%0\n\tnop", xoperands);
212: return "";
213: }
214: return "ld_dbl %0,%1\n\tnop";
215: }
216: else if (FP_REG_P (operands[1]))
217: {
218: if (GET_CODE (operands[0]) == REG)
219: {
220: rtx xoperands[2];
221: int offset = - get_frame_size () - 8;
222: xoperands[0] = gen_rtx (CONST_INT, VOIDmode, offset);
223: xoperands[1] = operands[1];
224: output_asm_insn ("st_dbl %1,r25,%0", xoperands);
225: xoperands[1] = operands[0];
226: output_asm_insn ("ld_32 %1,r25,%0\n\tnop", xoperands);
227: xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
228: xoperands[0] = gen_rtx (CONST_INT, VOIDmode, offset + 4);
229: output_asm_insn ("ld_32 %1,r25,%0\n\tnop", xoperands);
230: return "";
231: }
232: return "st_dbl %1,%0";
233: }
234: }
235:
236: /* Return a REG that occurs in ADDR with coefficient 1.
237: ADDR can be effectively incremented by incrementing REG. */
238:
239: static rtx
240: find_addr_reg (addr)
241: rtx addr;
242: {
243: while (GET_CODE (addr) == PLUS)
244: {
245: if (GET_CODE (XEXP (addr, 0)) == REG)
246: addr = XEXP (addr, 0);
247: if (GET_CODE (XEXP (addr, 1)) == REG)
248: addr = XEXP (addr, 1);
249: if (CONSTANT_P (XEXP (addr, 0)))
250: addr = XEXP (addr, 1);
251: if (CONSTANT_P (XEXP (addr, 1)))
252: addr = XEXP (addr, 0);
253: }
254: if (GET_CODE (addr) == REG)
255: return addr;
256: return 0;
257: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.