source: trunk/third/gcc/config/fx80/fx80.c @ 8834

Revision 8834, 8.7 KB checked in by ghudson, 28 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r8833, which included commits to RCS files with non-trunk default branches.
Line 
1/* Subroutines for insn-output.c for Alliant FX computers.
2   Copyright (C) 1989,1991 Free Software Foundation, Inc.
3
4This file is part of GNU CC.
5
6GNU CC is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2, or (at your option)
9any later version.
10
11GNU CC is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU CC; see the file COPYING.  If not, write to
18the Free Software Foundation, 59 Temple Place - Suite 330,
19Boston, MA 02111-1307, USA.  */
20
21
22/* Some output-actions in alliant.md need these.  */
23#include <stdio.h>
24#include "config.h"
25#include "rtl.h"
26#include "regs.h"
27#include "hard-reg-set.h"
28#include "real.h"
29#include "insn-config.h"
30#include "conditions.h"
31#include "insn-flags.h"
32#include "output.h"
33#include "insn-attr.h"
34
35/* Index into this array by (register number >> 3) to find the
36   smallest class which contains that register.  */
37enum reg_class regno_reg_class[]
38  = { DATA_REGS, ADDR_REGS, FP_REGS };
39
40static rtx find_addr_reg ();
41
42char *
43output_btst (operands, countop, dataop, insn, signpos)
44     rtx *operands;
45     rtx countop, dataop;
46     rtx insn;
47     int signpos;
48{
49  operands[0] = countop;
50  operands[1] = dataop;
51
52  if (GET_CODE (countop) == CONST_INT)
53    {
54      register int count = INTVAL (countop);
55      /* If COUNT is bigger than size of storage unit in use,
56         advance to the containing unit of same size.  */
57      if (count > signpos)
58        {
59          int offset = (count & ~signpos) / 8;
60          count = count & signpos;
61          operands[1] = dataop = adj_offsettable_operand (dataop, offset);
62        }
63      if (count == signpos)
64        cc_status.flags = CC_NOT_POSITIVE | CC_Z_IN_NOT_N;
65      else
66        cc_status.flags = CC_NOT_NEGATIVE | CC_Z_IN_NOT_N;
67
68      /* These three statements used to use next_insns_test_no...
69         but it appears that this should do the same job.  */
70      if (count == 31
71          && next_insn_tests_no_inequality (insn))
72        return "tst%.l %1";
73      if (count == 15
74          && next_insn_tests_no_inequality (insn))
75        return "tst%.w %1";
76      if (count == 7
77          && next_insn_tests_no_inequality (insn))
78        return "tst%.b %1";
79
80      cc_status.flags = CC_NOT_NEGATIVE;
81    }
82  return "btst %0,%1";
83}
84
85/* Return the best assembler insn template
86   for moving operands[1] into operands[0] as a fullword.  */
87
88static char *
89singlemove_string (operands)
90     rtx *operands;
91{
92  if (operands[1] != const0_rtx)
93    return "mov%.l %1,%0";
94  if (! ADDRESS_REG_P (operands[0]))
95    return "clr%.l %0";
96  return "sub%.l %0,%0";
97}
98
99/* Output assembler code to perform a doubleword move insn
100   with operands OPERANDS.  */
101
102char *
103output_move_double (operands)
104     rtx *operands;
105{
106  enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
107  rtx latehalf[2];
108  rtx addreg0 = 0, addreg1 = 0;
109
110  /* First classify both operands.  */
111
112  if (REG_P (operands[0]))
113    optype0 = REGOP;
114  else if (offsettable_memref_p (operands[0]))
115    optype0 = OFFSOP;
116  else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC)
117    optype0 = POPOP;
118  else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
119    optype0 = PUSHOP;
120  else if (GET_CODE (operands[0]) == MEM)
121    optype0 = MEMOP;
122  else
123    optype0 = RNDOP;
124
125  if (REG_P (operands[1]))
126    optype1 = REGOP;
127  else if (CONSTANT_P (operands[1]))
128    optype1 = CNSTOP;
129  else if (offsettable_memref_p (operands[1]))
130    optype1 = OFFSOP;
131  else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC)
132    optype1 = POPOP;
133  else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
134    optype1 = PUSHOP;
135  else if (GET_CODE (operands[1]) == MEM)
136    optype1 = MEMOP;
137  else
138    optype1 = RNDOP;
139
140  /* Check for the cases that the operand constraints are not
141     supposed to allow to happen.  Abort if we get one,
142     because generating code for these cases is painful.  */
143
144  if (optype0 == RNDOP || optype1 == RNDOP)
145    abort ();
146
147  /* If one operand is decrementing and one is incrementing
148     decrement the former register explicitly
149     and change that operand into ordinary indexing.  */
150
151  if (optype0 == PUSHOP && optype1 == POPOP)
152    {
153      operands[0] = XEXP (XEXP (operands[0], 0), 0);
154      output_asm_insn ("subq%.l %#8,%0", operands);
155      operands[0] = gen_rtx (MEM, DImode, operands[0]);
156      optype0 = OFFSOP;
157    }
158  if (optype0 == POPOP && optype1 == PUSHOP)
159    {
160      operands[1] = XEXP (XEXP (operands[1], 0), 0);
161      output_asm_insn ("subq%.l %#8,%1", operands);
162      operands[1] = gen_rtx (MEM, DImode, operands[1]);
163      optype1 = OFFSOP;
164    }
165
166  /* If an operand is an unoffsettable memory ref, find a register
167     we can increment temporarily to make it refer to the second word.  */
168
169  if (optype0 == MEMOP)
170    addreg0 = find_addr_reg (XEXP (operands[0], 0));
171
172  if (optype1 == MEMOP)
173    addreg1 = find_addr_reg (XEXP (operands[1], 0));
174
175  /* Ok, we can do one word at a time.
176     Normally we do the low-numbered word first,
177     but if either operand is autodecrementing then we
178     do the high-numbered word first.
179
180     In either case, set up in LATEHALF the operands to use
181     for the high-numbered word and in some cases alter the
182     operands in OPERANDS to be suitable for the low-numbered word.  */
183
184  if (optype0 == REGOP)
185    latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
186  else if (optype0 == OFFSOP)
187    latehalf[0] = adj_offsettable_operand (operands[0], 4);
188  else
189    latehalf[0] = operands[0];
190
191  if (optype1 == REGOP)
192    latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
193  else if (optype1 == OFFSOP)
194    latehalf[1] = adj_offsettable_operand (operands[1], 4);
195  else if (optype1 == CNSTOP)
196    {
197      if (GET_CODE (operands[1]) == CONST_DOUBLE)
198        split_double (operands[1], &operands[1], &latehalf[1]);
199      else if (CONSTANT_P (operands[1]))
200        {
201          latehalf[1] = operands[1];
202          operands[1] = const0_rtx;
203        }
204    }
205  else
206    latehalf[1] = operands[1];
207
208  /* If insn is effectively movd N(sp),-(sp) then we will do the
209     high word first.  We should use the adjusted operand 1 (which is N+4(sp))
210     for the low word as well, to compensate for the first decrement of sp.  */
211  if (optype0 == PUSHOP
212      && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
213      && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
214    operands[1] = latehalf[1];
215
216  /* If one or both operands autodecrementing,
217     do the two words, high-numbered first.  */
218
219  /* Likewise,  the first move would clobber the source of the second one,
220     do them in the other order.  This happens only for registers;
221     such overlap can't happen in memory unless the user explicitly
222     sets it up, and that is an undefined circumstance.  */
223
224  if (optype0 == PUSHOP || optype1 == PUSHOP
225      || (optype0 == REGOP && optype1 == REGOP
226          && REGNO (operands[0]) == REGNO (latehalf[1])))
227    {
228      /* Make any unoffsettable addresses point at high-numbered word.  */
229      if (addreg0)
230        output_asm_insn ("addql %#4,%0", &addreg0);
231      if (addreg1)
232        output_asm_insn ("addql %#4,%0", &addreg1);
233
234      /* Do that word.  */
235      output_asm_insn (singlemove_string (latehalf), latehalf);
236
237      /* Undo the adds we just did.  */
238      if (addreg0)
239        output_asm_insn ("subql %#4,%0", &addreg0);
240      if (addreg1)
241        output_asm_insn ("subql %#4,%0", &addreg1);
242
243      /* Do low-numbered word.  */
244      return singlemove_string (operands);
245    }
246
247  /* Normal case: do the two words, low-numbered first.  */
248
249  output_asm_insn (singlemove_string (operands), operands);
250
251  /* Make any unoffsettable addresses point at high-numbered word.  */
252  if (addreg0)
253    output_asm_insn ("addql %#4,%0", &addreg0);
254  if (addreg1)
255    output_asm_insn ("addql %#4,%0", &addreg1);
256
257  /* Do that word.  */
258  output_asm_insn (singlemove_string (latehalf), latehalf);
259
260  /* Undo the adds we just did.  */
261  if (addreg0)
262    output_asm_insn ("subql %#4,%0", &addreg0);
263  if (addreg1)
264    output_asm_insn ("subql %#4,%0", &addreg1);
265
266  return "";
267}
268
269/* Return a REG that occurs in ADDR with coefficient 1.
270   ADDR can be effectively incremented by incrementing REG.  */
271
272static rtx
273find_addr_reg (addr)
274     rtx addr;
275{
276  while (GET_CODE (addr) == PLUS)
277    {
278      if (GET_CODE (XEXP (addr, 0)) == REG)
279        addr = XEXP (addr, 0);
280      else if (GET_CODE (XEXP (addr, 1)) == REG)
281        addr = XEXP (addr, 1);
282      else if (CONSTANT_P (XEXP (addr, 0)))
283        addr = XEXP (addr, 1);
284      else if (CONSTANT_P (XEXP (addr, 1)))
285        addr = XEXP (addr, 0);
286      else
287        abort ();
288    }
289  if (GET_CODE (addr) == REG)
290    return addr;
291  abort ();
292}
293
294int
295standard_SunFPA_constant_p (x)
296     rtx x;
297{
298  return( 0 );
299}
300
Note: See TracBrowser for help on using the repository browser.