entered into RCS
From-SVN: r28
This commit is contained in:
parent
acde64ae54
commit
8480102e8b
299
gcc/config/fx80/fx80.c
Normal file
299
gcc/config/fx80/fx80.c
Normal file
@ -0,0 +1,299 @@
|
||||
/* Subroutines for insn-output.c for Alliant FX computers.
|
||||
Copyright (C) 1989,1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU CC.
|
||||
|
||||
GNU CC is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
GNU CC is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU CC; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
|
||||
/* Some output-actions in alliant.md need these. */
|
||||
#include <stdio.h>
|
||||
#include "config.h"
|
||||
#include "rtl.h"
|
||||
#include "regs.h"
|
||||
#include "hard-reg-set.h"
|
||||
#include "real.h"
|
||||
#include "insn-config.h"
|
||||
#include "conditions.h"
|
||||
#include "insn-flags.h"
|
||||
#include "output.h"
|
||||
#include "insn-attr.h"
|
||||
|
||||
/* Index into this array by (register number >> 3) to find the
|
||||
smallest class which contains that register. */
|
||||
enum reg_class regno_reg_class[]
|
||||
= { DATA_REGS, ADDR_REGS, FP_REGS };
|
||||
|
||||
static rtx find_addr_reg ();
|
||||
|
||||
char *
|
||||
output_btst (operands, countop, dataop, insn, signpos)
|
||||
rtx *operands;
|
||||
rtx countop, dataop;
|
||||
rtx insn;
|
||||
int signpos;
|
||||
{
|
||||
operands[0] = countop;
|
||||
operands[1] = dataop;
|
||||
|
||||
if (GET_CODE (countop) == CONST_INT)
|
||||
{
|
||||
register int count = INTVAL (countop);
|
||||
/* If COUNT is bigger than size of storage unit in use,
|
||||
advance to the containing unit of same size. */
|
||||
if (count > signpos)
|
||||
{
|
||||
int offset = (count & ~signpos) / 8;
|
||||
count = count & signpos;
|
||||
operands[1] = dataop = adj_offsettable_operand (dataop, offset);
|
||||
}
|
||||
if (count == signpos)
|
||||
cc_status.flags = CC_NOT_POSITIVE | CC_Z_IN_NOT_N;
|
||||
else
|
||||
cc_status.flags = CC_NOT_NEGATIVE | CC_Z_IN_NOT_N;
|
||||
|
||||
/* These three statements used to use next_insns_test_no...
|
||||
but it appears that this should do the same job. */
|
||||
if (count == 31
|
||||
&& next_insn_tests_no_inequality (insn))
|
||||
return "tst%.l %1";
|
||||
if (count == 15
|
||||
&& next_insn_tests_no_inequality (insn))
|
||||
return "tst%.w %1";
|
||||
if (count == 7
|
||||
&& next_insn_tests_no_inequality (insn))
|
||||
return "tst%.b %1";
|
||||
|
||||
cc_status.flags = CC_NOT_NEGATIVE;
|
||||
}
|
||||
return "btst %0,%1";
|
||||
}
|
||||
|
||||
/* Return the best assembler insn template
|
||||
for moving operands[1] into operands[0] as a fullword. */
|
||||
|
||||
static char *
|
||||
singlemove_string (operands)
|
||||
rtx *operands;
|
||||
{
|
||||
if (operands[1] != const0_rtx)
|
||||
return "mov%.l %1,%0";
|
||||
if (! ADDRESS_REG_P (operands[0]))
|
||||
return "clr%.l %0";
|
||||
return "sub%.l %0,%0";
|
||||
}
|
||||
|
||||
/* Output assembler code to perform a doubleword move insn
|
||||
with operands OPERANDS. */
|
||||
|
||||
char *
|
||||
output_move_double (operands)
|
||||
rtx *operands;
|
||||
{
|
||||
enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
|
||||
rtx latehalf[2];
|
||||
rtx addreg0 = 0, addreg1 = 0;
|
||||
|
||||
/* First classify both operands. */
|
||||
|
||||
if (REG_P (operands[0]))
|
||||
optype0 = REGOP;
|
||||
else if (offsettable_memref_p (operands[0]))
|
||||
optype0 = OFFSOP;
|
||||
else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC)
|
||||
optype0 = POPOP;
|
||||
else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
|
||||
optype0 = PUSHOP;
|
||||
else if (GET_CODE (operands[0]) == MEM)
|
||||
optype0 = MEMOP;
|
||||
else
|
||||
optype0 = RNDOP;
|
||||
|
||||
if (REG_P (operands[1]))
|
||||
optype1 = REGOP;
|
||||
else if (CONSTANT_P (operands[1]))
|
||||
optype1 = CNSTOP;
|
||||
else if (offsettable_memref_p (operands[1]))
|
||||
optype1 = OFFSOP;
|
||||
else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC)
|
||||
optype1 = POPOP;
|
||||
else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
|
||||
optype1 = PUSHOP;
|
||||
else if (GET_CODE (operands[1]) == MEM)
|
||||
optype1 = MEMOP;
|
||||
else
|
||||
optype1 = RNDOP;
|
||||
|
||||
/* Check for the cases that the operand constraints are not
|
||||
supposed to allow to happen. Abort if we get one,
|
||||
because generating code for these cases is painful. */
|
||||
|
||||
if (optype0 == RNDOP || optype1 == RNDOP)
|
||||
abort ();
|
||||
|
||||
/* If one operand is decrementing and one is incrementing
|
||||
decrement the former register explicitly
|
||||
and change that operand into ordinary indexing. */
|
||||
|
||||
if (optype0 == PUSHOP && optype1 == POPOP)
|
||||
{
|
||||
operands[0] = XEXP (XEXP (operands[0], 0), 0);
|
||||
output_asm_insn ("subq%.l %#8,%0", operands);
|
||||
operands[0] = gen_rtx (MEM, DImode, operands[0]);
|
||||
optype0 = OFFSOP;
|
||||
}
|
||||
if (optype0 == POPOP && optype1 == PUSHOP)
|
||||
{
|
||||
operands[1] = XEXP (XEXP (operands[1], 0), 0);
|
||||
output_asm_insn ("subq%.l %#8,%1", operands);
|
||||
operands[1] = gen_rtx (MEM, DImode, operands[1]);
|
||||
optype1 = OFFSOP;
|
||||
}
|
||||
|
||||
/* If an operand is an unoffsettable memory ref, find a register
|
||||
we can increment temporarily to make it refer to the second word. */
|
||||
|
||||
if (optype0 == MEMOP)
|
||||
addreg0 = find_addr_reg (XEXP (operands[0], 0));
|
||||
|
||||
if (optype1 == MEMOP)
|
||||
addreg1 = find_addr_reg (XEXP (operands[1], 0));
|
||||
|
||||
/* Ok, we can do one word at a time.
|
||||
Normally we do the low-numbered word first,
|
||||
but if either operand is autodecrementing then we
|
||||
do the high-numbered word first.
|
||||
|
||||
In either case, set up in LATEHALF the operands to use
|
||||
for the high-numbered word and in some cases alter the
|
||||
operands in OPERANDS to be suitable for the low-numbered word. */
|
||||
|
||||
if (optype0 == REGOP)
|
||||
latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
|
||||
else if (optype0 == OFFSOP)
|
||||
latehalf[0] = adj_offsettable_operand (operands[0], 4);
|
||||
else
|
||||
latehalf[0] = operands[0];
|
||||
|
||||
if (optype1 == REGOP)
|
||||
latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
|
||||
else if (optype1 == OFFSOP)
|
||||
latehalf[1] = adj_offsettable_operand (operands[1], 4);
|
||||
else if (optype1 == CNSTOP)
|
||||
{
|
||||
if (GET_CODE (operands[1]) == CONST_DOUBLE)
|
||||
split_double (operands[1], &operands[1], &latehalf[1]);
|
||||
else if (CONSTANT_P (operands[1]))
|
||||
{
|
||||
latehalf[1] = operands[1];
|
||||
operands[1] = const0_rtx;
|
||||
}
|
||||
}
|
||||
else
|
||||
latehalf[1] = operands[1];
|
||||
|
||||
/* If insn is effectively movd N(sp),-(sp) then we will do the
|
||||
high word first. We should use the adjusted operand 1 (which is N+4(sp))
|
||||
for the low word as well, to compensate for the first decrement of sp. */
|
||||
if (optype0 == PUSHOP
|
||||
&& REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
|
||||
&& reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
|
||||
operands[1] = latehalf[1];
|
||||
|
||||
/* If one or both operands autodecrementing,
|
||||
do the two words, high-numbered first. */
|
||||
|
||||
/* Likewise, the first move would clobber the source of the second one,
|
||||
do them in the other order. This happens only for registers;
|
||||
such overlap can't happen in memory unless the user explicitly
|
||||
sets it up, and that is an undefined circumstance. */
|
||||
|
||||
if (optype0 == PUSHOP || optype1 == PUSHOP
|
||||
|| (optype0 == REGOP && optype1 == REGOP
|
||||
&& REGNO (operands[0]) == REGNO (latehalf[1])))
|
||||
{
|
||||
/* Make any unoffsettable addresses point at high-numbered word. */
|
||||
if (addreg0)
|
||||
output_asm_insn ("addql %#4,%0", &addreg0);
|
||||
if (addreg1)
|
||||
output_asm_insn ("addql %#4,%0", &addreg1);
|
||||
|
||||
/* Do that word. */
|
||||
output_asm_insn (singlemove_string (latehalf), latehalf);
|
||||
|
||||
/* Undo the adds we just did. */
|
||||
if (addreg0)
|
||||
output_asm_insn ("subql %#4,%0", &addreg0);
|
||||
if (addreg1)
|
||||
output_asm_insn ("subql %#4,%0", &addreg1);
|
||||
|
||||
/* Do low-numbered word. */
|
||||
return singlemove_string (operands);
|
||||
}
|
||||
|
||||
/* Normal case: do the two words, low-numbered first. */
|
||||
|
||||
output_asm_insn (singlemove_string (operands), operands);
|
||||
|
||||
/* Make any unoffsettable addresses point at high-numbered word. */
|
||||
if (addreg0)
|
||||
output_asm_insn ("addql %#4,%0", &addreg0);
|
||||
if (addreg1)
|
||||
output_asm_insn ("addql %#4,%0", &addreg1);
|
||||
|
||||
/* Do that word. */
|
||||
output_asm_insn (singlemove_string (latehalf), latehalf);
|
||||
|
||||
/* Undo the adds we just did. */
|
||||
if (addreg0)
|
||||
output_asm_insn ("subql %#4,%0", &addreg0);
|
||||
if (addreg1)
|
||||
output_asm_insn ("subql %#4,%0", &addreg1);
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
/* Return a REG that occurs in ADDR with coefficient 1.
|
||||
ADDR can be effectively incremented by incrementing REG. */
|
||||
|
||||
static rtx
|
||||
find_addr_reg (addr)
|
||||
rtx addr;
|
||||
{
|
||||
while (GET_CODE (addr) == PLUS)
|
||||
{
|
||||
if (GET_CODE (XEXP (addr, 0)) == REG)
|
||||
addr = XEXP (addr, 0);
|
||||
else if (GET_CODE (XEXP (addr, 1)) == REG)
|
||||
addr = XEXP (addr, 1);
|
||||
else if (CONSTANT_P (XEXP (addr, 0)))
|
||||
addr = XEXP (addr, 1);
|
||||
else if (CONSTANT_P (XEXP (addr, 1)))
|
||||
addr = XEXP (addr, 0);
|
||||
else
|
||||
abort ();
|
||||
}
|
||||
if (GET_CODE (addr) == REG)
|
||||
return addr;
|
||||
abort ();
|
||||
}
|
||||
|
||||
int
|
||||
standard_SunFPA_constant_p (x)
|
||||
rtx x;
|
||||
{
|
||||
return( 0 );
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user