|
|
1.1 root 1: /* Subroutines for insn-output.c for Motorola 68000 family.
2: Copyright (C) 1987 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:
22: /* Some output-actions in m68k.md need these. */
23: #include <stdio.h>
24: extern FILE *asm_out_file;
25:
26: static rtx find_addr_reg ();
27:
28: char *
29: output_btst (operands, countop, dataop, insn, signpos)
30: rtx *operands;
31: rtx countop, dataop;
32: rtx insn;
33: int signpos;
34: {
35: operands[0] = countop;
36: operands[1] = dataop;
37: if (GET_CODE (countop) == CONST_INT)
38: {
39: register int count = INTVAL (countop);
40: if (count == signpos)
41: cc_status.flags = CC_NOT_POSITIVE | CC_Z_IN_NOT_N;
42: else
43: cc_status.flags = CC_NOT_NEGATIVE | CC_Z_IN_NOT_N;
44:
45: if (count == 31
46: && next_insn_tests_no_inequality (insn))
47: return "tst%.l %1";
48: if (count == 15
49: && next_insn_tests_no_inequality (insn))
50: return "tst%.w %1";
51: if (count == 7
52: && next_insn_tests_no_inequality (insn))
53: return "tst%.b %1";
54:
55: cc_status.flags = CC_NOT_NEGATIVE;
56: }
57: return "btst %0,%1";
58: }
59:
60: /* Return the best assembler insn template
61: for moving operands[1] into operands[0] as a fullword. */
62:
63: static char *
64: singlemove_string (operands)
65: rtx *operands;
66: {
67: if (operands[1] != const0_rtx)
68: return "move%.l %1,%0";
69: if (! ADDRESS_REG_P (operands[0]))
70: return "clr%.l %0";
71: return "sub%.l %0,%0";
72: }
73:
74: /* Output assembler code to perform a doubleword move insn
75: with operands OPERANDS. */
76:
77: char *
78: output_move_double (operands)
79: rtx *operands;
80: {
81: enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
82: rtx latehalf[2];
83: rtx addreg0 = 0, addreg1 = 0;
84:
85: /* First classify both operands. */
86:
87: if (REG_P (operands[0]))
88: optype0 = REGOP;
89: else if (offsetable_memref_p (operands[0]))
90: optype0 = OFFSOP;
91: else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC)
92: optype0 = POPOP;
93: else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
94: optype0 = PUSHOP;
95: else if (GET_CODE (operands[0]) == MEM)
96: optype0 = MEMOP;
97: else
98: optype0 = RNDOP;
99:
100: if (REG_P (operands[1]))
101: optype1 = REGOP;
102: else if (CONSTANT_P (operands[1])
103: || GET_CODE (operands[1]) == CONST_DOUBLE)
104: optype1 = CNSTOP;
105: else if (offsetable_memref_p (operands[1]))
106: optype1 = OFFSOP;
107: else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC)
108: optype1 = POPOP;
109: else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
110: optype1 = PUSHOP;
111: else if (GET_CODE (operands[1]) == MEM)
112: optype1 = MEMOP;
113: else
114: optype1 = RNDOP;
115:
116: /* Check for the cases that the operand constraints are not
117: supposed to allow to happen. Abort if we get one,
118: because generating code for these cases is painful. */
119:
120: if (optype0 == RNDOP || optype1 == RNDOP)
121: abort ();
122:
123: /* If one operand is decrementing and one is incrementing
124: decrement the former register explicitly
125: and change that operand into ordinary indexing. */
126:
127: if (optype0 == PUSHOP && optype1 == POPOP)
128: {
129: operands[0] = XEXP (XEXP (operands[0], 0), 0);
130: output_asm_insn ("subq%.l %#8,%0", operands);
131: operands[0] = gen_rtx (MEM, DImode, operands[0]);
132: optype0 = OFFSOP;
133: }
134: if (optype0 == POPOP && optype1 == PUSHOP)
135: {
136: operands[1] = XEXP (XEXP (operands[1], 0), 0);
137: output_asm_insn ("subq%.l %#8,%1", operands);
138: operands[1] = gen_rtx (MEM, DImode, operands[1]);
139: optype1 = OFFSOP;
140: }
141:
142: /* If an operand is an unoffsettable memory ref, find a register
143: we can increment temporarily to make it refer to the second word. */
144:
145: if (optype0 == MEMOP)
146: addreg0 = find_addr_reg (operands[0]);
147:
148: if (optype1 == MEMOP)
149: addreg1 = find_addr_reg (operands[1]);
150:
151: /* Ok, we can do one word at a time.
152: Normally we do the low-numbered word first,
153: but if either operand is autodecrementing then we
154: do the high-numbered word first.
155:
156: In either case, set up in LATEHALF the operands to use
157: for the high-numbered word and in some cases alter the
158: operands in OPERANDS to be suitable for the low-numbered word. */
159:
160: if (optype0 == REGOP)
161: latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
162: else if (optype0 == OFFSOP)
163: latehalf[0] = adj_offsetable_operand (operands[0], 4);
164: else
165: latehalf[0] = operands[0];
166:
167: if (optype1 == REGOP)
168: latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
169: else if (optype1 == OFFSOP)
170: latehalf[1] = adj_offsetable_operand (operands[1], 4);
171: else if (optype1 == CNSTOP)
172: {
173: if (CONSTANT_P (operands[1]))
174: latehalf[1] = const0_rtx;
175: else if (GET_CODE (operands[1]) == CONST_DOUBLE)
176: {
177: latehalf[1] = gen_rtx (CONST_INT, VOIDmode, XINT (operands[1], 1));
178: operands[1] = gen_rtx (CONST_INT, VOIDmode, XINT (operands[1], 0));
179: }
180: }
181: else
182: latehalf[1] = operands[1];
183:
184: /* If insn is effectively movd N(sp),-(sp) then we will do the
185: high word first. We should use the adjusted operand 1 (which is N+4(sp))
186: for the low word as well, to compensate for the first decrement of sp. */
187: if (optype0 == PUSHOP
188: && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
189: && reg_mentioned_p (XEXP (XEXP (operands[0], 0), 0), operands[1]))
190: operands[1] = latehalf[1];
191:
192: /* If one or both operands autodecrementing,
193: do the two words, high-numbered first. */
194:
195: /* Likewise, the first move would clobber the source of the second one,
196: do them in the other order. This happens only for registers;
197: such overlap can't happen in memory unless the user explicitly
198: sets it up, and that is an undefined circumstance. */
199:
200: if (optype0 == PUSHOP || optype1 == PUSHOP
201: || (optype0 == REGOP && optype1 == REGOP
202: && REGNO (operands[0]) == REGNO (latehalf[1])))
203: {
204: /* Make any unoffsetable addresses point at high-numbered word. */
205: if (addreg0)
206: output_asm_insn ("addql %#4,%0", &addreg0);
207: if (addreg1)
208: output_asm_insn ("addql %#4,%0", &addreg1);
209:
210: /* Do that word. */
211: output_asm_insn (singlemove_string (latehalf), latehalf);
212:
213: /* Undo the adds we just did. */
214: if (addreg0)
215: output_asm_insn ("subql %#4,%0", &addreg0);
216: if (addreg1)
217: output_asm_insn ("subql %#4,%0", &addreg1);
218:
219: /* Do low-numbered word. */
220: return singlemove_string (operands);
221: }
222:
223: /* Normal case: do the two words, low-numbered first. */
224:
225: output_asm_insn (singlemove_string (operands), operands);
226:
227: /* Make any unoffsetable 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: return "";
243: }
244:
245: /* Return a REG that occurs in ADDR with coefficient 1.
246: ADDR can be effectively incremented by incrementing REG. */
247:
248: static rtx
249: find_addr_reg (addr)
250: rtx addr;
251: {
252: while (GET_CODE (addr) == PLUS)
253: {
254: if (GET_CODE (XEXP (addr, 0)) == REG)
255: addr = XEXP (addr, 0);
256: if (GET_CODE (XEXP (addr, 1)) == REG)
257: addr = XEXP (addr, 1);
258: if (CONSTANT_P (XEXP (addr, 0)))
259: addr = XEXP (addr, 1);
260: if (CONSTANT_P (XEXP (addr, 1)))
261: addr = XEXP (addr, 0);
262: }
263: if (GET_CODE (addr) == REG)
264: return addr;
265: return 0;
266: }
267:
268: char *
269: output_move_const_double (operands)
270: rtx *operands;
271: {
272: int code = standard_68881_constant_p (operands[1]);
273:
274: if (code != 0)
275: {
276: static char buf[40];
277:
278: sprintf (buf, "fmovecr %%#0x%x,%%0", code & 0xff);
279: return buf;
280: }
281: return "fmove%.d %1,%0";
282: }
283:
284: char *
285: output_move_const_single (operands)
286: rtx *operands;
287: {
288: int code = standard_68881_constant_p (operands[1]);
289:
290: if (code != 0)
291: {
292: static char buf[40];
293:
294: sprintf (buf, "fmovecr %%#0x%x,%%0", code & 0xff);
295: return buf;
296: }
297: return "fmove%.s %f1,%0";
298: }
299:
300: /* Return nonzero if X, a CONST_DOUBLE, has a value that we can get
301: from the "fmovecr" instruction.
302: The value, anded with 0xff, gives the code to use in fmovecr
303: to get the desired constant. */
304:
305: int
306: standard_68881_constant_p (x)
307: rtx x;
308: {
309: union {double d; int i[2];} u;
310: register double d;
311: u.i[0] = XINT (x, 0);
312: u.i[1] = XINT (x, 1);
313: d = u.d;
314:
315: if (d == 0)
316: return 0x0f;
317: /* Note: there are various other constants available
318: but it is a nuisance to put in their values here. */
319: if (d == 1)
320: return 0x32;
321: if (d == 10)
322: return 0x33;
323: if (d == 100)
324: return 0x34;
325: if (d == 10000)
326: return 0x35;
327: if (d == 1e8)
328: return 0x36;
329: if (GET_MODE (x) == SFmode)
330: return 0;
331: if (d == 1e16)
332: return 0x37;
333: /* larger powers of ten in the constants ram are not used
334: because they are not equal to a `double' C constant. */
335: return 0;
336: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.