Commit 776749c5 by Mark Mitchell Committed by Mark Mitchell

genix.h: Remove.

	* config/ns32k/genix.h: Remove.
	* config/ns32k/x-genix: Likewise.
	* config/ns32k/xm-genix.h: Likewise.
	* config/fx80: Remove all filee in directory.
	* config/pyr: Likewise.
	* config/tahoe: Likewise.
	* config/gmicro: Likewise.
	* config/spur: Likewise.
	* configure.in: Remove configury bits for above targets.
	* configure: Regenerated.

From-SVN: r36691
parent a7b4171a
2000-10-01 Mark Mitchell <mark@codesourcery.com> 2000-10-01 Mark Mitchell <mark@codesourcery.com>
* config/ns32k/genix.h: Remove.
* config/ns32k/x-genix: Likewise.
* config/ns32k/xm-genix.h: Likewise.
* config/fx80: Remove all filee in directory.
* config/pyr: Likewise.
* config/tahoe: Likewise.
* config/gmicro: Likewise.
* config/spur: Likewise.
* configure.in: Remove configury bits for above targets.
* configure: Regenerated.
* configure.in: Don't configure chill by default. * configure.in: Don't configure chill by default.
* configure: Regenerated. * configure: Regenerated.
......
/* Subroutines for insn-output.c for Alliant FX computers.
Copyright (C) 1989, 1991, 1997, 1998, 1999 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, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* Some output-actions in alliant.md need these. */
#include "config.h"
#include "system.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 "function.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 );
}
/* Definitions of target machine for GNU compiler. Alliant FX version.
Copyright (C) 1989, 1993, 1994, 1995, 1996, 1998, 1999, 2000
Free Software Foundation, Inc.
Adapted from m68k.h by Paul Petersen (petersen@uicsrd.csrd.uiuc.edu)
and Joe Weening (weening@gang-of-four.stanford.edu).
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, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* This file is based on m68k.h, simplified by removing support for
the Sun FPA and other things not applicable to the Alliant. Some
remnants of these features remain. */
/* Names to predefine in the preprocessor for this target machine. */
#define CPP_PREDEFINES "-Dmc68000 -Dalliant -Dunix -Asystem(unix) -Acpu(m68k) -Amachine(m68k)"
/* Print subsidiary information on the compiler version in use. */
#define TARGET_VERSION fprintf (stderr, " (Alliant)");
/* Run-time compilation parameters selecting different hardware
subsets. The Alliant IP is an mc68020. (Older mc68010-based IPs
are no longer supported.) The Alliant CE is 68020-compatible, and
also has floating point, vector and concurrency instructions.
Although the IP doesn't have floating point, it emulates it in the
operating system. Using this generally is faster than running code
compiled with -msoft-float, because the soft-float code still uses
(simulated) FP registers and ends up emulating several fmove{s,d}
instructions per call. So I don't recommend using soft-float for
any Alliant code. -- JSW
*/
extern int target_flags;
/* Macros used in the machine description to test the flags. */
/* Compile for a 68020 (not a 68000 or 68010). */
#define TARGET_68020 (target_flags & 1)
/* Compile CE insns for floating point (not library calls). */
#define TARGET_CE (target_flags & 2)
/* Compile using 68020 bitfield insns. */
#define TARGET_BITFIELD (target_flags & 4)
/* Compile with 16-bit `int'. */
#define TARGET_SHORT (target_flags & 040)
/* Default 3 means compile 68020 and CE instructions. We don't use
bitfield instructions because there appears to be a bug in the
implementation of bfins on the CE. */
#define TARGET_DEFAULT 3
/* Define __HAVE_CE__ in preprocessor according to the -m flags.
This will control the use of inline FP insns in certain macros.
Also inform the program which CPU this is for. */
#if TARGET_DEFAULT & 02
/* -mce is the default */
#define CPP_SPEC \
"%{!msoft-float:-D__HAVE_CE__ }\
%{m68000:-Dmc68010}%{mc68000:-Dmc68010}%{!mc68000:%{!m68000:-Dmc68020}}"
#else
/* -msoft-float is the default */
#define CPP_SPEC \
"%{mce:-D__HAVE_CE__ }\
%{m68000:-Dmc68010}%{mc68000:-Dmc68010}%{!mc68000:%{!m68000:-Dmc68020}}"
#endif
/* Link with libg.a when debugging, for dbx's sake. */
#define LIB_SPEC "%{g:-lg} %{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p} "
/* Make the linker remove temporary labels, since the Alliant assembler
doesn't. */
#define LINK_SPEC "-X"
/* Every structure or union's size must be a multiple of 2 bytes. */
#define STRUCTURE_SIZE_BOUNDARY 16
/* This is BSD, so it wants DBX format. */
#define DBX_DEBUGGING_INFO
/* Macro to define tables used to set the flags.
This is a list in braces of pairs in braces,
each pair being { "NAME", VALUE }
where VALUE is the bits to set or minus the bits to clear.
An empty string NAME is used to identify the default VALUE. */
#define TARGET_SWITCHES \
{ { "68020", 5, N_("Generate code for a mc68020")}, \
{ "c68020", 5, N_("Generate code for a mc68020")}, \
{ "bitfield", 4, N_("Use bitfield instructions")}, \
{ "68000", -7, N_("Generate code for a mc68000")}, \
{ "c68000", -7, N_("Generate code for a mc68000")}, \
{ "soft-float", -2, N_("Generate software FP code")}, \
{ "nobitfield", -4, N_("Do not generate bitfield insns")}, \
{ "short", 040, N_("Use 16bit integers")}, \
{ "noshort", -040, N_("Use 32bit integers")}, \
{ "", TARGET_DEFAULT, NULL}}
/* target machine storage layout */
/* Define this if most significant bit is lowest numbered
in instructions that operate on numbered bit-fields.
This is true for 68020 insns such as bfins and bfexts.
We make it true always by avoiding using the single-bit insns
except in special cases with constant bit numbers. */
#define BITS_BIG_ENDIAN 1
/* Define this if most significant byte of a word is the lowest numbered. */
/* That is true on the 68000. */
#define BYTES_BIG_ENDIAN 1
/* Define this if most significant word of a multiword number is the lowest
numbered. */
/* For 68000 we can decide arbitrarily
since there are no machine instructions for them. */
#define WORDS_BIG_ENDIAN 0
/* number of bits in an addressable storage unit */
#define BITS_PER_UNIT 8
/* Width in bits of a "word", which is the contents of a machine register.
Note that this is not necessarily the width of data type `int';
if using 16-bit ints on a 68000, this would still be 32.
But on a machine with 16-bit registers, this would be 16. */
#define BITS_PER_WORD 32
/* Width of a word, in units (bytes). */
#define UNITS_PER_WORD 4
/* Width in bits of a pointer.
See also the macro `Pmode' defined below. */
#define POINTER_SIZE 32
/* Allocation boundary (in *bits*) for storing arguments in argument list. */
#define PARM_BOUNDARY (TARGET_SHORT ? 16 : 32)
/* Boundary (in *bits*) on which stack pointer should be aligned. */
#define STACK_BOUNDARY 16
/* Allocation boundary (in *bits*) for the code of a function. */
#define FUNCTION_BOUNDARY 16
/* Alignment of field after `int : 0' in a structure. */
#define EMPTY_FIELD_BOUNDARY 16
/* No data type wants to be aligned rounder than this. */
#define BIGGEST_ALIGNMENT 16
/* Set this non-zero if move instructions will actually fail to work
when given unaligned data. */
#define STRICT_ALIGNMENT 1
/* Define number of bits in most basic integer type.
(If undefined, default is BITS_PER_WORD). */
#define INT_TYPE_SIZE (TARGET_SHORT ? 16 : 32)
/* Define these to avoid dependence on meaning of `int'. */
#define WCHAR_TYPE "long int"
#define WCHAR_TYPE_SIZE 32
/* Standard register usage. */
/* Number of actual hardware registers.
The hardware registers are assigned numbers for the compiler
from 0 to just below FIRST_PSEUDO_REGISTER.
All registers that the compiler knows about must be given numbers,
even those that are not normally considered general registers.
For the Alliant, we give the data registers numbers 0-7,
the address registers numbers 010-017,
and the floating point registers numbers 020-027. */
#define FIRST_PSEUDO_REGISTER 24
/* 1 for registers that have pervasive standard uses
and are not available for the register allocator.
On the Alliant, these are a0 (argument pointer),
a6 (frame pointer) and a7 (stack pointer). */
#define FIXED_REGISTERS \
{0, 0, 0, 0, 0, 0, 0, 0, \
1, 0, 0, 0, 0, 0, 1, 1, \
0, 0, 0, 0, 0, 0, 0, 0 }
/* 1 for registers not available across function calls.
These must include the FIXED_REGISTERS and also any
registers that can be used without being saved.
The latter must include the registers where values are returned
and the register where structure-value addresses are passed.
Aside from that, you can include as many other registers as you like.
The Alliant calling sequence allows a function to use any register,
so we include them all here. */
#define CALL_USED_REGISTERS \
{1, 1, 1, 1, 1, 1, 1, 1, \
1, 1, 1, 1, 1, 1, 1, 1, \
1, 1, 1, 1, 1, 1, 1, 1 }
/* Return number of consecutive hard regs needed starting at reg REGNO
to hold something of mode MODE.
This is ordinarily the length in words of a value of mode MODE
but can be less for certain modes in special long registers.
On the Alliant, ordinary registers hold 32 bits worth;
for the FP registers, a single register is always enough for
any floating-point value. */
#define HARD_REGNO_NREGS(REGNO, MODE) \
((REGNO) >= 16 ? GET_MODE_NUNITS (MODE) \
: ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD))
/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE.
On the Alliant, the cpu registers can hold any mode but the FP registers
can hold only floating point. */
#define HARD_REGNO_MODE_OK(REGNO, MODE) \
((REGNO) < 16 || GET_MODE_CLASS (MODE) == MODE_FLOAT \
|| GET_MODE_CLASS (MODE) == MODE_COMPLEX_FLOAT)
/* Value is 1 if it is a good idea to tie two pseudo registers
when one has mode MODE1 and one has mode MODE2.
If HARD_REGNO_MODE_OK could produce different values for MODE1 and MODE2,
for any hard reg, then this must be 0 for correct output. */
#define MODES_TIEABLE_P(MODE1, MODE2) \
(((MODE1) == SFmode || (MODE1) == DFmode \
|| (MODE1) == SCmode || (MODE1) == DCmode) \
== ((MODE2) == SFmode || (MODE2) == DFmode \
|| (MODE2) == SCmode || (MODE2) == DCmode))
/* Specify the registers used for certain standard purposes.
The values of these macros are register numbers. */
/* m68000 pc isn't overloaded on a register. */
/* #define PC_REGNUM */
/* Register to use for pushing function arguments. */
#define STACK_POINTER_REGNUM 15
/* Base register for access to local variables of the function. */
#define FRAME_POINTER_REGNUM 14
/* Value should be nonzero if functions must have frame pointers.
Zero means the frame pointer need not be set up (and parms
may be accessed via the stack pointer) in functions that seem suitable.
This is computed in `reload', in reload1.c. */
/* Set for now on Alliant until we find a way to make this work with
their calling sequence. */
#define FRAME_POINTER_REQUIRED 1
/* Base register for access to arguments of the function. */
#define ARG_POINTER_REGNUM 8
/* Register in which static-chain is passed to a function. */
#define STATIC_CHAIN_REGNUM 10
/* Register in which address to store a structure value
is passed to a function. */
#define STRUCT_VALUE_REGNUM 9
/* Define the classes of registers for register constraints in the
machine description. Also define ranges of constants.
One of the classes must always be named ALL_REGS and include all hard regs.
If there is more than one class, another class must be named NO_REGS
and contain no registers.
The name GENERAL_REGS must be the name of a class (or an alias for
another name such as ALL_REGS). This is the class of registers
that is allowed by "g" or "r" in a register constraint.
Also, registers outside this class are allocated only when
instructions express preferences for them.
The classes must be numbered in nondecreasing order; that is,
a larger-numbered class must never be contained completely
in a smaller-numbered class.
For any two classes, it is very desirable that there be another
class that represents their union. */
/* The Alliant has three kinds of registers, so eight classes would be
a complete set. One of them is not needed. */
enum reg_class { NO_REGS, FP_REGS, DATA_REGS, DATA_OR_FP_REGS,
ADDR_REGS, GENERAL_REGS, ALL_REGS, LIM_REG_CLASSES };
#define N_REG_CLASSES (int) LIM_REG_CLASSES
/* Give names of register classes as strings for dump file. */
#define REG_CLASS_NAMES \
{ "NO_REGS", "FP_REGS", "DATA_REGS", "DATA_OR_FP_REGS", \
"ADDR_REGS", "GENERAL_REGS", "ALL_REGS" }
/* Define which registers fit in which classes.
This is an initializer for a vector of HARD_REG_SET
of length N_REG_CLASSES. */
#define REG_CLASS_CONTENTS \
{ \
0, /* NO_REGS */ \
0x00ff0000, /* FP_REGS */ \
0x000000ff, /* DATA_REGS */ \
0x00ff00ff, /* DATA_OR_FP_REGS */ \
0x0000ff00, /* ADDR_REGS */ \
0x0000ffff, /* GENERAL_REGS */ \
0x00ffffff /* ALL_REGS */ \
}
/* The same information, inverted:
Return the class number of the smallest class containing
reg number REGNO. This could be a conditional expression
or could index an array. */
extern enum reg_class regno_reg_class[];
#define REGNO_REG_CLASS(REGNO) (regno_reg_class[(REGNO)>>3])
/* The class value for index registers, and the one for base regs. */
#define INDEX_REG_CLASS GENERAL_REGS
#define BASE_REG_CLASS ADDR_REGS
/* Get reg_class from a letter such as appears in the machine description. */
#define REG_CLASS_FROM_LETTER(C) \
((C) == 'a' ? ADDR_REGS : \
((C) == 'd' ? DATA_REGS : \
((C) == 'f' ? FP_REGS : \
NO_REGS)))
/* The letters I, J, K, L and M in a register constraint string
can be used to stand for particular ranges of immediate operands.
This macro defines what the ranges are.
C is the letter, and VALUE is a constant value.
Return 1 if VALUE is in the range specified by C.
For the 68000, `I' is used for the range 1 to 8
allowed as immediate shift counts and in addq.
`J' is used for the range of signed numbers that fit in 16 bits.
`K' is for numbers that moveq can't handle.
`L' is for range -8 to -1, range of values that can be added with subq. */
#define CONST_OK_FOR_LETTER_P(VALUE, C) \
((C) == 'I' ? (VALUE) > 0 && (VALUE) <= 8 : \
(C) == 'J' ? (VALUE) >= -0x8000 && (VALUE) <= 0x7FFF : \
(C) == 'K' ? (VALUE) < -0x80 || (VALUE) >= 0x80 : \
(C) == 'L' ? (VALUE) < 0 && (VALUE) >= -8 : 0)
#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) 0
/* Given an rtx X being reloaded into a reg required to be
in class CLASS, return the class of reg to actually use.
In general this is just CLASS; but on some machines
in some cases it is preferable to use a more restrictive class.
On the 68000 series, use a data reg if possible when the
value is a constant in the range where moveq could be used
and we ensure that QImodes are reloaded into data regs. */
#define PREFERRED_RELOAD_CLASS(X,CLASS) \
((GET_CODE (X) == CONST_INT \
&& (unsigned) (INTVAL (X) + 0x80) < 0x100 \
&& (CLASS) != ADDR_REGS) \
? DATA_REGS \
: GET_MODE (X) == QImode \
? DATA_REGS \
: (CLASS))
/* Return the maximum number of consecutive registers
needed to represent mode MODE in a register of class CLASS. */
/* On the 68000, this is the size of MODE in words,
except in the FP regs, where a single reg is always enough. */
#define CLASS_MAX_NREGS(CLASS, MODE) \
((CLASS) == FP_REGS ? 1 \
: ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD))
/* Moves between fp regs and other regs are two insns. */
#define REGISTER_MOVE_COST(CLASS1, CLASS2) \
((((CLASS1) == FP_REGS && (CLASS2) != FP_REGS) \
|| ((CLASS2) == FP_REGS && (CLASS1) != FP_REGS)) \
? 4 : 2)
/* Stack layout; function entry, exit and calling. */
/* Define this if pushing a word on the stack
makes the stack pointer a smaller address. */
#define STACK_GROWS_DOWNWARD
/* Define this if the nominal address of the stack frame
is at the high-address end of the local variables;
that is, each additional local variable allocated
goes at a more negative offset in the frame. */
#define FRAME_GROWS_DOWNWARD
/* The Alliant uses -fcaller-saves by default. */
#define DEFAULT_CALLER_SAVES
/* Offset within stack frame to start allocating local variables at.
If FRAME_GROWS_DOWNWARD, this is the offset to the END of the
first local allocated. Otherwise, it is the offset to the BEGINNING
of the first local allocated. */
#define STARTING_FRAME_OFFSET -4
/* If we generate an insn to push BYTES bytes,
this says how many the stack pointer really advances by.
On the 68000, sp@- in a byte insn really pushes a word. */
#define PUSH_ROUNDING(BYTES) (((BYTES) + 1) & ~1)
/* Offset of first parameter from the argument pointer register value. */
#define FIRST_PARM_OFFSET(FNDECL) 0
/* Value is the number of bytes of arguments automatically
popped when returning from a subroutine call.
FUNDECL is the declaration node of the function (as a tree),
FUNTYPE is the data type of the function (as a tree),
or for a library call it is an identifier node for the subroutine name.
SIZE is the number of bytes of arguments passed on the stack.
On the Alliant we define this as SIZE and make the calling sequence
(in alliant.md) pop the args. This wouldn't be necessary if we
could add to the pending stack adjustment the size of the argument
descriptors that are pushed after the arguments. */
#define RETURN_POPS_ARGS(FUNDECL,FUNTYPE,SIZE) (SIZE)
/* Define how to find the value returned by a function.
VALTYPE is the data type of the value (as a tree).
If the precise function being called is known, FUNC is its FUNCTION_DECL;
otherwise, FUNC is 0. */
/* On the Alliant the return value is in FP0 if real, else D0. */
#define FUNCTION_VALUE(VALTYPE, FUNC) \
(TREE_CODE (VALTYPE) == REAL_TYPE \
? gen_rtx_REG (TYPE_MODE (VALTYPE), 16) \
: gen_rtx_REG (TYPE_MODE (VALTYPE), 0))
/* Define how to find the value returned by a library function
assuming the value has mode MODE. */
/* On the Alliant the return value is in FP0 if real, else D0. The
Alliant library functions for floating-point emulation return their
values both in FP0 and in D0/D1. But since not all libgcc functions
return the results of these directly, we cannot assume that D0/D1
contain the values we expect on return from a libgcc function. */
#define LIBCALL_VALUE(MODE) \
(((MODE) == DFmode || (MODE) == SFmode) \
? gen_rtx_REG (MODE, 16) \
: gen_rtx_REG (MODE, 0))
/* 1 if N is a possible register number for a function value.
On the Alliant, D0 and FP0 are the only registers thus used.
(No need to mention D1 when used as a pair with D0.) */
#define FUNCTION_VALUE_REGNO_P(N) (((N) & ~16) == 0)
/* Define this if PCC uses the nonreentrant convention for returning
structure and union values. */
#define PCC_STATIC_STRUCT_RETURN
/* 1 if N is a possible register number for function argument passing.
On the Alliant, no registers are used in this way. */
#define FUNCTION_ARG_REGNO_P(N) 0
/* Define a data type for recording info about an argument list
during the scan of that argument list. This data type should
hold all necessary information about the function itself
and about the args processed so far, enough to enable macros
such as FUNCTION_ARG to determine where the next arg should go.
On the Alliant, this is a single integer, which is a number of bytes
of arguments scanned so far. */
#define CUMULATIVE_ARGS int
/* Initialize a variable CUM of type CUMULATIVE_ARGS
for a call to a function whose data type is FNTYPE.
For a library call, FNTYPE is 0.
On the Alliant, the offset starts at 0. */
#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE,LIBNAME,INDIRECT) \
((CUM) = 0)
/* Update the data in CUM to advance over an argument
of mode MODE and data type TYPE.
(TYPE is null for libcalls where that information may not be available.) */
#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \
((CUM) += ((MODE) != BLKmode \
? (GET_MODE_SIZE (MODE) + 3) & ~3 \
: (int_size_in_bytes (TYPE) + 3) & ~3))
/* Define where to put the arguments to a function.
Value is zero to push the argument on the stack,
or a hard register in which to store the argument.
MODE is the argument's machine mode.
TYPE is the data type of the argument (as a tree).
This is null for libcalls where that information may
not be available.
CUM is a variable of type CUMULATIVE_ARGS which gives info about
the preceding args and about the function being called.
NAMED is nonzero if this argument is a named parameter
(otherwise it is an extra parameter matching an ellipsis). */
/* On the Alliant all args are pushed. */
#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) 0
/* For an arg passed partly in registers and partly in memory,
this is the number of registers used.
For args passed entirely in registers or entirely in memory, zero. */
#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) 0
/* This macro generates the assembly code for function entry.
FILE is a stdio stream to output the code to.
SIZE is an int: how many units of temporary storage to allocate.
Refer to the array `regs_ever_live' to determine which registers
to save; `regs_ever_live[I]' is nonzero if register number I
is ever used in the function. This macro is responsible for
knowing which registers should not be saved even if used.
The Alliant uses caller-saves, so this macro is very simple. */
#define FUNCTION_PROLOGUE(FILE, SIZE) \
{ int fsize = ((SIZE) - STARTING_FRAME_OFFSET + 3) & -4; \
if (frame_pointer_needed) \
{ \
if (fsize < 0x8000) \
fprintf(FILE,"\tlinkw a6,#%d\n", -fsize); \
else if (TARGET_68020) \
fprintf(FILE,"\tlinkl a6,#%d\n", -fsize); \
else \
fprintf(FILE,"\tlinkw a6,#0\n\tsubl #%d,sp\n", fsize); \
fprintf(FILE, "\tmovl a0,a6@(-4)\n" ); }}
/* Output assembler code to FILE to increment profiler label # LABELNO
for profiling a function entry. */
#define FUNCTION_PROFILER(FILE, LABELNO) \
fprintf (FILE, "\tjbsr __mcount_\n")
/* EXIT_IGNORE_STACK should be nonzero if, when returning from a function,
the stack pointer does not matter. The value is tested only in
functions that have frame pointers.
No definition is equivalent to always zero. */
#define EXIT_IGNORE_STACK 1
/* This macro generates the assembly code for function exit,
on machines that need it. If FUNCTION_EPILOGUE is not defined
then individual return instructions are generated for each
return statement. Args are same as for FUNCTION_PROLOGUE.
The function epilogue should not depend on the current stack pointer!
It should use the frame pointer only. This is mandatory because
of alloca; we also take advantage of it to omit stack adjustments
before returning. */
#define FUNCTION_EPILOGUE(FILE, SIZE) \
{ if (frame_pointer_needed) \
fprintf (FILE, "\tunlk a6\n"); \
fprintf (FILE, "\trts\n"); }
/* Store in the variable DEPTH the initial difference between the
frame pointer reg contents and the stack pointer reg contents,
as of the start of the function body. This depends on the layout
of the fixed parts of the stack frame and on how registers are saved. */
#define INITIAL_FRAME_POINTER_OFFSET(DEPTH) \
{ \
int regno; \
int offset = -4; \
for (regno = 16; regno < FIRST_PSEUDO_REGISTER; regno++) \
if (regs_ever_live[regno] && ! call_used_regs[regno]) \
offset += 12; \
for (regno = 0; regno < 16; regno++) \
if (regs_ever_live[regno] && ! call_used_regs[regno]) \
offset += 4; \
(DEPTH) = offset - ((get_frame_size () + 3) & -4); \
}
/* Addressing modes, and classification of registers for them. */
#define HAVE_POST_INCREMENT 1
/* #define HAVE_POST_DECREMENT 0 */
#define HAVE_PRE_DECREMENT 1
/* #define HAVE_PRE_INCREMENT 0 */
/* Macros to check register numbers against specific register classes. */
/* These assume that REGNO is a hard or pseudo reg number.
They give nonzero only if REGNO is a hard reg of the suitable class
or a pseudo reg currently allocated to a suitable hard reg.
Since they use reg_renumber, they are safe only once reg_renumber
has been allocated, which happens in local-alloc.c. */
#define REGNO_OK_FOR_INDEX_P(REGNO) \
((REGNO) < 16 || (unsigned) reg_renumber[REGNO] < 16)
#define REGNO_OK_FOR_BASE_P(REGNO) \
(((REGNO) ^ 010) < 8 || (unsigned) (reg_renumber[REGNO] ^ 010) < 8)
#define REGNO_OK_FOR_DATA_P(REGNO) \
((REGNO) < 8 || (unsigned) reg_renumber[REGNO] < 8)
#define REGNO_OK_FOR_FP_P(REGNO) \
(((REGNO) ^ 020) < 8 || (unsigned) (reg_renumber[REGNO] ^ 020) < 8)
/* Now macros that check whether X is a register and also,
strictly, whether it is in a specified class.
These macros are specific to the 68000, and may be used only
in code for printing assembler insns and in conditions for
define_optimization. */
/* 1 if X is a data register. */
#define DATA_REG_P(X) (REG_P (X) && REGNO_OK_FOR_DATA_P (REGNO (X)))
/* 1 if X is an fp register. */
#define FP_REG_P(X) (REG_P (X) && REGNO_OK_FOR_FP_P (REGNO (X)))
/* 1 if X is an address register */
#define ADDRESS_REG_P(X) (REG_P (X) && REGNO_OK_FOR_BASE_P (REGNO (X)))
/* Maximum number of registers that can appear in a valid memory address. */
#define MAX_REGS_PER_ADDRESS 2
/* Recognize any constant value that is a valid address. */
#define CONSTANT_ADDRESS_P(X) \
(GET_CODE (X) == LABEL_REF || GET_CODE (X) == SYMBOL_REF \
|| GET_CODE (X) == CONST_INT || GET_CODE (X) == CONST \
|| GET_CODE (X) == HIGH)
/* Nonzero if the constant value X is a legitimate general operand.
It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE. */
/* Alliant FP instructions don't take immediate operands, so this
forces them into memory. */
#define LEGITIMATE_CONSTANT_P(X) (GET_CODE (X) != CONST_DOUBLE)
/* The macros REG_OK_FOR..._P assume that the arg is a REG rtx
and check its validity for a certain class.
We have two alternate definitions for each of them.
The usual definition accepts all pseudo regs; the other rejects
them unless they have been allocated suitable hard regs.
The symbol REG_OK_STRICT causes the latter definition to be used.
Most source files want to accept pseudo regs in the hope that
they will get allocated to the class that the insn wants them to be in.
Source files for reload pass need to be strict.
After reload, it makes no difference, since pseudo regs have
been eliminated by then. */
#ifndef REG_OK_STRICT
/* Nonzero if X is a hard reg that can be used as an index
or if it is a pseudo reg. */
#define REG_OK_FOR_INDEX_P(X) ((REGNO (X) ^ 020) >= 8)
/* Nonzero if X is a hard reg that can be used as a base reg
or if it is a pseudo reg. */
#define REG_OK_FOR_BASE_P(X) ((REGNO (X) & ~027) != 0)
#else
/* Nonzero if X is a hard reg that can be used as an index. */
#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P (REGNO (X))
/* Nonzero if X is a hard reg that can be used as a base reg. */
#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P (REGNO (X))
#endif
/* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression
that is a valid memory address for an instruction.
The MODE argument is the machine mode for the MEM expression
that wants to use this address.
The other macros defined here are used only in GO_IF_LEGITIMATE_ADDRESS. */
#define INDIRECTABLE_1_ADDRESS_P(X) \
(CONSTANT_ADDRESS_P (X) \
|| (GET_CODE (X) == REG && REG_OK_FOR_BASE_P (X)) \
|| ((GET_CODE (X) == PRE_DEC || GET_CODE (X) == POST_INC) \
&& REG_P (XEXP (X, 0)) \
&& REG_OK_FOR_BASE_P (XEXP (X, 0))) \
|| (GET_CODE (X) == PLUS \
&& REG_P (XEXP (X, 0)) && REG_OK_FOR_BASE_P (XEXP (X, 0)) \
&& GET_CODE (XEXP (X, 1)) == CONST_INT \
&& ((unsigned) INTVAL (XEXP (X, 1)) + 0x8000) < 0x10000))
#define GO_IF_NONINDEXED_ADDRESS(X, ADDR) \
{ if (INDIRECTABLE_1_ADDRESS_P (X)) goto ADDR; }
#define GO_IF_INDEXABLE_BASE(X, ADDR) \
{ if (GET_CODE (X) == LABEL_REF) goto ADDR; \
if (GET_CODE (X) == REG && REG_OK_FOR_BASE_P (X)) goto ADDR; }
#define GO_IF_INDEXING(X, ADDR) \
{ if (GET_CODE (X) == PLUS && LEGITIMATE_INDEX_P (XEXP (X, 0))) \
{ GO_IF_INDEXABLE_BASE (XEXP (X, 1), ADDR); } \
if (GET_CODE (X) == PLUS && LEGITIMATE_INDEX_P (XEXP (X, 1))) \
{ GO_IF_INDEXABLE_BASE (XEXP (X, 0), ADDR); } }
#define GO_IF_INDEXED_ADDRESS(X, ADDR) \
{ GO_IF_INDEXING (X, ADDR); \
if (GET_CODE (X) == PLUS) \
{ if (GET_CODE (XEXP (X, 1)) == CONST_INT \
&& (unsigned) INTVAL (XEXP (X, 1)) + 0x80 < 0x100) \
{ rtx go_temp = XEXP (X, 0); GO_IF_INDEXING (go_temp, ADDR); } \
if (GET_CODE (XEXP (X, 0)) == CONST_INT \
&& (unsigned) INTVAL (XEXP (X, 0)) + 0x80 < 0x100) \
{ rtx go_temp = XEXP (X, 1); GO_IF_INDEXING (go_temp, ADDR); } } }
#define LEGITIMATE_INDEX_REG_P(X) \
((GET_CODE (X) == REG && REG_OK_FOR_INDEX_P (X)) \
|| (GET_CODE (X) == SIGN_EXTEND \
&& GET_CODE (XEXP (X, 0)) == REG \
&& GET_MODE (XEXP (X, 0)) == HImode \
&& REG_OK_FOR_INDEX_P (XEXP (X, 0))))
#define LEGITIMATE_INDEX_P(X) \
(LEGITIMATE_INDEX_REG_P (X) \
|| (TARGET_68020 && GET_CODE (X) == MULT \
&& LEGITIMATE_INDEX_REG_P (XEXP (X, 0)) \
&& GET_CODE (XEXP (X, 1)) == CONST_INT \
&& (INTVAL (XEXP (X, 1)) == 2 \
|| INTVAL (XEXP (X, 1)) == 4 \
|| INTVAL (XEXP (X, 1)) == 8)))
#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \
{ GO_IF_NONINDEXED_ADDRESS (X, ADDR); \
GO_IF_INDEXED_ADDRESS (X, ADDR); }
/* Try machine-dependent ways of modifying an illegitimate address
to be legitimate. If we find one, return the new, valid address.
This macro is used in only one place: `memory_address' in explow.c.
OLDX is the address as it was before break_out_memory_refs was called.
In some cases it is useful to look at this to decide what needs to be done.
MODE and WIN are passed so that this macro can use
GO_IF_LEGITIMATE_ADDRESS.
It is always safe for this macro to do nothing. It exists to recognize
opportunities to optimize the output.
For the 68000, we handle X+REG by loading X into a register R and
using R+REG. R will go in an address reg and indexing will be used.
However, if REG is a broken-out memory address or multiplication,
nothing needs to be done because REG can certainly go in an address reg. */
#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN) \
{ register int ch = (X) != (OLDX); \
if (GET_CODE (X) == PLUS) \
{ if (GET_CODE (XEXP (X, 0)) == MULT) \
ch = 1, XEXP (X, 0) = force_operand (XEXP (X, 0), 0); \
if (GET_CODE (XEXP (X, 1)) == MULT) \
ch = 1, XEXP (X, 1) = force_operand (XEXP (X, 1), 0); \
if (ch && GET_CODE (XEXP (X, 1)) == REG \
&& GET_CODE (XEXP (X, 0)) == REG) \
goto WIN; \
if (ch) { GO_IF_LEGITIMATE_ADDRESS (MODE, X, WIN); } \
if (GET_CODE (XEXP (X, 0)) == REG \
|| (GET_CODE (XEXP (X, 0)) == SIGN_EXTEND \
&& GET_CODE (XEXP (XEXP (X, 0), 0)) == REG \
&& GET_MODE (XEXP (XEXP (X, 0), 0)) == HImode)) \
{ register rtx temp = gen_reg_rtx (Pmode); \
register rtx val = force_operand (XEXP (X, 1), 0); \
emit_move_insn (temp, val); \
XEXP (X, 1) = temp; \
goto WIN; } \
else if (GET_CODE (XEXP (X, 1)) == REG \
|| (GET_CODE (XEXP (X, 1)) == SIGN_EXTEND \
&& GET_CODE (XEXP (XEXP (X, 1), 0)) == REG \
&& GET_MODE (XEXP (XEXP (X, 1), 0)) == HImode)) \
{ register rtx temp = gen_reg_rtx (Pmode); \
register rtx val = force_operand (XEXP (X, 0), 0); \
emit_move_insn (temp, val); \
XEXP (X, 0) = temp; \
goto WIN; }}}
/* Go to LABEL if ADDR (a legitimate address expression)
has an effect that depends on the machine mode it is used for.
On the 68000, only predecrement and postincrement address depend thus
(the amount of decrement or increment being the length of the operand). */
#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL) \
if (GET_CODE (ADDR) == POST_INC || GET_CODE (ADDR) == PRE_DEC) goto LABEL
/* Specify the machine mode that this machine uses
for the index in the tablejump instruction. */
#define CASE_VECTOR_MODE HImode
/* Define as C expression which evaluates to nonzero if the tablejump
instruction expects the table to contain offsets from the address of the
table.
Do not define this if the table should contain absolute addresses. */
#define CASE_VECTOR_PC_RELATIVE 1
/* Specify the tree operation to be used to convert reals to integers. */
#define IMPLICIT_FIX_EXPR FIX_ROUND_EXPR
/* This is the kind of divide that is easiest to do in the general case. */
#define EASY_DIV_EXPR TRUNC_DIV_EXPR
/* Define this as 1 if `char' should by default be signed; else as 0. */
#define DEFAULT_SIGNED_CHAR 1
/* Max number of bytes we can move from memory to memory
in one reasonably fast instruction. */
#define MOVE_MAX 4
/* Define this if zero-extension is slow (more than one real instruction). */
#define SLOW_ZERO_EXTEND
/* Nonzero if access to memory by bytes is slow and undesirable. */
#define SLOW_BYTE_ACCESS 0
/* Define this to be nonzero if shift instructions ignore all but the low-order
few bits. */
#define SHIFT_COUNT_TRUNCATED 1
/* Value is 1 if truncating an integer of INPREC bits to OUTPREC bits
is done just by pretending it is already truncated. */
#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1
/* We assume that the store-condition-codes instructions store 0 for false
and some other value for true. This is the value stored for true. */
#define STORE_FLAG_VALUE (-1)
/* When a prototype says `char' or `short', really pass an `int'. */
#define PROMOTE_PROTOTYPES 1
/* Specify the machine mode that pointers have.
After generation of rtl, the compiler makes no further distinction
between pointers and any other objects of this machine mode. */
#define Pmode SImode
/* A function address in a call instruction
is a byte address (for indexing purposes)
so give the MEM rtx a byte's mode. */
#define FUNCTION_MODE QImode
/* Compute the cost of computing a constant rtl expression RTX
whose rtx-code is CODE. The body of this macro is a portion
of a switch statement. If the code is computed here,
return it with a return statement. Otherwise, break from the switch. */
#define CONST_COSTS(RTX,CODE,OUTER_CODE) \
case CONST_INT: \
/* Constant zero is super cheap due to clr instruction. */ \
if (RTX == const0_rtx) return 0; \
if ((unsigned) INTVAL (RTX) < 077) return 1; \
case CONST: \
case LABEL_REF: \
case SYMBOL_REF: \
return 3; \
case CONST_DOUBLE: \
return 5;
/* Check a `double' value for validity for a particular machine mode.
This is defined to avoid crashes outputting certain constants. */
#define CHECK_FLOAT_VALUE(MODE, D, OVERFLOW) \
if (OVERFLOW) \
(D) = 3.4028234663852890e+38; \
else if ((MODE) == SFmode) \
{ \
if ((d) > 3.4028234663852890e+38) \
(OVERFLOW) = 1, (D) = 3.4028234663852890e+38; \
else if ((D) < -3.4028234663852890e+38) \
(OVERFLOW) = 1, (D) = -3.4028234663852890e+38; \
else if (((D) > 0) && ((D) < 1.1754943508222873e-38)) \
(OVERFLOW) = 1, (D) = 0.0; \
else if (((d) < 0) && ((d) > -1.1754943508222873e-38)) \
(OVERFLOW) = 1, (D) = 0.0; \
}
/* Tell final.c how to eliminate redundant test instructions. */
/* Here we define machine-dependent flags and fields in cc_status
(see `conditions.h'). */
/* On the Alliant, floating-point instructions do not modify the
ordinary CC register. Only fcmp and ftest instructions modify the
floating-point CC register. We should actually keep track of what
both kinds of CC registers contain, but for now we only consider
the most recent instruction that has set either register. */
/* Set if the cc value came from a floating point test, so a floating
point conditional branch must be output. */
#define CC_IN_FP 04000
/* Store in cc_status the expressions
that the condition codes will describe
after execution of an instruction whose pattern is EXP.
Do not alter them if the instruction would not alter the cc's. */
/* On the 68000, all the insns to store in an address register
fail to set the cc's. However, in some cases these instructions
can make it possibly invalid to use the saved cc's. In those
cases we clear out some or all of the saved cc's so they won't be used. */
#define NOTICE_UPDATE_CC(EXP, INSN) \
{ \
if (GET_CODE (EXP) == SET) \
{ if (ADDRESS_REG_P (SET_DEST (EXP)) || FP_REG_P (SET_DEST (EXP))) \
{ if (cc_status.value1 \
&& reg_overlap_mentioned_p (SET_DEST (EXP), cc_status.value1)) \
cc_status.value1 = 0; \
if (cc_status.value2 \
&& reg_overlap_mentioned_p (SET_DEST (EXP), cc_status.value2)) \
cc_status.value2 = 0; } \
else if (GET_CODE (SET_SRC (EXP)) == MOD \
|| GET_CODE (SET_SRC (EXP)) == UMOD \
|| (GET_CODE (SET_SRC (EXP)) == TRUNCATE \
&& (GET_CODE (XEXP (SET_SRC (EXP))) == MOD \
|| GET_CODE (XEXP (SET_SRC (EXP))) == UMOD))) \
/* The swap insn produces cc's that don't correspond to the \
result. */ \
CC_STATUS_INIT; \
else if (SET_DEST (EXP) != cc0_rtx \
&& (FP_REG_P (SET_SRC (EXP)) \
|| GET_CODE (SET_SRC (EXP)) == FIX \
|| GET_CODE (SET_SRC (EXP)) == FLOAT_TRUNCATE \
|| GET_CODE (SET_SRC (EXP)) == FLOAT_EXTEND)) \
{ CC_STATUS_INIT; } \
/* A pair of move insns doesn't produce a useful overall cc. */ \
else if (!FP_REG_P (SET_DEST (EXP)) \
&& !FP_REG_P (SET_SRC (EXP)) \
&& GET_MODE_SIZE (GET_MODE (SET_SRC (EXP))) > 4 \
&& (GET_CODE (SET_SRC (EXP)) == REG \
|| GET_CODE (SET_SRC (EXP)) == MEM \
|| GET_CODE (SET_SRC (EXP)) == CONST_DOUBLE))\
{ CC_STATUS_INIT; } \
else if (GET_CODE (SET_SRC (EXP)) == CALL) \
{ CC_STATUS_INIT; } \
else if (XEXP (EXP, 0) != pc_rtx) \
{ cc_status.flags = 0; \
cc_status.value1 = XEXP (EXP, 0); \
cc_status.value2 = XEXP (EXP, 1); } } \
else if (GET_CODE (EXP) == PARALLEL \
&& GET_CODE (XVECEXP (EXP, 0, 0)) == SET) \
{ \
if (ADDRESS_REG_P (XEXP (XVECEXP (EXP, 0, 0), 0))) \
CC_STATUS_INIT; \
else if (XEXP (XVECEXP (EXP, 0, 0), 0) != pc_rtx) \
{ cc_status.flags = 0; \
cc_status.value1 = XEXP (XVECEXP (EXP, 0, 0), 0); \
cc_status.value2 = XEXP (XVECEXP (EXP, 0, 0), 1); } } \
else CC_STATUS_INIT; \
if (cc_status.value2 != 0 \
&& ADDRESS_REG_P (cc_status.value2) \
&& GET_MODE (cc_status.value2) == QImode) \
CC_STATUS_INIT; \
if (cc_status.value2 != 0) \
switch (GET_CODE (cc_status.value2)) \
{ case PLUS: case MINUS: case MULT: \
case DIV: case UDIV: case MOD: case UMOD: case NEG: \
case ASHIFT: case ASHIFTRT: case LSHIFTRT: \
case ROTATE: case ROTATERT: \
if (GET_MODE (cc_status.value2) != VOIDmode) \
cc_status.flags |= CC_NO_OVERFLOW; \
break; \
case ZERO_EXTEND: \
/* (SET r1 (ZERO_EXTEND r2)) on this machine
ends with a move insn moving r2 in r2's mode.
Thus, the cc's are set for r2.
This can set N bit spuriously. */ \
cc_status.flags |= CC_NOT_NEGATIVE; } \
if (cc_status.value1 && GET_CODE (cc_status.value1) == REG \
&& cc_status.value2 \
&& reg_overlap_mentioned_p (cc_status.value1, cc_status.value2)) \
cc_status.value2 = 0; \
if ((cc_status.value1 && FP_REG_P (cc_status.value1)) \
|| (cc_status.value2 && FP_REG_P (cc_status.value2))) \
cc_status.flags = CC_IN_FP; }
#define OUTPUT_JUMP(NORMAL, FLOAT, NO_OV) \
{ if (cc_prev_status.flags & CC_IN_FP) \
return FLOAT; \
if (cc_prev_status.flags & CC_NO_OVERFLOW) \
return NO_OV; \
return NORMAL; }
/* Control the assembler format that we output. */
/* Output at beginning of assembler file. */
#define ASM_FILE_START(FILE) \
fprintf (FILE, "#NO_APP\n");
/* Output to assembler file text saying following lines
may contain character constants, extra white space, comments, etc. */
#define ASM_APP_ON "#APP\n"
/* Output to assembler file text saying following lines
no longer contain unusual constructs. */
#define ASM_APP_OFF "#NO_APP\n"
/* Output before read-only data. */
#define TEXT_SECTION_ASM_OP "\t.text"
/* Output before writable data. */
#define DATA_SECTION_ASM_OP "\t.data"
/* How to refer to registers in assembler output.
This sequence is indexed by compiler's hard-register-number (see above). */
#define REGISTER_NAMES \
{"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", \
"a0", "a1", "a2", "a3", "a4", "a5", "a6", "sp", \
"fp0", "fp1", "fp2", "fp3", "fp4", "fp5", "fp6", "fp7" }
/* How to renumber registers for dbx and gdb.
On the Sun-3, the floating point registers have numbers
18 to 25, not 16 to 23 as they do in the compiler. */
/* (On the Alliant, dbx isn't working yet at all. */
#define DBX_REGISTER_NUMBER(REGNO) ((REGNO) < 16 ? (REGNO) : (REGNO) + 2)
/* This is how to output the definition of a user-level label named NAME,
such as the label on a static function or variable NAME. */
#define ASM_OUTPUT_LABEL(FILE,NAME) \
do { assemble_name (FILE, NAME); fputs (":\n", FILE); } while (0)
/* This is how to output a command to make the user-level label named NAME
defined for reference from other files. */
#define ASM_GLOBALIZE_LABEL(FILE,NAME) \
do { fputs ("\t.globl ", FILE); assemble_name (FILE, NAME); fputs ("\n", FILE);} while (0)
/* The prefix to add to user-visible assembler symbols. */
#define USER_LABEL_PREFIX "_"
/* This is how to output an internal numbered label where
PREFIX is the class of label and NUM is the number within the class. */
#define ASM_OUTPUT_INTERNAL_LABEL(FILE,PREFIX,NUM) \
fprintf (FILE, "%s%d:\n", PREFIX, NUM)
/* This is how to store into the string LABEL
the symbol_ref name of an internal numbered label where
PREFIX is the class of label and NUM is the number within the class.
This is suitable for output with `assemble_name'. */
#define ASM_GENERATE_INTERNAL_LABEL(LABEL,PREFIX,NUM) \
sprintf (LABEL, "*%s%d", PREFIX, NUM)
/* This is how to output an assembler line defining a `double' constant. */
#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \
do { union { double d; long v[2];} tem; \
tem.d = (VALUE); \
fprintf (FILE, "\t.long 0x%x,0x%x\n", tem.v[0], tem.v[1]); \
} while (0)
/* This is how to output an assembler line defining a `float' constant. */
#define ASM_OUTPUT_FLOAT(FILE,VALUE) \
do { union { float f; long l;} tem; \
tem.f = (VALUE); \
fprintf (FILE, "\t.long 0x%x\n", tem.l); \
} while (0)
/* This is how to output an assembler line defining an `int' constant. */
#define ASM_OUTPUT_INT(FILE,VALUE) \
( fprintf (FILE, "\t.long "), \
output_addr_const (FILE, (VALUE)), \
fprintf (FILE, "\n"))
/* Likewise for `char' and `short' constants. */
#define ASM_OUTPUT_SHORT(FILE,VALUE) \
( fprintf (FILE, "\t.word "), \
output_addr_const (FILE, (VALUE)), \
fprintf (FILE, "\n"))
#define ASM_OUTPUT_CHAR(FILE,VALUE) \
( fprintf (FILE, "\t.byte "), \
output_addr_const (FILE, (VALUE)), \
fprintf (FILE, "\n"))
#define ASM_OUTPUT_ASCII(FILE,PTR,SIZE) \
do { int i; const unsigned char *pp = (const unsigned char *) (PTR); \
fprintf((FILE), "\t.byte %d", (unsigned int)*pp++); \
for (i = 1; i < (SIZE); ++i, ++pp) { \
if ((i % 8) == 0) \
fprintf((FILE), "\n\t.byte %d", (unsigned int) *pp); \
else \
fprintf((FILE), ",%d", (unsigned int) *pp); } \
fprintf ((FILE), "\n"); } while (0)
/* This is how to output an assembler line for a numeric constant byte. */
#define ASM_OUTPUT_BYTE(FILE,VALUE) \
fprintf (FILE, "\t.byte 0x%x\n", (VALUE))
/* This is how to output an insn to push a register on the stack.
It need not be very fast code. */
#define ASM_OUTPUT_REG_PUSH(FILE,REGNO) \
fprintf (FILE, "\tmovl %s,sp@-\n", reg_names[REGNO])
/* This is how to output an insn to pop a register from the stack.
It need not be very fast code. */
#define ASM_OUTPUT_REG_POP(FILE,REGNO) \
fprintf (FILE, "\tmovl sp@+,%s\n", reg_names[REGNO])
/* This is how to output an element of a case-vector that is absolute.
(The 68000 does not use such vectors,
but we must define this macro anyway.) */
#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \
fprintf (FILE, "\t.long L%d\n", VALUE)
/* This is how to output an element of a case-vector that is relative. */
#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \
fprintf (FILE, "\t.word L%d-L%d\n", VALUE, REL)
/* This is how to output an assembler line
that says to advance the location counter
to a multiple of 2**LOG bytes. */
#define ASM_OUTPUT_ALIGN(FILE,LOG) \
if ((LOG) == 1) \
fprintf (FILE, "\t.even\n"); \
else if ((LOG) != 0) \
fprintf (FILE, "\t.align %dn", (LOG));
#define ASM_OUTPUT_SKIP(FILE,SIZE) \
fprintf (FILE, "\t. = . + %u\n", (SIZE))
/* This says how to output an assembler line
to define a global common symbol. */
#define ASM_OUTPUT_COMMON(FILE, NAME, SIZE, ROUNDED) \
( fputs ("\t.comm ", (FILE)), \
assemble_name ((FILE), (NAME)), \
fprintf ((FILE), ",%u\n", (ROUNDED)))
/* This says how to output an assembler line
to define a local common symbol. */
#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \
( fputs ("\t.lcomm ", (FILE)), \
assemble_name ((FILE), (NAME)), \
fprintf ((FILE), ",%u\n", (ROUNDED)))
/* Store in OUTPUT a string (made with alloca) containing
an assembler-name for a local static variable named NAME.
LABELNO is an integer which is different for each call. */
#define ASM_FORMAT_PRIVATE_NAME(OUTPUT, NAME, LABELNO) \
( (OUTPUT) = (char *) alloca (strlen ((NAME)) + 10), \
sprintf ((OUTPUT), "%s.%d", (NAME), (LABELNO)))
/* Define the parentheses used to group arithmetic operations
in assembler code. */
#define ASM_OPEN_PAREN "("
#define ASM_CLOSE_PAREN ")"
/* Define results of standard character escape sequences. */
#define TARGET_BELL 007
#define TARGET_BS 010
#define TARGET_TAB 011
#define TARGET_NEWLINE 012
#define TARGET_VT 013
#define TARGET_FF 014
#define TARGET_CR 015
/* Print operand X (an rtx) in assembler syntax to file FILE.
CODE is a letter or dot (`z' in `%z0') or 0 if no letter was specified.
For `%' followed by punctuation, CODE is the punctuation and X is null.
On the Alliant, we use several CODE characters:
'.' for dot needed in Motorola-style opcode names.
'-' for an operand pushing on the stack:
sp@-, -(sp) or -(%sp) depending on the style of syntax.
'+' for an operand pushing on the stack:
sp@+, (sp)+ or (%sp)+ depending on the style of syntax.
'@' for a reference to the top word on the stack:
sp@, (sp) or (%sp) depending on the style of syntax.
'#' for an immediate operand prefix (# in MIT and Motorola syntax
but & in SGS syntax).
'!' for the cc register (used in an `and to cc' insn).
'b' for byte insn (no effect, on the Sun; this is for the ISI).
'd' to force memory addressing to be absolute, not relative.
'f' for float insn (print a CONST_DOUBLE as a float rather than in hex)
'x' for float insn (print a CONST_DOUBLE as a float rather than in hex),
or print pair of registers as rx:ry. */
#define PRINT_OPERAND_PUNCT_VALID_P(CODE) \
((CODE) == '.' || (CODE) == '#' || (CODE) == '-' \
|| (CODE) == '+' || (CODE) == '@' || (CODE) == '!')
#define PRINT_OPERAND(FILE, X, CODE) \
{ int i; \
if (CODE == '.') ; \
else if (CODE == '#') fprintf (FILE, "#"); \
else if (CODE == '-') fprintf (FILE, "sp@-"); \
else if (CODE == '+') fprintf (FILE, "sp@+"); \
else if (CODE == '@') fprintf (FILE, "sp@"); \
else if (CODE == '!') fprintf (FILE, "cc"); \
else if ((X) == 0 ) ; \
else if (GET_CODE (X) == REG) \
{ if (REGNO (X) < 16 && (CODE == 'y' || CODE == 'x') && GET_MODE (X) == DFmode) \
fprintf (FILE, "%s,%s", reg_names[REGNO (X)], reg_names[REGNO (X)+1]); \
else \
fprintf (FILE, "%s", reg_names[REGNO (X)]); \
} \
else if (GET_CODE (X) == MEM) \
{ \
output_address (XEXP (X, 0)); \
if (CODE == 'd' && ! TARGET_68020 \
&& CONSTANT_ADDRESS_P (XEXP (X, 0)) \
&& !(GET_CODE (XEXP (X, 0)) == CONST_INT \
&& INTVAL (XEXP (X, 0)) < 0x8000 \
&& INTVAL (XEXP (X, 0)) >= -0x8000)) \
fprintf (FILE, ":l"); \
} \
else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) == SFmode) \
{ union { double d; int i[2]; } u; \
union { float f; int i; } u1; \
u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); \
u1.f = u.d; \
if (CODE == 'f') \
fprintf (FILE, "#0r%.9g", u1.f); \
else \
fprintf (FILE, "#0x%x", u1.i); } \
else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) != VOIDmode) \
{ union { double d; int i[2]; } u; \
u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); \
fprintf (FILE, "#0r%.20g", u.d); } \
else { putc ('#', FILE); output_addr_const (FILE, X); }}
/* Note that this contains a kludge that knows that the only reason
we have an address (plus (label_ref...) (reg...))
is in the insn before a tablejump, and we know that m68k.md
generates a label LInnn: on such an insn. */
#define PRINT_OPERAND_ADDRESS(FILE, ADDR) \
{ register rtx reg1, reg2, breg, ireg; \
register rtx addr = ADDR; \
static char *sz = ".BW.L...D"; \
rtx offset; \
switch (GET_CODE (addr)) \
{ \
case REG: \
fprintf (FILE, "%s@", reg_names[REGNO (addr)]); \
break; \
case PRE_DEC: \
fprintf (FILE, "%s@-", reg_names[REGNO (XEXP (addr, 0))]); \
break; \
case POST_INC: \
fprintf (FILE, "%s@+", reg_names[REGNO (XEXP (addr, 0))]); \
break; \
case PLUS: \
reg1 = 0; reg2 = 0; \
ireg = 0; breg = 0; \
offset = 0; \
if (CONSTANT_ADDRESS_P (XEXP (addr, 0))) \
{ \
offset = XEXP (addr, 0); \
addr = XEXP (addr, 1); \
} \
else if (CONSTANT_ADDRESS_P (XEXP (addr, 1))) \
{ \
offset = XEXP (addr, 1); \
addr = XEXP (addr, 0); \
} \
if (GET_CODE (addr) != PLUS) ; \
else if (GET_CODE (XEXP (addr, 0)) == SIGN_EXTEND) \
{ \
reg1 = XEXP (addr, 0); \
addr = XEXP (addr, 1); \
} \
else if (GET_CODE (XEXP (addr, 1)) == SIGN_EXTEND) \
{ \
reg1 = XEXP (addr, 1); \
addr = XEXP (addr, 0); \
} \
else if (GET_CODE (XEXP (addr, 0)) == MULT) \
{ \
reg1 = XEXP (addr, 0); \
addr = XEXP (addr, 1); \
} \
else if (GET_CODE (XEXP (addr, 1)) == MULT) \
{ \
reg1 = XEXP (addr, 1); \
addr = XEXP (addr, 0); \
} \
else if (GET_CODE (XEXP (addr, 0)) == REG) \
{ \
reg1 = XEXP (addr, 0); \
addr = XEXP (addr, 1); \
} \
else if (GET_CODE (XEXP (addr, 1)) == REG) \
{ \
reg1 = XEXP (addr, 1); \
addr = XEXP (addr, 0); \
} \
if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT \
|| GET_CODE (addr) == SIGN_EXTEND) \
{ if (reg1 == 0) reg1 = addr; else reg2 = addr; addr = 0; } \
/* for OLD_INDEXING \
else if (GET_CODE (addr) == PLUS) \
{ \
if (GET_CODE (XEXP (addr, 0)) == REG) \
{ \
reg2 = XEXP (addr, 0); \
addr = XEXP (addr, 1); \
} \
else if (GET_CODE (XEXP (addr, 1)) == REG) \
{ \
reg2 = XEXP (addr, 1); \
addr = XEXP (addr, 0); \
} \
} \
*/ \
if (offset != 0) { if (addr != 0) abort (); addr = offset; } \
if ((reg1 && (GET_CODE (reg1) == SIGN_EXTEND \
|| GET_CODE (reg1) == MULT)) \
|| (reg2 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg2)))) \
{ breg = reg2; ireg = reg1; } \
else if (reg1 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg1))) \
{ breg = reg1; ireg = reg2; } \
if (ireg != 0 && breg == 0 && GET_CODE (addr) == LABEL_REF) \
{ int scale = 1; \
if (GET_CODE (ireg) == MULT) \
{ scale = INTVAL (XEXP (ireg, 1)); \
ireg = XEXP (ireg, 0); } \
if (GET_CODE (ireg) == SIGN_EXTEND) \
fprintf (FILE, "pc@(L%d-LI%d-2:B)[%s:W", \
CODE_LABEL_NUMBER (XEXP (addr, 0)), \
CODE_LABEL_NUMBER (XEXP (addr, 0)), \
reg_names[REGNO (XEXP (ireg, 0))]); \
else \
fprintf (FILE, "pc@(L%d-LI%d-2:B)[%s:L", \
CODE_LABEL_NUMBER (XEXP (addr, 0)), \
CODE_LABEL_NUMBER (XEXP (addr, 0)), \
reg_names[REGNO (ireg)]); \
fprintf (FILE, ":%c", sz[scale]); \
putc (']', FILE); \
break; } \
if (breg != 0 && ireg == 0 && GET_CODE (addr) == LABEL_REF) \
{ fprintf (FILE, "pc@(L%d-LI%d-2:B)[%s:L:B]", \
CODE_LABEL_NUMBER (XEXP (addr, 0)), \
CODE_LABEL_NUMBER (XEXP (addr, 0)), \
reg_names[REGNO (breg)]); \
break; } \
if (ireg != 0 || breg != 0) \
{ int scale = 1; \
if (breg == 0) \
abort (); \
if (addr && GET_CODE (addr) == LABEL_REF) abort (); \
fprintf (FILE, "%s@", reg_names[REGNO (breg)]); \
if (addr != 0) { \
putc( '(', FILE ); \
output_addr_const (FILE, addr); \
if (ireg != 0) { \
if (GET_CODE(addr) == CONST_INT) { \
int size_of = 1, val = INTVAL(addr); \
if (val < -0x8000 || val >= 0x8000) \
size_of = 4; \
else if (val < -0x80 || val >= 0x80) \
size_of = 2; \
fprintf(FILE, ":%c", sz[size_of]); \
} \
else \
fprintf(FILE, ":L"); } \
putc( ')', FILE ); } \
if (ireg != 0) { \
putc ('[', FILE); \
if (ireg != 0 && GET_CODE (ireg) == MULT) \
{ scale = INTVAL (XEXP (ireg, 1)); \
ireg = XEXP (ireg, 0); } \
if (ireg != 0 && GET_CODE (ireg) == SIGN_EXTEND) \
fprintf (FILE, "%s:W", reg_names[REGNO (XEXP (ireg, 0))]); \
else if (ireg != 0) \
fprintf (FILE, "%s:L", reg_names[REGNO (ireg)]); \
fprintf (FILE, ":%c", sz[scale]); \
putc (']', FILE); \
} \
break; \
} \
else if (reg1 != 0 && GET_CODE (addr) == LABEL_REF) \
{ fprintf (FILE, "pc@(L%d-LI%d-2:B)[%s:L:B]", \
CODE_LABEL_NUMBER (XEXP (addr, 0)), \
CODE_LABEL_NUMBER (XEXP (addr, 0)), \
reg_names[REGNO (reg1)]); \
break; } \
default: \
if (GET_CODE (addr) == CONST_INT \
&& INTVAL (addr) < 0x8000 \
&& INTVAL (addr) >= -0x8000) \
fprintf (FILE, "%d:W", INTVAL (addr)); \
else \
output_addr_const (FILE, addr); \
}}
/*
Local variables:
version-control: t
End:
*/
;;- Machine description for GNU C compiler for Alliant FX systems
;; Copyright (C) 1989, 1994, 1996, 1998, 1999 Free Software Foundation, Inc.
;; Adapted from m68k.md by Paul Petersen (petersen@uicsrd.csrd.uiuc.edu)
;; and Joe Weening (weening@gang-of-four.stanford.edu).
;; 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, 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.
;;- instruction definitions
;;- @@The original PO technology requires these to be ordered by speed,
;;- @@ so that assigner will pick the fastest.
;;- See file "rtl.def" for documentation on define_insn, match_*, et. al.
;;- When naming insn's (operand 0 of define_insn) be careful about using
;;- names from other targets machine descriptions.
;;- cpp macro #define NOTICE_UPDATE_CC in file tm.h handles condition code
;;- updates for most instructions.
;;- Operand classes for the register allocator:
;;- 'a' one of the address registers can be used.
;;- 'd' one of the data registers can be used.
;;- 'f' one of the CE floating point registers can be used
;;- 'r' either a data or an address register can be used.
;;- Immediate integer operand constraints:
;;- 'I' 1 .. 8
;;- 'J' -32768 .. 32767
;;- 'K' -128 .. 127
;;- 'L' -8 .. -1
;;- Some remnants of constraint codes for the m68k ('x','y','G','H')
;;- may remain in the insn definitions.
;;- Some of these insn's are composites of several Alliant op codes.
;;- The assembler (or final @@??) insures that the appropriate one is
;;- selected.
;; We don't want to allow a constant operand for test insns because
;; (set (cc0) (const_int foo)) has no mode information. Such insns will
;; be folded while optimizing anyway.
(define_insn "tstsi"
[(set (cc0)
(match_operand:SI 0 "nonimmediate_operand" "rm"))]
""
"*
{
if (TARGET_68020 || ! ADDRESS_REG_P (operands[0]))
return \"tst%.l %0\";
/* If you think that the 68020 does not support tstl a0,
reread page B-167 of the 68020 manual more carefully. */
/* On an address reg, cmpw may replace cmpl. */
return \"cmp%.w %#0,%0\";
}")
(define_insn "tsthi"
[(set (cc0)
(match_operand:HI 0 "nonimmediate_operand" "rm"))]
""
"*
{
if (TARGET_68020 || ! ADDRESS_REG_P (operands[0]))
return \"tst%.w %0\";
return \"cmp%.w %#0,%0\";
}")
(define_insn "tstqi"
[(set (cc0)
(match_operand:QI 0 "nonimmediate_operand" "dm"))]
""
"tst%.b %0")
(define_insn "tstsf"
[(set (cc0)
(match_operand:SF 0 "nonimmediate_operand" "fm"))]
"TARGET_CE"
"*
{
cc_status.flags = CC_IN_FP;
return \"ftest%.s %0\";
}")
(define_insn "tstdf"
[(set (cc0)
(match_operand:DF 0 "nonimmediate_operand" "fm"))]
"TARGET_CE"
"*
{
cc_status.flags = CC_IN_FP;
return \"ftest%.d %0\";
}")
;; compare instructions.
;; A composite of the cmp, cmpa, & cmpi m68000 op codes.
(define_insn "cmpsi"
[(set (cc0)
(compare (match_operand:SI 0 "nonimmediate_operand" "rKs,mr,>")
(match_operand:SI 1 "general_operand" "mr,Ksr,>")))]
""
"*
{
if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM)
return \"cmpm%.l %1,%0\";
if (REG_P (operands[1])
|| (!REG_P (operands[0]) && GET_CODE (operands[0]) != MEM))
{
cc_status.flags |= CC_REVERSED;
return \"cmp%.l %d0,%d1\";
}
return \"cmp%.l %d1,%d0\";
}")
(define_insn "cmphi"
[(set (cc0)
(compare (match_operand:HI 0 "nonimmediate_operand" "rnm,d,n,m")
(match_operand:HI 1 "general_operand" "d,rnm,m,n")))]
""
"*
{
if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM)
return \"cmpm%.w %1,%0\";
if ((REG_P (operands[1]) && !ADDRESS_REG_P (operands[1]))
|| (!REG_P (operands[0]) && GET_CODE (operands[0]) != MEM))
{ cc_status.flags |= CC_REVERSED;
return \"cmp%.w %d0,%d1\";
}
return \"cmp%.w %d1,%d0\";
}")
(define_insn "cmpqi"
[(set (cc0)
(compare (match_operand:QI 0 "nonimmediate_operand" "dn,md,>")
(match_operand:QI 1 "general_operand" "dm,nd,>")))]
""
"*
{
if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM)
return \"cmpm%.b %1,%0\";
if (REG_P (operands[1])
|| (!REG_P (operands[0]) && GET_CODE (operands[0]) != MEM))
{
cc_status.flags |= CC_REVERSED;
return \"cmp%.b %d0,%d1\";
}
return \"cmp%.b %d1,%d0\";
}")
(define_insn "cmpdf"
[(set (cc0)
(compare (match_operand:DF 0 "nonimmediate_operand" "f,m")
(match_operand:DF 1 "nonimmediate_operand" "fm,f")))]
"TARGET_CE"
"*
{
cc_status.flags = CC_IN_FP;
if (FP_REG_P (operands[0]))
return \"fcmp%.d %1,%0\";
cc_status.flags |= CC_REVERSED;
return \"fcmp%.d %0,%1\";
}")
(define_insn "cmpsf"
[(set (cc0)
(compare (match_operand:SF 0 "nonimmediate_operand" "f,m")
(match_operand:SF 1 "nonimmediate_operand" "fm,f")))]
"TARGET_CE"
"*
{
cc_status.flags = CC_IN_FP;
if (FP_REG_P (operands[0]))
return \"fcmp%.s %1,%0\";
cc_status.flags |= CC_REVERSED;
return \"fcmp%.s %0,%1\";
}")
;; Recognizers for btst instructions.
(define_insn ""
[(set (cc0) (zero_extract (match_operand:QI 0 "memory_operand" "o")
(const_int 1)
(minus:SI (const_int 7)
(match_operand:SI 1 "general_operand" "di"))))]
""
"* { return output_btst (operands, operands[1], operands[0], insn, 7); }")
(define_insn ""
[(set (cc0) (zero_extract (match_operand:SI 0 "register_operand" "d")
(const_int 1)
(minus:SI (const_int 31)
(match_operand:SI 1 "general_operand" "di"))))]
""
"* { return output_btst (operands, operands[1], operands[0], insn, 31); }")
;; The following two patterns are like the previous two
;; except that they use the fact that bit-number operands
;; are automatically masked to 3 or 5 bits.
(define_insn ""
[(set (cc0) (zero_extract (match_operand:QI 0 "memory_operand" "o")
(const_int 1)
(minus:SI (const_int 7)
(and:SI
(match_operand:SI 1 "general_operand" "d")
(const_int 7)))))]
""
"* { return output_btst (operands, operands[1], operands[0], insn, 7); }")
(define_insn ""
[(set (cc0) (zero_extract (match_operand:SI 0 "register_operand" "d")
(const_int 1)
(minus:SI (const_int 31)
(and:SI
(match_operand:SI 1 "general_operand" "d")
(const_int 31)))))]
""
"* { return output_btst (operands, operands[1], operands[0], insn, 31); }")
;; Nonoffsettable mem refs are ok in this one pattern
;; since we don't try to adjust them.
(define_insn ""
[(set (cc0) (zero_extract (match_operand:QI 0 "memory_operand" "m")
(const_int 1)
(match_operand:SI 1 "general_operand" "i")))]
"GET_CODE (operands[1]) == CONST_INT
&& (unsigned) INTVAL (operands[1]) < 8"
"*
{
operands[1] = GEN_INT (7 - INTVAL (operands[1]));
return output_btst (operands, operands[1], operands[0], insn, 7);
}")
(define_insn ""
[(set (cc0) (zero_extract (match_operand:SI 0 "register_operand" "do")
(const_int 1)
(match_operand:SI 1 "general_operand" "i")))]
"GET_CODE (operands[1]) == CONST_INT"
"*
{
if (GET_CODE (operands[0]) == MEM)
{
operands[0] = adj_offsettable_operand (operands[0],
INTVAL (operands[1]) / 8);
operands[1] = GEN_INT (7 - INTVAL (operands[1]) % 8);
return output_btst (operands, operands[1], operands[0], insn, 7);
}
operands[1] = GEN_INT (31 - INTVAL (operands[1]));
return output_btst (operands, operands[1], operands[0], insn, 31);
}")
;; move instructions
;; A special case in which it is not desirable
;; to reload the constant into a data register.
(define_insn ""
[(set (match_operand:SI 0 "push_operand" "=m")
(match_operand:SI 1 "general_operand" "J"))]
"GET_CODE (operands[1]) == CONST_INT
&& INTVAL (operands[1]) >= -0x8000
&& INTVAL (operands[1]) < 0x8000"
"*
{
if (operands[1] == const0_rtx)
return \"clr%.l %0\";
return \"pea %a1\";
}")
;This is never used.
;(define_insn "swapsi"
; [(set (match_operand:SI 0 "general_operand" "r")
; (match_operand:SI 1 "general_operand" "r"))
; (set (match_dup 1) (match_dup 0))]
; ""
; "exg %1,%0")
;; Special case of fullword move when source is zero.
;; The reason this is special is to avoid loading a zero
;; into a data reg with moveq in order to store it elsewhere.
(define_insn ""
[(set (match_operand:SI 0 "general_operand" "=a,g")
(const_int 0))]
""
"@
sub%.l %0,%0
clr%.l %0")
;; General case of fullword move. The register constraints
;; force integer constants in range for a moveq to be reloaded
;; if they are headed for memory.
(define_insn "movsi"
;; Notes: make sure no alternative allows g vs g.
;; We don't allow f-regs since fixed point cannot go in them.
;; We do allow y and x regs since fixed point is allowed in them.
[(set (match_operand:SI 0 "general_operand" "=g,da,y,!*x*r*m")
(match_operand:SI 1 "general_operand" "daymKs,i,g,*x*r*m"))]
""
"*
{
if (GET_CODE (operands[1]) == CONST_INT)
{
if (operands[1] == const0_rtx
&& (DATA_REG_P (operands[0])
|| GET_CODE (operands[0]) == MEM))
return \"clr%.l %0\";
else if (DATA_REG_P (operands[0])
&& INTVAL (operands[1]) < 128
&& INTVAL (operands[1]) >= -128)
return \"moveq %1,%0\";
else if (ADDRESS_REG_P (operands[0])
&& INTVAL (operands[1]) < 0x8000
&& INTVAL (operands[1]) >= -0x8000)
return \"mov%.w %1,%0\";
else if (push_operand (operands[0], SImode)
&& INTVAL (operands[1]) < 0x8000
&& INTVAL (operands[1]) >= -0x8000)
return \"pea %a1\";
}
else if ((GET_CODE (operands[1]) == SYMBOL_REF
|| GET_CODE (operands[1]) == CONST)
&& push_operand (operands[0], SImode))
return \"pea %a1\";
else if ((GET_CODE (operands[1]) == SYMBOL_REF
|| GET_CODE (operands[1]) == CONST)
&& ADDRESS_REG_P (operands[0]))
return \"lea %a1,%0\";
return \"mov%.l %1,%0\";
}")
(define_insn "movhi"
[(set (match_operand:HI 0 "general_operand" "=g")
(match_operand:HI 1 "general_operand" "g"))]
""
"*
{
if (GET_CODE (operands[1]) == CONST_INT)
{
if (operands[1] == const0_rtx
&& (DATA_REG_P (operands[0])
|| GET_CODE (operands[0]) == MEM))
return \"clr%.w %0\";
else if (DATA_REG_P (operands[0])
&& INTVAL (operands[1]) < 128
&& INTVAL (operands[1]) >= -128)
{
return \"moveq %1,%0\";
}
else if (INTVAL (operands[1]) < 0x8000
&& INTVAL (operands[1]) >= -0x8000)
return \"mov%.w %1,%0\";
}
else if (CONSTANT_P (operands[1]))
return \"mov%.l %1,%0\";
/* Recognize the insn before a tablejump, one that refers
to a table of offsets. Such an insn will need to refer
to a label on the insn. So output one. Use the label-number
of the table of offsets to generate this label. */
if (GET_CODE (operands[1]) == MEM
&& GET_CODE (XEXP (operands[1], 0)) == PLUS
&& (GET_CODE (XEXP (XEXP (operands[1], 0), 0)) == LABEL_REF
|| GET_CODE (XEXP (XEXP (operands[1], 0), 1)) == LABEL_REF)
&& GET_CODE (XEXP (XEXP (operands[1], 0), 0)) != PLUS
&& GET_CODE (XEXP (XEXP (operands[1], 0), 1)) != PLUS)
{
rtx labelref;
if (GET_CODE (XEXP (XEXP (operands[1], 0), 0)) == LABEL_REF)
labelref = XEXP (XEXP (operands[1], 0), 0);
else
labelref = XEXP (XEXP (operands[1], 0), 1);
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"LI\",
CODE_LABEL_NUMBER (XEXP (labelref, 0)));
}
return \"mov%.w %1,%0\";
}")
(define_insn "movstricthi"
[(set (strict_low_part (match_operand:HI 0 "general_operand" "+dm"))
(match_operand:HI 1 "general_operand" "rmn"))]
""
"*
{
if (operands[1] == const0_rtx)
return \"clr%.w %0\";
return \"mov%.w %1,%0\";
}")
(define_insn "movqi"
[(set (match_operand:QI 0 "general_operand" "=d,*a,m,m,?*a")
(match_operand:QI 1 "general_operand" "dmi*a,d*a,dmi,?*a,m"))]
""
"*
{
rtx xoperands[4];
if (ADDRESS_REG_P (operands[0]) && GET_CODE (operands[1]) == MEM)
{
xoperands[1] = operands[1];
xoperands[2]
= gen_rtx_MEM (QImode, plus_constant (stack_pointer_rtx, 1));
xoperands[3] = stack_pointer_rtx;
/* Just pushing a byte puts it in the high byte of the halfword. */
/* We must put it in the low half, the second byte. */
output_asm_insn (\"subq%.w %#2,%3\;mov%.b %1,%2\", xoperands);
return \"mov%.w %+,%0\";
}
if (ADDRESS_REG_P (operands[1]) && GET_CODE (operands[0]) == MEM)
{
xoperands[0] = operands[0];
xoperands[1] = operands[1];
xoperands[2]
= gen_rtx_MEM (QImode, plus_constant (stack_pointer_rtx, 1));
xoperands[3] = stack_pointer_rtx;
output_asm_insn (\"mov%.w %1,%-\;mov%.b %2,%0\;addq%.w %#2,%3\", xoperands);
return \"\";
}
if (operands[1] == const0_rtx)
return \"clr%.b %0\";
if (GET_CODE (operands[1]) == CONST_INT
&& INTVAL (operands[1]) == -1)
return \"st %0\";
if (GET_CODE (operands[1]) != CONST_INT && CONSTANT_P (operands[1]))
return \"mov%.l %1,%0\";
if (ADDRESS_REG_P (operands[0]) || ADDRESS_REG_P (operands[1]))
return \"mov%.w %1,%0\";
return \"mov%.b %1,%0\";
}")
(define_insn "movstrictqi"
[(set (strict_low_part (match_operand:QI 0 "general_operand" "+dm"))
(match_operand:QI 1 "general_operand" "dmn"))]
""
"*
{
if (operands[1] == const0_rtx)
return \"clr%.b %0\";
return \"mov%.b %1,%0\";
}")
;; Floating-point moves on a CE are faster using an FP register than
;; with movl instructions. (Especially for double floats, but also
;; for single floats, even though it takes an extra instruction.) But
;; on an IP, the FP registers are simulated and so should be avoided.
;; We do this by using define_expand for movsf and movdf, and using
;; different constraints for each target type. The constraints for
;; TARGET_CE allow general registers because they sometimes need to
;; hold floats, but they are not preferable.
(define_expand "movsf"
[(set (match_operand:SF 0 "general_operand" "")
(match_operand:SF 1 "nonimmediate_operand" ""))]
""
"")
(define_insn ""
[(set (match_operand:SF 0 "general_operand" "=f,m,!*r,!f*m")
(match_operand:SF 1 "nonimmediate_operand" "fm,f,f*r*m,*r"))]
"TARGET_CE"
"*
{
if (FP_REG_P (operands[0]))
{
if (FP_REG_P (operands[1]))
return \"fmove%.s %1,%0\";
if (REG_P (operands[1]))
return \"mov%.l %1,%-\;fmove%.s %+,%0\";
return \"fmove%.s %1,%0\";
}
if (FP_REG_P (operands[1]))
{
if (REG_P (operands[0]))
return \"fmove%.s %1,%-\;mov%.l %+,%0\";
return \"fmove%.s %1,%0\";
}
return \"mov%.l %1,%0\";
}")
(define_insn ""
[(set (match_operand:SF 0 "general_operand" "=frm")
(match_operand:SF 1 "nonimmediate_operand" "frm"))]
"!TARGET_CE"
"*
{
if (FP_REG_P (operands[0]))
{
if (FP_REG_P (operands[1]))
return \"fmove%.s %1,%0\";
if (REG_P (operands[1]))
return \"mov%.l %1,%-\;fmove%.s %+,%0\";
return \"fmove%.s %1,%0\";
}
if (FP_REG_P (operands[1]))
{
if (REG_P (operands[0]))
return \"fmove%.s %1,%-\;mov%.l %+,%0\";
return \"fmove%.s %1,%0\";
}
return \"mov%.l %1,%0\";
}")
(define_expand "movdf"
[(set (match_operand:DF 0 "general_operand" "")
(match_operand:DF 1 "nonimmediate_operand" ""))]
""
"")
(define_insn ""
[(set (match_operand:DF 0 "general_operand" "=f,m,!*r,!f*m")
(match_operand:DF 1 "nonimmediate_operand" "fm,f,f*r*m,*r"))]
"TARGET_CE"
"*
{
if (FP_REG_P (operands[0]))
{
if (FP_REG_P (operands[1]))
return \"fmove%.d %1,%0\";
if (REG_P (operands[1]))
{
rtx xoperands[2];
xoperands[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1);
output_asm_insn (\"mov%.l %1,%-\", xoperands);
output_asm_insn (\"mov%.l %1,%-\", operands);
return \"fmove%.d %+,%0\";
}
return \"fmove%.d %1,%0\";
}
else if (FP_REG_P (operands[1]))
{
if (REG_P (operands[0]))
{
output_asm_insn (\"fmove%.d %1,%-\;mov%.l %+,%0\", operands);
operands[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
return \"mov%.l %+,%0\";
}
return \"fmove%.d %1,%0\";
}
return output_move_double (operands);
}")
(define_insn ""
[(set (match_operand:DF 0 "general_operand" "=frm")
(match_operand:DF 1 "nonimmediate_operand" "frm"))]
"!TARGET_CE"
"*
{
if (FP_REG_P (operands[0]))
{
if (FP_REG_P (operands[1]))
return \"fmove%.d %1,%0\";
if (REG_P (operands[1]))
{
rtx xoperands[2];
xoperands[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1);
output_asm_insn (\"mov%.l %1,%-\", xoperands);
output_asm_insn (\"mov%.l %1,%-\", operands);
return \"fmove%.d %+,%0\";
}
return \"fmove%.d %1,%0\";
}
else if (FP_REG_P (operands[1]))
{
if (REG_P (operands[0]))
{
output_asm_insn (\"fmove%.d %1,%-\;mov%.l %+,%0\", operands);
operands[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
return \"mov%.l %+,%0\";
}
return \"fmove%.d %1,%0\";
}
return output_move_double (operands);
}")
(define_insn "movdi"
[(set (match_operand:DI 0 "general_operand" "=rm,&r,&ro<>")
(match_operand:DI 1 "general_operand" "r,m,roi<>"))]
""
"*
{
return output_move_double (operands);
}
")
;; This goes after the move instructions
;; because the move instructions are better (require no spilling)
;; when they can apply. It goes before the add/sub insns
;; so we will prefer it to them.
(define_insn "pushasi"
[(set (match_operand:SI 0 "push_operand" "=m")
(match_operand:SI 1 "address_operand" "p"))]
""
"pea %a1")
;; truncation instructions
(define_insn "truncsiqi2"
[(set (match_operand:QI 0 "general_operand" "=dm,d")
(truncate:QI
(match_operand:SI 1 "general_operand" "doJ,i")))]
""
"*
{
if (GET_CODE (operands[0]) == REG)
return \"mov%.l %1,%0\";
if (GET_CODE (operands[1]) == MEM)
operands[1] = adj_offsettable_operand (operands[1], 3);
return \"mov%.b %1,%0\";
}")
(define_insn "trunchiqi2"
[(set (match_operand:QI 0 "general_operand" "=dm,d")
(truncate:QI
(match_operand:HI 1 "general_operand" "doJ,i")))]
""
"*
{
if (GET_CODE (operands[0]) == REG
&& (GET_CODE (operands[1]) == MEM
|| GET_CODE (operands[1]) == CONST_INT))
return \"mov%.w %1,%0\";
if (GET_CODE (operands[0]) == REG)
return \"mov%.l %1,%0\";
if (GET_CODE (operands[1]) == MEM)
operands[1] = adj_offsettable_operand (operands[1], 1);
return \"mov%.b %1,%0\";
}")
(define_insn "truncsihi2"
[(set (match_operand:HI 0 "general_operand" "=dm,d")
(truncate:HI
(match_operand:SI 1 "general_operand" "roJ,i")))]
""
"*
{
if (GET_CODE (operands[0]) == REG)
return \"mov%.l %1,%0\";
if (GET_CODE (operands[1]) == MEM)
operands[1] = adj_offsettable_operand (operands[1], 2);
return \"mov%.w %1,%0\";
}")
;; zero extension instructions
(define_expand "zero_extendhisi2"
[(set (match_operand:SI 0 "register_operand" "")
(const_int 0))
(set (strict_low_part (subreg:HI (match_dup 0) 0))
(match_operand:HI 1 "general_operand" ""))]
""
"operands[1] = make_safe_from (operands[1], operands[0]);")
(define_expand "zero_extendqihi2"
[(set (match_operand:HI 0 "register_operand" "")
(const_int 0))
(set (strict_low_part (subreg:QI (match_dup 0) 0))
(match_operand:QI 1 "general_operand" ""))]
""
"operands[1] = make_safe_from (operands[1], operands[0]);")
(define_expand "zero_extendqisi2"
[(set (match_operand:SI 0 "register_operand" "")
(const_int 0))
(set (strict_low_part (subreg:QI (match_dup 0) 0))
(match_operand:QI 1 "general_operand" ""))]
""
" operands[1] = make_safe_from (operands[1], operands[0]); ")
;; Patterns to recognize zero-extend insns produced by the combiner.
(define_insn ""
[(set (match_operand:SI 0 "general_operand" "=do<>")
(zero_extend:SI
(match_operand:HI 1 "nonimmediate_operand" "rm")))]
""
"*
{
if (DATA_REG_P (operands[0]))
{
if (GET_CODE (operands[1]) == REG
&& REGNO (operands[0]) == REGNO (operands[1]))
return \"and%.l %#0xFFFF,%0\";
if (reg_mentioned_p (operands[0], operands[1]))
return \"mov%.w %1,%0\;and%.l %#0xFFFF,%0\";
return \"clr%.l %0\;mov%.w %1,%0\";
}
else if (GET_CODE (operands[0]) == MEM
&& GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
return \"mov%.w %1,%0\;clr%.w %0\";
else if (GET_CODE (operands[0]) == MEM
&& GET_CODE (XEXP (operands[0], 0)) == POST_INC)
return \"clr%.w %0\;mov%.w %1,%0\";
else
{
output_asm_insn (\"clr%.w %0\", operands);
operands[0] = adj_offsettable_operand (operands[0], 2);
return \"mov%.w %1,%0\";
}
}")
(define_insn ""
[(set (match_operand:HI 0 "general_operand" "=do<>")
(zero_extend:HI
(match_operand:QI 1 "nonimmediate_operand" "dm")))]
""
"*
{
if (DATA_REG_P (operands[0]))
{
if (GET_CODE (operands[1]) == REG
&& REGNO (operands[0]) == REGNO (operands[1]))
return \"and%.w %#0xFF,%0\";
if (reg_mentioned_p (operands[0], operands[1]))
return \"mov%.b %1,%0\;and%.w %#0xFF,%0\";
return \"clr%.w %0\;mov%.b %1,%0\";
}
else if (GET_CODE (operands[0]) == MEM
&& GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
{
if (REGNO (XEXP (XEXP (operands[0], 0), 0))
== STACK_POINTER_REGNUM)
return \"clr%.w %-\;mov%.b %1,%0\";
else
return \"mov%.b %1,%0\;clr%.b %0\";
}
else if (GET_CODE (operands[0]) == MEM
&& GET_CODE (XEXP (operands[0], 0)) == POST_INC)
return \"clr%.b %0\;mov%.b %1,%0\";
else
{
output_asm_insn (\"clr%.b %0\", operands);
operands[0] = adj_offsettable_operand (operands[0], 1);
return \"mov%.b %1,%0\";
}
}")
(define_insn ""
[(set (match_operand:SI 0 "general_operand" "=do<>")
(zero_extend:SI
(match_operand:QI 1 "nonimmediate_operand" "dm")))]
""
"*
{
if (DATA_REG_P (operands[0]))
{
if (GET_CODE (operands[1]) == REG
&& REGNO (operands[0]) == REGNO (operands[1]))
return \"and%.l %#0xFF,%0\";
if (reg_mentioned_p (operands[0], operands[1]))
return \"mov%.b %1,%0\;and%.l %#0xFF,%0\";
return \"clr%.l %0\;mov%.b %1,%0\";
}
else if (GET_CODE (operands[0]) == MEM
&& GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
{
operands[0] = XEXP (XEXP (operands[0], 0), 0);
return \"clr%.l %0@-\;mov%.b %1,%0@(3)\";
}
else if (GET_CODE (operands[0]) == MEM
&& GET_CODE (XEXP (operands[0], 0)) == POST_INC)
{
operands[0] = XEXP (XEXP (operands[0], 0), 0);
return \"clr%.l %0@+\;mov%.b %1,%0@(-1)\";
}
else
{
output_asm_insn (\"clr%.l %0\", operands);
operands[0] = adj_offsettable_operand (operands[0], 3);
return \"mov%.b %1,%0\";
}
}")
;; sign extension instructions
(define_insn "extendhisi2"
[(set (match_operand:SI 0 "general_operand" "=*d,a")
(sign_extend:SI
(match_operand:HI 1 "nonimmediate_operand" "0,rmn")))]
""
"@
ext%.l %0
mov%.w %1,%0")
(define_insn "extendqihi2"
[(set (match_operand:HI 0 "general_operand" "=d")
(sign_extend:HI
(match_operand:QI 1 "nonimmediate_operand" "0")))]
""
"ext%.w %0")
(define_insn "extendqisi2"
[(set (match_operand:SI 0 "general_operand" "=d")
(sign_extend:SI
(match_operand:QI 1 "nonimmediate_operand" "0")))]
"TARGET_68020"
"extb%.l %0")
;; Conversions between float and double.
(define_insn "extendsfdf2"
[(set (match_operand:DF 0 "general_operand" "=f,m")
(float_extend:DF
(match_operand:SF 1 "nonimmediate_operand" "fm,f")))]
"TARGET_CE"
"fmovesd %1,%0")
(define_insn "truncdfsf2"
[(set (match_operand:SF 0 "general_operand" "=f,m")
(float_truncate:SF
(match_operand:DF 1 "nonimmediate_operand" "fm,f")))]
"TARGET_CE"
"fmoveds %1,%0")
;; Conversion between fixed point and floating point.
;; Note that among the fix-to-float insns
;; the ones that start with SImode come first.
;; That is so that an operand that is a CONST_INT
;; (and therefore lacks a specific machine mode).
;; will be recognized as SImode (which is always valid)
;; rather than as QImode or HImode.
(define_insn "floatsisf2"
[(set (match_operand:SF 0 "register_operand" "=f")
(float:SF (match_operand:SI 1 "nonimmediate_operand" "dm")))]
"TARGET_CE"
"fmovels %1,%0")
(define_insn "floatsidf2"
[(set (match_operand:DF 0 "register_operand" "=f")
(float:DF (match_operand:SI 1 "nonimmediate_operand" "dm")))]
"TARGET_CE"
"fmoveld %1,%0")
(define_insn "floathisf2"
[(set (match_operand:SF 0 "register_operand" "=f")
(float:SF (match_operand:HI 1 "nonimmediate_operand" "dm")))]
"TARGET_CE"
"fmovews %1,%0")
(define_insn "floathidf2"
[(set (match_operand:DF 0 "register_operand" "=f")
(float:DF (match_operand:HI 1 "nonimmediate_operand" "dm")))]
"TARGET_CE"
"fmovewd %1,%0")
(define_insn "floatqisf2"
[(set (match_operand:SF 0 "register_operand" "=f")
(float:SF (match_operand:QI 1 "nonimmediate_operand" "dm")))]
"TARGET_CE"
"fmovebs %1,%0")
(define_insn "floatqidf2"
[(set (match_operand:DF 0 "register_operand" "=f")
(float:DF (match_operand:QI 1 "nonimmediate_operand" "dm")))]
"TARGET_CE"
"fmovebd %1,%0")
;; Float-to-fix conversion insns.
(define_insn "fix_truncsfqi2"
[(set (match_operand:QI 0 "general_operand" "=dm")
(fix:QI (fix:SF (match_operand:SF 1 "register_operand" "f"))))]
"TARGET_CE"
"fmovesb %1,%0")
(define_insn "fix_truncsfhi2"
[(set (match_operand:HI 0 "general_operand" "=dm")
(fix:HI (fix:SF (match_operand:SF 1 "register_operand" "f"))))]
"TARGET_CE"
"fmovesw %1,%0")
(define_insn "fix_truncsfsi2"
[(set (match_operand:SI 0 "general_operand" "=dm")
(fix:SI (fix:SF (match_operand:SF 1 "register_operand" "f"))))]
"TARGET_CE"
"fmovesl %1,%0")
(define_insn "fix_truncdfqi2"
[(set (match_operand:QI 0 "general_operand" "=dm")
(fix:QI (fix:DF (match_operand:DF 1 "register_operand" "f"))))]
"TARGET_CE"
"fmovedb %1,%0")
(define_insn "fix_truncdfhi2"
[(set (match_operand:HI 0 "general_operand" "=dm")
(fix:HI (fix:DF (match_operand:DF 1 "register_operand" "f"))))]
"TARGET_CE"
"fmovedw %1,%0")
(define_insn "fix_truncdfsi2"
[(set (match_operand:SI 0 "general_operand" "=dm")
(fix:SI (fix:DF (match_operand:DF 1 "register_operand" "f"))))]
"TARGET_CE"
"fmovedl %1,%0")
;; add instructions
(define_insn "addsi3"
[(set (match_operand:SI 0 "general_operand" "=m,r,!a,!a")
(plus:SI (match_operand:SI 1 "general_operand" "%0,0,a,rJK")
(match_operand:SI 2 "general_operand" "dIKLs,mrIKLs,rJK,a")))]
""
"*
{
if (! operands_match_p (operands[0], operands[1]))
{
if (!ADDRESS_REG_P (operands[1]))
{
rtx tmp = operands[1];
operands[1] = operands[2];
operands[2] = tmp;
}
/* These insns can result from reloads to access
stack slots over 64k from the frame pointer. */
if (GET_CODE (operands[2]) == CONST_INT
&& INTVAL (operands[2]) + 0x8000 >= (unsigned) 0x10000)
return \"mov%.l %2,%0\;add%.l %1,%0\";
if (GET_CODE (operands[2]) == REG)
return \"lea %1@[%2:L:B],%0\";
else
return \"lea %1@(%c2),%0\";
}
if (GET_CODE (operands[2]) == CONST_INT)
{
if (INTVAL (operands[2]) > 0
&& INTVAL (operands[2]) <= 8)
return (ADDRESS_REG_P (operands[0])
? \"addq%.w %2,%0\"
: \"addq%.l %2,%0\");
if (INTVAL (operands[2]) < 0
&& INTVAL (operands[2]) >= -8)
{
operands[2] = GEN_INT (- INTVAL (operands[2]));
return (ADDRESS_REG_P (operands[0])
? \"subq%.w %2,%0\"
: \"subq%.l %2,%0\");
}
if (ADDRESS_REG_P (operands[0])
&& INTVAL (operands[2]) >= -0x8000
&& INTVAL (operands[2]) < 0x8000)
return \"add%.w %2,%0\";
}
return \"add%.l %2,%0\";
}")
(define_insn ""
[(set (match_operand:SI 0 "general_operand" "=a")
(plus:SI (match_operand:SI 1 "general_operand" "0")
(sign_extend:SI (match_operand:HI 2 "nonimmediate_operand" "rmn"))))]
""
"add%.w %2,%0")
(define_insn "addhi3"
[(set (match_operand:HI 0 "general_operand" "=mr,mr,m,r")
(plus:HI (match_operand:HI 1 "general_operand" "%0,0,0,0")
(match_operand:HI 2 "general_operand" "I,L,dn,rmn")))]
""
"@
addq%.w %2,%0
subq%.w #%n2,%0
add%.w %2,%0
add%.w %2,%0")
(define_insn ""
[(set (strict_low_part (match_operand:HI 0 "general_operand" "+m,d"))
(plus:HI (match_dup 0)
(match_operand:HI 1 "general_operand" "dn,rmn")))]
""
"add%.w %1,%0")
(define_insn "addqi3"
[(set (match_operand:QI 0 "general_operand" "=md,mr,m,d")
(plus:QI (match_operand:QI 1 "general_operand" "%0,0,0,0")
(match_operand:QI 2 "general_operand" "I,L,dn,dmn")))]
""
"@
addq%.b %2,%0
subq%.b #%n2,%0
add%.b %2,%0
add%.b %2,%0")
(define_insn ""
[(set (strict_low_part (match_operand:QI 0 "general_operand" "+m,d"))
(plus:QI (match_dup 0)
(match_operand:QI 1 "general_operand" "dn,dmn")))]
""
"add%.b %1,%0")
(define_insn "adddf3"
[(set (match_operand:DF 0 "register_operand" "=f")
(plus:DF (match_operand:DF 1 "nonimmediate_operand" "%f")
(match_operand:DF 2 "nonimmediate_operand" "fm")))]
"TARGET_CE"
"fadd%.d %2,%1,%0")
(define_insn "addsf3"
[(set (match_operand:SF 0 "register_operand" "=f")
(plus:SF (match_operand:SF 1 "nonimmediate_operand" "%f")
(match_operand:SF 2 "nonimmediate_operand" "fm")))]
"TARGET_CE"
"fadd%.s %2,%1,%0")
;; subtract instructions
(define_insn "subsi3"
[(set (match_operand:SI 0 "general_operand" "=m,r,!a,?d")
(minus:SI (match_operand:SI 1 "general_operand" "0,0,a,mrIKs")
(match_operand:SI 2 "general_operand" "dIKs,mrIKs,J,0")))]
""
"*
{
if (! operands_match_p (operands[0], operands[1]))
{
if (operands_match_p (operands[0], operands[2]))
{
if (GET_CODE (operands[1]) == CONST_INT)
{
if (INTVAL (operands[1]) > 0
&& INTVAL (operands[1]) <= 8)
return \"subq%.l %1,%0\;neg%.l %0\";
}
return \"sub%.l %1,%0\;neg%.l %0\";
}
/* This case is matched by J, but negating -0x8000
in an lea would give an invalid displacement.
So do this specially. */
if (INTVAL (operands[2]) == -0x8000)
return \"mov%.l %1,%0\;sub%.l %2,%0\";
return \"lea %1@(%n2),%0\";
}
if (GET_CODE (operands[2]) == CONST_INT)
{
if (INTVAL (operands[2]) > 0
&& INTVAL (operands[2]) <= 8)
return \"subq%.l %2,%0\";
if (ADDRESS_REG_P (operands[0])
&& INTVAL (operands[2]) >= -0x8000
&& INTVAL (operands[2]) < 0x8000)
return \"sub%.w %2,%0\";
}
return \"sub%.l %2,%0\";
}")
(define_insn ""
[(set (match_operand:SI 0 "general_operand" "=a")
(minus:SI (match_operand:SI 1 "general_operand" "0")
(sign_extend:SI (match_operand:HI 2 "nonimmediate_operand" "rmn"))))]
""
"sub%.w %2,%0")
(define_insn "subhi3"
[(set (match_operand:HI 0 "general_operand" "=m,r")
(minus:HI (match_operand:HI 1 "general_operand" "0,0")
(match_operand:HI 2 "general_operand" "dn,rmn")))]
""
"sub%.w %2,%0")
(define_insn ""
[(set (strict_low_part (match_operand:HI 0 "general_operand" "+m,d"))
(minus:HI (match_dup 0)
(match_operand:HI 1 "general_operand" "dn,rmn")))]
""
"sub%.w %1,%0")
(define_insn "subqi3"
[(set (match_operand:QI 0 "general_operand" "=m,d")
(minus:QI (match_operand:QI 1 "general_operand" "0,0")
(match_operand:QI 2 "general_operand" "dn,dmn")))]
""
"sub%.b %2,%0")
(define_insn ""
[(set (strict_low_part (match_operand:QI 0 "general_operand" "+m,d"))
(minus:QI (match_dup 0)
(match_operand:QI 1 "general_operand" "dn,dmn")))]
""
"sub%.b %1,%0")
(define_insn "subdf3"
[(set (match_operand:DF 0 "register_operand" "=f,f,f")
(minus:DF (match_operand:DF 1 "nonimmediate_operand" "f,f,m")
(match_operand:DF 2 "nonimmediate_operand" "f,m,f")))]
"TARGET_CE"
"@
fsub%.d %2,%1,%0
fsub%.d %2,%1,%0
frsub%.d %1,%2,%0")
(define_insn "subsf3"
[(set (match_operand:SF 0 "register_operand" "=f,f,f")
(minus:SF (match_operand:SF 1 "nonimmediate_operand" "f,f,m")
(match_operand:SF 2 "nonimmediate_operand" "f,m,f")))]
"TARGET_CE"
"@
fsub%.s %2,%1,%0
fsub%.s %2,%1,%0
frsub%.s %1,%2,%0")
;; multiply instructions
(define_insn "mulhi3"
[(set (match_operand:HI 0 "general_operand" "=d")
(mult:HI (match_operand:HI 1 "general_operand" "%0")
(match_operand:HI 2 "general_operand" "dmn")))]
""
"muls %2,%0")
(define_insn "mulhisi3"
[(set (match_operand:SI 0 "general_operand" "=d")
(mult:SI (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "%0"))
(sign_extend:SI (match_operand:HI 2 "nonimmediate_operand" "dm"))))]
""
"muls %2,%0")
(define_insn ""
[(set (match_operand:SI 0 "general_operand" "=d")
(mult:SI (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "%0"))
(match_operand:SI 2 "const_int_operand" "n")))]
""
"muls %2,%0")
(define_insn "mulsi3"
[(set (match_operand:SI 0 "general_operand" "=d")
(mult:SI (match_operand:SI 1 "general_operand" "%0")
(match_operand:SI 2 "general_operand" "dmsK")))]
"TARGET_68020"
"muls%.l %2,%0")
(define_insn "umulhisi3"
[(set (match_operand:SI 0 "general_operand" "=d")
(mult:SI (zero_extend:SI
(match_operand:HI 1 "nonimmediate_operand" "%0"))
(zero_extend:SI
(match_operand:HI 2 "nonimmediate_operand" "dm"))))]
""
"mulu %2,%0")
(define_insn ""
[(set (match_operand:SI 0 "general_operand" "=d")
(mult:SI (zero_extend:SI
(match_operand:HI 1 "nonimmediate_operand" "%0"))
(match_operand:SI 2 "const_int_operand" "n")))]
""
"mulu %2,%0")
(define_insn "muldf3"
[(set (match_operand:DF 0 "register_operand" "=f")
(mult:DF (match_operand:DF 1 "nonimmediate_operand" "%f")
(match_operand:DF 2 "nonimmediate_operand" "fm")))]
"TARGET_CE"
"fmul%.d %2,%1,%0")
(define_insn "mulsf3"
[(set (match_operand:SF 0 "register_operand" "=f")
(mult:SF (match_operand:SF 1 "nonimmediate_operand" "%f")
(match_operand:SF 2 "nonimmediate_operand" "fm")))]
"TARGET_CE"
"fmul%.s %2,%1,%0")
;; divide instructions
(define_insn "divhi3"
[(set (match_operand:HI 0 "general_operand" "=d")
(div:HI (match_operand:HI 1 "general_operand" "0")
(match_operand:HI 2 "general_operand" "dmn")))]
""
"extl %0\;divs %2,%0")
(define_insn "divhisi3"
[(set (match_operand:HI 0 "general_operand" "=d")
(truncate:HI
(div:SI
(match_operand:SI 1 "general_operand" "0")
(sign_extend:SI (match_operand:HI 2 "nonimmediate_operand" "dm")))))]
""
"divs %2,%0")
(define_insn ""
[(set (match_operand:HI 0 "general_operand" "=d")
(truncate:HI (div:SI (match_operand:SI 1 "general_operand" "0")
(match_operand:SI 2 "const_int_operand" "n"))))]
""
"divs %2,%0")
(define_insn "divsi3"
[(set (match_operand:SI 0 "general_operand" "=d")
(div:SI (match_operand:SI 1 "general_operand" "0")
(match_operand:SI 2 "general_operand" "dmsK")))]
"TARGET_68020"
"divs%.l %2,%0,%0")
(define_insn "udivhi3"
[(set (match_operand:HI 0 "general_operand" "=d")
(udiv:HI (match_operand:HI 1 "general_operand" "0")
(match_operand:HI 2 "general_operand" "dmn")))]
""
"and%.l %#0xFFFF,%0\;divu %2,%0")
(define_insn "udivhisi3"
[(set (match_operand:HI 0 "general_operand" "=d")
(truncate:HI
(udiv:SI
(match_operand:SI 1 "general_operand" "0")
(zero_extend:SI (match_operand:HI 2 "nonimmediate_operand" "dm")))))]
""
"divu %2,%0")
(define_insn ""
[(set (match_operand:HI 0 "general_operand" "=d")
(truncate:HI (udiv:SI (match_operand:SI 1 "nonimmediate_operand" "0")
(match_operand:HI 2 "const_int_operand" "n"))))]
""
"divu %2,%0")
(define_insn "udivsi3"
[(set (match_operand:SI 0 "general_operand" "=d")
(udiv:SI (match_operand:SI 1 "general_operand" "0")
(match_operand:SI 2 "general_operand" "dmsK")))]
"TARGET_68020"
"divu%.l %2,%0,%0")
(define_insn "divdf3"
[(set (match_operand:DF 0 "register_operand" "=f,f,f")
(div:DF (match_operand:DF 1 "nonimmediate_operand" "f,f,m")
(match_operand:DF 2 "nonimmediate_operand" "f,m,f")))]
"TARGET_CE"
"@
fdiv%.d %2,%1,%0
fdiv%.d %2,%1,%0
frdiv%.d %1,%2,%0")
(define_insn "divsf3"
[(set (match_operand:SF 0 "register_operand" "=f,f,f")
(div:SF (match_operand:SF 1 "nonimmediate_operand" "f,f,m")
(match_operand:SF 2 "nonimmediate_operand" "f,m,f")))]
"TARGET_CE"
"@
fdiv%.s %2,%1,%0
fdiv%.s %2,%1,%0
frdiv%.s %1,%2,%0")
;; Remainder instructions.
(define_insn "modhi3"
[(set (match_operand:HI 0 "general_operand" "=d")
(mod:HI (match_operand:HI 1 "general_operand" "0")
(match_operand:HI 2 "general_operand" "dmn")))]
""
"extl %0\;divs %2,%0\;swap %0")
(define_insn "modhisi3"
[(set (match_operand:HI 0 "general_operand" "=d")
(truncate:HI
(mod:SI
(match_operand:SI 1 "general_operand" "0")
(sign_extend:SI (match_operand:HI 2 "nonimmediate_operand" "dm")))))]
""
"divs %2,%0\;swap %0")
(define_insn ""
[(set (match_operand:HI 0 "general_operand" "=d")
(truncate:HI (mod:SI (match_operand:SI 1 "general_operand" "0")
(match_operand:SI 2 "const_int_operand" "n"))))]
""
"divs %2,%0\;swap %0")
(define_insn "umodhi3"
[(set (match_operand:HI 0 "general_operand" "=d")
(umod:HI (match_operand:HI 1 "general_operand" "0")
(match_operand:HI 2 "general_operand" "dmn")))]
""
"and%.l %#0xFFFF,%0\;divu %2,%0\;swap %0")
(define_insn "umodhisi3"
[(set (match_operand:HI 0 "general_operand" "=d")
(truncate:HI
(umod:SI
(match_operand:SI 1 "general_operand" "0")
(zero_extend:SI (match_operand:HI 2 "nonimmediate_operand" "dm")))))]
""
"divu %2,%0\;swap %0")
(define_insn ""
[(set (match_operand:HI 0 "general_operand" "=d")
(truncate:HI (umod:SI (match_operand:SI 1 "general_operand" "0")
(match_operand:SI 2 "const_int_operand" "n"))))]
""
"divu %2,%0\;swap %0")
(define_insn "divmodsi4"
[(set (match_operand:SI 0 "general_operand" "=d")
(div:SI (match_operand:SI 1 "general_operand" "0")
(match_operand:SI 2 "general_operand" "dmsK")))
(set (match_operand:SI 3 "general_operand" "=d")
(mod:SI (match_dup 1) (match_dup 2)))]
"TARGET_68020"
"divs%.l %2,%0,%3")
(define_insn "udivmodsi4"
[(set (match_operand:SI 0 "general_operand" "=d")
(udiv:SI (match_operand:SI 1 "general_operand" "0")
(match_operand:SI 2 "general_operand" "dmsK")))
(set (match_operand:SI 3 "general_operand" "=d")
(umod:SI (match_dup 1) (match_dup 2)))]
"TARGET_68020"
"divu%.l %2,%0,%3")
;; logical-and instructions
(define_insn "andsi3"
[(set (match_operand:SI 0 "general_operand" "=m,d")
(and:SI (match_operand:SI 1 "general_operand" "%0,0")
(match_operand:SI 2 "general_operand" "dKs,dmKs")))]
""
"*
{
if (GET_CODE (operands[2]) == CONST_INT
&& (INTVAL (operands[2]) | 0xffff) == 0xffffffff
&& (DATA_REG_P (operands[0])
|| offsettable_memref_p (operands[0])))
{
if (GET_CODE (operands[0]) != REG)
operands[0] = adj_offsettable_operand (operands[0], 2);
operands[2] = GEN_INT (INTVAL (operands[2]) & 0xffff);
/* Do not delete a following tstl %0 insn; that would be incorrect. */
CC_STATUS_INIT;
if (operands[2] == const0_rtx)
return \"clr%.w %0\";
return \"and%.w %2,%0\";
}
return \"and%.l %2,%0\";
}")
(define_insn "andhi3"
[(set (match_operand:HI 0 "general_operand" "=m,d")
(and:HI (match_operand:HI 1 "general_operand" "%0,0")
(match_operand:HI 2 "general_operand" "dn,dmn")))]
""
"and%.w %2,%0")
(define_insn "andqi3"
[(set (match_operand:QI 0 "general_operand" "=m,d")
(and:QI (match_operand:QI 1 "general_operand" "%0,0")
(match_operand:QI 2 "general_operand" "dn,dmn")))]
""
"and%.b %2,%0")
;; inclusive-or instructions
(define_insn "iorsi3"
[(set (match_operand:SI 0 "general_operand" "=m,d")
(ior:SI (match_operand:SI 1 "general_operand" "%0,0")
(match_operand:SI 2 "general_operand" "dKs,dmKs")))]
""
"*
{
register int logval;
if (GET_CODE (operands[2]) == CONST_INT
&& INTVAL (operands[2]) >> 16 == 0
&& (DATA_REG_P (operands[0])
|| offsettable_memref_p (operands[0])))
{
if (GET_CODE (operands[0]) != REG)
operands[0] = adj_offsettable_operand (operands[0], 2);
/* Do not delete a following tstl %0 insn; that would be incorrect. */
CC_STATUS_INIT;
return \"or%.w %2,%0\";
}
if (GET_CODE (operands[2]) == CONST_INT
&& (logval = exact_log2 (INTVAL (operands[2]))) >= 0
&& (DATA_REG_P (operands[0])
|| offsettable_memref_p (operands[0])))
{
if (DATA_REG_P (operands[0]))
operands[1] = GEN_INT (logval);
else
{
operands[0]
= adj_offsettable_operand (operands[0], 3 - (logval / 8));
operands[1] = GEN_INT (logval % 8);
}
return \"bset %1,%0\";
}
return \"or%.l %2,%0\";
}")
(define_insn "iorhi3"
[(set (match_operand:HI 0 "general_operand" "=m,d")
(ior:HI (match_operand:HI 1 "general_operand" "%0,0")
(match_operand:HI 2 "general_operand" "dn,dmn")))]
""
"or%.w %2,%0")
(define_insn "iorqi3"
[(set (match_operand:QI 0 "general_operand" "=m,d")
(ior:QI (match_operand:QI 1 "general_operand" "%0,0")
(match_operand:QI 2 "general_operand" "dn,dmn")))]
""
"or%.b %2,%0")
;; xor instructions
(define_insn "xorsi3"
[(set (match_operand:SI 0 "general_operand" "=do,m")
(xor:SI (match_operand:SI 1 "general_operand" "%0,0")
(match_operand:SI 2 "general_operand" "di,dKs")))]
""
"*
{
if (GET_CODE (operands[2]) == CONST_INT
&& INTVAL (operands[2]) >> 16 == 0
&& (offsettable_memref_p (operands[0]) || DATA_REG_P (operands[0])))
{
if (! DATA_REG_P (operands[0]))
operands[0] = adj_offsettable_operand (operands[0], 2);
/* Do not delete a following tstl %0 insn; that would be incorrect. */
CC_STATUS_INIT;
return \"eor%.w %2,%0\";
}
return \"eor%.l %2,%0\";
}")
(define_insn "xorhi3"
[(set (match_operand:HI 0 "general_operand" "=dm")
(xor:HI (match_operand:HI 1 "general_operand" "%0")
(match_operand:HI 2 "general_operand" "dn")))]
""
"eor%.w %2,%0")
(define_insn "xorqi3"
[(set (match_operand:QI 0 "general_operand" "=dm")
(xor:QI (match_operand:QI 1 "general_operand" "%0")
(match_operand:QI 2 "general_operand" "dn")))]
""
"eor%.b %2,%0")
;; negation instructions
(define_insn "negsi2"
[(set (match_operand:SI 0 "general_operand" "=dm")
(neg:SI (match_operand:SI 1 "general_operand" "0")))]
""
"neg%.l %0")
(define_insn "neghi2"
[(set (match_operand:HI 0 "general_operand" "=dm")
(neg:HI (match_operand:HI 1 "general_operand" "0")))]
""
"neg%.w %0")
(define_insn "negqi2"
[(set (match_operand:QI 0 "general_operand" "=dm")
(neg:QI (match_operand:QI 1 "general_operand" "0")))]
""
"neg%.b %0")
(define_insn "negsf2"
[(set (match_operand:SF 0 "register_operand" "=f")
(neg:SF (match_operand:SF 1 "nonimmediate_operand" "fm")))]
"TARGET_CE"
"fneg%.s %1,%0")
(define_insn "negdf2"
[(set (match_operand:DF 0 "register_operand" "=f")
(neg:DF (match_operand:DF 1 "nonimmediate_operand" "fm")))]
"TARGET_CE"
"fneg%.d %1,%0")
;; Absolute value instructions
(define_insn "abssf2"
[(set (match_operand:SF 0 "register_operand" "=f")
(abs:SF (match_operand:SF 1 "nonimmediate_operand" "fm")))]
"TARGET_CE"
"fabs%.s %1,%0")
(define_insn "absdf2"
[(set (match_operand:DF 0 "register_operand" "=f")
(abs:DF (match_operand:DF 1 "nonimmediate_operand" "fm")))]
"TARGET_CE"
"fabs%.d %1,%0")
;; Square root instructions
(define_insn "sqrtsf2"
[(set (match_operand:SF 0 "register_operand" "=f")
(sqrt:SF (match_operand:SF 1 "nonimmediate_operand" "fm")))]
"TARGET_CE"
"fsqrt%.s %1,%0")
(define_insn "sqrtdf2"
[(set (match_operand:DF 0 "register_operand" "=f")
(sqrt:DF (match_operand:DF 1 "nonimmediate_operand" "fm")))]
"TARGET_CE"
"fsqrt%.d %1,%0")
;; one complement instructions
(define_insn "one_cmplsi2"
[(set (match_operand:SI 0 "general_operand" "=dm")
(not:SI (match_operand:SI 1 "general_operand" "0")))]
""
"not%.l %0")
(define_insn "one_cmplhi2"
[(set (match_operand:HI 0 "general_operand" "=dm")
(not:HI (match_operand:HI 1 "general_operand" "0")))]
""
"not%.w %0")
(define_insn "one_cmplqi2"
[(set (match_operand:QI 0 "general_operand" "=dm")
(not:QI (match_operand:QI 1 "general_operand" "0")))]
""
"not%.b %0")
;; arithmetic shift instructions
;; We don't need the shift memory by 1 bit instruction
(define_insn "ashlsi3"
[(set (match_operand:SI 0 "general_operand" "=d")
(ashift:SI (match_operand:SI 1 "general_operand" "0")
(match_operand:SI 2 "general_operand" "dI")))]
""
"asl%.l %2,%0")
(define_insn "ashlhi3"
[(set (match_operand:HI 0 "general_operand" "=d")
(ashift:HI (match_operand:HI 1 "general_operand" "0")
(match_operand:HI 2 "general_operand" "dI")))]
""
"asl%.w %2,%0")
(define_insn "ashlqi3"
[(set (match_operand:QI 0 "general_operand" "=d")
(ashift:QI (match_operand:QI 1 "general_operand" "0")
(match_operand:QI 2 "general_operand" "dI")))]
""
"asl%.b %2,%0")
(define_insn "ashrsi3"
[(set (match_operand:SI 0 "general_operand" "=d")
(ashiftrt:SI (match_operand:SI 1 "general_operand" "0")
(match_operand:SI 2 "general_operand" "dI")))]
""
"asr%.l %2,%0")
(define_insn "ashrhi3"
[(set (match_operand:HI 0 "general_operand" "=d")
(ashiftrt:HI (match_operand:HI 1 "general_operand" "0")
(match_operand:HI 2 "general_operand" "dI")))]
""
"asr%.w %2,%0")
(define_insn "ashrqi3"
[(set (match_operand:QI 0 "general_operand" "=d")
(ashiftrt:QI (match_operand:QI 1 "general_operand" "0")
(match_operand:QI 2 "general_operand" "dI")))]
""
"asr%.b %2,%0")
;; logical shift instructions
(define_insn "lshrsi3"
[(set (match_operand:SI 0 "general_operand" "=d")
(lshiftrt:SI (match_operand:SI 1 "general_operand" "0")
(match_operand:SI 2 "general_operand" "dI")))]
""
"lsr%.l %2,%0")
(define_insn "lshrhi3"
[(set (match_operand:HI 0 "general_operand" "=d")
(lshiftrt:HI (match_operand:HI 1 "general_operand" "0")
(match_operand:HI 2 "general_operand" "dI")))]
""
"lsr%.w %2,%0")
(define_insn "lshrqi3"
[(set (match_operand:QI 0 "general_operand" "=d")
(lshiftrt:QI (match_operand:QI 1 "general_operand" "0")
(match_operand:QI 2 "general_operand" "dI")))]
""
"lsr%.b %2,%0")
;; rotate instructions
(define_insn "rotlsi3"
[(set (match_operand:SI 0 "general_operand" "=d")
(rotate:SI (match_operand:SI 1 "general_operand" "0")
(match_operand:SI 2 "general_operand" "dI")))]
""
"rol%.l %2,%0")
(define_insn "rotlhi3"
[(set (match_operand:HI 0 "general_operand" "=d")
(rotate:HI (match_operand:HI 1 "general_operand" "0")
(match_operand:HI 2 "general_operand" "dI")))]
""
"rol%.w %2,%0")
(define_insn "rotlqi3"
[(set (match_operand:QI 0 "general_operand" "=d")
(rotate:QI (match_operand:QI 1 "general_operand" "0")
(match_operand:QI 2 "general_operand" "dI")))]
""
"rol%.b %2,%0")
(define_insn "rotrsi3"
[(set (match_operand:SI 0 "general_operand" "=d")
(rotatert:SI (match_operand:SI 1 "general_operand" "0")
(match_operand:SI 2 "general_operand" "dI")))]
""
"ror%.l %2,%0")
(define_insn "rotrhi3"
[(set (match_operand:HI 0 "general_operand" "=d")
(rotatert:HI (match_operand:HI 1 "general_operand" "0")
(match_operand:HI 2 "general_operand" "dI")))]
""
"ror%.w %2,%0")
(define_insn "rotrqi3"
[(set (match_operand:QI 0 "general_operand" "=d")
(rotatert:QI (match_operand:QI 1 "general_operand" "0")
(match_operand:QI 2 "general_operand" "dI")))]
""
"ror%.b %2,%0")
;; Special cases of bit-field insns which we should
;; recognize in preference to the general case.
;; These handle aligned 8-bit and 16-bit fields,
;; which can usually be done with move instructions.
(define_insn ""
[(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+do")
(match_operand:SI 1 "const_int_operand" "i")
(match_operand:SI 2 "const_int_operand" "i"))
(match_operand:SI 3 "general_operand" "d"))]
"TARGET_68020 && TARGET_BITFIELD
&& (INTVAL (operands[1]) == 8 || INTVAL (operands[1]) == 16)
&& INTVAL (operands[2]) % INTVAL (operands[1]) == 0
&& (GET_CODE (operands[0]) == REG
|| ! mode_dependent_address_p (XEXP (operands[0], 0)))"
"*
{
if (REG_P (operands[0]))
{
if (INTVAL (operands[1]) + INTVAL (operands[2]) != 32)
return \"bfins %3,[%c2,%c1]%0\";
}
else
operands[0]
= adj_offsettable_operand (operands[0], INTVAL (operands[2]) / 8);
if (GET_CODE (operands[3]) == MEM)
operands[3] = adj_offsettable_operand (operands[3],
(32 - INTVAL (operands[1])) / 8);
if (INTVAL (operands[1]) == 8)
return \"mov%.b %3,%0\";
return \"mov%.w %3,%0\";
}")
(define_insn ""
[(set (match_operand:SI 0 "general_operand" "=&d")
(zero_extract:SI (match_operand:SI 1 "register_operand" "do")
(match_operand:SI 2 "const_int_operand" "i")
(match_operand:SI 3 "const_int_operand" "i")))]
"TARGET_68020 && TARGET_BITFIELD
&& (INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 16)
&& INTVAL (operands[3]) % INTVAL (operands[2]) == 0
&& (GET_CODE (operands[1]) == REG
|| ! mode_dependent_address_p (XEXP (operands[1], 0)))"
"*
{
if (REG_P (operands[1]))
{
if (INTVAL (operands[2]) + INTVAL (operands[3]) != 32)
return \"bfextu [%c3,%c2]%1,%0\";
}
else
operands[1]
= adj_offsettable_operand (operands[1], INTVAL (operands[3]) / 8);
output_asm_insn (\"clrl %0\", operands);
if (GET_CODE (operands[0]) == MEM)
operands[0] = adj_offsettable_operand (operands[0],
(32 - INTVAL (operands[1])) / 8);
if (INTVAL (operands[2]) == 8)
return \"mov%.b %1,%0\";
return \"mov%.w %1,%0\";
}")
(define_insn ""
[(set (match_operand:SI 0 "general_operand" "=d")
(sign_extract:SI (match_operand:SI 1 "register_operand" "do")
(match_operand:SI 2 "const_int_operand" "i")
(match_operand:SI 3 "const_int_operand" "i")))]
"TARGET_68020 && TARGET_BITFIELD
&& (INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 16)
&& INTVAL (operands[3]) % INTVAL (operands[2]) == 0
&& (GET_CODE (operands[1]) == REG
|| ! mode_dependent_address_p (XEXP (operands[1], 0)))"
"*
{
if (REG_P (operands[1]))
{
if (INTVAL (operands[2]) + INTVAL (operands[3]) != 32)
return \"bfexts [%c3,%c2]%1,%0\";
}
else
operands[1]
= adj_offsettable_operand (operands[1], INTVAL (operands[3]) / 8);
if (INTVAL (operands[2]) == 8)
return \"mov%.b %1,%0\;extb%.l %0\";
return \"mov%.w %1,%0\;ext%.l %0\";
}")
;; Bit field instructions, general cases.
;; "o,d" constraint causes a nonoffsettable memref to match the "o"
;; so that its address is reloaded.
(define_expand "extv"
[(set (match_operand:SI 0 "general_operand" "")
(sign_extract:SI (match_operand:SI 1 "general_operand" "")
(match_operand:SI 2 "general_operand" "")
(match_operand:SI 3 "general_operand" "")))]
"TARGET_68020 && TARGET_BITFIELD"
"")
(define_insn ""
[(set (match_operand:SI 0 "general_operand" "=d")
(sign_extract:SI (match_operand:QI 1 "memory_operand" "o")
(match_operand:SI 2 "general_operand" "di")
(match_operand:SI 3 "general_operand" "di")))]
"TARGET_68020 && TARGET_BITFIELD"
"bfexts [%c3,%c2]%1,%0")
(define_expand "extzv"
[(set (match_operand:SI 0 "general_operand" "")
(zero_extract:SI (match_operand:SI 1 "general_operand" "")
(match_operand:SI 2 "general_operand" "")
(match_operand:SI 3 "general_operand" "")))]
"TARGET_68020 && TARGET_BITFIELD"
"")
(define_insn ""
[(set (match_operand:SI 0 "general_operand" "=d")
(zero_extract:SI (match_operand:QI 1 "memory_operand" "o")
(match_operand:SI 2 "general_operand" "di")
(match_operand:SI 3 "general_operand" "di")))]
"TARGET_68020 && TARGET_BITFIELD"
"bfextu [%c3,%c2]%1,%0")
(define_insn ""
[(set (zero_extract:SI (match_operand:QI 0 "memory_operand" "+o")
(match_operand:SI 1 "general_operand" "di")
(match_operand:SI 2 "general_operand" "di"))
(xor:SI (zero_extract:SI (match_dup 0) (match_dup 1) (match_dup 2))
(match_operand:SI 3 "const_int_operand" "i,i")))]
"TARGET_68020 && TARGET_BITFIELD
&& (INTVAL (operands[3]) == -1
|| (GET_CODE (operands[1]) == CONST_INT
&& (~ INTVAL (operands[3]) & ((1 << INTVAL (operands[1]))- 1)) == 0))"
"*
{
CC_STATUS_INIT;
return \"bfchg [%c2,%c1]%0\";
}")
(define_insn ""
[(set (zero_extract:SI (match_operand:QI 0 "memory_operand" "+o")
(match_operand:SI 1 "general_operand" "di")
(match_operand:SI 2 "general_operand" "di"))
(const_int 0))]
"TARGET_68020 && TARGET_BITFIELD"
"*
{
CC_STATUS_INIT;
return \"bfclr [%c2,%c1]%0\";
}")
(define_insn ""
[(set (zero_extract:SI (match_operand:QI 0 "memory_operand" "+o")
(match_operand:SI 1 "general_operand" "di")
(match_operand:SI 2 "general_operand" "di"))
(const_int -1))]
"TARGET_68020 && TARGET_BITFIELD"
"*
{
CC_STATUS_INIT;
return \"bfset [%c2,%c1]%0\";
}")
(define_expand "insv"
[(set (zero_extract:SI (match_operand:SI 0 "general_operand" "")
(match_operand:SI 1 "general_operand" "")
(match_operand:SI 2 "general_operand" ""))
(match_operand:SI 3 "general_operand" ""))]
"TARGET_68020 && TARGET_BITFIELD"
"")
(define_insn ""
[(set (zero_extract:SI (match_operand:QI 0 "memory_operand" "+o")
(match_operand:SI 1 "general_operand" "di")
(match_operand:SI 2 "general_operand" "di"))
(match_operand:SI 3 "general_operand" "d"))]
"TARGET_68020 && TARGET_BITFIELD"
"bfins %3,[%c2,%c1]%0")
;; Now recognize bit field insns that operate on registers
;; (or at least were intended to do so).
(define_insn ""
[(set (match_operand:SI 0 "general_operand" "=d")
(sign_extract:SI (match_operand:SI 1 "register_operand" "d")
(match_operand:SI 2 "general_operand" "di")
(match_operand:SI 3 "general_operand" "di")))]
"TARGET_68020 && TARGET_BITFIELD"
"bfexts [%c3,%c2]%1,%0")
(define_insn ""
[(set (match_operand:SI 0 "general_operand" "=d")
(zero_extract:SI (match_operand:SI 1 "register_operand" "d")
(match_operand:SI 2 "general_operand" "di")
(match_operand:SI 3 "general_operand" "di")))]
"TARGET_68020 && TARGET_BITFIELD"
"bfextu [%c3,%c2]%1,%0")
(define_insn ""
[(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+d")
(match_operand:SI 1 "general_operand" "di")
(match_operand:SI 2 "general_operand" "di"))
(const_int 0))]
"TARGET_68020 && TARGET_BITFIELD"
"*
{
CC_STATUS_INIT;
return \"bfclr [%c2,%c1]%0\";
}")
(define_insn ""
[(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+d")
(match_operand:SI 1 "general_operand" "di")
(match_operand:SI 2 "general_operand" "di"))
(const_int -1))]
"TARGET_68020 && TARGET_BITFIELD"
"*
{
CC_STATUS_INIT;
return \"bfset [%c2,%c1]%0\";
}")
(define_insn ""
[(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+d")
(match_operand:SI 1 "general_operand" "di")
(match_operand:SI 2 "general_operand" "di"))
(match_operand:SI 3 "general_operand" "d"))]
"TARGET_68020 && TARGET_BITFIELD"
"*
{
return \"bfins %3,[%c2,%c1]%0\";
}")
;; Special patterns for optimizing bit-field instructions.
(define_insn ""
[(set (cc0)
(zero_extract:SI (match_operand:QI 0 "memory_operand" "o")
(match_operand:SI 1 "const_int_operand" "i")
(match_operand:SI 2 "general_operand" "di")))]
"TARGET_68020 && TARGET_BITFIELD"
"*
{
if (operands[1] == const1_rtx
&& GET_CODE (operands[2]) == CONST_INT)
{
int width = GET_CODE (operands[0]) == REG ? 31 : 7;
return output_btst (operands, GEN_INT (width - INTVAL (operands[2])),
operands[0], insn, 1000);
/* Pass 1000 as SIGNPOS argument so that btst will
not think we are testing the sign bit for an `and'
and assume that nonzero implies a negative result. */
}
if (INTVAL (operands[1]) != 32)
cc_status.flags = CC_NOT_NEGATIVE;
return \"bftst [%c2,%c1]%0\";
}")
;;; now handle the register cases
(define_insn ""
[(set (cc0)
(zero_extract:SI (match_operand:SI 0 "register_operand" "d")
(match_operand:SI 1 "const_int_operand" "i")
(match_operand:SI 2 "general_operand" "di")))]
"TARGET_68020 && TARGET_BITFIELD"
"*
{
if (operands[1] == const1_rtx
&& GET_CODE (operands[2]) == CONST_INT)
{
int width = GET_CODE (operands[0]) == REG ? 31 : 7;
return output_btst (operands, GEN_INT (width - INTVAL (operands[2])),
operands[0], insn, 1000);
/* Pass 1000 as SIGNPOS argument so that btst will
not think we are testing the sign bit for an `and'
and assume that nonzero implies a negative result. */
}
if (INTVAL (operands[1]) != 32)
cc_status.flags = CC_NOT_NEGATIVE;
return \"bftst [%c2,%c1]%0\";
}")
(define_insn "seq"
[(set (match_operand:QI 0 "general_operand" "=d")
(eq:QI (cc0) (const_int 0)))]
""
"*
cc_status = cc_prev_status;
OUTPUT_JUMP (\"seq %0\", \"fseq %0\", \"seq %0\");
")
(define_insn "sne"
[(set (match_operand:QI 0 "general_operand" "=d")
(ne:QI (cc0) (const_int 0)))]
""
"*
cc_status = cc_prev_status;
OUTPUT_JUMP (\"sne %0\", \"fsneq %0\", \"sne %0\");
")
(define_insn "sgt"
[(set (match_operand:QI 0 "general_operand" "=d")
(gt:QI (cc0) (const_int 0)))]
""
"*
cc_status = cc_prev_status;
OUTPUT_JUMP (\"sgt %0\", \"fsgt %0\", \"and%.b %#0xc,%!\;sgt %0\");
")
(define_insn "sgtu"
[(set (match_operand:QI 0 "general_operand" "=d")
(gtu:QI (cc0) (const_int 0)))]
""
"* cc_status = cc_prev_status;
return \"shi %0\"; ")
(define_insn "slt"
[(set (match_operand:QI 0 "general_operand" "=d")
(lt:QI (cc0) (const_int 0)))]
""
"* cc_status = cc_prev_status;
OUTPUT_JUMP (\"slt %0\", \"fslt %0\", \"smi %0\"); ")
(define_insn "sltu"
[(set (match_operand:QI 0 "general_operand" "=d")
(ltu:QI (cc0) (const_int 0)))]
""
"* cc_status = cc_prev_status;
return \"scs %0\"; ")
(define_insn "sge"
[(set (match_operand:QI 0 "general_operand" "=d")
(ge:QI (cc0) (const_int 0)))]
""
"* cc_status = cc_prev_status;
OUTPUT_JUMP (\"sge %0\", \"fsge %0\", \"spl %0\"); ")
(define_insn "sgeu"
[(set (match_operand:QI 0 "general_operand" "=d")
(geu:QI (cc0) (const_int 0)))]
""
"* cc_status = cc_prev_status;
return \"scc %0\"; ")
(define_insn "sle"
[(set (match_operand:QI 0 "general_operand" "=d")
(le:QI (cc0) (const_int 0)))]
""
"*
cc_status = cc_prev_status;
OUTPUT_JUMP (\"sle %0\", \"fsle %0\", \"and%.b %#0xc,%!\;sle %0\");
")
(define_insn "sleu"
[(set (match_operand:QI 0 "general_operand" "=d")
(leu:QI (cc0) (const_int 0)))]
""
"* cc_status = cc_prev_status;
return \"sls %0\"; ")
;; Basic conditional jump instructions.
(define_insn "beq"
[(set (pc)
(if_then_else (eq (cc0)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"*
{
OUTPUT_JUMP (\"jeq %l0\", \"fbeq %l0\", \"jeq %l0\");
}")
(define_insn "bne"
[(set (pc)
(if_then_else (ne (cc0)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"*
{
OUTPUT_JUMP (\"jne %l0\", \"fbneq %l0\", \"jne %l0\");
}")
(define_insn "bgt"
[(set (pc)
(if_then_else (gt (cc0)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"*
OUTPUT_JUMP (\"jgt %l0\", \"fbgt %l0\", \"and%.b %#0xc,%!\;jgt %l0\");
")
(define_insn "bgtu"
[(set (pc)
(if_then_else (gtu (cc0)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"*
return \"jhi %l0\";
")
(define_insn "blt"
[(set (pc)
(if_then_else (lt (cc0)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"*
OUTPUT_JUMP (\"jlt %l0\", \"fblt %l0\", \"jmi %l0\");
")
(define_insn "bltu"
[(set (pc)
(if_then_else (ltu (cc0)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"*
return \"jcs %l0\";
")
(define_insn "bge"
[(set (pc)
(if_then_else (ge (cc0)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"*
OUTPUT_JUMP (\"jge %l0\", \"fbge %l0\", \"jpl %l0\");
")
(define_insn "bgeu"
[(set (pc)
(if_then_else (geu (cc0)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"*
return \"jcc %l0\";
")
(define_insn "ble"
[(set (pc)
(if_then_else (le (cc0)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"*
OUTPUT_JUMP (\"jle %l0\", \"fble %l0\", \"and%.b %#0xc,%!\;jle %l0\");
")
(define_insn "bleu"
[(set (pc)
(if_then_else (leu (cc0)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"*
return \"jls %l0\";
")
;; Negated conditional jump instructions.
(define_insn ""
[(set (pc)
(if_then_else (eq (cc0)
(const_int 0))
(pc)
(label_ref (match_operand 0 "" ""))))]
""
"*
{
OUTPUT_JUMP (\"jne %l0\", \"fbneq %l0\", \"jne %l0\");
}")
(define_insn ""
[(set (pc)
(if_then_else (ne (cc0)
(const_int 0))
(pc)
(label_ref (match_operand 0 "" ""))))]
""
"*
{
OUTPUT_JUMP (\"jeq %l0\", \"fbeq %l0\", \"jeq %l0\");
}")
(define_insn ""
[(set (pc)
(if_then_else (gt (cc0)
(const_int 0))
(pc)
(label_ref (match_operand 0 "" ""))))]
""
"*
OUTPUT_JUMP (\"jle %l0\", \"fbngt %l0\", \"and%.b %#0xc,%!\;jle %l0\");
")
(define_insn ""
[(set (pc)
(if_then_else (gtu (cc0)
(const_int 0))
(pc)
(label_ref (match_operand 0 "" ""))))]
""
"*
return \"jls %l0\";
")
(define_insn ""
[(set (pc)
(if_then_else (lt (cc0)
(const_int 0))
(pc)
(label_ref (match_operand 0 "" ""))))]
""
"*
OUTPUT_JUMP (\"jge %l0\", \"fbnlt %l0\", \"jpl %l0\");
")
(define_insn ""
[(set (pc)
(if_then_else (ltu (cc0)
(const_int 0))
(pc)
(label_ref (match_operand 0 "" ""))))]
""
"*
return \"jcc %l0\";
")
(define_insn ""
[(set (pc)
(if_then_else (ge (cc0)
(const_int 0))
(pc)
(label_ref (match_operand 0 "" ""))))]
""
"*
OUTPUT_JUMP (\"jlt %l0\", \"fbnge %l0\", \"jmi %l0\");
")
(define_insn ""
[(set (pc)
(if_then_else (geu (cc0)
(const_int 0))
(pc)
(label_ref (match_operand 0 "" ""))))]
""
"*
return \"jcs %l0\";
")
(define_insn ""
[(set (pc)
(if_then_else (le (cc0)
(const_int 0))
(pc)
(label_ref (match_operand 0 "" ""))))]
""
"*
OUTPUT_JUMP (\"jgt %l0\", \"fbnle %l0\", \"and%.b %#0xc,%!\;jgt %l0\");
")
(define_insn ""
[(set (pc)
(if_then_else (leu (cc0)
(const_int 0))
(pc)
(label_ref (match_operand 0 "" ""))))]
""
"*
return \"jhi %l0\";
")
;; Subroutines of "casesi".
(define_expand "casesi_1"
[(set (match_operand:SI 3 "general_operand" "")
(plus:SI (match_operand:SI 0 "general_operand" "")
;; Note operand 1 has been negated!
(match_operand:SI 1 "immediate_operand" "")))
(set (cc0) (compare (match_operand:SI 2 "nonimmediate_operand" "")
(match_dup 3)))
(set (pc) (if_then_else (ltu (cc0) (const_int 0))
(label_ref (match_operand 4 "" "")) (pc)))]
""
"")
(define_expand "casesi_2"
[(set (match_operand:HI 0 "" "") (mem:HI (match_operand:SI 1 "" "")))
;; The USE here is so that at least one jump-insn will refer to the label,
;; to keep it alive in jump_optimize.
(parallel [(set (pc)
(plus:SI (pc) (sign_extend:SI (match_dup 0))))
(use (label_ref (match_operand 2 "" "")))])]
""
"")
;; Operand 0 is index (in bytes); operand 1 is minimum, operand 2 the maximum;
;; operand 3 is CODE_LABEL for the table;
;; operand 4 is the CODE_LABEL to go to if index out of range.
(define_expand "casesi"
;; We don't use these for generating the RTL, but we must describe
;; the operands here.
[(match_operand:HI 0 "general_operand" "")
(match_operand:SI 1 "immediate_operand" "")
(match_operand:SI 2 "general_operand" "")
(match_operand 3 "" "")
(match_operand 4 "" "")]
""
"
{
rtx table_elt_addr;
rtx index_diff;
operands[1] = negate_rtx (SImode, operands[1]);
index_diff = gen_reg_rtx (SImode);
/* Emit the first few insns. */
emit_insn (gen_casesi_1 (operands[0], operands[1], operands[2],
index_diff, operands[4]));
/* Construct a memory address. This may emit some insns. */
table_elt_addr
= memory_address_noforce
(HImode,
gen_rtx_PLUS (Pmode,
gen_rtx_MULT (Pmode, index_diff, GEN_INT (2)),
gen_rtx_LABEL_REF (Pmode, operands[3])));
/* Emit the last few insns. */
emit_insn (gen_casesi_2 (gen_reg_rtx (HImode), table_elt_addr, operands[3]));
DONE;
}")
;; Recognize one of the insns resulting from casesi_2.
(define_insn ""
[(set (pc)
(plus:SI (pc)
(sign_extend:SI (match_operand:HI 0 "general_operand" "r"))))
(use (label_ref (match_operand 1 "" "")))]
""
"*
return \"jmp pc@(2:B)[%0:W:B]\";
")
;; Unconditional and other jump instructions
(define_insn "jump"
[(set (pc)
(label_ref (match_operand 0 "" "")))]
""
"*
return \"jra %l0\";
")
(define_insn ""
[(set (pc)
(if_then_else
(ne (match_operand:HI 0 "general_operand" "d,m,g")
(const_int 0))
(label_ref (match_operand 1 "" ""))
(pc)))
(set (match_dup 0)
(plus:HI (match_dup 0)
(const_int -1)))]
""
"@
dbra %0,%l1
subq%.w %#1,%0\;jcc %l1
subq%.w %#1,%0\;cmp%.w %#-1,%0\;jne %l1")
(define_insn ""
[(set (pc)
(if_then_else
(ne (match_operand:SI 0 "general_operand" "d,m,g")
(const_int 0))
(label_ref (match_operand 1 "" ""))
(pc)))
(set (match_dup 0)
(plus:SI (match_dup 0)
(const_int -1)))]
""
"@
dbra %0,%l1\;clr%.w %0\;subq%.l %#1,%0\;jcc %l1
subq%.l %#1,%0\;jcc %l1
subq%.l %#1,%0\;cmp%.l %#-1,%0\;jne %l1")
;; dbra patterns that use REG_NOTES info generated by strength_reduce.
(define_expand "decrement_and_branch_until_zero"
[(parallel [(set (pc)
(if_then_else
(ge (match_operand:SI 0 "general_operand" "")
(const_int 1))
(label_ref (match_operand 1 "" ""))
(pc)))
(set (match_dup 0)
(plus:SI (match_dup 0)
(const_int -1)))])]
""
"")
(define_insn ""
[(set (pc)
(if_then_else
(ge (match_operand:SI 0 "general_operand" "d,m,g")
(const_int 1))
(label_ref (match_operand 1 "" ""))
(pc)))
(set (match_dup 0)
(plus:SI (match_dup 0)
(const_int -1)))]
"find_reg_note (insn, REG_NONNEG, 0)"
"@
dbra %0,%l1\;clrw %0\;subql %#1,%0\;jcc %l1
subq%.l %#1,%0\;jcc %l1
subq%.l %#1,%0\;cmp%.l %#-1,%0\;jne %l1")
;; Call subroutine with no return value.
(define_insn "call"
[(call (match_operand:QI 0 "memory_operand" "o")
(match_operand:SI 1 "general_operand" "g"))]
""
"*
{
rtx xoperands[2];
int size = XINT(operands[1],0);
if (size == 0)
output_asm_insn (\"sub%.l a0,a0\;jbsr %0\", operands);
else
{
xoperands[1] = GEN_INT (size/4);
output_asm_insn (\"mov%.l sp,a0\;pea %a1\", xoperands);
output_asm_insn (\"jbsr %0\", operands);
size = size + 4;
xoperands[1] = GEN_INT (size);
if (size <= 8)
output_asm_insn (\"addq%.l %1,sp\", xoperands);
else if (size < 0x8000)
output_asm_insn (\"add%.w %1,sp\", xoperands);
else
output_asm_insn (\"add%.l %1,sp\", xoperands);
}
return \"mov%.l a6@(-4),a0\";
}")
;; Call subroutine, returning value in operand 0
;; (which must be a hard register).
(define_insn "call_value"
[(set (match_operand 0 "" "=rf")
(call (match_operand:QI 1 "memory_operand" "o")
(match_operand:SI 2 "general_operand" "g")))]
""
"*
{
rtx xoperands[3];
int size = XINT(operands[2],0);
if (size == 0)
output_asm_insn(\"sub%.l a0,a0\;jbsr %1\", operands);
else
{
xoperands[2] = GEN_INT (size/4);
output_asm_insn (\"mov%.l sp,a0\;pea %a2\", xoperands);
output_asm_insn (\"jbsr %1\", operands);
size = size + 4;
xoperands[2] = GEN_INT (size);
if (size <= 8)
output_asm_insn (\"addq%.l %2,sp\", xoperands);
else if (size < 0x8000)
output_asm_insn (\"add%.w %2,sp\", xoperands);
else
output_asm_insn (\"add%.l %2,sp\", xoperands);
}
return \"mov%.l a6@(-4),a0\";
}")
;; Call subroutine returning any type.
(define_expand "untyped_call"
[(parallel [(call (match_operand 0 "" "")
(const_int 0))
(match_operand 1 "" "")
(match_operand 2 "" "")])]
""
"
{
int i;
emit_call_insn (GEN_CALL (operands[0], const0_rtx, NULL, const0_rtx));
for (i = 0; i < XVECLEN (operands[2], 0); i++)
{
rtx set = XVECEXP (operands[2], 0, i);
emit_move_insn (SET_DEST (set), SET_SRC (set));
}
/* The optimizer does not know that the call sets the function value
registers we stored in the result block. We avoid problems by
claiming that all hard registers are used and clobbered at this
point. */
emit_insn (gen_blockage ());
DONE;
}")
;; UNSPEC_VOLATILE is considered to use and clobber all hard registers and
;; all of memory. This blocks insns from being moved across this point.
(define_insn "blockage"
[(unspec_volatile [(const_int 0)] 0)]
""
"")
(define_insn "nop"
[(const_int 0)]
""
"nop")
;; This should not be used unless the add/sub insns can't be.
(define_insn ""
[(set (match_operand:SI 0 "general_operand" "=a")
(match_operand:QI 1 "address_operand" "p"))]
""
"lea %a1,%0")
;; This is the first machine-dependent peephole optimization.
;; It is useful when a floating value is returned from a function call
;; and then is moved into an FP register.
;; But it is mainly intended to test the support for these optimizations.
;Not applicable to Alliant -- floating results are returned in fp0
;(define_peephole
; [(set (reg:SI 15) (plus:SI (reg:SI 15) (const_int 4)))
; (set (match_operand:DF 0 "register_operand" "f")
; (match_operand:DF 1 "register_operand" "ad"))]
; "FP_REG_P (operands[0]) && ! FP_REG_P (operands[1])"
; "*
;{
; rtx xoperands[2];
; xoperands[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1);
; output_asm_insn (\"mov%.l %1,%@\", xoperands);
; output_asm_insn (\"mov%.l %1,%-\", operands);
; return \"fmove%.d %+,%0\";
;}
;")
/* Configuration for GNU C-compiler for Alliant FX computers.
Copyright (C) 1989, 1993 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, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* #defines that need visibility everywhere. */
#define FALSE 0
#define TRUE 1
/* This describes the machine the compiler is hosted on. */
#define HOST_BITS_PER_CHAR 8
#define HOST_BITS_PER_SHORT 16
#define HOST_BITS_PER_INT 32
#define HOST_BITS_PER_LONG 32
#define HOST_BITS_PER_LONGLONG 64
/* target machine dependencies.
tm.h is a symbolic link to the actual target specific file. */
#include "tm.h"
/* Arguments to use with `exit'. */
#define SUCCESS_EXIT_CODE 0
#define FATAL_EXIT_CODE 33
/* Subroutines for insn-output.c for the Gmicro.
Copyright (C) 1990, 1991, 1997, 1998, 1999 Free Software Foundation, Inc.
Contributed by Masanobu Yuhara, Fujitsu Laboratories LTD.
(yuhara@flab.fujitsu.co.jp)
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.
Among other things, the copyright
notice and this notice must be preserved on all copies.
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, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include "config.h"
#include "system.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 "function.h"
#include "insn-attr.h"
mypr (s, a1, a2, a3, a4, a5)
char *s;
int a1, a2, a3, a4, a5;
{
fprintf (stderr, s, a1, a2, a3, a4, a5);
}
myprcode (i)
int i;
{
if (i < 0 || i > 90)
fprintf (stderr, "code = %d\n", i);
else
fprintf (stderr, "code = %s\n", GET_RTX_NAME(i));
}
myabort (i)
int i;
{
fprintf (stderr, "myabort");
myprcode (i);
}
/* This is how to output an ascii string. */
/* See ASM_OUTPUT_ASCII in gmicro.h. */
output_ascii (file, p, size)
FILE *file;
char *p;
int size;
{
int i;
int in_quote = 0;
register int c;
fprintf (file, "\t.sdata ");
for (i = 0; i < size; i++)
{
c = p[i];
if (c >= ' ' && c < 0x7f)
{
if (!in_quote)
{
putc ('"', file);
in_quote = 1;
}
putc (c, file);
}
else
{
if (in_quote)
{
putc ('"', file);
in_quote = 0;
}
fprintf (file, "<%d>", c);
}
}
if (in_quote)
putc ('"', file);
putc ('\n', file);
}
/* call this when GET_CODE (index) is MULT. */
print_scaled_index (file, index)
FILE *file;
register rtx index;
{
register rtx ireg;
int scale;
if (GET_CODE (XEXP (index, 0)) == REG)
{
ireg = XEXP (index, 0);
scale = INTVAL (XEXP (index, 1));
}
else
{
ireg = XEXP (index, 1);
scale = INTVAL (XEXP (index, 0));
}
if (scale == 1)
fprintf (file, "%s", reg_names[REGNO (ireg)]);
else
fprintf (file, "%s*%d", reg_names[REGNO (ireg)], scale);
}
print_operand_address (file, addr)
FILE *file;
register rtx addr;
{
register rtx xtmp0, xtmp1, breg, ixreg;
int scale;
int needcomma = 0;
rtx offset;
fprintf (file, "@");
retry:
switch (GET_CODE (addr))
{
case MEM:
fprintf (file, "@");
addr = XEXP (addr, 0);
goto retry;
case REG:
fprintf (file, "%s", reg_names[REGNO (addr)]);
break;
case MULT:
print_scaled_index (file, addr);
break;
case PRE_DEC:
fprintf (file, "-%s", reg_names[REGNO (XEXP (addr, 0))]);
break;
case POST_INC:
fprintf (file, "%s+", reg_names[REGNO (XEXP (addr, 0))]);
break;
case PLUS:
xtmp0 = XEXP (addr, 0);
xtmp1 = XEXP (addr, 1);
ixreg = 0; breg = 0;
offset = 0;
if (CONSTANT_ADDRESS_P (xtmp0))
{
offset = xtmp0;
breg = xtmp1;
}
else if (CONSTANT_ADDRESS_P (xtmp1))
{
offset = xtmp1;
breg = xtmp0;
}
else
{
goto NOT_DISP;
}
if (REG_CODE_BASE_P (breg))
goto PRINT_MEM;
if (GET_CODE (breg) == MULT)
{
if (REG_CODE_INDEX_P (XEXP (breg, 0)))
{
ixreg = XEXP (breg, 0);
scale = INTVAL (XEXP (breg, 1));
breg = 0;
}
else
{
ixreg = XEXP (breg, 1);
scale = INTVAL (XEXP (breg, 0));
breg = 0;
}
goto PRINT_MEM;
}
/* GET_CODE (breg) must be PLUS here. */
xtmp0 = XEXP (breg, 0);
xtmp1 = XEXP (breg, 1);
if (REG_CODE_BASE_P (xtmp0))
{
breg = xtmp0;
xtmp0 = xtmp1;
}
else
{
breg = xtmp1;
/* xtmp0 = xtmp0; */
}
if (GET_CODE (xtmp0) == MULT)
{
if (REG_CODE_INDEX_P (XEXP (xtmp0, 0)))
{
ixreg = XEXP (xtmp0, 0);
scale = INTVAL (XEXP (xtmp0, 1));
}
else
{
ixreg = XEXP (xtmp0, 1);
scale = INTVAL (XEXP (xtmp0, 0));
}
}
else
{
ixreg = xtmp0;
scale = 1;
}
goto PRINT_MEM;
NOT_DISP:
if (REG_CODE_BASE_P (xtmp0))
{
breg = xtmp0;
xtmp0 = xtmp1;
}
else if (REG_CODE_BASE_P (xtmp1))
{
breg = xtmp1;
/* xtmp0 = xtmp0; */
}
else
goto NOT_BASE;
if (REG_CODE_INDEX_P (xtmp0))
{
ixreg = xtmp0;
scale = 1;
goto PRINT_MEM;
}
else if (CONSTANT_ADDRESS_P (xtmp0))
{
offset = xtmp0;
goto PRINT_MEM;
}
else if (GET_CODE (xtmp0) == MULT)
{
if (REG_CODE_INDEX_P (XEXP (xtmp0, 0)))
{
ixreg = XEXP (xtmp0, 0);
scale = INTVAL (XEXP (xtmp0, 1));
}
else
{
ixreg = XEXP (xtmp0, 1);
scale = INTVAL (XEXP (xtmp0, 0));
}
goto PRINT_MEM;
}
/* GET_CODE (xtmp0) must be PLUS. */
xtmp1 = XEXP (xtmp0, 1);
xtmp0 = XEXP (xtmp0, 0);
if (CONSTANT_ADDRESS_P (xtmp0))
{
offset = xtmp0;
xtmp0 = xtmp1;
}
else
{
offset = xtmp1;
/* xtmp0 = xtmp0; */
}
if (REG_CODE_INDEX_P (xtmp0))
{
ixreg = xtmp0;
}
else
{ /* GET_CODE (xtmp0) must be MULT. */
if (REG_CODE_INDEX_P (XEXP (xtmp0, 0)))
{
ixreg = XEXP (xtmp0, 0);
scale = INTVAL (XEXP (xtmp0, 1));
}
else
{
ixreg = XEXP (xtmp0, 1);
scale = INTVAL (XEXP (xtmp0, 0));
}
}
goto PRINT_MEM;
NOT_BASE:
if (GET_CODE (xtmp0) == PLUS)
{
ixreg = xtmp1;
/* xtmp0 = xtmp0; */
}
else
{
ixreg = xtmp0;
xtmp0 = xtmp1;
}
if (REG_CODE_INDEX_P (ixreg))
{
scale = 1;
}
else if (REG_CODE_INDEX_P (XEXP (ixreg, 0)))
{
scale = INTVAL (XEXP (ixreg, 1));
ixreg = XEXP (ixreg, 0);
}
else
{ /* was else if with no condition. OK ??? */
scale = INTVAL (XEXP (ixreg, 0));
ixreg = XEXP (ixreg, 1);
}
if (REG_CODE_BASE_P (XEXP (xtmp0, 0)))
{
breg = XEXP (xtmp0, 0);
offset = XEXP (xtmp0, 1);
}
else
{
breg = XEXP (xtmp0, 1);
offset = XEXP (xtmp0, 0);
}
PRINT_MEM:
if (breg == 0 && ixreg == 0)
{
output_address (offset);
break;
}
else if (ixreg == 0 && offset == 0)
{
fprintf (file, "%s", reg_names[REGNO (breg)]);
break;
}
else
{
fprintf (file, "(");
if (offset != 0)
{
output_addr_const (file, offset);
needcomma = 1;
}
if (breg != 0)
{
if (needcomma)
fprintf (file, ",");
fprintf (file, "%s", reg_names[REGNO (breg)]);
needcomma = 1;
}
if (ixreg != 0)
{
if (needcomma)
fprintf (file, ",");
fprintf (file, "%s", reg_names[REGNO (ixreg)]);
if (scale != 1)
fprintf (file,"*%d", scale);
}
fprintf (file, ")");
break;
}
default:
output_addr_const (file, addr);
}
}
/* 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 (GET_CODE (XEXP (addr, 0)) == PLUS)
addr = XEXP (addr, 0);
else if (GET_CODE (XEXP (addr, 1)) == PLUS)
addr = XEXP (addr, 1);
}
if (GET_CODE (addr) == REG)
return addr;
return 0;
}
/* Return the best assembler insn template
for moving operands[1] into operands[0] as a fullword. */
static char *
singlemove_string (operands)
rtx *operands;
{
if (FPU_REG_P (operands[0]) || FPU_REG_P (operands[1]))
{
if (GREG_P (operands[0]) || GREG_P (operands[1]))
{
myabort (101); /* Not Supported yet !! */
}
else
{
return "fmov.s %1,%0";
}
}
return "mov.w %1,%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)
myabort (102);
/* 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 ("sub.w %#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 ("sub.w %#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 (operands[0]);
if (optype1 == MEMOP)
addreg1 = find_addr_reg (operands[1]);
/* 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] = 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 ("add.w %#4,%0", &addreg0);
if (addreg1)
output_asm_insn ("add.w %#4,%0", &addreg1);
/* Do that word. */
output_asm_insn (singlemove_string (latehalf), latehalf);
/* Undo the adds we just did. */
if (addreg0)
output_asm_insn ("sub.w %#4,%0", &addreg0);
if (addreg1)
output_asm_insn ("sub.w %#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 ("add.w %#4,%0", &addreg0);
if (addreg1)
output_asm_insn ("add.w %#4,%0", &addreg1);
/* Do that word. */
output_asm_insn (singlemove_string (latehalf), latehalf);
/* Undo the adds we just did. */
if (addreg0)
output_asm_insn ("sub.w %#4,%0", &addreg0);
if (addreg1)
output_asm_insn ("sub.w %#4,%0", &addreg1);
return "";
}
/* Move const_double to floating point register (DF) */
char *
output_move_const_double (operands)
rtx *operands;
{
int code = standard_fpu_constant_p (operands[1]);
if (FPU_REG_P (operands[0]))
{
if (code != 0)
{
static char buf[40];
sprintf (buf, "fmvr from%d,%%0.d", code);
return buf;
}
else
{
return "fmov %1,%0.d";
}
}
else if (GREG_P (operands[0]))
{
rtx xoperands[2];
xoperands[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
xoperands[1] = GEN_INT (CONST_DOUBLE_HIGH (operands[1]));
output_asm_insn ("mov.w %1,%0", xoperands);
operands[1] = GEN_INT (CONST_DOUBLE_LOW (operands[1]));
return "mov.w %1,%0";
}
else
return output_move_double (operands); /* ?????? */
}
char *
output_move_const_single (operands)
rtx *operands;
{
int code = standard_fpu_constant_p (operands[1]);
static char buf[40];
if (FPU_REG_P (operands[0]))
{
if (code != 0)
{
sprintf (buf, "fmvr from%d,%%0.s", code);
return buf;
}
return "fmov.s %f1,%0";
}
else
return "mov.w %f1,%0";
}
/* Return nonzero if X, a CONST_DOUBLE, has a value that we can get
from the "fmvr" instruction of the Gmicro FPU.
The value, anded with 0xff, gives the code to use in fmovecr
to get the desired constant. */
u.i[0] = CONST_DOUBLE_LOW (x);
u.i[1] = CONST_DOUBLE_HIGH (x);
d = u.d;
if (d == 0.0) /* +0.0 */
return 0x0;
/* Note: there are various other constants available
but it is a nuisance to put in their values here. */
if (d == 1.0) /* +1.0 */
return 0x1;
/*
* Stuff that looks different if it's single or double
*/
if (GET_MODE (x) == SFmode)
{
if (d == S_PI)
return 0x2;
if (d == (S_PI / 2.0))
return 0x3;
if (d == S_E)
return 0x4;
if (d == S_LOGEof2)
return 0x5;
if (d == S_LOGEof10)
return 0x6;
if (d == S_LOG10of2)
return 0x7;
if (d == S_LOG10ofE)
return 0x8;
if (d == S_LOG2ofE)
return 0x9;
}
else
{
if (d == D_PI)
return 0x2;
if (d == (D_PI / 2.0))
return 0x3;
if (d == D_E)
return 0x4;
if (d == D_LOGEof2)
return 0x5;
if (d == D_LOGEof10)
return 0x6;
if (d == D_LOG10of2)
return 0x7;
if (d == D_LOG10ofE)
return 0x8;
if (d == D_LOG2ofE)
return 0x9;
}
return 0;
}
#undef S_PI
#undef D_PI
#undef S_E
#undef D_E
#undef S_LOGEof2
#undef D_LOGEof2
#undef S_LOGEof10
#undef D_LOGEof10
#undef S_LOG10of2
#undef D_LOG10of2
#undef S_LOG10ofE
#undef D_LOG10ofE
#undef S_LOG2ofE
#undef D_LOG2ofE
/* dest should be operand 0 */
/* imm should be operand 1 */
extern char *sub_imm_word ();
char *
add_imm_word (imm, dest, immp)
int imm;
rtx dest, *immp;
{
int is_reg, short_ok;
if (imm < 0)
{
*immp = GEN_INT (-imm);
return sub_imm_word (-imm, dest);
}
if (imm == 0)
return "mov:l.w #0,%0";
short_ok = short_format_ok (dest);
if (short_ok && imm <= 8)
return "add:q %1,%0.w";
if (imm < 128)
return "add:e %1,%0.w";
is_reg = (GET_CODE (dest) == REG);
if (is_reg)
return "add:l %1,%0.w";
if (short_ok)
return "add:i %1,%0.w";
return "add %1,%0.w";
}
char *
sub_imm_word (imm, dest, immp)
int imm;
rtx dest, *immp;
{
int is_reg, short_ok;
if (imm < 0 && imm != 0x80000000)
{
*immp = GEN_INT (-imm);
return add_imm_word (-imm, dest);
}
if (imm == 0)
return "mov:z.w #0,%0";
short_ok = short_format_ok (dest);
if (short_ok && imm <= 8)
return "sub:q %1,%0.w";
if (imm < 128)
return "sub:e %1,%0.w";
is_reg = (GET_CODE (dest) == REG);
if (is_reg)
return "sub:l %1,%0.w";
if (short_ok)
return "sub:i %1,%0.w";
return "sub %1,%0.w";
}
int
short_format_ok (x)
rtx x;
{
rtx x0, x1;
if (GET_CODE (x) == REG)
return 1;
if (GET_CODE (x) == MEM
&& GET_CODE (XEXP (x, 0)) == PLUS)
{
x0 = XEXP (XEXP (x, 0), 0);
x1 = XEXP (XEXP (x, 0), 1);
return ((GET_CODE (x0) == REG
&& CONSTANT_P (x1)
&& ((unsigned) (INTVAL (x1) + 0x8000) < 0x10000))
||
(GET_CODE (x1) == REG
&& CONSTANT_P (x0)
&& ((unsigned) (INTVAL (x0) + 0x8000) < 0x10000)));
}
return 0;
}
myoutput_sp_adjust (file, op, fsize)
FILE *file;
char *op;
int fsize;
{
if (fsize == 0)
;
else if (fsize < 8)
fprintf (file, "\t%s:q #%d,sp.w\n", op, fsize);
else if (fsize < 128)
fprintf (file, "\t%s:e #%d,sp.w\n", op, fsize);
else
fprintf (file, "\t%s:l #%d,sp.w\n", op, fsize);
}
char *
mov_imm_word (imm, dest)
int imm;
rtx dest;
{
int is_reg, short_ok;
if (imm == 0)
return "mov:z.w #0,%0";
short_ok = short_format_ok (dest);
if (short_ok && imm > 0 && imm <= 8)
return "mov:q %1,%0.w";
if (-128 <= imm && imm < 128)
return "mov:e %1,%0.w";
is_reg = (GET_CODE (dest) == REG);
if (is_reg)
return "mov:l %1,%0.w";
if (short_ok)
return "mov:i %1,%0.w";
return "mov %1,%0.w";
}
char *
cmp_imm_word (imm, dest)
int imm;
rtx dest;
{
int is_reg, short_ok;
if (imm == 0)
return "cmp:z.w #0,%0";
short_ok = short_format_ok (dest);
if (short_ok && imm >0 && imm <= 8)
return "cmp:q %1,%0.w";
if (-128 <= imm && imm < 128)
return "cmp:e %1,%0.w";
is_reg = (GET_CODE (dest) == REG);
if (is_reg)
return "cmp:l %1,%0.w";
if (short_ok)
return "cmp:i %1,%0.w";
return "cmp %1,%0.w";
}
char *
push_imm_word (imm)
int imm;
{
if (imm == 0)
return "mov:z.w #0,%-";
if (imm > 0 && imm <= 8)
return "mov:q %1,%-.w";
if (-128 <= imm && imm < 128)
return "mov:e %1,%-.w";
return "mov:g %1,%-.w";
/* In some cases, g-format may be better than I format.??
return "mov %1,%0.w";
*/
}
my_signed_comp (insn)
rtx insn;
{
rtx my_insn;
my_insn = NEXT_INSN (insn);
if (GET_CODE (my_insn) != JUMP_INSN)
{
fprintf (stderr, "my_signed_comp: Not Jump_insn ");
myabort (GET_CODE (my_insn));
}
my_insn = PATTERN (my_insn);
if (GET_CODE (my_insn) != SET)
{
fprintf (stderr, "my_signed_comp: Not Set ");
myabort (GET_CODE (my_insn));
}
my_insn = SET_SRC (my_insn);
if (GET_CODE (my_insn) != IF_THEN_ELSE)
{
fprintf (stderr, "my_signed_comp: Not if_then_else ");
myabort (GET_CODE (my_insn));
}
switch (GET_CODE (XEXP (my_insn, 0)))
{
case NE:
case EQ:
case GE:
case GT:
case LE:
case LT:
return 1;
case GEU:
case GTU:
case LEU:
case LTU:
return 0;
}
fprintf (stderr, "my_signed_comp: Not cccc ");
myabort (GET_CODE (XEXP (my_insn, 0)));
}
/* Definitions of target machine for GNU compiler. Gmicro (TRON) version.
Copyright (C) 1987, 1988, 1989, 1995, 1996, 1997, 1998, 1999, 2000
Free Software Foundation, Inc.
Contributed by Masanobu Yuhara, Fujitsu Laboratories LTD.
(yuhara@flab.fujitsu.co.jp)
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, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* Note that some other tm.h files include this one and then override
many of the definitions that relate to assembler syntax. */
/* Names to predefine in the preprocessor for this target machine. */
#define CPP_PREDEFINES "-Dgmicro -Acpu(tron) -Amachine(tron)"
/* #define CPP_SPEC ** currently not defined **/
/* #define CC1_SPEC ** currently not defined **/
/* Print subsidiary information on the compiler version in use. */
/*
#define TARGET_VERSION fprintf (stderr, " (Gmicro syntax)");
*/
/* Run-time compilation parameters selecting different hardware subsets. */
extern int target_flags;
/* Macros used in the machine description to test the flags. */
/* Compile for a Gmicro/300. */
#define TARGET_G300 (target_flags & 1)
/* Compile for a Gmicro/200. */
#define TARGET_G200 (target_flags & 2)
/* Compile for a Gmicro/100. */
#define TARGET_G100 (target_flags & 4)
/* Compile FPU insns for floating point (not library calls). */
#define TARGET_FPU (target_flags & 8)
/* Pop up arguments by called function. */
#define TARGET_RTD (target_flags & 0x10)
/* Compile passing first args in regs 0 and 1.
This exists only to test compiler features that will be needed for
RISC chips. It is not usable and is not intended to be usable on
this cpu ;-< */
#define TARGET_REGPARM (target_flags & 0x20)
#define TARGET_BITFIELD (target_flags & 0x40)
#define TARGET_NEWRETURN (target_flags & 0x80)
/* Do not expand __builtin_smov (strcpy) to multiple movs.
Use the smov instruction. */
#define TARGET_FORCE_SMOV (target_flags & 0x100)
/* default options are -m300, -mFPU,
with bitfield instructions added because it won't always work otherwise.
If there are versions of the gmicro that don't support bitfield instructions
then it will take some thinking to figure out how to make them work. */
#define TARGET_DEFAULT 0x49
/* Macro to define tables used to set the flags.
This is a list in braces of pairs in braces,
each pair being { "NAME", VALUE }
where VALUE is the bits to set or minus the bits to clear.
An empty string NAME is used to identify the default VALUE. */
#define TARGET_SWITCHES \
{ { "g300", 1, _("Compile for Gmicro/300")}, \
{ "g200", 2, _("Compile for Gmicro/200")}, \
{ "g100", 4, _("Compile for Gmicro/100")}, \
{ "fpu", 8, _("Use floating point co-processor")}, \
{ "soft-float", -8, \
_("Do not use floating point co-processor")}, \
{ "rtd", 0x10, _("Alternate calling convention")}, \
{ "no-rtd", -0x10, _("Use normal calling convention")}, \
{ "regparm", 0x20, NULL}, \
{ "no-regparm", -0x20, NULL}, \
#if 0 /* Since we don't define PCC_BITFIELD_TYPE_MATTERS or use a large
STRUCTURE_SIZE_BOUNDARY, we must have bitfield instructions. */
{ "bitfield", 0x40, _("Use bitfield instructions")}, \
{ "no-bitfield", -0x40, \
_("Do not use bitfield instructions")}, \
#endif
{ "newreturn", 0x80, _("Use alternative return sequence")}, \
{ "no-newreturn", -0x80, _("Use normal return sequence")}, \
{ "force-smov", 0x100, _("Always use string instruction")}, \
{ "no-force-smov", -0x100, \
_("Use string instruction when appropriate")}, \
{ "", TARGET_DEFAULT, NULL}}
/* Blow away G100 flag silently off TARGET_fpu (since we can't clear
any bits in TARGET_SWITCHES above) */
#define OVERRIDE_OPTIONS \
{ \
if (TARGET_G100) target_flags &= ~8; \
}
/* target machine storage layout */
/* Define this if most significant bit is lowest numbered
in instructions that operate on numbered bit-fields.
This is true for Gmicro insns.
We make it true always by avoiding using the single-bit insns
except in special cases with constant bit numbers. */
#define BITS_BIG_ENDIAN 1
/* Define this if most significant byte of a word is the lowest numbered. */
/* That is true on the Gmicro. */
#define BYTES_BIG_ENDIAN 1
/* Define this if most significant word of a multiword number is the lowest
numbered. */
/* For Gmicro we can decide arbitrarily
since there are no machine instructions for them. ????? */
#define WORDS_BIG_ENDIAN 0
/* number of bits in an addressable storage unit */
#define BITS_PER_UNIT 8
/* Width in bits of a "word", which is the contents of a machine register. */
#define BITS_PER_WORD 32
/* Width of a word, in units (bytes). */
#define UNITS_PER_WORD 4
/* Width in bits of a pointer.
See also the macro `Pmode' defined below. */
#define POINTER_SIZE 32
/* Allocation boundary (in *bits*) for storing arguments in argument list. */
#define PARM_BOUNDARY 32
/* Boundary (in *bits*) on which stack pointer should be aligned. */
#define STACK_BOUNDARY 32
/* Allocation boundary (in *bits*) for the code of a function. */
/* Instructions of the Gmicro should be on half-word boundary */
/* But word boundary gets better performance */
#define FUNCTION_BOUNDARY 32
/* Alignment of field after `int : 0' in a structure. */
#define EMPTY_FIELD_BOUNDARY 32
/* No data type wants to be aligned rounder than this. */
/* This is not necessarily 32 on the Gmicro */
#define BIGGEST_ALIGNMENT 32
/* Set this non-zero if move instructions will actually fail to work
when given unaligned data.
Unaligned data is allowed on Gmicro, though the access is slow. */
#define STRICT_ALIGNMENT 1
#define SLOW_UNALIGNED_ACCESS(MODE, ALIGN) 1
/* Make strings word-aligned so strcpy from constants will be faster. */
#define CONSTANT_ALIGNMENT(EXP, ALIGN) \
(TREE_CODE (EXP) == STRING_CST \
&& (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN))
/* Make arrays of chars word-aligned for the same reasons. */
#define DATA_ALIGNMENT(TYPE, ALIGN) \
(TREE_CODE (TYPE) == ARRAY_TYPE \
&& TYPE_MODE (TREE_TYPE (TYPE)) == QImode \
&& (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN))
/* Define number of bits in most basic integer type.
(If undefined, default is BITS_PER_WORD). */
#define INT_TYPE_SIZE 32
/* #define PCC_BITFIELD_TYPE_MATTERS 1 ????? */
/* #define CHECK_FLOAT_VALUE (MODE, VALUE) ????? */
/* Standard register usage. */
/* Number of actual hardware registers.
The hardware registers are assigned numbers for the compiler
from 0 to just below FIRST_PSEUDO_REGISTER.
All registers that the compiler knows about must be given numbers,
even those that are not normally considered general registers.
For the Gmicro, we give the general registers numbers 0-15,
and the FPU floating point registers numbers 16-31. */
#define FIRST_PSEUDO_REGISTER 32
/* 1 for registers that have pervasive standard uses
and are not available for the register allocator.
On the Gmicro, the stack pointer and the frame pointer are
such registers. */
/* frame pointer is not indicated as fixed, because fp may be used freely
when a frame is not built. */
#define FIXED_REGISTERS \
{0, 0, 0, 0, 0, 0, 0, 0, \
0, 0, 0, 0, 0, 0, 0, 1, \
/* FPU registers. */ \
0, 0, 0, 0, 0, 0, 0, 0, \
0, 0, 0, 0, 0, 0, 0, 0, }
/* 1 for registers not available across function calls.
These must include the FIXED_REGISTERS and also any
registers that can be used without being saved.
The latter must include the registers where values are returned
and the register where structure-value addresses are passed.
Aside from that, you can include as many other registers as you like. */
#define CALL_USED_REGISTERS \
{1, 1, 1, 1, 0, 0, 0, 0, \
0, 0, 0, 0, 0, 0, 0, 1, \
/* FPU registers. */ \
1, 1, 1, 1, 0, 0, 0, 0, \
0, 0, 0, 0, 0, 0, 0, 0, }
/* Make sure everything's fine if we *don't* have a given processor.
This assumes that putting a register in fixed_regs will keep the
compilers mitt's completely off it. We don't bother to zero it out
of register classes. If TARGET_FPU is not set,
the compiler won't touch since no instructions that use these
registers will be valid. */
/* This Macro is not defined now.
#define CONDITIONAL_REGISTER_USAGE */
/* Return number of consecutive hard regs needed starting at reg REGNO
to hold something of mode MODE.
This is ordinarily the length in words of a value of mode MODE
but can be less for certain modes in special long registers.
On the Gmicro, ordinary registers hold 32 bits worth;
for the Gmicro/FPU registers, a single register is always enough for
anything that can be stored in them at all. */
#define HARD_REGNO_NREGS(REGNO, MODE) \
((REGNO) >= 16 ? 1 \
: ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD))
/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE.
On the Gmicro, the cpu registers can hold any mode but the FPU registers
can hold only SFmode or DFmode. And the FPU registers can't hold anything
if FPU use is disabled. */
#define HARD_REGNO_MODE_OK(REGNO, MODE) \
((REGNO) < 16 \
|| ((REGNO) < 32 \
? TARGET_FPU && (GET_MODE_CLASS (MODE) == MODE_FLOAT || \
GET_MODE_CLASS (MODE) == MODE_COMPLEX_FLOAT) \
: 0 ))
/* Value is 1 if it is a good idea to tie two pseudo registers
when one has mode MODE1 and one has mode MODE2.
If HARD_REGNO_MODE_OK could produce different values for MODE1 and MODE2,
for any hard reg, then this must be 0 for correct output. */
#define MODES_TIEABLE_P(MODE1, MODE2) \
(! TARGET_FPU \
|| ((GET_MODE_CLASS (MODE1) == MODE_FLOAT || \
GET_MODE_CLASS (MODE1) == MODE_COMPLEX_FLOAT) \
== ((MODE2) == SFmode || (MODE2) == DFmode)))
/* Specify the registers used for certain standard purposes.
The values of these macros are register numbers. */
/* Gmicro pc isn't overloaded on a register. */
/* #define PC_REGNUM */
/* Register to use for pushing function arguments. */
#define STACK_POINTER_REGNUM 15
/* Base register for access to local variables of the function. */
#define FRAME_POINTER_REGNUM 14
/* Value should be nonzero if functions must have frame pointers.
Zero means the frame pointer need not be set up (and parms
may be accessed via the stack pointer) in functions that seem suitable.
This is computed in `reload', in reload1.c. */
#define FRAME_POINTER_REQUIRED 0
/* Base register for access to arguments of the function. */
/* The Gmicro does not have hardware ap. Fp is treated as ap */
#define ARG_POINTER_REGNUM 14
/* Register in which static-chain is passed to a function. */
#define STATIC_CHAIN_REGNUM 0
/* Register in which address to store a structure value
is passed to a function. */
#define STRUCT_VALUE_REGNUM 1
/* Define the classes of registers for register constraints in the
machine description. Also define ranges of constants.
One of the classes must always be named ALL_REGS and include all hard regs.
If there is more than one class, another class must be named NO_REGS
and contain no registers.
The name GENERAL_REGS must be the name of a class (or an alias for
another name such as ALL_REGS). This is the class of registers
that is allowed by "g" or "r" in a register constraint.
Also, registers outside this class are allocated only when
instructions express preferences for them.
The classes must be numbered in nondecreasing order; that is,
a larger-numbered class must never be contained completely
in a smaller-numbered class.
For any two classes, it is very desirable that there be another
class that represents their union. */
/* The Gmicro has two kinds of registers, so four classes would be
a complete set. */
enum reg_class { NO_REGS, FPU_REGS, GENERAL_REGS, ALL_REGS, LIM_REG_CLASSES };
#define N_REG_CLASSES (int) LIM_REG_CLASSES
/* Give names of register classes as strings for dump file. */
#define REG_CLASS_NAMES \
{ "NO_REGS", "FPU_REGS", "GENERAL_REGS", "ALL_REGS" }
/* Define which registers fit in which classes.
This is an initializer for a vector of HARD_REG_SET
of length N_REG_CLASSES. */
#define REG_CLASS_CONTENTS \
{ \
0, /* NO_REGS */ \
0xffff0000, /* FPU_REGS */ \
0x0000ffff, /* GENERAL_REGS */ \
0xffffffff /* ALL_REGS */ \
}
/* The same information, inverted:
Return the class number of the smallest class containing
reg number REGNO. This could be a conditional expression
or could index an array. */
extern enum reg_class regno_reg_class[];
#define REGNO_REG_CLASS(REGNO) ( (REGNO < 16) ? GENERAL_REGS : FPU_REGS )
/* The class value for index registers, and the one for base regs. */
#define INDEX_REG_CLASS GENERAL_REGS
#define BASE_REG_CLASS GENERAL_REGS
/* Get reg_class from a letter such as appears in the machine description.
We do a trick here to modify the effective constraints on the
machine description; we zorch the constraint letters that aren't
appropriate for a specific target. This allows us to guarantee
that a specific kind of register will not be used for a given target
without fiddling with the register classes above. */
#define REG_CLASS_FROM_LETTER(C) \
((C) == 'r' ? GENERAL_REGS : \
((C) == 'f' ? (TARGET_FPU ? FPU_REGS : NO_REGS) : \
NO_REGS))
/* The letters I, J, K, L and M in a register constraint string
can be used to stand for particular ranges of immediate operands.
This macro defines what the ranges are.
C is the letter, and VALUE is a constant value.
Return 1 if VALUE is in the range specified by C.
For the Gmicro, all immediate value optimizations are done
by assembler, so no machine dependent definition is necessary ??? */
/* #define CONST_OK_FOR_LETTER_P(VALUE, C) ((C) == 'I') */
#define CONST_OK_FOR_LETTER_P(VALUE, C) 0
/*
* The letters G defines all of the floating constants tha are *NOT*
* Gmicro-FPU constant.
*/
#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) \
((C) == 'F' || \
(C) == 'G' && !(TARGET_FPU && standard_fpu_constant_p (VALUE)))
/* Given an rtx X being reloaded into a reg required to be
in class CLASS, return the class of reg to actually use.
In general this is just CLASS; but on some machines
in some cases it is preferable to use a more restrictive class. */
/* On the Gmicro series, there is no restriction on GENERAL_REGS,
so CLASS is returned. I do not know whether I should treat FPU_REGS
specially or not (at least, m68k does not). */
#define PREFERRED_RELOAD_CLASS(X,CLASS) CLASS
/* Return the maximum number of consecutive registers
needed to represent mode MODE in a register of class CLASS. */
/* On the Gmicro, this is the size of MODE in words,
except in the FPU regs, where a single reg is always enough. */
#define CLASS_MAX_NREGS(CLASS, MODE) \
((CLASS) == FPU_REGS ? \
1 : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD))
/* Stack layout; function entry, exit and calling. */
/* Define this if pushing a word on the stack
makes the stack pointer a smaller address. */
#define STACK_GROWS_DOWNWARD
/* Define this if the nominal address of the stack frame
is at the high-address end of the local variables;
that is, each additional local variable allocated
goes at a more negative offset in the frame. */
#define FRAME_GROWS_DOWNWARD
/* Offset within stack frame to start allocating local variables at.
If FRAME_GROWS_DOWNWARD, this is the offset to the END of the
first local allocated. Otherwise, it is the offset to the BEGINNING
of the first local allocated. */
/* On the Gmicro, FP points to the old FP and the first local variables are
at (FP - 4). */
#define STARTING_FRAME_OFFSET 0
/* If we generate an insn to push BYTES bytes,
this says how many the stack pointer really advances by. */
/* On the Gmicro, sp is decremented by the exact size of the operand */
#define PUSH_ROUNDING(BYTES) (BYTES)
/* Offset of first parameter from the argument pointer register value. */
/* On the Gmicro, the first argument is found at (ap + 8) where ap is fp. */
#define FIRST_PARM_OFFSET(FNDECL) 8
/* Value is the number of byte of arguments automatically
popped when returning from a subroutine call.
FUNDECL is the declaration node of the function (as a tree),
FUNTYPE is the data type of the function (as a tree),
or for a library call it is an identifier node for the subroutine name.
SIZE is the number of bytes of arguments passed on the stack.
On the Gmicro, the EXITD insn may be used to pop them if the number
of args is fixed, but if the number is variable then the caller must pop
them all. The adjsp operand of the EXITD insn can't be used for library
calls now because the library is compiled with the standard compiler.
Use of adjsp operand is a selectable option, since it is incompatible with
standard Unix calling sequences. If the option is not selected,
the caller must always pop the args.
On the m68k this is an RTD option, so I use the same name
for the Gmicro. The option name may be changed in the future. */
#define RETURN_POPS_ARGS(FUNDECL,FUNTYPE,SIZE) \
((TARGET_RTD && (!(FUNDECL) || TREE_CODE (FUNDECL) != IDENTIFIER_NODE) \
&& (TYPE_ARG_TYPES (FUNTYPE) == 0 \
|| (TREE_VALUE (tree_last (TYPE_ARG_TYPES (FUNTYPE))) \
== void_type_node))) \
? (SIZE) : 0)
/* Define how to find the value returned by a function.
VALTYPE is the data type of the value (as a tree).
If the precise function being called is known, FUNC is its FUNCTION_DECL;
otherwise, FUNC is 0. */
/* On the Gmicro the floating return value is in fr0 not r0. */
#define FUNCTION_VALUE(VALTYPE, FUNC) LIBCALL_VALUE (TYPE_MODE (VALTYPE))
/* Define how to find the value returned by a library function
assuming the value has mode MODE. */
#define LIBCALL_VALUE(MODE) \
(gen_rtx_REG ((MODE), \
((TARGET_FPU && ((MODE) == SFmode || (MODE) == DFmode)) \
? 16 : 0)))
/* 1 if N is a possible register number for a function value.
On the Gmicro, r0 and fp0 are the possible registers. */
#define FUNCTION_VALUE_REGNO_P(N) ((N) == 0 || (N) == 16)
/* Define this if PCC uses the nonreentrant convention for returning
structure and union values. */
#define PCC_STATIC_STRUCT_RETURN
/* 1 if N is a possible register number for function argument passing.
On the Gmicro, no registers are used in this way. */
/* Really? For the performance improvement, registers should be used !! */
#define FUNCTION_ARG_REGNO_P(N) 0
/* Define a data type for recording info about an argument list
during the scan of that argument list. This data type should
hold all necessary information about the function itself
and about the args processed so far, enough to enable macros
such as FUNCTION_ARG to determine where the next arg should go.
On the Gmicro, this is a single integer, which is a number of bytes
of arguments scanned so far. */
#define CUMULATIVE_ARGS int
/* Initialize a variable CUM of type CUMULATIVE_ARGS
for a call to a function whose data type is FNTYPE.
For a library call, FNTYPE is 0.
On the Gmicro, the offset starts at 0. */
#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE,LIBNAME,INDIRECT) \
((CUM) = 0)
/* Update the data in CUM to advance over an argument
of mode MODE and data type TYPE.
(TYPE is null for libcalls where that information may not be available.) */
#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \
((CUM) += ((MODE) != BLKmode \
? (GET_MODE_SIZE (MODE) + 3) & ~3 \
: (int_size_in_bytes (TYPE) + 3) & ~3))
/* Define where to put the arguments to a function.
Value is zero to push the argument on the stack,
or a hard register in which to store the argument.
MODE is the argument's machine mode.
TYPE is the data type of the argument (as a tree).
This is null for libcalls where that information may
not be available.
CUM is a variable of type CUMULATIVE_ARGS which gives info about
the preceding args and about the function being called.
NAMED is nonzero if this argument is a named parameter
(otherwise it is an extra parameter matching an ellipsis). */
/* On the Gmicro all args are pushed, except if -mregparm is specified
then the first two words of arguments are passed in d0, d1.
*NOTE* -mregparm does not work.
It exists only to test register calling conventions. */
#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \
((TARGET_REGPARM && (CUM) < 8) ? gen_rtx_REG ((MODE), (CUM) / 4) : 0)
/* For an arg passed partly in registers and partly in memory,
this is the number of registers used.
For args passed entirely in registers or entirely in memory, zero. */
#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) \
((TARGET_REGPARM && (CUM) < 8 \
&& 8 < ((CUM) + ((MODE) == BLKmode \
? int_size_in_bytes (TYPE) \
: GET_MODE_SIZE (MODE)))) \
? 2 - (CUM) / 4 : 0)
/* The following macro is defined to output register list.
The LSB of Mask is the lowest number register.
Regoff is MY_GREG_OFF or MY_FREG_OFF.
Do NOT use <i> in File, Mask, Regoff !!
Should be changed from macros to functions. M.Yuhara */
#define MY_GREG_OFF 0
#define MY_FREG_OFF 16
#define MY_PRINT_MASK(File, Mask, Regoff) \
{ \
int i, first = -1; \
if ((Mask) == 0) { \
fprintf(File, "#0"); \
} else { \
fprintf(File, "("); \
for (i = 0; i < 16; i++) { \
if ( (Mask) & (1 << i) ) { \
if (first < 0) { \
if (first == -2) { \
fprintf(File, ","); \
} \
first = i; \
fprintf(File, "%s", reg_names[Regoff + i]); \
} \
} else if (first >= 0) { \
if (i > first + 1) { \
fprintf(File, "-%s", reg_names[Regoff + i - 1]); \
} \
first = -2; \
} \
} \
if ( (first >= 0) && (first != 15) ) \
fprintf(File, "-%s", reg_names[Regoff + 15]);\
fprintf(File, ")"); \
} \
}
#define MY_PRINT_ONEREG_L(FILE,MASK) \
{ register int i; \
for (i = 0; i < 16; i++) \
if ( (1 << i) & (MASK)) { \
fprintf(FILE, "%s", reg_names[i]); \
(MASK) &= ~(1 << i); \
break; \
} \
}
#define MY_PRINT_ONEREG_H(FILE,MASK) \
{ register int i; \
for (i = 15; i >= 0; i--) \
if ( (1 << i) & (MASK)) { \
fprintf(FILE, "%s", reg_names[i]); \
(MASK) &= ~(1 << i); \
break; \
} \
}
/* This macro generates the assembly code for function entry.
FILE is a stdio stream to output the code to.
SIZE is an int: how many units of temporary storage to allocate.
Refer to the array `regs_ever_live' to determine which registers
to save; `regs_ever_live[I]' is nonzero if register number I
is ever used in the function. This macro is responsible for
knowing which registers should not be saved even if used. */
/* The next macro needs much optimization !!
M.Yuhara */
#define FUNCTION_PROLOGUE(FILE, SIZE) \
{ register int regno; \
register int mask = 0; \
register int nregs = 0; \
static const char * const reg_names[] = REGISTER_NAMES; \
extern char call_used_regs[]; \
int fsize = ((SIZE) + 3) & -4; \
for (regno = 0; regno < 16; regno++) \
if (regs_ever_live[regno] && !call_used_regs[regno]) { \
mask |= (1 << regno); \
nregs++; \
} \
if (frame_pointer_needed) { \
mask &= ~(1 << FRAME_POINTER_REGNUM); \
if (nregs > 4) { \
fprintf(FILE, "\tenter.w #%d,", fsize); \
MY_PRINT_MASK(FILE, mask, MY_GREG_OFF); \
fprintf(FILE,"\n"); \
} else { \
fprintf(FILE, "\tmov.w fp,@-sp\n"); \
fprintf(FILE, "\tmov.w sp,fp\n"); \
if (fsize > 0) \
myoutput_sp_adjust(FILE, "sub", fsize); \
while (nregs--) { \
fprintf(FILE, "\tmov.w "); \
MY_PRINT_ONEREG_H(FILE, mask); \
fprintf(FILE, ",@-sp\n"); \
} \
} \
} else { \
if (fsize > 0) \
myoutput_sp_adjust(FILE, "sub", fsize); \
if (mask != 0) { \
if (nregs > 4) { \
fprintf(FILE, "\tstm.w "); \
MY_PRINT_MASK(FILE, mask, MY_GREG_OFF); \
fprintf(FILE, ",@-sp\n"); \
} else { \
while (nregs--) { \
fprintf(FILE, "\tmov.w "); \
MY_PRINT_ONEREG_H(FILE, mask); \
fprintf(FILE, ",@-sp\n"); \
} \
} \
} \
} \
mask = 0; \
for (regno = 16; regno < 32; regno++) \
if (regs_ever_live[regno] && !call_used_regs[regno]) \
mask |= 1 << (regno - 16); \
if (mask != 0) { \
fprintf(FILE, "\tfstm.w "); \
MY_PRINT_MASK(FILE, mask, MY_FREG_OFF); \
fprintf(FILE, ",@-sp\n", mask); \
} \
}
/* Output assembler code to FILE to increment profiler label # LABELNO
for profiling a function entry. */
/* ??? M.Yuhara */
#define FUNCTION_PROFILER(FILE, LABELNO) \
fprintf (FILE, "\tmova @LP%d,r0\n\tjsr mcount\n", (LABELNO))
/* Output assembler code to FILE to initialize this source file's
basic block profiling info, if that has not already been done. */
#define FUNCTION_BLOCK_PROFILER(FILE, LABELNO) \
fprintf (FILE, "\tcmp #0,@LPBX0\n\tbne LPI%d\n\tpusha @LPBX0\n\tjsr ___bb_init_func\n\tadd #4,sp\nLPI%d:\n", \
LABELNO, LABELNO);
/* Output assembler code to FILE to increment the entry-count for
the BLOCKNO'th basic block in this source file. */
#define BLOCK_PROFILER(FILE, BLOCKNO) \
fprintf (FILE, "\tadd #1,@(LPBX2+%d)\n", 4 * BLOCKNO)
/* EXIT_IGNORE_STACK should be nonzero if, when returning from a function,
the stack pointer does not matter. The value is tested only in
functions that have frame pointers.
No definition is equivalent to always zero. */
#define EXIT_IGNORE_STACK 1
/* This macro generates the assembly code for function exit,
on machines that need it. If FUNCTION_EPILOGUE is not defined
then individual return instructions are generated for each
return statement. Args are same as for FUNCTION_PROLOGUE.
The function epilogue should not depend on the current stack pointer (when
frame_pinter_needed) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
It should use the frame pointer only. This is mandatory because
of alloca; we also take advantage of it to omit stack adjustments
before returning. */
/* The Gmicro FPU seems to be unable to fldm/fstm double or single
floating. It only allows extended !! */
/* Optimization is not enough, especially FREGs load !! M.Yuhara */
#define FUNCTION_EPILOGUE(FILE, SIZE) \
{ register int regno; \
register int mask, fmask; \
register int nregs, nfregs; \
int offset, foffset; \
extern char call_used_regs[]; \
static const char * const reg_names[] = REGISTER_NAMES; \
int fsize = ((SIZE) + 3) & -4; \
FUNCTION_EXTRA_EPILOGUE (FILE, SIZE); \
nfregs = 0; fmask = 0; \
for (regno = 16; regno < 31; regno++) \
if (regs_ever_live[regno] && ! call_used_regs[regno]) \
{ nfregs++; fmask |= 1 << (regno - 16); } \
foffset = nfregs * 12; \
nregs = 0; mask = 0; \
if (frame_pointer_needed) regs_ever_live[FRAME_POINTER_REGNUM] = 0; \
for (regno = 0; regno < 16; regno++) \
if (regs_ever_live[regno] && ! call_used_regs[regno]) \
{ nregs++; mask |= 1 << regno; } \
if (frame_pointer_needed) { \
offset = nregs * 4 + fsize; \
if (nfregs > 0) { \
fprintf(FILE, "\tfldm.x @(%d,fp),", -(foffset + offset));\
MY_PRINT_MASK(FILE, fmask, MY_FREG_OFF); \
fprintf(FILE, "\n"); \
} \
if (nregs > 4 \
|| current_function_pops_args) { \
fprintf(FILE, "\tmova @(%d,fp),sp\n", -offset); \
fprintf(FILE, "\texitd "); \
MY_PRINT_MASK(FILE, mask, MY_GREG_OFF); \
fprintf(FILE, ",#%d\n", current_function_pops_args); \
} else { \
while (nregs--) { \
fprintf(FILE, "\tmov:l.w @(%d,fp),", -offset); \
MY_PRINT_ONEREG_L(FILE, mask); \
fprintf(FILE, "\n"); \
offset -= 4; \
} \
if (TARGET_NEWRETURN) { \
fprintf(FILE, "\tmova.w @(4,fp),sp\n"); \
fprintf(FILE, "\tmov:l.w @fp,fp\n"); \
} else { \
fprintf(FILE, "\tmov.w fp,sp\n"); \
fprintf(FILE, "\tmov.w @sp+,fp\n"); \
} \
fprintf(FILE, "\trts\n"); \
} \
} else { \
if (nfregs > 0) { \
fprintf(FILE, "\tfldm.w @sp+,"); \
MY_PRINT_MASK(FILE, fmask, MY_FREG_OFF); \
fprintf(FILE, "\n"); \
} \
if (nregs > 4) { \
fprintf(FILE, "\tldm.w @sp+,"); \
MY_PRINT_MASK(FILE, mask, MY_GREG_OFF); \
fprintf(FILE, "\n"); \
} else { \
while (nregs--) { \
fprintf(FILE, "\tmov.w @sp+,"); \
MY_PRINT_ONEREG_L(FILE,mask); \
fprintf(FILE, "\n"); \
} \
} \
if (current_function_pops_args) { \
myoutput_sp_adjust(FILE, "add", \
(fsize + 4 + current_function_pops_args)); \
fprintf(FILE, "\tjmp @(%d,sp)\n", current_function_pops_args);\
} else { \
if (fsize > 0) \
myoutput_sp_adjust(FILE, "add", fsize); \
fprintf(FILE, "\trts\n"); \
} \
} \
}
/* This is a hook for other tm files to change. */
#define FUNCTION_EXTRA_EPILOGUE(FILE, SIZE)
/* If the memory address ADDR is relative to the frame pointer,
correct it to be relative to the stack pointer instead.
This is for when we don't use a frame pointer.
ADDR should be a variable name. */
/* You have to change the next macro if you want to use more complex
addressing modes (such as double indirection and more than one
chain-addressing stages). */
#define FIX_FRAME_POINTER_ADDRESS(ADDR,DEPTH) \
{ int offset = -1; \
rtx regs = stack_pointer_rtx; \
if (ADDR == frame_pointer_rtx) \
offset = 0; \
else if (GET_CODE (ADDR) == PLUS && XEXP (ADDR, 0) == frame_pointer_rtx \
&& GET_CODE (XEXP (ADDR, 1)) == CONST_INT) \
offset = INTVAL (XEXP (ADDR, 1)); \
else if (GET_CODE (ADDR) == PLUS && XEXP (ADDR, 0) == frame_pointer_rtx) \
{ rtx other_reg = XEXP (ADDR, 1); \
offset = 0; \
regs = gen_rtx_PLUS (Pmode, stack_pointer_rtx, other_reg); } \
else if (GET_CODE (ADDR) == PLUS && XEXP (ADDR, 1) == frame_pointer_rtx) \
{ rtx other_reg = XEXP (ADDR, 0); \
offset = 0; \
regs = gen_rtx_PLUS (Pmode, stack_pointer_rtx, other_reg); } \
else if (GET_CODE (ADDR) == PLUS \
&& GET_CODE (XEXP (ADDR, 0)) == PLUS \
&& XEXP (XEXP (ADDR, 0), 0) == frame_pointer_rtx \
&& GET_CODE (XEXP (ADDR, 1)) == CONST_INT) \
{ rtx other_reg = XEXP (XEXP (ADDR, 0), 1); \
offset = INTVAL (XEXP (ADDR, 1)); \
regs = gen_rtx_PLUS (Pmode, stack_pointer_rtx, other_reg); } \
else if (GET_CODE (ADDR) == PLUS \
&& GET_CODE (XEXP (ADDR, 0)) == PLUS \
&& XEXP (XEXP (ADDR, 0), 1) == frame_pointer_rtx \
&& GET_CODE (XEXP (ADDR, 1)) == CONST_INT) \
{ rtx other_reg = XEXP (XEXP (ADDR, 0), 0); \
offset = INTVAL (XEXP (ADDR, 1)); \
regs = gen_rtx_PLUS (Pmode, stack_pointer_rtx, other_reg); } \
if (offset >= 0) \
{ int regno; \
extern char call_used_regs[]; \
for (regno = 16; regno < 32; regno++) \
if (regs_ever_live[regno] && ! call_used_regs[regno]) \
offset += 12; \
for (regno = 0; regno < 16; regno++) \
if (regs_ever_live[regno] && ! call_used_regs[regno]) \
offset += 4; \
offset -= 4; \
ADDR = plus_constant (regs, offset + (DEPTH)); } }
/* Addressing modes, and classification of registers for them. */
/* #define HAVE_POST_INCREMENT 0 */
/* #define HAVE_POST_DECREMENT 0 */
/* #define HAVE_PRE_DECREMENT 0 */
/* #define HAVE_PRE_INCREMENT 0 */
/* Macros to check register numbers against specific register classes. */
/* These assume that REGNO is a hard or pseudo reg number.
They give nonzero only if REGNO is a hard reg of the suitable class
or a pseudo reg currently allocated to a suitable hard reg.
Since they use reg_renumber, they are safe only once reg_renumber
has been allocated, which happens in local-alloc.c. */
/* Gmicro */
#define REGNO_OK_FOR_GREG_P(REGNO) \
((REGNO) < 16 || (unsigned) reg_renumber[REGNO] < 16)
#define REGNO_OK_FOR_FPU_P(REGNO) \
(((REGNO) ^ 0x10) < 16 || (unsigned) (reg_renumber[REGNO] ^ 0x10) < 16)
#define REGNO_OK_FOR_INDEX_P(REGNO) REGNO_OK_FOR_GREG_P(REGNO)
#define REGNO_OK_FOR_BASE_P(REGNO) REGNO_OK_FOR_GREG_P(REGNO)
/* Now macros that check whether X is a register and also,
strictly, whether it is in a specified class.
These macros are specific to the Gmicro, and may be used only
in code for printing assembler insns and in conditions for
define_optimization. */
/* 1 if X is an fpu register. */
#define FPU_REG_P(X) (REG_P (X) && REGNO_OK_FOR_FPU_P (REGNO (X)))
/* I used GREG_P in the gmicro.md file. */
#ifdef REG_OK_STRICT
#define GREG_P(X) (REG_P (X) && REGNO_OK_FOR_GREG_P (REGNO(X)))
#else
#define GREG_P(X) (REG_P (X) && ((REGNO (X) & ~0xf) != 0x10))
#endif
/* Maximum number of registers that can appear in a valid memory address. */
/* The Gmicro allows more registers in the chained addressing mode.
But I do not know gcc supports such an architecture. */
#define MAX_REGS_PER_ADDRESS 2
/* Recognize any constant value that is a valid address. */
#define CONSTANT_ADDRESS_P(X) \
(GET_CODE (X) == LABEL_REF || GET_CODE (X) == SYMBOL_REF \
|| GET_CODE (X) == CONST_INT || GET_CODE (X) == CONST \
|| GET_CODE (X) == HIGH)
/* Nonzero if the constant value X is a legitimate general operand.
It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE. */
#define LEGITIMATE_CONSTANT_P(X) 1
/* The macros REG_OK_FOR..._P assume that the arg is a REG rtx
and check its validity for a certain class.
We have two alternate definitions for each of them.
The usual definition accepts all pseudo regs; the other rejects
them unless they have been allocated suitable hard regs.
The symbol REG_OK_STRICT causes the latter definition to be used.
Most source files want to accept pseudo regs in the hope that
they will get allocated to the class that the insn wants them to be in.
Source files for reload pass need to be strict.
After reload, it makes no difference, since pseudo regs have
been eliminated by then. */
#ifndef REG_OK_STRICT
/* Nonzero if X is a hard reg that can be used as an index
or if it is a pseudo reg. */
#define REG_OK_FOR_INDEX_P(X) ((REGNO (X) & ~0xf) != 0x10)
/* Nonzero if X is a hard reg that can be used as a base reg
or if it is a pseudo reg. */
#define REG_OK_FOR_BASE_P(X) ((REGNO (X) & ~0xf) != 0x10)
#else
/* Nonzero if X is a hard reg that can be used as an index. */
#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P (REGNO (X))
/* Nonzero if X is a hard reg that can be used as a base reg. */
#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P (REGNO (X))
#endif
/* The gcc uses the following effective address of the Gmicro.
(without using PC!!).
{@} ( {Rbase} + {Disp} + {Rindex * [1,2,4,8]} )
where
@: memory indirection.
Rbase: Base Register = General Register.
Disp: Displacement (up to 32bits)
Rindex: Index Register = General Register.
[1,2,4,8]: Scale of Index. 1 or 2 or 4 or 8.
The inside of { } can be omitted.
This restricts the chained addressing up to 1 stage. */
/* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression
that is a valid memory address for an instruction.
The MODE argument is the machine mode for the MEM expression
that wants to use this address.
The other macros defined here are used only in GO_IF_LEGITIMATE_ADDRESS,
except for CONSTANT_ADDRESS_P which is actually machine-independent. */
#define REG_CODE_BASE_P(X) \
(GET_CODE (X) == REG && REG_OK_FOR_BASE_P (X))
#define REG_CODE_INDEX_P(X) \
(GET_CODE (X) == REG && REG_OK_FOR_INDEX_P (X))
/* GET_CODE(X) must be PLUS. This macro does not check for PLUS! */
#define BASE_PLUS_DISP_P(X) \
( REG_CODE_BASE_P (XEXP (X, 0)) \
&& CONSTANT_ADDRESS_P (XEXP (X, 1)) \
|| \
REG_CODE_BASE_P (XEXP (X, 1)) \
&& CONSTANT_ADDRESS_P (XEXP (X, 0)) )
/* 1 if X is {0,Rbase} + {0,disp}. */
#define BASED_ADDRESS_P(X) \
(CONSTANT_ADDRESS_P (X) \
|| REG_CODE_BASE_P (X) \
|| (GET_CODE (X) == PLUS) \
&& BASE_PLUS_DISP_P (X))
/* 1 if X is 1 or 2 or 4 or 8. GET_CODE(X) must be CONST_INT. */
#define SCALE_OF_INDEX_P(X) \
( INTVAL(X) == 4 \
|| INTVAL(X) == 2 \
|| INTVAL(X) == 8 \
|| INTVAL(X) == 1 )
/* #define INDEX_TERM_P(X,MODE) */
#define INDEX_TERM_P(X) \
( REG_CODE_INDEX_P(X) \
|| (GET_CODE (X) == MULT \
&& ( (xfoo0 = XEXP (X, 0)), (xfoo1 = XEXP(X, 1)), \
( ( (GET_CODE (xfoo0) == CONST_INT) \
&& SCALE_OF_INDEX_P (xfoo0) \
&& REG_CODE_INDEX_P (xfoo1) ) \
|| \
( (GET_CODE (xfoo1) == CONST_INT) \
&& SCALE_OF_INDEX_P (xfoo1) \
&& REG_CODE_INDEX_P (xfoo0) ) ))))
/* Assumes there are no cases such that X = (Ireg + Disp) + Disp */
#define BASE_DISP_INDEX_P(X) \
( BASED_ADDRESS_P (X) \
|| ( (GET_CODE (X) == PLUS) \
&& ( ( (xboo0 = XEXP (X, 0)), (xboo1 = XEXP (X, 1)), \
(REG_CODE_BASE_P (xboo0) \
&& (GET_CODE (xboo1) == PLUS) \
&& ( ( CONSTANT_ADDRESS_P (XEXP (xboo1, 0)) \
&& INDEX_TERM_P (XEXP (xboo1, 1)) ) \
|| ( CONSTANT_ADDRESS_P (XEXP (xboo1, 1)) \
&& INDEX_TERM_P (XEXP (xboo1, 0))) ))) \
|| \
(CONSTANT_ADDRESS_P (xboo0) \
&& (GET_CODE (xboo1) == PLUS) \
&& ( ( REG_CODE_BASE_P (XEXP (xboo1, 0)) \
&& INDEX_TERM_P (XEXP (xboo1, 1)) ) \
|| ( REG_CODE_BASE_P (XEXP (xboo1, 1)) \
&& INDEX_TERM_P (XEXP (xboo1, 0))) )) \
|| \
(INDEX_TERM_P (xboo0) \
&& ( ( (GET_CODE (xboo1) == PLUS) \
&& ( ( REG_CODE_BASE_P (XEXP (xboo1, 0)) \
&& CONSTANT_ADDRESS_P (XEXP (xboo1, 1)) ) \
|| ( REG_CODE_BASE_P (XEXP (xboo1, 1)) \
&& CONSTANT_ADDRESS_P (XEXP (xboo1, 0))) )) \
|| \
(CONSTANT_ADDRESS_P (xboo1)) \
|| \
(REG_CODE_BASE_P (xboo1)) )))))
/*
If you want to allow double-indirection,
you have to change the <fp-relative> => <sp-relative> conversion
routine. M.Yuhara
#ifdef REG_OK_STRICT
#define DOUBLE_INDIRECTION(X,ADDR) {\
if (BASE_DISP_INDEX_P (XEXP (XEXP (X, 0), 0) )) goto ADDR; \
}
#else
#define DOUBLE_INDIRECTION(X,ADDR) { }
#endif
*/
#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) {\
register rtx xboo0, xboo1, xfoo0, xfoo1; \
if (GET_CODE (X) == MEM) { \
/* \
if (GET_CODE (XEXP (X,0)) == MEM) { \
DOUBLE_INDIRECTION(X,ADDR); \
} else { \
if (BASE_DISP_INDEX_P (XEXP (X, 0))) goto ADDR; \
} \
*/ \
} else { \
if (BASE_DISP_INDEX_P (X)) goto ADDR; \
if ((GET_CODE (X) == PRE_DEC || GET_CODE (X) == POST_INC) \
&& REG_P (XEXP (X, 0)) \
&& (REGNO (XEXP (X, 0)) == STACK_POINTER_REGNUM)) \
goto ADDR; \
} \
}
/* Try machine-dependent ways of modifying an illegitimate address
to be legitimate. If we find one, return the new, valid address.
This macro is used in only one place: `memory_address' in explow.c.
OLDX is the address as it was before break_out_memory_refs was called.
In some cases it is useful to look at this to decide what needs to be done.
MODE and WIN are passed so that this macro can use
GO_IF_LEGITIMATE_ADDRESS.
It is always safe for this macro to do nothing. It exists to recognize
opportunities to optimize the output.
For the Gmicro, nothing is done now. */
#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN) {}
/* Go to LABEL if ADDR (a legitimate address expression)
has an effect that depends on the machine mode it is used for.
On the VAX, the predecrement and postincrement address depend thus
(the amount of decrement or increment being the length of the operand)
and all indexed address depend thus (because the index scale factor
is the length of the operand).
The Gmicro mimics the VAX now. Since ADDE is legitimate, it cannot
include auto-inc/dec. */
/* Unnecessary ??? */
#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL) \
{ if (GET_CODE (ADDR) == POST_INC || GET_CODE (ADDR) == PRE_DEC) \
goto LABEL; }
/* Specify the machine mode that this machine uses
for the index in the tablejump instruction. */
/* #define CASE_VECTOR_MODE HImode */
#define CASE_VECTOR_MODE SImode
/* Define as C expression which evaluates to nonzero if the tablejump
instruction expects the table to contain offsets from the address of the
table.
Do not define this if the table should contain absolute addresses. */
#define CASE_VECTOR_PC_RELATIVE 1
/* Specify the tree operation to be used to convert reals to integers. */
#define IMPLICIT_FIX_EXPR FIX_ROUND_EXPR
/* This is the kind of divide that is easiest to do in the general case. */
#define EASY_DIV_EXPR TRUNC_DIV_EXPR
/* Define this as 1 if `char' should by default be signed; else as 0. */
#define DEFAULT_SIGNED_CHAR 1
/* Max number of bytes we can move from memory to memory
in one reasonably fast instruction. */
#define MOVE_MAX 4
/* Define this if zero-extension is slow (more than one real instruction). */
/* #define SLOW_ZERO_EXTEND */
/* Nonzero if access to memory by bytes is slow and undesirable. */
#define SLOW_BYTE_ACCESS 0
/* Define if shifts truncate the shift count
which implies one can omit a sign-extension or zero-extension
of a shift count. */
/* #define SHIFT_COUNT_TRUNCATED */
/* Value is 1 if truncating an integer of INPREC bits to OUTPREC bits
is done just by pretending it is already truncated. */
#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1
/* We assume that the store-condition-codes instructions store 0 for false
and some other value for true. This is the value stored for true. */
/* #define STORE_FLAG_VALUE (-1) */
/* When a prototype says `char' or `short', really pass an `int'. */
#define PROMOTE_PROTOTYPES 1
/* Specify the machine mode that pointers have.
After generation of rtl, the compiler makes no further distinction
between pointers and any other objects of this machine mode. */
#define Pmode SImode
/* A function address in a call instruction
is a byte address (for indexing purposes)
so give the MEM rtx a byte's mode. */
#define FUNCTION_MODE QImode
/* Compute the cost of computing a constant rtl expression RTX
whose rtx-code is CODE. The body of this macro is a portion
of a switch statement. If the code is computed here,
return it with a return statement. Otherwise, break from the switch. */
#define CONST_COSTS(RTX,CODE,OUTER_CODE) \
case CONST_INT: \
if ((unsigned) INTVAL (RTX) < 8) return 0; \
if ((unsigned) (INTVAL (RTX) + 0x80) < 0x100) return 1; \
if ((unsigned) (INTVAL (RTX) + 0x8000) < 0x10000) return 2; \
case CONST: \
case LABEL_REF: \
case SYMBOL_REF: \
return 3; \
case CONST_DOUBLE: \
return 5;
/* Define subroutines to call to handle multiply and divide.
The `*' prevents an underscore from being prepended by the compiler. */
/* Use libgcc on Gmicro */
/* #define UDIVSI3_LIBCALL "*udiv" */
/* #define UMODSI3_LIBCALL "*urem" */
/* Tell final.c how to eliminate redundant test instructions. */
/* Here we define machine-dependent flags and fields in cc_status
(see `conditions.h'). */
/* Set if the cc value is actually in the FPU, so a floating point
conditional branch must be output. */
#define CC_IN_FPU 04000
/* Store in cc_status the expressions
that the condition codes will describe
after execution of an instruction whose pattern is EXP.
Do not alter them if the instruction would not alter the cc's. */
/* Since Gmicro's compare instructions depend on the branch condition,
all branch should be kept.
More work must be done to optimize condition code !! M.Yuhara */
#define NOTICE_UPDATE_CC(EXP, INSN) {CC_STATUS_INIT;}
/* The skeleton of the next macro is taken from "vax.h".
FPU-reg manipulation is added. M.Yuhara */
/* Now comment out.
#define NOTICE_UPDATE_CC(EXP, INSN) { \
if (GET_CODE (EXP) == SET) { \
if ( !FPU_REG_P (XEXP (EXP, 0)) \
&& (XEXP (EXP, 0) != cc0_rtx) \
&& (FPU_REG_P (XEXP (EXP, 1)) \
|| GET_CODE (XEXP (EXP, 1)) == FIX \
|| GET_CODE (XEXP (EXP, 1)) == FLOAT_TRUNCATE \
|| GET_CODE (XEXP (EXP, 1)) == FLOAT_EXTEND)) { \
CC_STATUS_INIT; \
} else if (GET_CODE (SET_SRC (EXP)) == CALL) { \
CC_STATUS_INIT; \
} else if (GET_CODE (SET_DEST (EXP)) != PC) { \
cc_status.flags = 0; \
cc_status.value1 = SET_DEST (EXP); \
cc_status.value2 = SET_SRC (EXP); \
} \
} else if (GET_CODE (EXP) == PARALLEL \
&& GET_CODE (XVECEXP (EXP, 0, 0)) == SET \
&& GET_CODE (SET_DEST (XVECEXP (EXP, 0, 0))) != PC) {\
cc_status.flags = 0; \
cc_status.value1 = SET_DEST (XVECEXP (EXP, 0, 0)); \
cc_status.value2 = SET_SRC (XVECEXP (EXP, 0, 0)); \
/* PARALLELs whose first element sets the PC are aob, sob VAX insns. \
They do change the cc's. So drop through and forget the cc's. * / \
} else CC_STATUS_INIT; \
if (cc_status.value1 && GET_CODE (cc_status.value1) == REG \
&& cc_status.value2 \
&& reg_overlap_mentioned_p (cc_status.value1, cc_status.value2)) \
cc_status.value2 = 0; \
if (cc_status.value1 && GET_CODE (cc_status.value1) == MEM \
&& cc_status.value2 \
&& GET_CODE (cc_status.value2) == MEM) \
cc_status.value2 = 0; \
if ( (cc_status.value1 && FPU_REG_P (cc_status.value1)) \
|| (cc_status.value2 && FPU_REG_P (cc_status.value2))) \
cc_status.flags = CC_IN_FPU; \
}
*/
#define OUTPUT_JUMP(NORMAL, FLOAT, NO_OV) \
{ if (cc_prev_status.flags & CC_IN_FPU) \
return FLOAT; \
if (cc_prev_status.flags & CC_NO_OVERFLOW) \
return NO_OV; \
return NORMAL; }
/* Control the assembler format that we output. */
/* Output before read-only data. */
#define TEXT_SECTION_ASM_OP "\t.section text,code,align=4"
/* Output before writable data. */
#define DATA_SECTION_ASM_OP "\t.section data,data,align=4"
/* Output before uninitialized data. */
#define BSS_SECTION_ASM_OP "\t.section bss,data,align=4"
/* Output at beginning of assembler file.
It is not appropriate for this to print a list of the options used,
since that's not the convention that we use. */
#define ASM_FILE_START(FILE)
/* Output at the end of assembler file. */
#define ASM_FILE_END(FILE) fprintf (FILE, "\t.end\n");
/* Don't try to define `gcc_compiled.' since the assembler do not
accept symbols with periods and GDB doesn't run on this machine anyway. */
#define ASM_IDENTIFY_GCC(FILE)
/* Output to assembler file text saying following lines
may contain character constants, extra white space, comments, etc. */
#define ASM_APP_ON ""
/* #define ASM_APP_ON "#APP\n" */
/* Output to assembler file text saying following lines
no longer contain unusual constructs. */
#define ASM_APP_OFF ""
/* #define ASM_APP_OFF ";#NO_APP\n" */
/* How to refer to registers in assembler output.
This sequence is indexed by compiler's hard-register-number (see above). */
#define REGISTER_NAMES \
{"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \
"r8", "r9", "r10", "r11", "r12", "r13", "fp", "sp", \
"fr0", "fr1", "fr2", "fr3", "fr4", "fr5", "fr6", "fr7", \
"fr8", "fr9", "fr10", "fr11", "fr12", "fr13", "fr14", "fr15"}
/* How to renumber registers for dbx and gdb. */
#define DBX_REGISTER_NUMBER(REGNO) (REGNO)
/* Define this if gcc should produce debugging output for dbx in response
to the -g flag. This does not work for the Gmicro now */
#define DBX_DEBUGGING_INFO
/* This is how to output the definition of a user-level label named NAME,
such as the label on a static function or variable NAME. */
#define ASM_OUTPUT_LABEL(FILE,NAME) { \
assemble_name (FILE, NAME); \
fputs (":\n", FILE); \
}
/* This is how to output a command to make the user-level label named NAME
defined for reference from other files. */
#define ASM_GLOBALIZE_LABEL(FILE,NAME) {\
fputs ("\t.global ", FILE); \
assemble_name (FILE, NAME); \
fputs ("\n", FILE); \
}
/* This is how to output a command to make the external label named NAME
which are not defined in the file to be referable */
/* ".import" does not work ??? */
#define ASM_OUTPUT_EXTERNAL(FILE,DECL,NAME) { \
fputs ("\t.global ", FILE); \
assemble_name (FILE, NAME); \
fputs ("\n", FILE); \
}
/* The prefix to add to user-visible assembler symbols. */
#define USER_LABEL_PREFIX "_"
/* This is how to output an internal numbered label where
PREFIX is the class of label and NUM is the number within the class. */
#define ASM_OUTPUT_INTERNAL_LABEL(FILE,PREFIX,NUM) \
fprintf (FILE, "%s%d:\n", PREFIX, NUM)
/* This is how to store into the string LABEL
the symbol_ref name of an internal numbered label where
PREFIX is the class of label and NUM is the number within the class.
This is suitable for output with `assemble_name'. */
#define ASM_GENERATE_INTERNAL_LABEL(LABEL,PREFIX,NUM) \
sprintf (LABEL, "*%s%d", PREFIX, NUM)
/* This is how to output an assembler line defining a `double' constant. */
/* do {...} while(0) is necessary, because these macros are used as
if (xxx) MACRO; else ....
^
*/
#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \
do { union { double d; long l[2];} tem; \
tem.d = (VALUE); \
fprintf (FILE, "\t.fdata.d h'%x%08x.d\n", tem.l[0], tem.l[1]); \
} while(0)
/* This is how to output an assembler line defining a `float' constant. */
#define ASM_OUTPUT_FLOAT(FILE,VALUE) \
do { union { float f; long l;} tem; \
tem.f = (VALUE); \
fprintf (FILE, "\t.fdata.s h'%x.s\n", tem.l); \
} while(0)
/* This is how to output an assembler line defining an `int' constant. */
#define ASM_OUTPUT_INT(FILE,VALUE) \
( fprintf (FILE, "\t.data.w "), \
output_addr_const (FILE, (VALUE)), \
fprintf (FILE, "\n"))
/* Likewise for `char' and `short' constants. */
#define ASM_OUTPUT_SHORT(FILE,VALUE) \
( fprintf (FILE, "\t.data.h "), \
output_addr_const (FILE, (VALUE)), \
fprintf (FILE, "\n"))
#define ASM_OUTPUT_CHAR(FILE,VALUE) \
( fprintf (FILE, "\t.data.b "), \
output_addr_const (FILE, (VALUE)), \
fprintf (FILE, "\n"))
/* This is how to output an assembler line for a numeric constant byte. */
#define ASM_OUTPUT_BYTE(FILE,VALUE) \
fprintf (FILE, "\t.data.b h'%x\n", (VALUE))
#define ASM_OUTPUT_ASCII(FILE,P,SIZE) \
output_ascii ((FILE), (P), (SIZE))
/* This is how to output an insn to push a register on the stack.
It need not be very fast code. */
#define ASM_OUTPUT_REG_PUSH(FILE,REGNO) \
fprintf (FILE, "\tmov %s,@-sp\n", reg_names[REGNO])
/* This is how to output an insn to pop a register from the stack.
It need not be very fast code. */
#define ASM_OUTPUT_REG_POP(FILE,REGNO) \
fprintf (FILE, "\tmov @sp+,%s\n", reg_names[REGNO])
/* This is how to output an element of a case-vector that is absolute.
(The Gmicro does not use such vectors,
but we must define this macro anyway.) */
#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \
fprintf (FILE, "\t.data.w L%d\n", VALUE)
/* This is how to output an element of a case-vector that is relative. */
#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \
fprintf (FILE, "\t.data.w L%d-L%d\n", VALUE, REL)
/* This is how to output an assembler line
that says to advance the location counter
to a multiple of 2**LOG bytes. */
#define ASM_OUTPUT_ALIGN(FILE,LOG) \
fprintf (FILE, "\t.align %d\n", (1 << (LOG)));
#define ASM_OUTPUT_SKIP(FILE,SIZE) \
fprintf (FILE, "\t.res.b %d\n", (SIZE))
/* This says how to output an assembler line
to define a global common symbol. */
#define ASM_OUTPUT_COMMON(FILE, NAME, SIZE, ROUNDED) \
( bss_section (), \
assemble_name ((FILE), (NAME)), \
fprintf ((FILE), ":\t.res.b %d\n", (ROUNDED)),\
fprintf ((FILE), "\t.export "), \
assemble_name ((FILE), (NAME)), \
fprintf ((FILE), "\n") )
/* This says how to output an assembler line
to define a local common symbol. */
#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \
( bss_section (), \
assemble_name ((FILE), (NAME)), \
fprintf ((FILE), ":\t.res.b %d\n", (ROUNDED)))
/* Store in OUTPUT a string (made with alloca) containing
an assembler-name for a local static variable named NAME.
LABELNO is an integer which is different for each call. */
/* $__ is unique ????? M.Yuhara */
#define ASM_FORMAT_PRIVATE_NAME(OUTPUT, NAME, LABELNO) \
( (OUTPUT) = (char *) alloca (strlen ((NAME)) + 12), \
sprintf ((OUTPUT), "$__%s%d", (NAME), (LABELNO)))
/* Define the parentheses used to group arithmetic operations
in assembler code. */
#define ASM_OPEN_PAREN "("
#define ASM_CLOSE_PAREN ")"
/* Define results of standard character escape sequences. */
#define TARGET_BELL 007
#define TARGET_BS 010
#define TARGET_TAB 011
#define TARGET_NEWLINE 012
#define TARGET_VT 013
#define TARGET_FF 014
#define TARGET_CR 015
/* Output a float value (represented as a C double) as an immediate operand.
This macro is a Gmicro/68k-specific macro. */
#define ASM_OUTPUT_FLOAT_OPERAND(FILE,VALUE) \
do { union { float f; long l;} tem; \
tem.f = (VALUE); \
fprintf (FILE, "#h'%x.s", tem.l); \
} while(0)
/* Output a double value (represented as a C double) as an immediate operand.
This macro is a 68k-specific macro. */
#define ASM_OUTPUT_DOUBLE_OPERAND(FILE,VALUE) \
do { union { double d; long l[2];} tem; \
tem.d = (VALUE); \
fprintf (FILE, "#h'%x%08x.d", tem.l[0], tem.l[1]); \
} while(0)
/* Print operand X (an rtx) in assembler syntax to file FILE.
CODE is a letter or dot (`z' in `%z0') or 0 if no letter was specified.
For `%' followed by punctuation, CODE is the punctuation and X is null.
On the Gmicro, we use several CODE characters:
'f' for float insn (print a CONST_DOUBLE as a float rather than in hex)
'b' for branch target label.
'-' for an operand pushing on the stack.
'+' for an operand pushing on the stack.
'#' for an immediate operand prefix
*/
#define PRINT_OPERAND_PUNCT_VALID_P(CODE) \
( (CODE) == '#' || (CODE) == '-' \
|| (CODE) == '+' || (CODE) == '@' || (CODE) == '!')
#define PRINT_OPERAND(FILE, X, CODE) \
{ int i; \
static char *reg_name[] = REGISTER_NAMES; \
/* fprintf (stderr, "PRINT_OPERAND CODE=%c(0x%x), ", CODE, CODE);\
myprcode(GET_CODE(X)); */ \
if (CODE == '#') fprintf (FILE, "#"); \
else if (CODE == '-') fprintf (FILE, "@-sp"); \
else if (CODE == '+') fprintf (FILE, "@sp+"); \
else if (CODE == 's') fprintf (stderr, "err: PRINT_OPERAND <s>\n"); \
else if (CODE == '!') fprintf (stderr, "err: PRINT_OPERAND <!>\n"); \
else if (CODE == '.') fprintf (stderr, "err: PRINT_OPERAND <.>\n"); \
else if (CODE == 'b') { \
if (GET_CODE (X) == MEM) \
output_addr_const (FILE, XEXP (X, 0)); /* for bsr */ \
else \
output_addr_const (FILE, X); /* for bcc */ \
} \
else if (CODE == 'p') \
print_operand_address (FILE, X); \
else if (GET_CODE (X) == REG) \
fprintf (FILE, "%s", reg_name[REGNO (X)]); \
else if (GET_CODE (X) == MEM) \
output_address (XEXP (X, 0)); \
else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) == SFmode) \
{ union { double d; int i[2]; } u; \
union { float f; int i; } u1; \
u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); \
u1.f = u.d; \
if (CODE == 'f') \
ASM_OUTPUT_FLOAT_OPERAND (FILE, u1.f); \
else \
fprintf (FILE, "#h'%x", u1.i); } \
else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) == DFmode) \
{ union { double d; int i[2]; } u; \
u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); \
ASM_OUTPUT_DOUBLE_OPERAND (FILE, u.d); } \
else { putc ('#', FILE); \
output_addr_const (FILE, X); }}
/* Note that this contains a kludge that knows that the only reason
we have an address (plus (label_ref...) (reg...))
is in the insn before a tablejump, and we know that m68k.md
generates a label LInnn: on such an insn. */
#define PRINT_OPERAND_ADDRESS(FILE, ADDR) \
{ print_operand_address (FILE, ADDR); }
/*
Local variables:
version-control: t
End:
*/
;;- Machine description for GNU compiler, Fujitsu Gmicro Version
;; Copyright (C) 1990, 1994, 1996, 1998, 1999 Free Software Foundation, Inc.
;; Contributed by M.Yuhara, Fujitsu Laboratories LTD.
;; 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.
;; Among other things, the copyright
;; notice and this notice must be preserved on all copies.
;; 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, 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.
;;- instruction definitions
;;- See file "rtl.def" for documentation on define_insn, match_*, et. al.
;;- When naming insn's (operand 0 of define_insn) be careful about using
;;- names from other targets machine descriptions.
;;- cpp macro #define NOTICE_UPDATE_CC is essentially a no-op for the
;;- gmicro; no compares are eliminated.
;;- The original structure of this file is m68k.md.
;; ??? Work to be done:
;; Add patterns for ACB and SCB instructions.
;; Add define_insn patterns to recognize the insns that extend a byte
;; to a word and add it into a word, etc.
;;- Some of these insn's are composites of several Gmicro op codes.
;;- The assembler (or final @@??) insures that the appropriate one is
;;- selected.
(define_insn ""
[(set (match_operand:DF 0 "push_operand" "=m")
(match_operand:DF 1 "general_operand" "rmfF"))]
""
"*
{
if (FPU_REG_P (operands[1]))
return \"fmov.d %f1,%0\";
return output_move_double (operands);
}")
;; This pattern is illegal (modes of SET_DEST and SET_SRC don't match).
;; It is not clear what it was intended to accomplish, therefore
;; I have not corrected it. -zw, 1999-09-13
;(define_insn ""
; [(set (match_operand:DI 0 "push_operand" "=m")
; (match_operand:DF 1 "general_operand" "rmF"))]
; ""
; "*
;{
; return output_move_double (operands);
;}")
;; We don't want to allow a constant operand for test insns because
;; (set (cc0) (const_int foo)) has no mode information. Such insns will
;; be folded while optimizing anyway.
(define_insn "tstsi"
[(set (cc0)
(match_operand:SI 0 "nonimmediate_operand" "rm"))]
""
"cmp:z.w #0,%0")
(define_insn "tsthi"
[(set (cc0)
(match_operand:HI 0 "nonimmediate_operand" "rm"))]
""
"cmp:z.h #0,%0")
(define_insn "tstqi"
[(set (cc0)
(match_operand:QI 0 "nonimmediate_operand" "rm"))]
""
"cmp:z.b #0,%0")
(define_insn "tstsf"
[(set (cc0)
(match_operand:SF 0 "general_operand" "fmF"))]
"TARGET_FPU"
"*
{
cc_status.flags = CC_IN_FPU;
return \"ftst.s %0\";
}")
(define_insn "tstdf"
[(set (cc0)
(match_operand:DF 0 "general_operand" "fmF"))]
"TARGET_FPU"
"*
{
cc_status.flags = CC_IN_FPU;
return \"ftst.d %0\";
}")
;; compare instructions.
;; (operand0 - operand1)
(define_insn "cmpsi"
[(set (cc0)
(compare (match_operand:SI 0 "nonimmediate_operand" "ri,rm")
(match_operand:SI 1 "general_operand" "rm,rmi")))]
""
"*
{
int signed_flag = my_signed_comp (insn);
if (which_alternative == 0)
{
cc_status.flags |= CC_REVERSED;
if (signed_flag && GET_CODE (operands[0]) == CONST_INT)
{
register rtx xfoo;
xfoo = operands[1];
operands[0] = operands[1];
operands[1] = xfoo;
return cmp_imm_word (INTVAL (operands[1]), operands[0]);
}
if (signed_flag)
return \"cmp.w %0,%1\";
return \"cmpu.w %0,%1\";
}
if (signed_flag)
{
if (GET_CODE (operands[1]) == CONST_INT)
return cmp_imm_word (INTVAL (operands[1]), operands[0]);
return \"cmp.w %1,%0\";
}
else
return \"cmpu.w %1,%0\";
}")
(define_insn "cmphi"
[(set (cc0)
(compare (match_operand:HI 0 "nonimmediate_operand" "ri,rm")
(match_operand:HI 1 "general_operand" "rm,rmi")))]
""
"*
{
int signed_flag = my_signed_comp (insn);
if (which_alternative == 0)
{
cc_status.flags |= CC_REVERSED;
if (signed_flag)
return \"cmp.h %0,%1\";
return \"cmpu.h %0,%1\";
}
if (signed_flag)
return \"cmp.h %1,%0\";
return \"cmpu.h %1,%0\";
}")
(define_insn "cmpqi"
[(set (cc0)
(compare (match_operand:QI 0 "nonimmediate_operand" "ri,rm")
(match_operand:QI 1 "general_operand" "rm,rmi")))]
""
"*
{
int signed_flag = my_signed_comp (insn);
if (which_alternative == 0)
{
cc_status.flags |= CC_REVERSED;
if (signed_flag)
return \"cmp.b %0,%1\";
return \"cmpu.b %0,%1\";
}
if (signed_flag)
return \"cmp.b %1,%0\";
return \"cmpu.b %1,%0\";
}")
(define_insn "cmpdf"
[(set (cc0)
(compare (match_operand:DF 0 "general_operand" "f,mG")
(match_operand:DF 1 "general_operand" "fmG,f")))]
"TARGET_FPU"
"*
{
cc_status.flags = CC_IN_FPU;
if (FPU_REG_P (operands[0]))
return \"fcmp.d %f1,%f0\";
cc_status.flags |= CC_REVERSED;
return \"fcmp.d %f0,%f1\";
}")
(define_insn "cmpsf"
[(set (cc0)
(compare (match_operand:SF 0 "general_operand" "f,mG")
(match_operand:SF 1 "general_operand" "fmG,f")))]
"TARGET_FPU"
"*
{
cc_status.flags = CC_IN_FPU;
if (FPU_REG_P (operands[0]))
return \"fcmp.s %f1,%0\";
cc_status.flags |= CC_REVERSED;
return \"fcmp.s %f0,%1\";
}")
;; Recognizers for btst instructions.
(define_insn ""
[(set (cc0) (zero_extract (match_operand:QI 0 "memory_operand" "m")
(const_int 1)
(match_operand:SI 1 "general_operand" "rmi")))]
""
"btst %1.w,%0.b")
(define_insn ""
[(set (cc0) (zero_extract (match_operand:SI 0 "register_operand" "rm")
(const_int 1)
(match_operand:SI 1 "general_operand" "rmi")))]
""
"btst %1.w,%0.w")
;; The following two patterns are like the previous two
;; except that they use the fact that bit-number operands (offset)
;; are automatically masked to 3 or 5 bits when the base is a register.
(define_insn ""
[(set (cc0) (zero_extract (match_operand:QI 0 "memory_operand" "m")
(const_int 1)
(and:SI
(match_operand:SI 1 "general_operand" "rmi")
(const_int 7))))]
""
"btst %1.w,%0.b")
(define_insn ""
[(set (cc0) (zero_extract (match_operand:SI 0 "register_operand" "r")
(const_int 1)
(and:SI
(match_operand:SI 1 "general_operand" "rmi")
(const_int 31))))]
""
"btst %1.w,%0.w")
; More various size-patterns are allowed for btst, but not
; included yet. M.Yuhara
(define_insn ""
[(set (cc0) (and:SI (sign_extend:SI
(sign_extend:HI
(match_operand:QI 0 "nonimmediate_operand" "rm")))
(match_operand:SI 1 "general_operand" "i")))]
"(GET_CODE (operands[1]) == CONST_INT
&& (unsigned) INTVAL (operands[1]) < 0x100
&& exact_log2 (INTVAL (operands[1])) >= 0)"
"*
{
register int log = exact_log2 (INTVAL (operands[1]));
operands[1] = GEN_INT (log);
return \"btst %1,%0.b\";
}")
; I can add more patterns like above. But not yet. M.Yuhara
; mtst is supported only by G/300.
(define_insn ""
[(set (cc0)
(and:SI (match_operand:SI 0 "general_operand" "%rmi")
(match_operand:SI 1 "general_operand" "rm")))]
"TARGET_G300"
"*
{
if (GET_CODE (operands[0]) == CONST_INT)
return \"mtst.w %0,%1\";
return \"mtst.w %1,%0\";
}")
(define_insn ""
[(set (cc0)
(and:HI (match_operand:HI 0 "general_operand" "%rmi")
(match_operand:HI 1 "general_operand" "rm")))]
"TARGET_G300"
"*
{
if (GET_CODE (operands[0]) == CONST_INT)
return \"mtst.h %0,%1\";
return \"mtst.h %1,%0\";
}")
(define_insn ""
[(set (cc0)
(and:QI (match_operand:QI 0 "general_operand" "%rmi")
(match_operand:QI 1 "general_operand" "rm")))]
"TARGET_G300"
"*
{
if (GET_CODE (operands[0]) == CONST_INT)
return \"mtst.b %0,%1\";
return \"mtst.b %1,%0\";
}")
;; move instructions
/* added by M.Yuhara */
;; 1.35.04 89.08.28 modification start
;; register_operand -> general_operand
;; ashift -> mult
(define_insn ""
[(set (mem:SI (plus:SI
(match_operand:SI 0 "general_operand" "r")
(ashift:SI
(match_operand:SI 1 "general_operand" "r")
(const_int 2))))
(match_operand:SI 2 "general_operand" "rmi"))]
""
"*
{
return \"mov.w %2,@(%0:b,%1*4)\";
}")
(define_insn ""
[(set (mem:SI (plus:SI
(ashift:SI
(match_operand:SI 0 "general_operand" "r")
(const_int 2))
(match_operand:SI 1 "general_operand" "r")))
(match_operand:SI 2 "general_operand" "rmi"))]
""
"*
{
return \"mov.w %2,@(%1:b,%0*4)\";
}")
(define_insn ""
[(set (mem:SI (plus:SI
(match_operand:SI 0 "register_operand" "r")
(mult:SI
(match_operand:SI 1 "register_operand" "r")
(const_int 4))))
(match_operand:SI 2 "general_operand" "rmi"))]
""
"*
{
return \"mov.w %2,@(%0:b,%1*4)\";
}")
(define_insn ""
[(set (mem:SI (plus:SI
(mult:SI
(match_operand:SI 0 "register_operand" "r")
(const_int 4))
(match_operand:SI 1 "register_operand" "r")))
(match_operand:SI 2 "general_operand" "rmi"))]
""
"*
{
return \"mov.w %2,@(%1:b,%0*4)\";
}")
(define_insn ""
[(set (mem:SI (plus:SI
(match_operand:SI 0 "general_operand" "r")
(plus:SI
(match_operand:SI 1 "register_operand" "r")
(match_operand:SI 2 "register_operand" "i"))))
(match_operand:SI 3 "general_operand" "rmi"))]
""
"*
{
return \"mov.w %3,@(%c2,%0,%1)\";
}")
(define_insn ""
[(set (mem:SI (plus:SI
(plus:SI
(match_operand:SI 0 "register_operand" "r")
(match_operand:SI 1 "register_operand" "r"))
(match_operand:SI 2 "general_operand" "i")))
(match_operand:SI 3 "general_operand" "rmi"))]
""
"*
{
return \"mov.w %3,@(%c2,%0,%1)\";
}")
(define_insn ""
[(set (mem:SI (plus:SI
(match_operand:SI 0 "general_operand" "i")
(plus:SI
(match_operand:SI 1 "register_operand" "r")
(mult:SI
(match_operand:SI 2 "register_operand" "r")
(const_int 4)))))
(match_operand:SI 3 "general_operand" "rmi"))]
""
"*
{
return \"mov.w %3,@(%1:b,%0,%2*4)\";
}")
;; 89.08.28 1.35.04 modification end
;; Should add "!" to op2 ??
;; General move-address-to-operand should handle these.
;; If that does not work, please figure out why.
;(define_insn ""
; [(set (match_operand:SI 0 "push_operand" "=m")
; (plus:SI
; (match_operand:SI 1 "immediate_operand" "i")
; (match_operand:SI 2 "general_operand" "r")))]
; ""
; "mova.w @(%c1,%2),%-")
;(define_insn ""
; [(set (match_operand:SI 0 "push_operand" "=m")
; (plus:SI
; (match_operand:SI 1 "general_operand" "r")
; (match_operand:SI 2 "immediate_operand" "i")))]
; ""
; "mova.w @(%c2,%1),%-")
(define_insn ""
[(set (match_operand:SI 0 "push_operand" "=m")
(minus:SI
(match_operand:SI 1 "general_operand" "r")
(match_operand:SI 2 "immediate_operand" "i")))]
""
"mova.w @(%n2,%1),%-")
;; General case of fullword move.
(define_insn "movsi"
[(set (match_operand:SI 0 "general_operand" "=rm")
(match_operand:SI 1 "general_operand" "rmi"))]
""
"*
{
if (GET_CODE (operands[1]) == CONST_INT)
return mov_imm_word (INTVAL (operands[1]), operands[0]);
/* if (address_operand (operands[1], SImode))
return \"mova.w %1,%0\"; */
if (push_operand (operands[0], SImode))
return \"mov.w %1,%-\";
return \"mov.w %1,%0\";
}")
/* pushsi 89.08.10 for test M.Yuhara */
/*
(define_insn ""
[(set (match_operand:SI 0 "push_operand" "=m")
(match_operand:SI 1 "general_operand" "rmi"))]
""
"*
{
if (GET_CODE (operands[1]) == CONST_INT)
return mov_imm_word (INTVAL (operands[1]), operands[0]);
if (push_operand (operands[0], SImode))
return \"mov.w %1,%-\";
return \"mov.w %1,%0\";
}")
*/
(define_insn "movhi"
[(set (match_operand:HI 0 "general_operand" "=rm")
(match_operand:HI 1 "general_operand" "rmi"))]
""
"*
{
if (push_operand (operands[0], SImode))
return \"mov.h %1,%-\";
return \"mov.h %1,%0\";
}")
;; Is the operand constraint "+" necessary ????
;; Should I check push_operand ????
(define_insn "movstricthi"
[(set (strict_low_part (match_operand:HI 0 "general_operand" "+rm"))
(match_operand:HI 1 "general_operand" "rmi"))]
""
"mov.h %1,%0");
(define_insn "movqi"
[(set (match_operand:QI 0 "general_operand" "=rm")
(match_operand:QI 1 "general_operand" "rmi"))]
""
"*
{
if (GREG_P (operands[0]))
{
if (CONSTANT_P (operands[1]))
return \"mov:l %1,%0.w\";
else
return \"mov:l %1.b,%0.w\";
}
if (GREG_P (operands[1]))
return \"mov:s %1.w,%0.b\";
return \"mov.b %1,%0\";
}")
(define_insn "movstrictqi"
[(set (strict_low_part (match_operand:QI 0 "general_operand" "+rm"))
(match_operand:QI 1 "general_operand" "rmi"))]
""
"mov.b %1,%0")
(define_insn "movsf"
[(set (match_operand:SF 0 "general_operand" "=f,mf,rm,fr")
(match_operand:SF 1 "general_operand" "mfF,f,rmF,fr"))]
""
"*
{
switch (which_alternative)
{
case 0:
if (GET_CODE (operands[1]) == CONST_DOUBLE)
return output_move_const_single (operands);
return \"fmov.s %1,%0\";
case 1:
return \"fmov.s %1,%0\";
case 2:
if (GET_CODE (operands[1]) == CONST_DOUBLE)
return output_move_const_single (operands);
return \"mov.w %1,%0\";
case 3:
if (FPU_REG_P (operands[0]))
return \"mov.w %1,%-\\n\\tfmov.s %+,%0\";
return \"fmov.s %1,%-\\n\\tmov.w %+,%0\";
}
}")
(define_insn "movdf"
[(set (match_operand:DF 0 "general_operand" "=f,mf,rm,fr")
(match_operand:DF 1 "general_operand" "mfF,f,rmF,fr"))]
""
"*
{
switch (which_alternative)
{
case 0:
if (GET_CODE (operands[1]) == CONST_DOUBLE)
return output_move_const_double (operands);
return \"fmov.d %1,%0\";
case 1:
return \"fmov.d %1,%0\";
case 2:
if (GET_CODE (operands[1]) == CONST_DOUBLE)
return output_move_const_double (operands);
return output_move_double (operands);
case 3:
if (FPU_REG_P (operands[0]))
{
rtx xoperands[2];
xoperands[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1);
output_asm_insn (\"mov.w %1,%-\", xoperands);
output_asm_insn (\"mov.w %1,%-\", operands);
return \"fmov.d %+,%0\";
}
else
{
output_asm_insn (\"fmov.d %f1,%-\", operands);
output_asm_insn (\"mov.w %+,%0\", operands);
operands[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
return \"mov.w %+,%0\";
}
}
}")
;; movdi can apply to fp regs in some cases
;; Must check again. you can use fsti/fldi, etc.
;; FPU reg should be included ??
;; 89.12.13 for test
(define_insn "movdi"
;; Let's see if it really still needs to handle fp regs, and, if so, why.
[(set (match_operand:DI 0 "general_operand" "=rm,&r,&ro")
(match_operand:DI 1 "general_operand" "rF,m,roiF"))]
""
"*
{
if (FPU_REG_P (operands[0]))
{
if (FPU_REG_P (operands[1]))
return \"fmov.d %1,%0\";
if (REG_P (operands[1]))
{
rtx xoperands[2];
xoperands[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1);
output_asm_insn (\"mov.w %1,%-\", xoperands);
output_asm_insn (\"mov.w %1,%-\", operands);
return \"fmov.d %+,%0\";
}
if (GET_CODE (operands[1]) == CONST_DOUBLE)
return output_move_const_double (operands);
return \"fmov.d %f1,%0\";
}
else if (FPU_REG_P (operands[1]))
{
if (REG_P (operands[0]))
{
output_asm_insn (\"fmov.d %f1,%-\;mov.w %+,%0\", operands);
operands[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
return \"mov.w %+,%0\";
}
else
return \"fmov.d %f1,%0\";
}
return output_move_double (operands);
}
")
;; The definition of this insn does not really explain what it does,
;; but it should suffice
;; that anything generated as this insn will be recognized as one
;; and that it won't successfully combine with anything.
;; This is dangerous when %0 and %1 overlapped !!!!!
;; Ugly code...
(define_insn "movstrhi"
[(set (match_operand:BLK 0 "general_operand" "=m")
(match_operand:BLK 1 "general_operand" "m"))
(use (match_operand:HI 2 "general_operand" "rmi"))
(clobber (reg:SI 0))
(clobber (reg:SI 1))
(clobber (reg:SI 2))]
""
"*
{
int op2const;
rtx tmpx;
if (CONSTANT_P (operands[1]))
{
fprintf (stderr, \"smov 1 const err \");
abort ();
}
else if (GET_CODE (operands[1]) == REG)
{
fprintf (stderr, \"smov 1 reg err \");
abort ();
}
else if (GET_CODE (operands[1]) == MEM)
{
tmpx = XEXP (operands[1], 0);
if (CONSTANT_ADDRESS_P (tmpx) || GREG_P (tmpx))
{
operands[1] = tmpx;
output_asm_insn (\"mov.w %1,r0\", operands);
}
else
{
output_asm_insn (\"mova %1,r0\", operands);
}
}
else
{
fprintf (stderr, \"smov 1 else err \");
abort ();
output_asm_insn (\"mova.w %p1,r0\", operands);
}
if (CONSTANT_P (operands[0]))
{
fprintf (stderr, \"smov 0 const err \");
abort ();
}
else if (GET_CODE (operands[0]) == REG)
{
fprintf (stderr, \"smov 0 reg err \");
abort ();
}
else if (GET_CODE (operands[0]) == MEM)
{
tmpx = XEXP (operands[0], 0);
if (CONSTANT_ADDRESS_P (tmpx) || GREG_P (tmpx))
{
operands[0] = tmpx;
output_asm_insn (\"mov.w %0,r1\", operands);
}
else
{
output_asm_insn (\"mova %0,r1\", operands);
}
}
else
{
fprintf (stderr, \"smov 0 else err \");
abort ();
}
if (GET_CODE (operands[2]) == CONST_INT)
{
op2const = INTVAL (operands[2]);
if (op2const % 4 != 0)
{
output_asm_insn (\"mov.w %2,r2\", operands);
return \"smov/n/f.b\";
}
op2const = op2const / 4;
if (op2const <= 4)
{
if (op2const == 0)
abort (0);
if (op2const == 1)
return \"mov.w @r0,@r1\";
output_asm_insn (\"mov.w @r0,@r1\", operands);
if (op2const == 2)
return \"mov.w @(4,r0),@(4,r1)\";
output_asm_insn (\"mov.w @(4,r0),@(4,r1)\", operands);
if (op2const == 3)
return \"mov.w @(8,r0),@(8,r1)\";
output_asm_insn (\"mov.w @(8,r0),@(8,r1)\", operands);
return \"mov.w @(12,r0),@(12,r1)\";
}
operands[2] = GEN_INT (op2const);
output_asm_insn (\"mov.w %2,r2\", operands);
return \"smov/n/f.w\";
}
else
{
fprintf (stderr, \"smov 0 else err \");
abort ();
output_asm_insn (\"mov %2.h,r2.w\", operands);
return \"smov/n/f.b\";
}
}")
;; M.Yuhara 89.08.24
;; experiment on the built-in strcpy (__builtin_smov)
;;
;; len = 0 means unknown string length.
;;
;; mem:SI is dummy. Necessary so as not to be deleted by optimization.
;; Use of BLKmode would be better...
;;
;;
(define_insn "smovsi"
[(set (mem:SI (match_operand:SI 0 "general_operand" "=rm"))
(mem:SI (match_operand:SI 1 "general_operand" "rm")))
(use (match_operand:SI 2 "general_operand" "i"))
(clobber (reg:SI 0))
(clobber (reg:SI 1))
(clobber (reg:SI 2))
(clobber (reg:SI 3))]
""
"*
{
int len, wlen, blen, offset;
char tmpstr[128];
rtx xoperands[1];
len = INTVAL (operands[2]);
output_asm_insn (\"mov.w %1,r0\\t; begin built-in strcpy\", operands);
output_asm_insn (\"mov.w %0,r1\", operands);
if (len == 0)
{
output_asm_insn (\"mov:z.w #0,r2\", operands);
output_asm_insn (\"mov:z.w #0,r3\", operands);
return \"smov/eq/f.b\\t; end built-in strcpy\";
}
wlen = len / 4;
blen = len - wlen * 4;
if (wlen > 0)
{
if (len <= 40 && !TARGET_FORCE_SMOV)
{
output_asm_insn (\"mov.w @r0,@r1\", operands);
offset = 4;
while ( (blen = len - offset) > 0)
{
if (blen >= 4)
{
sprintf (tmpstr, \"mov.w @(%d,r0),@(%d,r1)\",
offset, offset);
output_asm_insn (tmpstr, operands);
offset += 4;
}
else if (blen >= 2)
{
sprintf (tmpstr, \"mov.h @(%d,r0),@(%d,r1)\",
offset, offset);
output_asm_insn (tmpstr, operands);
offset += 2;
}
else
{
sprintf (tmpstr, \"mov.b @(%d,r0),@(%d,r1)\",
offset, offset);
output_asm_insn (tmpstr, operands);
offset++;
}
}
return \"\\t\\t; end built-in strcpy\";
}
else
{
xoperands[0] = GEN_INT (wlen);
output_asm_insn (\"mov.w %0,r2\", xoperands);
output_asm_insn (\"smov/n/f.w\", operands);
}
}
if (blen >= 2)
{
output_asm_insn (\"mov.h @r0,@r1\", operands);
if (blen == 3)
output_asm_insn (\"mov.b @(2,r0),@(2,r1)\", operands);
}
else if (blen == 1)
{
output_asm_insn (\"mov.b @r0,@r1\", operands);
}
return \"\\t\\t; end built-in strcpy\";
}")
;; truncation instructions
(define_insn "truncsiqi2"
[(set (match_operand:QI 0 "general_operand" "=rm")
(truncate:QI
(match_operand:SI 1 "general_operand" "rmi")))]
""
"mov %1.w,%0.b")
; "*
;{
; if (GET_CODE (operands[0]) == REG)
; return \"mov.w %1,%0\";
; if (GET_CODE (operands[1]) == MEM)
; operands[1] = adj_offsettable_operand (operands[1], 3);
; return \"mov.b %1,%0\";
;}")
(define_insn "trunchiqi2"
[(set (match_operand:QI 0 "general_operand" "=rm")
(truncate:QI
(match_operand:HI 1 "general_operand" "rmi")))]
""
"mov %1.h,%0.b")
; "*
;{
; if (GET_CODE (operands[0]) == REG)
; return \"mov.h %1,%0\";
; if (GET_CODE (operands[1]) == MEM)
; operands[1] = adj_offsettable_operand (operands[1], 1);
; return \"mov.b %1,%0\";
;}")
(define_insn "truncsihi2"
[(set (match_operand:HI 0 "general_operand" "=rm")
(truncate:HI
(match_operand:SI 1 "general_operand" "rmi")))]
""
"mov %1.w,%0.h")
; "*
;{
; if (GET_CODE (operands[0]) == REG)
; return \"mov.w %1,%0\";
; if (GET_CODE (operands[1]) == MEM)
; operands[1] = adj_offsettable_operand (operands[1], 2);
; return \"mov.h %1,%0\";
;}")
;; zero extension instructions
;; define_expand (68k) -> define_insn (Gmicro)
(define_insn "zero_extendhisi2"
[(set (match_operand:SI 0 "general_operand" "=rm")
(zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "rm")))]
""
"movu %1.h,%0.w")
(define_insn "zero_extendqihi2"
[(set (match_operand:HI 0 "general_operand" "=rm")
(zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "rm")))]
""
"movu %1.b,%0.h")
(define_insn "zero_extendqisi2"
[(set (match_operand:SI 0 "general_operand" "=rm")
(zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "rm")))]
""
"movu %1.b,%0.w")
;; sign extension instructions
(define_insn "extendhisi2"
[(set (match_operand:SI 0 "general_operand" "=rm")
(sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "rm")))]
""
"mov %1.h,%0.w")
(define_insn "extendqihi2"
[(set (match_operand:HI 0 "general_operand" "=rm")
(sign_extend:HI (match_operand:QI 1 "nonimmediate_operand" "rm")))]
""
"mov %1.b,%0.h")
(define_insn "extendqisi2"
[(set (match_operand:SI 0 "general_operand" "=rm")
(sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "rm")))]
""
"mov %1.b,%0.w")
;; Conversions between float and double.
(define_insn "extendsfdf2"
[(set (match_operand:DF 0 "general_operand" "=*frm,f")
(float_extend:DF
(match_operand:SF 1 "general_operand" "f,rmF")))]
"TARGET_FPU"
"*
{
if (FPU_REG_P (operands[0]))
{
if (GET_CODE (operands[1]) == CONST_DOUBLE)
return output_move_const_double (operands);
if (GREG_P (operands[1]))
{
output_asm_insn (\"mov.w %1,%-\", operands);
return \"fmov %+.s,%0.d\";
}
return \"fmov %1.s,%0.d\";
}
else
{
if (GREG_P (operands[0]))
{
output_asm_insn (\"fmov %1.s,%-.d\", operands);
output_asm_insn (\"mov.w %+,%0\", operands);
operands[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
return \"mov.w %+,%0\";
}
return \"fmov %1.s,%0.d\";
}
}")
(define_insn "truncdfsf2"
[(set (match_operand:SF 0 "general_operand" "=rfm")
(float_truncate:SF
(match_operand:DF 1 "general_operand" "f")))]
"TARGET_FPU"
"*
{
if (GREG_P (operands[0]))
{
output_asm_insn (\"fmov %1.d,%-.s\", operands);
return \"mov.w %+,%0\";
}
return \"fmov %1.d,%0.s\";
}")
;; Conversion between fixed point and floating point.
;; Note that among the fix-to-float insns
;; the ones that start with SImode come first.
;; That is so that an operand that is a CONST_INT
;; (and therefore lacks a specific machine mode).
;; will be recognized as SImode (which is always valid)
;; rather than as QImode or HImode.
(define_insn "floatsisf2"
[(set (match_operand:SF 0 "general_operand" "=f")
(float:SF (match_operand:SI 1 "general_operand" "rmi")))]
"TARGET_FPU"
"fldi %1.w,%0.s")
(define_insn "floatsidf2"
[(set (match_operand:DF 0 "general_operand" "=f")
(float:DF (match_operand:SI 1 "general_operand" "rmi")))]
"TARGET_FPU"
"fldi %1.w,%0.d")
(define_insn "floathisf2"
[(set (match_operand:SF 0 "general_operand" "=f")
(float:SF (match_operand:HI 1 "general_operand" "rmi")))]
"TARGET_FPU"
"fldi %1.h,%0.s")
(define_insn "floathidf2"
[(set (match_operand:DF 0 "general_operand" "=f")
(float:DF (match_operand:HI 1 "general_operand" "rmi")))]
"TARGET_FPU"
"fldi %1.h,%0.d")
(define_insn "floatqisf2"
[(set (match_operand:SF 0 "general_operand" "=f")
(float:SF (match_operand:QI 1 "general_operand" "rmi")))]
"TARGET_FPU"
"fldi %1.b,%0.s")
(define_insn "floatqidf2"
[(set (match_operand:DF 0 "general_operand" "=f")
(float:DF (match_operand:QI 1 "general_operand" "rmi")))]
"TARGET_FPU"
"fldi %1.b,%0.d")
;;; Convert a float to a float whose value is an integer.
;;; This is the first stage of converting it to an integer type.
;
;(define_insn "ftruncdf2"
; [(set (match_operand:DF 0 "general_operand" "=f")
; (fix:DF (match_operand:DF 1 "general_operand" "fFm")))]
; "TARGET_FPU"
; "*
;{
; return \"fintrz.d %f1,%0\";
;}")
;
;(define_insn "ftruncsf2"
; [(set (match_operand:SF 0 "general_operand" "=f")
; (fix:SF (match_operand:SF 1 "general_operand" "fFm")))]
; "TARGET_FPU"
; "*
;{
; return \"fintrz.s %f1,%0\";
;}")
;; Convert a float to an integer.
(define_insn "fix_truncsfqi2"
[(set (match_operand:QI 0 "general_operand" "=rm")
(fix:QI (fix:SF (match_operand:SF 1 "general_operand" "f"))))]
"TARGET_FPU"
"fsti %1.s,%0.b")
(define_insn "fix_truncsfhi2"
[(set (match_operand:HI 0 "general_operand" "=rm")
(fix:HI (fix:SF (match_operand:SF 1 "general_operand" "f"))))]
"TARGET_FPU"
"fsti %1.s,%0.h")
(define_insn "fix_truncsfsi2"
[(set (match_operand:SI 0 "general_operand" "=rm")
(fix:SI (fix:SF (match_operand:SF 1 "general_operand" "f"))))]
"TARGET_FPU"
"fsti %1.s,%0.w")
(define_insn "fix_truncdfqi2"
[(set (match_operand:QI 0 "general_operand" "=rm")
(fix:QI (fix:DF (match_operand:DF 1 "general_operand" "f"))))]
"TARGET_FPU"
"fsti %1.d,%0.b")
(define_insn "fix_truncdfhi2"
[(set (match_operand:HI 0 "general_operand" "=rm")
(fix:HI (fix:DF (match_operand:DF 1 "general_operand" "f"))))]
"TARGET_FPU"
"fsti %1.d,%0.h")
(define_insn "fix_truncdfsi2"
[(set (match_operand:SI 0 "general_operand" "=rm")
(fix:SI (fix:DF (match_operand:DF 1 "general_operand" "f"))))]
"TARGET_FPU"
"fsti %1.d,%0.w")
;;; Special add patterns
;;; 89.09.28
;; This should be redundant; please find out why regular addsi3
;; fails to match this case.
;(define_insn ""
; [(set (mem:SI (plus:SI
; (plus:SI (match_operand 0 "general_operand" "r")
; (match_operand 1 "general_operand" "r"))
; (match_operand 2 "general_operand" "i")))
; (plus:SI
; (mem:SI (plus:SI
; (plus:SI (match_dup 0)
; (match_dup 1))
; (match_dup 2)))
; (match_operand 3 "general_operand" "rmi")))]
; ""
; "add.w %3,@(%c2,%0,%1)")
;; add instructions
;; Note that the last two alternatives are near-duplicates
;; in order to handle insns generated by reload.
;; This is needed since they are not themselves reloaded,
;; so commutativity won't apply to them.
(define_insn "addsi3"
[(set (match_operand:SI 0 "general_operand" "=rm,!r,!r")
(plus:SI (match_operand:SI 1 "general_operand" "%0,r,ri")
(match_operand:SI 2 "general_operand" "rmi,ri,r")))]
""
"*
{
if (which_alternative == 0)
{
if (GET_CODE (operands[2]) == CONST_INT)
{
operands[1] = operands[2];
return add_imm_word (INTVAL (operands[1]), operands[0], &operands[1]);
}
else
return \"add.w %2,%0\";
}
else
{
if (GET_CODE (operands[1]) == REG
&& REGNO (operands[0]) == REGNO (operands[1]))
return \"add.w %2,%0\";
if (GET_CODE (operands[2]) == REG
&& REGNO (operands[0]) == REGNO (operands[2]))
return \"add.w %1,%0\";
if (GET_CODE (operands[1]) == REG)
{
if (GET_CODE (operands[2]) == REG)
return \"mova.w @(%1,%2),%0\";
else
return \"mova.w @(%c2,%1),%0\";
}
else
return \"mova.w @(%c1,%2),%0\";
}
}")
(define_insn ""
[(set (match_operand:SI 0 "general_operand" "=rm")
(plus:SI (match_operand:SI 1 "general_operand" "0")
(sign_extend:SI (match_operand:HI 2 "nonimmediate_operand" "rmi"))))]
""
"*
{
if (CONSTANT_P (operands[2]))
{
operands[1] = operands[2];
return add_imm_word (INTVAL (operands[1]), operands[0], &operands[1]);
}
else
return \"add %2.h,%0.w\";
}")
(define_insn "addhi3"
[(set (match_operand:HI 0 "general_operand" "=rm")
(plus:HI (match_operand:HI 1 "general_operand" "%0")
(match_operand:HI 2 "general_operand" "rmi")))]
""
"*
{
if (GET_CODE (operands[2]) == CONST_INT
&& INTVAL (operands[2]) < 0)
return \"sub.h #%n2,%0\";
if (GREG_P (operands[0]))
{
if (CONSTANT_P (operands[2]))
return \"add:l %2,%0.w\";
else
return \"add:l %2.h,%0.w\";
}
return \"add.h %2,%0\";
}")
(define_insn ""
[(set (strict_low_part (match_operand:HI 0 "general_operand" "+rm"))
(plus:HI (match_dup 0)
(match_operand:HI 1 "general_operand" "rmi")))]
""
"add.h %1,%0")
(define_insn "addqi3"
[(set (match_operand:QI 0 "general_operand" "=rm")
(plus:QI (match_operand:QI 1 "general_operand" "%0")
(match_operand:QI 2 "general_operand" "rmi")))]
""
"*
{
if (GET_CODE (operands[2]) == CONST_INT
&& INTVAL (operands[2]) < 0)
return \"sub.b #%n2,%0\";
if (GREG_P (operands[0]))
{
if (CONSTANT_P (operands[2]))
return \"add:l %2,%0.w\";
else
return \"add:l %2.b,%0.w\";
}
return \"add.b %2,%0\";
}")
(define_insn ""
[(set (strict_low_part (match_operand:QI 0 "general_operand" "+rm"))
(plus:QI (match_dup 0)
(match_operand:QI 1 "general_operand" "rmi")))]
""
"add.b %1,%0")
(define_insn "adddf3"
[(set (match_operand:DF 0 "general_operand" "=f")
(plus:DF (match_operand:DF 1 "general_operand" "%0")
(match_operand:DF 2 "general_operand" "fmG")))]
"TARGET_FPU"
"fadd.d %f2,%0")
(define_insn "addsf3"
[(set (match_operand:SF 0 "general_operand" "=f")
(plus:SF (match_operand:SF 1 "general_operand" "%0")
(match_operand:SF 2 "general_operand" "fmG")))]
"TARGET_FPU"
"fadd.s %f2,%0")
;; subtract instructions
(define_insn "subsi3"
[(set (match_operand:SI 0 "general_operand" "=rm,!r")
(minus:SI (match_operand:SI 1 "general_operand" "0,r")
(match_operand:SI 2 "general_operand" "rmi,i")))]
""
"*
{
if (which_alternative == 0
|| (GET_CODE (operands[1]) == REG
&& REGNO (operands[0]) == REGNO (operands[1])))
{
if (GET_CODE (operands[2]) == CONST_INT)
{
operands[1] = operands[2];
return sub_imm_word (INTVAL (operands[1]),
operands[0], &operands[1]);
}
else
return \"sub.w %2,%0\";
}
else
return \"mova.w @(%n2,%1),%0\";
}")
(define_insn ""
[(set (match_operand:SI 0 "general_operand" "=rm")
(minus:SI (match_operand:SI 1 "general_operand" "0")
(sign_extend:SI (match_operand:HI 2 "nonimmediate_operand" "rmi"))))]
""
"sub %2.h,%0.w")
(define_insn "subhi3"
[(set (match_operand:HI 0 "general_operand" "=rm")
(minus:HI (match_operand:HI 1 "general_operand" "0")
(match_operand:HI 2 "general_operand" "rmi")))]
""
"*
{
if (GET_CODE (operands[2]) == CONST_INT
&& INTVAL (operands[2]) < 0
&& INTVAL (operands[2]) != 0x8000)
return \"add.h #%n2,%0\";
return \"sub.h %2,%0\";
}")
(define_insn ""
[(set (strict_low_part (match_operand:HI 0 "general_operand" "+rm"))
(minus:HI (match_dup 0)
(match_operand:HI 1 "general_operand" "rmi")))]
""
"sub.h %1,%0")
(define_insn "subqi3"
[(set (match_operand:QI 0 "general_operand" "=rm")
(minus:QI (match_operand:QI 1 "general_operand" "0")
(match_operand:QI 2 "general_operand" "rmi")))]
""
"*
{
if (GET_CODE (operands[2]) == CONST_INT
&& INTVAL (operands[2]) < 0
&& INTVAL (operands[2]) != 0x80)
return \"add.b #%n2,%0\";
return \"sub.b %2,%0\";
}")
(define_insn ""
[(set (strict_low_part (match_operand:QI 0 "general_operand" "+rm"))
(minus:QI (match_dup 0)
(match_operand:QI 1 "general_operand" "rmi")))]
""
"sub.b %1,%0")
(define_insn "subdf3"
[(set (match_operand:DF 0 "general_operand" "=f")
(minus:DF (match_operand:DF 1 "general_operand" "0")
(match_operand:DF 2 "general_operand" "fmG")))]
"TARGET_FPU"
"fsub.d %f2,%0")
(define_insn "subsf3"
[(set (match_operand:SF 0 "general_operand" "=f")
(minus:SF (match_operand:SF 1 "general_operand" "0")
(match_operand:SF 2 "general_operand" "fmG")))]
"TARGET_FPU"
"fsub.s %f2,%0")
;; multiply instructions
(define_insn "mulqi3"
[(set (match_operand:QI 0 "general_operand" "=rm")
(mult:QI (match_operand:QI 1 "general_operand" "%0")
(match_operand:QI 2 "general_operand" "rmi")))]
""
"mul.b %2,%0")
(define_insn "mulhi3"
[(set (match_operand:HI 0 "general_operand" "=rm")
(mult:HI (match_operand:HI 1 "general_operand" "%0")
(match_operand:HI 2 "general_operand" "rmi")))]
""
"mul.h %2,%0")
;; define_insn "mulhisi3"
(define_insn "mulsi3"
[(set (match_operand:SI 0 "general_operand" "=rm")
(mult:SI (match_operand:SI 1 "general_operand" "%0")
(match_operand:SI 2 "general_operand" "rmi")))]
""
"mul.w %2,%0")
(define_insn "muldf3"
[(set (match_operand:DF 0 "general_operand" "=f")
(mult:DF (match_operand:DF 1 "general_operand" "%0")
(match_operand:DF 2 "general_operand" "fmG")))]
"TARGET_FPU"
"fmul.d %f2,%0")
(define_insn "mulsf3"
[(set (match_operand:SF 0 "general_operand" "=f")
(mult:SF (match_operand:SF 1 "general_operand" "%0")
(match_operand:SF 2 "general_operand" "fmG")))]
"TARGET_FPU"
"fmul.s %f2,%0")
;; divide instructions
(define_insn "divqi3"
[(set (match_operand:QI 0 "general_operand" "=rm")
(div:QI (match_operand:QI 1 "general_operand" "0")
(match_operand:QI 2 "general_operand" "rmi")))]
""
"div.b %2,%0")
(define_insn "divhi3"
[(set (match_operand:HI 0 "general_operand" "=rm")
(div:HI (match_operand:HI 1 "general_operand" "0")
(match_operand:HI 2 "general_operand" "rmi")))]
""
"div.h %2,%0")
(define_insn "divhisi3"
[(set (match_operand:HI 0 "general_operand" "=r")
(div:HI (match_operand:SI 1 "general_operand" "0")
(match_operand:HI 2 "general_operand" "rmi")))]
""
"div %2.h,%0.w")
(define_insn "divsi3"
[(set (match_operand:SI 0 "general_operand" "=rm")
(div:SI (match_operand:SI 1 "general_operand" "0")
(match_operand:SI 2 "general_operand" "rmi")))]
""
"div.w %2,%0")
(define_insn "udivqi3"
[(set (match_operand:QI 0 "general_operand" "=rm")
(udiv:QI (match_operand:QI 1 "general_operand" "0")
(match_operand:QI 2 "general_operand" "rmi")))]
""
"divu.b %2,%0")
(define_insn "udivhi3"
[(set (match_operand:HI 0 "general_operand" "=rm")
(udiv:HI (match_operand:HI 1 "general_operand" "0")
(match_operand:HI 2 "general_operand" "rmi")))]
""
"divu.h %2,%0")
(define_insn "udivhisi3"
[(set (match_operand:HI 0 "general_operand" "=r")
(udiv:HI (match_operand:SI 1 "general_operand" "0")
(match_operand:HI 2 "general_operand" "rmi")))]
""
"divu %2.h,%0.w")
(define_insn "udivsi3"
[(set (match_operand:SI 0 "general_operand" "=rm")
(udiv:SI (match_operand:SI 1 "general_operand" "0")
(match_operand:SI 2 "general_operand" "rmi")))]
""
"divu.w %2,%0")
(define_insn "divdf3"
[(set (match_operand:DF 0 "general_operand" "=f")
(div:DF (match_operand:DF 1 "general_operand" "0")
(match_operand:DF 2 "general_operand" "fmG")))]
"TARGET_FPU"
"fdiv.d %f2,%0")
(define_insn "divsf3"
[(set (match_operand:SF 0 "general_operand" "=f")
(div:SF (match_operand:SF 1 "general_operand" "0")
(match_operand:SF 2 "general_operand" "fmG")))]
"TARGET_FPU"
"fdiv.s %f2,%0")
;; Remainder instructions.
(define_insn "modqi3"
[(set (match_operand:QI 0 "general_operand" "=rm")
(mod:QI (match_operand:QI 1 "general_operand" "0")
(match_operand:QI 2 "general_operand" "rmi")))]
""
"rem.b %2,%0")
(define_insn "modhisi3"
[(set (match_operand:HI 0 "general_operand" "=r")
(mod:HI (match_operand:SI 1 "general_operand" "0")
(match_operand:HI 2 "general_operand" "rmi")))]
""
"rem.h %2,%0")
(define_insn "umodqi3"
[(set (match_operand:QI 0 "general_operand" "=rm")
(umod:QI (match_operand:QI 1 "general_operand" "0")
(match_operand:QI 2 "general_operand" "rmi")))]
""
"remu.b %2,%0")
(define_insn "umodhi3"
[(set (match_operand:HI 0 "general_operand" "=rm")
(umod:HI (match_operand:HI 1 "general_operand" "0")
(match_operand:HI 2 "general_operand" "rmi")))]
""
"remu.h %2,%0")
(define_insn "umodhisi3"
[(set (match_operand:HI 0 "general_operand" "=r")
(umod:HI (match_operand:SI 1 "general_operand" "0")
(match_operand:HI 2 "general_operand" "rmi")))]
""
"remu %2.h,%0.w")
;; define_insn "divmodsi4"
(define_insn "udivmodsi4"
[(set (match_operand:SI 0 "general_operand" "=rm")
(udiv:SI (match_operand:SI 1 "general_operand" "0")
(match_operand:SI 2 "general_operand" "rmi")))
(set (match_operand:SI 3 "general_operand" "=r")
(umod:SI (match_dup 1) (match_dup 2)))]
""
"mov.w #0,%3;divx.w %2,%0,%3")
;; logical-and instructions
(define_insn "andsi3"
[(set (match_operand:SI 0 "general_operand" "=rm")
(and:SI (match_operand:SI 1 "general_operand" "%0")
(match_operand:SI 2 "general_operand" "rmi")))]
""
"*
{
if (GET_CODE (operands[2]) == CONST_INT
&& (INTVAL (operands[2]) | 0xffff) == 0xffffffff
&& (GREG_P (operands[0])
|| offsettable_memref_p (operands[0])))
{
if (GET_CODE (operands[0]) != REG)
operands[0] = adj_offsettable_operand (operands[0], 2);
operands[2] = GEN_INT (INTVAL (operands[2]) & 0xffff);
/* Do not delete a following tstl %0 insn; that would be incorrect. */
CC_STATUS_INIT;
return \"and.h %2,%0\";
}
return \"and.w %2,%0\";
}")
(define_insn "andhi3"
[(set (match_operand:HI 0 "general_operand" "=rm")
(and:HI (match_operand:HI 1 "general_operand" "%0")
(match_operand:HI 2 "general_operand" "rmi")))]
""
"and.h %2,%0")
(define_insn "andqi3"
[(set (match_operand:QI 0 "general_operand" "=rm")
(and:QI (match_operand:QI 1 "general_operand" "%0")
(match_operand:QI 2 "general_operand" "rmi")))]
""
"and.b %2,%0")
(define_insn ""
[(set (match_operand:SI 0 "general_operand" "=r")
(and:SI (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "rm"))
(match_operand:SI 2 "general_operand" "0")))]
""
"*
{
if (GET_CODE (operands[1]) == CONST_INT)
return \"and %1,%0.w\";
return \"and %1.h,%0.w\";
}")
(define_insn ""
[(set (match_operand:SI 0 "general_operand" "=r")
(and:SI (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "rm"))
(match_operand:SI 2 "general_operand" "0")))]
""
"*
{
if (GET_CODE (operands[1]) == CONST_INT)
return \"and %1,%0.w\";
return \"and %1.b,%0.w\";
}")
;; inclusive-or instructions
(define_insn "iorsi3"
[(set (match_operand:SI 0 "general_operand" "=rm")
(ior:SI (match_operand:SI 1 "general_operand" "%0")
(match_operand:SI 2 "general_operand" "rmi")))]
""
"*
{
register int logval;
if (GET_CODE (operands[2]) == CONST_INT
&& INTVAL (operands[2]) >> 16 == 0
&& (GREG_P (operands[0])
|| offsettable_memref_p (operands[0])))
{
if (GET_CODE (operands[0]) != REG)
operands[0] = adj_offsettable_operand (operands[0], 2);
/* Do not delete a following tstl %0 insn; that would be incorrect. */
CC_STATUS_INIT;
return \"or.h %2,%0\";
}
if (GET_CODE (operands[2]) == CONST_INT
&& (logval = exact_log2 (INTVAL (operands[2]))) >= 0
&& (GREG_P (operands[0])
|| offsettable_memref_p (operands[0])))
{
if (GREG_P (operands[0]))
{
if (logval < 7)
{
operands[1] = GEN_INT (7 - logval);
return \"bset.b %1,%0\";
}
operands[1] = GEN_INT (31 - logval);
return \"bset.w %1,%0\";
}
else
{
operands[0]
= adj_offsettable_operand (operands[0], 3 - (logval / 8));
operands[1] = GEN_INT (7 - (logval % 8));
}
return \"bset.b %1,%0\";
}
return \"or.w %2,%0\";
}")
(define_insn "iorhi3"
[(set (match_operand:HI 0 "general_operand" "=rm")
(ior:HI (match_operand:HI 1 "general_operand" "%0")
(match_operand:HI 2 "general_operand" "rmi")))]
""
"or.h %2,%0")
(define_insn "iorqi3"
[(set (match_operand:QI 0 "general_operand" "=rm")
(ior:QI (match_operand:QI 1 "general_operand" "%0")
(match_operand:QI 2 "general_operand" "rmi")))]
""
"or.b %2,%0")
;; xor instructions
(define_insn "xorsi3"
[(set (match_operand:SI 0 "general_operand" "=rm")
(xor:SI (match_operand:SI 1 "general_operand" "%0")
(match_operand:SI 2 "general_operand" "rmi")))]
""
"*
{
if (GET_CODE (operands[2]) == CONST_INT
&& INTVAL (operands[2]) >> 16 == 0
&& (offsettable_memref_p (operands[0]) || GREG_P (operands[0])))
{
if (! GREG_P (operands[0]))
operands[0] = adj_offsettable_operand (operands[0], 2);
/* Do not delete a following tstl %0 insn; that would be incorrect. */
CC_STATUS_INIT;
return \"xor.h %2,%0\";
}
return \"xor.w %2,%0\";
}")
(define_insn "xorhi3"
[(set (match_operand:HI 0 "general_operand" "=rm")
(xor:HI (match_operand:HI 1 "general_operand" "%0")
(match_operand:HI 2 "general_operand" "rmi")))]
""
"xor.h %2,%0")
(define_insn "xorqi3"
[(set (match_operand:QI 0 "general_operand" "=rm")
(xor:QI (match_operand:QI 1 "general_operand" "%0")
(match_operand:QI 2 "general_operand" "rmi")))]
""
"xor.b %2,%0")
;; negation instructions
(define_insn "negsi2"
[(set (match_operand:SI 0 "general_operand" "=rm")
(neg:SI (match_operand:SI 1 "general_operand" "0")))]
""
"neg.w %0")
(define_insn "neghi2"
[(set (match_operand:HI 0 "general_operand" "=rm")
(neg:HI (match_operand:HI 1 "general_operand" "0")))]
""
"neg.h %0")
(define_insn "negqi2"
[(set (match_operand:QI 0 "general_operand" "=rm")
(neg:QI (match_operand:QI 1 "general_operand" "0")))]
""
"neg.b %0")
(define_insn "negsf2"
[(set (match_operand:SF 0 "general_operand" "=f")
(neg:SF (match_operand:SF 1 "general_operand" "fmF")))]
"TARGET_FPU"
"fneg.s %f1,%0")
(define_insn "negdf2"
[(set (match_operand:DF 0 "general_operand" "=f")
(neg:DF (match_operand:DF 1 "general_operand" "fmF")))]
"TARGET_FPU"
"fneg.d %f1,%0")
;; Absolute value instructions
(define_insn "abssf2"
[(set (match_operand:SF 0 "general_operand" "=f")
(abs:SF (match_operand:SF 1 "general_operand" "fmF")))]
"TARGET_FPU"
"fabs.s %f1,%0")
(define_insn "absdf2"
[(set (match_operand:DF 0 "general_operand" "=f")
(abs:DF (match_operand:DF 1 "general_operand" "fmF")))]
"TARGET_FPU"
"fabs.d %f1,%0")
;; one complement instructions
(define_insn "one_cmplsi2"
[(set (match_operand:SI 0 "general_operand" "=rm")
(not:SI (match_operand:SI 1 "general_operand" "0")))]
""
"not.w %0")
(define_insn "one_cmplhi2"
[(set (match_operand:HI 0 "general_operand" "=rm")
(not:HI (match_operand:HI 1 "general_operand" "0")))]
""
"not.h %0")
(define_insn "one_cmplqi2"
[(set (match_operand:QI 0 "general_operand" "=rm")
(not:QI (match_operand:QI 1 "general_operand" "0")))]
""
"not.b %0")
;; Optimized special case of shifting.
;; Must precede the general case.
(define_insn ""
[(set (match_operand:SI 0 "general_operand" "=r")
(ashiftrt:SI (match_operand:SI 1 "memory_operand" "m")
(const_int 24)))]
"GET_CODE (XEXP (operands[1], 0)) != POST_INC
&& GET_CODE (XEXP (operands[1], 0)) != PRE_DEC"
"mov:l %1.b,%0.w")
(define_insn ""
[(set (match_operand:SI 0 "general_operand" "=r")
(lshiftrt:SI (match_operand:SI 1 "memory_operand" "m")
(const_int 24)))]
"GET_CODE (XEXP (operands[1], 0)) != POST_INC
&& GET_CODE (XEXP (operands[1], 0)) != PRE_DEC"
"movu %1.b,%0.w")
(define_insn ""
[(set (cc0) (compare (match_operand:QI 0 "general_operand" "i")
(lshiftrt:SI (match_operand:SI 1 "memory_operand" "m")
(const_int 24))))]
"(GET_CODE (operands[0]) == CONST_INT
&& (INTVAL (operands[0]) & ~0xff) == 0)"
"*
{
cc_status.flags |= CC_REVERSED;
if (my_signed_comp (insn))
return \"cmp.b %0,%1\";
return \"cmpu.b %0,%1\";
}")
(define_insn ""
[(set (cc0) (compare (lshiftrt:SI (match_operand:SI 0 "memory_operand" "m")
(const_int 24))
(match_operand:QI 1 "general_operand" "i")))]
"(GET_CODE (operands[1]) == CONST_INT
&& (INTVAL (operands[1]) & ~0xff) == 0)"
"*
if (my_signed_comp (insn))
return \"cmp.b %1,%0\";
return \"cmpu.b %1,%0\";
")
(define_insn ""
[(set (cc0) (compare (match_operand:QI 0 "general_operand" "i")
(ashiftrt:SI (match_operand:SI 1 "memory_operand" "m")
(const_int 24))))]
"(GET_CODE (operands[0]) == CONST_INT
&& ((INTVAL (operands[0]) + 0x80) & ~0xff) == 0)"
"*
cc_status.flags |= CC_REVERSED;
if (my_signed_comp (insn))
return \"cmp.b %0,%1\";
return \"cmpu.b %0,%1\";
")
(define_insn ""
[(set (cc0) (compare (ashiftrt:SI (match_operand:SI 0 "memory_operand" "m")
(const_int 24))
(match_operand:QI 1 "general_operand" "i")))]
"(GET_CODE (operands[1]) == CONST_INT
&& ((INTVAL (operands[1]) + 0x80) & ~0xff) == 0)"
"*
if (my_signed_comp (insn))
return \"cmp.b %1,%0\";
return \"cmpu.b %1,%0\";
")
;; arithmetic shift instructions
;; We don't need the shift memory by 1 bit instruction
(define_insn "ashlsi3"
[(set (match_operand:SI 0 "general_operand" "=rm")
(ashift:SI (match_operand:SI 1 "general_operand" "0")
(match_operand:SI 2 "general_operand" "rmi")))]
""
"sha.w %2,%0")
(define_insn "ashlhi3"
[(set (match_operand:HI 0 "general_operand" "=rm")
(ashift:HI (match_operand:HI 1 "general_operand" "0")
(match_operand:HI 2 "general_operand" "rmi")))]
""
"sha.h %2,%0")
(define_insn "ashlqi3"
[(set (match_operand:QI 0 "general_operand" "=rm")
(ashift:QI (match_operand:QI 1 "general_operand" "0")
(match_operand:QI 2 "general_operand" "rmi")))]
""
"sha.b %2,%0")
;; Arithmetic right shift on the Gmicro works by negating the shift count
;; ashiftrt -> ashift
(define_expand "ashrsi3"
[(set (match_operand:SI 0 "general_operand" "=rm")
(ashift:SI (match_operand:SI 1 "general_operand" "0")
(match_operand:SI 2 "general_operand" "rmi")))]
""
"{ operands[2] = negate_rtx (SImode, operands[2]); }")
;; ashiftrt -> ashift
(define_expand "ashrhi3"
[(set (match_operand:HI 0 "general_operand" "=rm")
(ashift:HI (match_operand:HI 1 "general_operand" "0")
(match_operand:HI 2 "general_operand" "rmi")))]
""
" { operands[2] = negate_rtx (HImode, operands[2]); }")
;; ashiftrt -> ashift
(define_expand "ashrqi3"
[(set (match_operand:QI 0 "general_operand" "=rm")
(ashift:QI (match_operand:QI 1 "general_operand" "0")
(match_operand:QI 2 "general_operand" "rmi")))]
""
" { operands[2] = negate_rtx (QImode, operands[2]); }")
;; logical shift instructions
;; Logical right shift on the gmicro works by negating the shift count,
;; then emitting a right shift with the shift count negated. This means
;; that all actual shift counts in the RTL will be positive. This
;; prevents converting shifts to ZERO_EXTRACTs with negative positions,
;; which isn't valid.
(define_expand "lshrsi3"
[(set (match_operand:SI 0 "general_operand" "=g")
(lshiftrt:SI (match_operand:SI 1 "general_operand" "g")
(match_operand:SI 2 "general_operand" "g")))]
""
"
{
if (GET_CODE (operands[2]) != CONST_INT)
operands[2] = gen_rtx_NEG (SImode, negate_rtx (SImode, operands[2]));
}")
(define_insn ""
[(set (match_operand:SI 0 "general_operand" "=rm")
(lshiftrt:SI (match_operand:SI 1 "general_operand" "0")
(match_operand:SI 2 "const_int_operand" "n")))]
""
"shl.w %n2,%0")
(define_insn ""
[(set (match_operand:SI 0 "general_operand" "=rm")
(lshiftrt:SI (match_operand:SI 1 "general_operand" "0")
(neg:SI (match_operand:SI 2 "general_operand" "rm"))))]
""
"shl.w %2,%0")
(define_expand "lshrhi3"
[(set (match_operand:HI 0 "general_operand" "=g")
(lshiftrt:HI (match_operand:HI 1 "general_operand" "g")
(match_operand:HI 2 "general_operand" "g")))]
""
"
{
if (GET_CODE (operands[2]) != CONST_INT)
operands[2] = gen_rtx_NEG (HImode, negate_rtx (HImode, operands[2]));
}")
(define_insn ""
[(set (match_operand:HI 0 "general_operand" "=rm")
(lshiftrt:HI (match_operand:HI 1 "general_operand" "0")
(match_operand:HI 2 "const_int_operand" "n")))]
""
"shl.h %n2,%0")
(define_insn ""
[(set (match_operand:HI 0 "general_operand" "=rm")
(lshiftrt:HI (match_operand:HI 1 "general_operand" "0")
(neg:HI (match_operand:HI 2 "general_operand" "rm"))))]
""
"shl.h %2,%0")
(define_expand "lshrqi3"
[(set (match_operand:QI 0 "general_operand" "=g")
(lshiftrt:QI (match_operand:QI 1 "general_operand" "g")
(match_operand:QI 2 "general_operand" "g")))]
""
"
{
if (GET_CODE (operands[2]) != CONST_INT)
operands[2] = gen_rtx_NEG (QImode, negate_rtx (QImode, operands[2]));
}")
(define_insn ""
[(set (match_operand:QI 0 "general_operand" "=rm")
(lshiftrt:QI (match_operand:QI 1 "general_operand" "0")
(match_operand:QI 2 "const_int_operand" "n")))]
""
"shl.b %n2,%0")
(define_insn ""
[(set (match_operand:QI 0 "general_operand" "=rm")
(lshiftrt:QI (match_operand:QI 1 "general_operand" "0")
(neg:QI (match_operand:QI 2 "general_operand" "rm"))))]
""
"shl.b %2,%0")
;; rotate instructions
(define_insn "rotlsi3"
[(set (match_operand:SI 0 "general_operand" "=rm")
(rotate:SI (match_operand:SI 1 "general_operand" "0")
(match_operand:SI 2 "general_operand" "rmi")))]
""
"rol.w %2,%0")
(define_insn "rotlhi3"
[(set (match_operand:HI 0 "general_operand" "=rm")
(rotate:HI (match_operand:HI 1 "general_operand" "0")
(match_operand:HI 2 "general_operand" "rmi")))]
""
"rol.h %2,%0")
(define_insn "rotlqi3"
[(set (match_operand:QI 0 "general_operand" "=rm")
(rotate:QI (match_operand:QI 1 "general_operand" "0")
(match_operand:QI 2 "general_operand" "rmi")))]
""
"rol.b %2,%0")
(define_expand "rotrsi3"
[(set (match_operand:SI 0 "general_operand" "=rm")
(rotatert:SI (match_operand:SI 1 "general_operand" "0")
(match_operand:SI 2 "general_operand" "rmi")))]
""
" { operands[2] = negate_rtx (SImode, operands[2]); }")
(define_expand "rotrhi3"
[(set (match_operand:HI 0 "general_operand" "=rm")
(rotatert:HI (match_operand:HI 1 "general_operand" "0")
(match_operand:HI 2 "general_operand" "rmi")))]
""
" { operands[2] = negate_rtx (HImode, operands[2]); }")
(define_expand "rotrqi3"
[(set (match_operand:QI 0 "general_operand" "=rm")
(rotatert:QI (match_operand:QI 1 "general_operand" "0")
(match_operand:QI 2 "general_operand" "rmi")))]
""
" { operands[2] = negate_rtx (QImode, operands[2]); }")
;; Special cases of bit-field insns which we should
;; recognize in preference to the general case.
;; These handle aligned 8-bit and 16-bit fields,
;; which can usually be done with move instructions.
;; Should I add mode_dependent_address_p ????
(define_insn ""
[(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+rm")
(match_operand:SI 1 "immediate_operand" "i")
(match_operand:SI 2 "immediate_operand" "i"))
(match_operand:SI 3 "general_operand" "rm"))]
"TARGET_BITFIELD
&& GET_CODE (operands[1]) == CONST_INT
&& (INTVAL (operands[1]) == 8 || INTVAL (operands[1]) == 16)
&& GET_CODE (operands[2]) == CONST_INT
&& INTVAL (operands[2]) % INTVAL (operands[1]) == 0
&& (GET_CODE (operands[0]) != REG
|| ( INTVAL (operands[1]) + INTVAL (operands[2]) == 32))"
"*
{
if (GET_CODE (operands[3]) == MEM)
operands[3] = adj_offsettable_operand (operands[3],
(32 - INTVAL (operands[1])) / 8);
if (GET_CODE (operands[0]) == REG)
{
if (INTVAL (operands[1]) == 8)
return \"movu %3.b,%0.w\";
return \"movu %3.h,%0.w\";
}
else
{
operands[0]
= adj_offsettable_operand (operands[0], INTVAL (operands[2]) / 8);
if (INTVAL (operands[1]) == 8)
return \"mov.b %3,%0\";
return \"mov.h %3,%0\";
}
}")
(define_insn ""
[(set (match_operand:SI 0 "general_operand" "=&r")
(zero_extract:SI (match_operand:SI 1 "register_operand" "rm")
(match_operand:SI 2 "immediate_operand" "i")
(match_operand:SI 3 "immediate_operand" "i")))]
"TARGET_BITFIELD
&& GET_CODE (operands[2]) == CONST_INT
&& (INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 16)
&& GET_CODE (operands[3]) == CONST_INT
&& INTVAL (operands[3]) % INTVAL (operands[2]) == 0"
"*
{
if (!REG_P (operands[1]))
operands[1]
= adj_offsettable_operand (operands[1], INTVAL (operands[3]) / 8);
if (REG_P (operands[0]))
{
if (REG_P (operands[1]))
{
if (INTVAL (operands[2]) == 8)
{ /* width == 8 */
switch (INTVAL (operands[3]))
{
case 0:
return \"mov.w %1,%0;shl.w #-24,%0\";
break;
case 8:
return \"mov.w %1,%0;shl.w #8,%0;shl.w #-24,%0\";
break;
case 16:
return \"mov.w %1,%0;shl.w #16,%0;shl.w #-24,%0\";
break;
case 24:
return \"movu %1.b,%0.w\";
break;
default:
myabort (2);
}
}
else
{
switch (INTVAL (operands[3]))
{
case 0:
return \"mov.w %1,%0;shl.w #-16,%0\";
break;
case 16:
return \"movu %1.h,%0.w\";
break;
default:
myabort (3);
}
}
}
else
{
if (INTVAL (operands[2]) == 8)
return \"movu %1.h,%0.w\";
else
return \"movu %1.b,%0.w\";
}
}
else
{ /* op[0] == MEM */
if (INTVAL (operands[2]) == 8)
return \"movu %1.b,%0.w\";
return \"movu %1.h,%0.w\";
}
}")
(define_insn ""
[(set (match_operand:SI 0 "general_operand" "=r")
(sign_extract:SI (match_operand:SI 1 "register_operand" "ro")
(match_operand:SI 2 "immediate_operand" "i")
(match_operand:SI 3 "immediate_operand" "i")))]
"TARGET_BITFIELD
&& GET_CODE (operands[2]) == CONST_INT
&& (INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 16)
&& GET_CODE (operands[3]) == CONST_INT
&& INTVAL (operands[3]) % INTVAL (operands[2]) == 0"
"*
{
if (!REG_P (operands[1]))
operands[1]
= adj_offsettable_operand (operands[1], INTVAL (operands[3]) / 8);
if (REG_P (operands[0]))
{
if (REG_P (operands[1]))
{
if (INTVAL (operands[2]) == 8)
{ /* width == 8 */
switch (INTVAL (operands[3]))
{
case 0:
return \"mov.w %1,%0;sha.w #-24,%0\";
break;
case 8:
return \"mov.w %1,%0;shl.w #8,%0;sha.w #-24,%0\";
break;
case 16:
return \"mov.w %1,%0;shl.w #16,%0;sha.w #-24,%0\";
break;
case 24:
return \"mov %1.b,%0.w\";
break;
default:
myabort (4);
}
}
else
{
switch (INTVAL (operands[3]))
{
case 0:
return \"mov.w %1,%0;sha.w #-16,%0\";
break;
case 16:
return \"mov %1.h,%0.w\";
break;
default:
myabort (5);
}
}
}
else
{
if (INTVAL (operands[2]) == 8)
return \"mov %1.h,%0.w\";
else
return \"mov %1.b,%0.w\";
}
}
else
{ /* op[0] == MEM */
if (INTVAL (operands[2]) == 8)
return \"mov %1.b,%0.w\";
return \"mov %1.h,%0.w\";
}
}")
;; Bit field instructions, general cases.
;; "o,d" constraint causes a nonoffsettable memref to match the "o"
;; so that its address is reloaded.
;; extv dest:SI src(:QI/:SI) width:SI pos:SI
;; r.w m r.w/# rmi
;; %0 %1 %2 %3
(define_expand "extv"
[(set (match_operand:SI 0 "general_operand" "")
(sign_extract:SI (match_operand:SI 1 "general_operand" "")
(match_operand:SI 2 "general_operand" "")
(match_operand:SI 3 "general_operand" "")))]
"TARGET_BITFIELD"
"")
(define_insn ""
[(set (match_operand:SI 0 "general_operand" "=r")
(sign_extract:SI (match_operand:QI 1 "memory_operand" "m")
(match_operand:SI 2 "general_operand" "ri")
(match_operand:SI 3 "general_operand" "rmi")))]
"TARGET_BITFIELD"
"bfext %3,%2,%1,%0")
(define_expand "extzv"
[(set (match_operand:SI 0 "general_operand" "")
(zero_extract:SI (match_operand:SI 1 "general_operand" "")
(match_operand:SI 2 "general_operand" "")
(match_operand:SI 3 "general_operand" "")))]
"TARGET_BITFIELD"
"")
(define_insn ""
[(set (match_operand:SI 0 "general_operand" "=r")
(zero_extract:SI (match_operand:QI 1 "memory_operand" "m")
(match_operand:SI 2 "general_operand" "ri")
(match_operand:SI 3 "general_operand" "rmi")))]
"TARGET_BITFIELD"
"bfextu %3,%2,%1,%0")
;; There is no insn on the Gmicro to NOT/SET/CLR bitfield.
;; insv dest(BF):QI/SI width:SI pos:SI src:SI
;; m r.w rmi r.w/i
;; 0 1 2 3
(define_expand "insv"
[(set (zero_extract:SI (match_operand:SI 0 "general_operand" "")
(match_operand:SI 1 "general_operand" "")
(match_operand:SI 2 "general_operand" ""))
(match_operand:SI 3 "general_operand" ""))]
"TARGET_BITFIELD"
"")
(define_insn ""
[(set (zero_extract:SI (match_operand:QI 0 "memory_operand" "+m,m")
(match_operand:SI 1 "general_operand" "r,i")
(match_operand:SI 2 "general_operand" "rmi,i"))
(match_operand:SI 3 "general_operand" "ri,ri"))]
"TARGET_BITFIELD"
"bfinsu %3,%2,%1,%0")
;;; bfins/bfinsu ????????
;; == == == == == == == == == == == == ==
;; Now recognize bit field insns that operate on registers
;; (or at least were intended to do so).
;; On the Gmicro/300,
;; bitfield instructions are not applicable to registers ;-<
;; But I write the register cases, because without them the gcc
;; seems to use "and" instruction with some other instructions
;; instead of using a shift instruction.
;; It is because on many processors shift instructions are slower.
;; On the Gmicro/300 which has a barrel shifter,
;; it is faster to use a shift instruction.
;;
;; Restricts width and offset to be immediates.
;;
(define_insn ""
[(set (match_operand:SI 0 "general_operand" "=r")
(sign_extract:SI (match_operand:SI 1 "register_operand" "r")
(match_operand:SI 2 "immediate_operand" "i")
(match_operand:SI 3 "immediate_operand" "i")))]
"TARGET_BITFIELD"
"*
{
if (REGNO (operands[0]) != REGNO (operands[1]))
output_asm_insn (\"mov.w %1,%0\", operands);
if (INTVAL (operands[3]) != 0)
output_asm_insn (\"shl.w %3,%0\", operands);
operands[2] = GEN_INT (-(32 - INTVAL (operands[2])));
return \"sha.w %3,%0\";
}")
(define_insn ""
[(set (match_operand:SI 0 "general_operand" "=r")
(zero_extract:SI (match_operand:SI 1 "register_operand" "r")
(match_operand:SI 2 "immediate_operand" "i")
(match_operand:SI 3 "immediate_operand" "i")))]
"TARGET_BITFIELD"
"*
{
if (REGNO (operands[0]) != REGNO (operands[1]))
output_asm_insn (\"mov.w %1,%0\", operands);
if (INTVAL (operands[3]) != 0)
output_asm_insn (\"shl.w %3,%0\", operands);
operands[2] = GEN_INT (- (32 - INTVAL (operands[2])));
return \"shl.w %3,%0\";
}")
;; There are more descriptions for m68k, but not yet for the Gmicro.
;;
;; Basic conditional jump instructions.
(define_insn "beq"
[(set (pc)
(if_then_else (eq (cc0)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"*
{
OUTPUT_JUMP (\"beq %b0\", \"fbeq %b0\", \"beq %b0\");
}")
(define_insn "bne"
[(set (pc)
(if_then_else (ne (cc0)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"*
{
OUTPUT_JUMP (\"bne %b0\", \"fbne %b0\", \"bne %b0\");
}")
(define_insn "bgt"
[(set (pc)
(if_then_else (gt (cc0)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"*
OUTPUT_JUMP (\"bgt %b0\", \"fbgt %b0\", 0);
")
(define_insn "bgtu"
[(set (pc)
(if_then_else (gtu (cc0)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"bgt %b0")
(define_insn "blt"
[(set (pc)
(if_then_else (lt (cc0)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"*
OUTPUT_JUMP (\"blt %b0\", \"fblt %b0\", \"bms %b0\");
")
;; bms ?????
;;
(define_insn "bltu"
[(set (pc)
(if_then_else (ltu (cc0)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"blt %b0")
(define_insn "bge"
[(set (pc)
(if_then_else (ge (cc0)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"*
OUTPUT_JUMP (\"bge %b0\", \"fbge %b0\", \"bmc %b0\");
")
;; bmc ??
(define_insn "bgeu"
[(set (pc)
(if_then_else (geu (cc0)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"bge %b0")
(define_insn "ble"
[(set (pc)
(if_then_else (le (cc0)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"ble %b0")
(define_insn "bleu"
[(set (pc)
(if_then_else (leu (cc0)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"ble %b0")
;; Negated conditional jump instructions.
(define_insn ""
[(set (pc)
(if_then_else (eq (cc0)
(const_int 0))
(pc)
(label_ref (match_operand 0 "" ""))))]
""
"*
{
OUTPUT_JUMP (\"bne %b0\", \"fbne %b0\", \"bne %b0\");
}")
(define_insn ""
[(set (pc)
(if_then_else (ne (cc0)
(const_int 0))
(pc)
(label_ref (match_operand 0 "" ""))))]
""
"*
{
OUTPUT_JUMP (\"beq %b0\", \"fbeq %b0\", \"beq %b0\");
}")
(define_insn ""
[(set (pc)
(if_then_else (gt (cc0)
(const_int 0))
(pc)
(label_ref (match_operand 0 "" ""))))]
""
"*
OUTPUT_JUMP (\"ble %b0\", \"fbngt %b0\", 0);
")
;; fbngt ???
(define_insn ""
[(set (pc)
(if_then_else (gtu (cc0)
(const_int 0))
(pc)
(label_ref (match_operand 0 "" ""))))]
""
"ble %b0")
(define_insn ""
[(set (pc)
(if_then_else (lt (cc0)
(const_int 0))
(pc)
(label_ref (match_operand 0 "" ""))))]
""
"*
OUTPUT_JUMP (\"bge %b0\", \"fbnlt %b0\", \"jbmc %b0\");
")
(define_insn ""
[(set (pc)
(if_then_else (ltu (cc0)
(const_int 0))
(pc)
(label_ref (match_operand 0 "" ""))))]
""
"blt %b0")
(define_insn ""
[(set (pc)
(if_then_else (ge (cc0)
(const_int 0))
(pc)
(label_ref (match_operand 0 "" ""))))]
""
"*
OUTPUT_JUMP (\"blt %b0\", \"fbnge %b0\", \"jbms %b0\");
")
(define_insn ""
[(set (pc)
(if_then_else (geu (cc0)
(const_int 0))
(pc)
(label_ref (match_operand 0 "" ""))))]
""
"blt %b0")
;; ????
(define_insn ""
[(set (pc)
(if_then_else (le (cc0)
(const_int 0))
(pc)
(label_ref (match_operand 0 "" ""))))]
""
"*
OUTPUT_JUMP (\"bgt %b0\", \"fbnle %b0\", 0);
")
(define_insn ""
[(set (pc)
(if_then_else (leu (cc0)
(const_int 0))
(pc)
(label_ref (match_operand 0 "" ""))))]
""
"bgt %b0")
;; Unconditional and other jump instructions
(define_insn "jump"
[(set (pc)
(label_ref (match_operand 0 "" "")))]
""
"bra %b0")
(define_insn "tablejump"
[(set (pc)
(plus:SI (pc) (match_operand:SI 0 "general_operand" "r")))
(use (label_ref (match_operand 1 "" "")))]
""
"jmp @(pc:b,4:4,%0)")
;;
;; Should Add code for "ACB", "SCB". !!! ????
;; See m68k.h (dbra)
;;
;; Call subroutine with no return value.
(define_insn "call"
[(call (match_operand:QI 0 "general_operand" "m")
(match_operand:SI 1 "general_operand" "rmi"))]
;; Operand 1 not really used on the Gmicro.
""
"*
{
if (GET_CODE (operands[0]) == MEM
&& GET_CODE (XEXP (operands[0],0)) == SYMBOL_REF)
return \"bsr %b0\";
return \"jsr %0\";
}")
;; Call subroutine, returning value in operand 0
;; (which must be a hard register).
(define_insn "call_value"
[(set (match_operand 0 "" "=rf")
(call (match_operand:QI 1 "general_operand" "m")
(match_operand:SI 2 "general_operand" "rmi")))]
;; Operand 2 not really used on the Gmicro.
""
"*
{
if (GET_CODE (operands[1]) == MEM
&& GET_CODE (XEXP (operands[1],0)) == SYMBOL_REF)
return \"bsr %b1\";
return \"jsr %1\";
}")
;; Call subroutine returning any type.
(define_expand "untyped_call"
[(parallel [(call (match_operand 0 "" "")
(const_int 0))
(match_operand 1 "" "")
(match_operand 2 "" "")])]
""
"
{
int i;
emit_call_insn (gen_call (operands[0], const0_rtx, NULL, const0_rtx));
for (i = 0; i < XVECLEN (operands[2], 0); i++)
{
rtx set = XVECEXP (operands[2], 0, i);
emit_move_insn (SET_DEST (set), SET_SRC (set));
}
/* The optimizer does not know that the call sets the function value
registers we stored in the result block. We avoid problems by
claiming that all hard registers are used and clobbered at this
point. */
emit_insn (gen_blockage ());
DONE;
}")
;; UNSPEC_VOLATILE is considered to use and clobber all hard registers and
;; all of memory. This blocks insns from being moved across this point.
(define_insn "blockage"
[(unspec_volatile [(const_int 0)] 0)]
""
"")
(define_insn "nop"
[(const_int 0)]
""
"nop")
;; Turned off because the general move-an-address pattern handles it.
;;
;; Thus goes after the move instructions
;; because the move instructions are better (require no spilling)
;; when they can apply.
;; After add/sub now !!
;(define_insn "pushasi"
; [(set (match_operand:SI 0 "push_operand" "=m")
; (match_operand:SI 1 "address_operand" "p"))]
; ""
; "*
;{
; if (GET_CODE (operands[1]) == CONST_INT)
; return push_imm_word (INTVAL (operands[1]), operands[0]);
; if (CONSTANT_P (operands[1]))
; return \"mov.w %1,%-\";
; if (GET_CODE (operands[1]) == REG)
; return \"mov.w %1,%-\";
; else if (GET_CODE (operands[1]) == MEM)
; {
; return \"mov.w %1,%-\";
; }
; else
; return \"mova.w %p1,%-\";
;}")
;; This should not be used unless the add/sub insns can't be.
/* mova.[whq] 89.08.11 for test M.Yuhara */
;(define_insn ""
; [(set (match_operand:SI 0 "general_operand" "=rm")
; (match_operand:SI 1 "address_operand" "p"))]
; ""
; "*
;{
; if (GET_CODE (operands[1]) == CONST_INT)
; return mov_imm_word (INTVAL (operands[1]), operands[0]);
; if (CONSTANT_P (operands[1]))
; return \"mov.w %1,%0\";
; if (GET_CODE (operands[1]) == REG)
; return \"mov.w %1,%0\";
; else if (GET_CODE (operands[1]) == MEM) {
; operands[1] = XEXP (operands[1],0);
; return \"mov.w %1,%0\";
; }
; else
; return \"mova.w %p1,%0\";
;}")
(define_insn ""
[(set (match_operand:SI 0 "general_operand" "=rm")
(match_operand:HI 1 "address_operand" "p"))]
""
"*
{
if (GET_CODE (operands[1]) == CONST_INT)
return mov_imm_word (INTVAL (operands[1]), operands[0]);
if (CONSTANT_P (operands[1]))
return \"mov.w %1,%0\";
if (GET_CODE (operands[1]) == REG)
return \"mov.w %1,%0\";
else if (GET_CODE (operands[1]) == MEM)
{
operands[1] = XEXP (operands[1],0);
return \"mov.w %1,%0\"; /* OK ? */
}
else
return \"mova.w %p1,%0\";
}")
;(define_insn ""
; [(set (match_operand:SI 0 "general_operand" "=rm")
; (match_operand:QI 1 "address_operand" "p"))]
; ""
; "*
;{
; if (push_operand (operands[0], SImode))
; return \"mova %1,%-\";
; return \"mova %1,%0\";
;}")
;(define_insn ""
; [(set (match_operand:SI 0 "general_operand" "=rm")
; (match_operand:QI 1 "address_operand" "p"))]
; ""
; "*
;{
; if (CONSTANT_P (operands[1]))
; return \"mov.w %1,%0\";
; else if (GET_CODE (operands[1]) == REG)
; return \"mov.w %1,%0\";
; else if (GET_CODE (operands[1]) == MEM)
; {
; operands[1] = XEXP (operands[1],0);
; return \"mov.w %1,%0 ; OK?\";
; }
; else if (GET_CODE (operands[0]) == REG
; && GET_CODE (operands[1]) == PLUS)
; {
; rtx xreg, xdisp;
;
; if (GET_CODE (XEXP (operands[1], 0)) == REG
; && REGNO (XEXP (operands[1], 0)) == REGNO (operands[0]))
; {
; xreg = XEXP (operands[1], 0);
; xdisp = XEXP (operands[1],1);
; }
; else
; {
; xreg = XEXP (operands[1], 1);
; xdisp = XEXP (operands[1],0);
; }
;
; if (GET_CODE (xreg) == REG
; && REGNO (xreg) == REGNO (operands[0])
; && (CONSTANT_P (xdisp) || GET_CODE (xdisp) == REG))
; {
; operands[1] = xdisp;
; if (CONSTANT_P (xdisp))
; return add_imm_word (INTVAL (xdisp), xreg, &operands[1]);
; else
; return \"add.w %1,%0\";
; }
; }
; return \"mova.w %p1,%0\";
;}")
;; This is the first machine-dependent peephole optimization.
;; It is useful when a floating value is returned from a function call
;; and then is moved into an FP register.
;; But it is mainly intended to test the support for these optimizations.
(define_peephole
[(set (reg:SI 15) (plus:SI (reg:SI 15) (const_int 4)))
(set (match_operand:DF 0 "register_operand" "=f")
(match_operand:DF 1 "register_operand" "r"))]
"FPU_REG_P (operands[0]) && ! FPU_REG_P (operands[1])"
"*
{
rtx xoperands[2];
xoperands[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1);
output_asm_insn (\"mov.w %1,@sp\", xoperands);
output_asm_insn (\"mov.w %1,%-\", operands);
return \"fmov.d %+,%0\";
}
")
/* Definitions of target machine for GNU compiler. Genix ns32000 version.
Copyright (C) 1987, 1988, 1994 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, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include "ns32k/encore.h"
/* We don't want the one Encore needs. */
#undef ASM_SPEC
/* The following defines override ones in ns32k.h and prevent any attempts
to explicitly or implicitly make references to the SB register in the GCC
generated code. It is necessary to avoid such references under Genix V.3.1
because this OS doesn't even save/restore the SB on context switches! */
#define IS_OK_REG_FOR_BASE_P(X) \
( (GET_CODE (X) == REG) && REG_OK_FOR_BASE_P (X) )
#undef INDIRECTABLE_1_ADDRESS_P
#define INDIRECTABLE_1_ADDRESS_P(X) \
(CONSTANT_ADDRESS_NO_LABEL_P (X) \
|| IS_OK_REG_FOR_BASE_P (X) \
|| (GET_CODE (X) == PLUS \
&& IS_OK_REG_FOR_BASE_P (XEXP (X, 0)) \
&& CONSTANT_ADDRESS_P (XEXP (X, 1)) ) )
/* Note that for double indirects, only FP, SP, and SB are allowed
as the inner-most base register. But we are avoiding use of SB. */
#undef MEM_REG
#define MEM_REG(X) \
( (GET_CODE (X) == REG) \
&& ( (REGNO (X) == FRAME_POINTER_REGNUM) \
|| (REGNO (X) == STACK_POINTER_REGNUM) ) )
#undef INDIRECTABLE_2_ADDRESS_P
#define INDIRECTABLE_2_ADDRESS_P(X) \
(GET_CODE (X) == MEM \
&& (((xfoo0 = XEXP (X, 0), MEM_REG (xfoo0)) \
|| (GET_CODE (xfoo0) == PLUS \
&& MEM_REG (XEXP (xfoo0, 0)) \
&& CONSTANT_ADDRESS_NO_LABEL_P (XEXP (xfoo0, 1)))) \
|| CONSTANT_ADDRESS_NO_LABEL_P (xfoo0)))
/* Go to ADDR if X is a valid address not using indexing.
(This much is the easy part.) */
#undef GO_IF_NONINDEXED_ADDRESS
#define GO_IF_NONINDEXED_ADDRESS(X, ADDR) \
{ register rtx xfoob = (X); \
if (GET_CODE (xfoob) == REG) goto ADDR; \
if (INDIRECTABLE_1_ADDRESS_P(X)) goto ADDR; \
if (CONSTANT_P(X)) goto ADDR; \
if (INDIRECTABLE_2_ADDRESS_P (X)) goto ADDR; \
if (GET_CODE (X) == PLUS) \
if (CONSTANT_ADDRESS_NO_LABEL_P (XEXP (X, 1))) \
if (INDIRECTABLE_2_ADDRESS_P (XEXP (X, 0))) \
goto ADDR; \
}
/* A bug in the GNX 3.X assembler causes references to external symbols to
be mishandled if the symbol is also used as the name of a function-local
variable or as the name of a struct or union field. The problem only
appears when you are also using the -g option so that SDB debugging
directives are also being produced by GCC. In such cases, the assembler
gets the external entity confused with the local entity and addressing
havoc ensues. The solution is to get GCC to produce .global directives
for all external entities which are actually referenced within the current
source file. The following macro does this. */
#define ASM_OUTPUT_EXTERNAL(FILE, DECL, NAME) \
ASM_GLOBALIZE_LABEL(FILE,NAME);
/* Genix wants 0l instead of 0f. */
#undef ASM_OUTPUT_DOUBLE
#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \
fprintf (FILE, "\t.long 0l%.20e\n", (VALUE))
/* A bug in the GNX 3.X linker prevents symbol-table entries with a storage-
class field of C_EFCN (-1) from being accepted. */
#ifdef PUT_SDB_EPILOGUE_END
#undef PUT_SDB_EPILOGUE_END
#endif
#define PUT_SDB_EPILOGUE_END(NAME)
#undef TARGET_VERSION
#define TARGET_VERSION fprintf (stderr, " (32000, National syntax)");
/* Same as the encore definition except
* Different syntax for double constants.
* Don't output `?' before external regs.
* Output `(sb)' in certain indirect refs. */
#error this has not been updated since version 1.
#error it is certainly wrong.
#undef PRINT_OPERAND
#define PRINT_OPERAND(FILE, X, CODE) \
{ if (CODE == '$') putc ('$', FILE); \
else if (CODE == '?'); \
else if (GET_CODE (X) == REG) \
fprintf (FILE, "%s", reg_names[REGNO (X)]); \
else if (GET_CODE (X) == MEM) \
{ \
rtx xfoo; \
xfoo = XEXP (X, 0); \
switch (GET_CODE (xfoo)) \
{ \
case MEM: \
if (GET_CODE (XEXP (xfoo, 0)) == REG) \
if (REGNO (XEXP (xfoo, 0)) == STACK_POINTER_REGNUM) \
fprintf (FILE, "0(0(sp))"); \
else fprintf (FILE, "0(0(%s))", \
reg_names[REGNO (XEXP (xfoo, 0))]); \
else \
{ \
extern int paren_base_reg_printed; \
fprintf (FILE, "0("); \
paren_base_reg_printed = 0; \
output_address (xfoo); \
if (!paren_base_reg_printed) \
fprintf (FILE, "(sb)"); \
putc (')', FILE); \
} \
break; \
case REG: \
fprintf (FILE, "0(%s)", reg_names[REGNO (xfoo)]); \
break; \
case PRE_DEC: \
case POST_INC: \
fprintf (FILE, "tos"); \
break; \
case CONST_INT: \
fprintf (FILE, "@%d", INTVAL (xfoo)); \
break; \
default: \
output_address (xfoo); \
break; \
} \
} \
else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) != VOIDmode) \
if (GET_MODE (X) == DFmode) \
{ union { double d; int i[2]; } u; \
u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); \
fprintf (FILE, "$0l%.20e", u.d); } \
else { union { double d; int i[2]; } u; \
u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); \
fprintf (FILE, "$0f%.20e", u.d); } \
else if (GET_CODE (X) == CONST) \
output_addr_const (FILE, X); \
else { putc ('$', FILE); output_addr_const (FILE, X); }}
# Makefile modifications for compilation on Genix.
ALLOCA=alloca.o
MALLOC = malloc.o
# You must get malloc.c and getpagesize.h from GNU Emacs.
/* Config file for ns32k running system V. */
#define memcpy(src,dst,len) bcopy ((dst),(src),(len))
#define memset gcc_memset
#define memcmp(left,right,len) bcmp ((left),(right),(len))
#define USG
/* Subroutines for insn-output.c for Pyramid 90x, 9000, and MIServer Series.
Copyright (C) 1989, 1991, 1997, 1998, 1999 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, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* Some output-actions in pyr.md need these. */
#include "config.h"
#include "system.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"
#include "tree.h"
#include "function.h"
/*
* Do FUNCTION_ARG.
* This cannot be defined as a macro on pyramids, because Pyramid Technology's
* C compiler dies on (several equivalent definitions of) this macro.
* The only way around this cc bug was to make this a function.
* While it would be possible to use a macro version for gcc, it seems
* more reliable to have a single version of the code.
*/
void *
pyr_function_arg(cum, mode, type, named)
CUMULATIVE_ARGS cum;
enum machine_mode mode;
tree type;
{
return (void *)(FUNCTION_ARG_HELPER (cum, mode,type,named));
}
/* Do the hard part of PARAM_SAFE_FOR_REG_P.
* This cannot be defined as a macro on pyramids, because Pyramid Technology's
* C compiler dies on (several equivalent definitions of) this macro.
* The only way around this cc bug was to make this a function.
*/
int
inner_param_safe_helper (type)
tree type;
{
return (INNER_PARAM_SAFE_HELPER(type));
}
/* Return 1 if OP is a non-indexed operand of mode MODE.
This is either a register reference, a memory reference,
or a constant. In the case of a memory reference, the address
is checked to make sure it isn't indexed.
Register and memory references must have mode MODE in order to be valid,
but some constants have no machine mode and are valid for any mode.
If MODE is VOIDmode, OP is checked for validity for whatever mode
it has.
The main use of this function is as a predicate in match_operand
expressions in the machine description.
It is useful to compare this with general_operand(). They should
be identical except for one line.
This function seems necessary because of the non-orthogonality of
Pyramid insns.
For any 2-operand insn, and any combination of operand modes,
if indexing is valid for the isn's second operand, it is invalid
for the first operand to be indexed. */
extern int volatile_ok;
int
nonindexed_operand (op, mode)
register rtx op;
enum machine_mode mode;
{
register RTX_CODE code = GET_CODE (op);
int mode_altering_drug = 0;
if (mode == VOIDmode)
mode = GET_MODE (op);
/* Don't accept CONST_INT or anything similar
if the caller wants something floating. */
if (GET_MODE (op) == VOIDmode && mode != VOIDmode
&& GET_MODE_CLASS (mode) != MODE_INT)
return 0;
if (CONSTANT_P (op))
return ((GET_MODE (op) == VOIDmode || GET_MODE (op) == mode)
&& LEGITIMATE_CONSTANT_P (op));
/* Except for certain constants with VOIDmode, already checked for,
OP's mode must match MODE if MODE specifies a mode. */
if (GET_MODE (op) != mode)
return 0;
while (code == SUBREG)
{
op = SUBREG_REG (op);
code = GET_CODE (op);
#if 0
/* No longer needed, since (SUBREG (MEM...))
will load the MEM into a reload reg in the MEM's own mode. */
mode_altering_drug = 1;
#endif
}
if (code == REG)
return 1;
if (code == CONST_DOUBLE)
return LEGITIMATE_CONSTANT_P (op);
if (code == MEM)
{
register rtx y = XEXP (op, 0);
if (! volatile_ok && MEM_VOLATILE_P (op))
return 0;
GO_IF_NONINDEXED_ADDRESS (y, win);
}
return 0;
win:
if (mode_altering_drug)
return ! mode_dependent_address_p (XEXP (op, 0));
return 1;
}
/* Return non-zero if the rtx OP has an immediate component. An
immediate component or additive term equal to zero is rejected
due to assembler problems. */
int
has_direct_base (op)
rtx op;
{
if ((CONSTANT_ADDRESS_P (op)
&& op != const0_rtx)
|| (GET_CODE (op) == PLUS
&& ((CONSTANT_ADDRESS_P (XEXP (op, 1))
&& XEXP (op, 1) != const0_rtx)
|| (CONSTANT_ADDRESS_P (XEXP (op, 0))
&& XEXP (op, 0) != const0_rtx))))
return 1;
return 0;
}
/* Return zero if the rtx OP has a (scaled) index. */
int
has_index (op)
rtx op;
{
if (GET_CODE (op) == PLUS
&& (GET_CODE (XEXP (op, 0)) == MULT
|| (GET_CODE (XEXP (op, 1)) == MULT)))
return 1;
else
return 0;
}
int swap_operands;
/* weird_memory_memory -- return 1 if OP1 and OP2 can be compared (or
exchanged with xchw) with one instruction. If the operands need to
be swapped, set the global variable SWAP_OPERANDS. This function
silently assumes that both OP0 and OP1 are valid memory references.
*/
int
weird_memory_memory (op0, op1)
rtx op0, op1;
{
RTX_CODE code0, code1;
op0 = XEXP (op0, 0);
op1 = XEXP (op1, 0);
code0 = GET_CODE (op0);
code1 = GET_CODE (op1);
swap_operands = 0;
if (code1 == REG || code1 == SUBREG)
{
return 1;
}
if (code0 == REG || code0 == SUBREG)
{
swap_operands = 1;
return 1;
}
if (has_direct_base (op0) && has_direct_base (op1))
{
if (has_index (op1))
{
if (has_index (op0))
return 0;
swap_operands = 1;
}
return 1;
}
return 0;
}
int
signed_comparison (x, mode)
rtx x;
enum machine_mode mode;
{
return ! TRULY_UNSIGNED_COMPARE_P (GET_CODE (x));
}
extern rtx force_reg ();
rtx test_op0, test_op1;
enum machine_mode test_mode;
/* Sign-extend or zero-extend constant X from FROM_MODE to TO_MODE. */
rtx
extend_const (x, extop, from_mode, to_mode)
rtx x;
RTX_CODE extop;
enum machine_mode from_mode, to_mode;
{
int val;
int negative;
if (from_mode == to_mode)
return x;
if (GET_CODE (x) != CONST_INT)
abort ();
val = INTVAL (x);
negative = val & (1 << (GET_MODE_BITSIZE (from_mode) - 1));
if (GET_MODE_BITSIZE (from_mode) == HOST_BITS_PER_INT)
abort ();
if (negative && extop == SIGN_EXTEND)
val = val | ((-1) << (GET_MODE_BITSIZE (from_mode)));
else
val = val & ~((-1) << (GET_MODE_BITSIZE (from_mode)));
if (GET_MODE_BITSIZE (to_mode) == HOST_BITS_PER_INT)
return GEN_INT (val);
return GEN_INT (val & ~((-1) << (GET_MODE_BITSIZE (to_mode))));
}
rtx
ensure_extended (op, extop, from_mode)
rtx op;
RTX_CODE extop;
enum machine_mode from_mode;
{
if (GET_CODE (op) == CONST_INT)
return extend_const (op, extop, from_mode, SImode);
else
return force_reg (SImode, gen_rtx (extop, SImode, op));
}
/* Emit rtl for a branch, as well as any delayed (integer) compare insns.
The compare insn to perform is determined by the global variables
test_op0 and test_op1. */
void
extend_and_branch (extop)
RTX_CODE extop;
{
rtx op0, op1;
RTX_CODE code0, code1;
op0 = test_op0, op1 = test_op1;
if (op0 == 0)
return;
code0 = GET_CODE (op0);
if (op1 != 0)
code1 = GET_CODE (op1);
test_op0 = test_op1 = 0;
if (op1 == 0)
{
op0 = ensure_extended (op0, extop, test_mode);
emit_insn (gen_rtx_SET (VOIDmode, cc0_rtx, op0));
}
else
{
if (CONSTANT_P (op0) && CONSTANT_P (op1))
{
op0 = ensure_extended (op0, extop, test_mode);
op1 = ensure_extended (op1, extop, test_mode);
}
else if (extop == ZERO_EXTEND && test_mode == HImode)
{
/* Pyramids have no unsigned "cmphi" instructions. We need to
zero extend unsigned halfwords into temporary registers. */
op0 = ensure_extended (op0, extop, test_mode);
op1 = ensure_extended (op1, extop, test_mode);
}
else if (CONSTANT_P (op0))
{
op0 = ensure_extended (op0, extop, test_mode);
op1 = ensure_extended (op1, extop, test_mode);
}
else if (CONSTANT_P (op1))
{
op1 = ensure_extended (op1, extop, test_mode);
op0 = ensure_extended (op0, extop, test_mode);
}
else if ((code0 == REG || code0 == SUBREG)
&& (code1 == REG || code1 == SUBREG))
{
/* I could do this case without extension, by using the virtual
register address (but that would lose for global regs). */
op0 = ensure_extended (op0, extop, test_mode);
op1 = ensure_extended (op1, extop, test_mode);
}
else if (code0 == MEM && code1 == MEM)
{
/* Load into a reg if the address combination can't be handled
directly. */
if (! weird_memory_memory (op0, op1))
op0 = force_reg (test_mode, op0);
}
emit_insn (gen_rtx_SET (VOIDmode, cc0_rtx,
gen_rtx_COMPARE (VOIDmode, op0, op1)));
}
}
/* Return non-zero if the two single-word moves with operands[0]
and operands[1] for the first single-word move, and operands[2]
and operands[3] for the second single-word move, is possible to
combine to a double word move.
The criterion is whether the operands are in consecutive memory cells,
registers, etc. */
int
movdi_possible (operands)
rtx operands[];
{
int cnst_diff0, cnst_diff1;
RTX_CODE code0 = GET_CODE (operands[0]);
RTX_CODE code1 = GET_CODE (operands[1]);
/* Don't dare to combine (possibly overlapping) memory -> memory moves. */
/* It would be possible to detect the cases where we dare, by using
constant_diff (operands[0], operands[1])!!! */
if (code0 == MEM && code1 == MEM)
return 0;
cnst_diff0 = consecutive_operands (operands[0], operands[2]);
if (cnst_diff0 == 0)
return 0;
cnst_diff1 = consecutive_operands (operands[1], operands[3]);
if (cnst_diff1 == 0)
return 0;
if (cnst_diff0 & cnst_diff1)
{
/* The source and destination operands are consecutive. */
/* If the first move writes into the source of the second move,
we cannot combine. */
if ((code0 == REG
&& reg_overlap_mentioned_p (operands[0], operands[3]))
|| (code0 == SUBREG
&& subreg_overlap_mentioned_p (operands[0], operands[3])))
return 0;
if (cnst_diff0 & 1)
/* operands[0],[1] has higher addresses than operands[2],[3]. */
swap_operands = 0;
else
/* operands[0],[1] has lower addresses than operands[2],[3]. */
swap_operands = 1;
return 1;
}
return 0;
}
/* Like reg_overlap_mentioned_p, but accepts a subreg rtx instead
of a reg. */
int
subreg_overlap_mentioned_p (subreg, x)
rtx subreg, x;
{
rtx reg = SUBREG_REG (subreg);
int regno = REGNO (reg) + SUBREG_WORD (subreg);
int endregno = regno + HARD_REGNO_NREGS (regno, GET_MODE (subreg));
return refers_to_regno_p (regno, endregno, x, 0);
}
/* Return 1 if OP0 is a consecutive operand to OP1, 2 if OP1 is a
consecutive operand to OP0.
This function is used to determine if addresses are consecutive,
and therefore possible to combine to fewer instructions. */
int
consecutive_operands (op0, op1)
rtx op0, op1;
{
RTX_CODE code0, code1;
int cnst_diff;
int regno_off0, regno_off1;
code0 = GET_CODE (op0);
code1 = GET_CODE (op1);
regno_off0 = 0;
if (code0 == SUBREG)
{
if (GET_MODE_SIZE (GET_MODE (SUBREG_REG (op0))) <= UNITS_PER_WORD)
return 0;
regno_off0 = SUBREG_WORD (op0);
op0 = SUBREG_REG (op0);
code0 = REG;
}
regno_off1 = 0;
if (code1 == SUBREG)
{
if (GET_MODE_SIZE (GET_MODE (SUBREG_REG (op1))) <= UNITS_PER_WORD)
return 0;
regno_off1 = SUBREG_WORD (op1);
op1 = SUBREG_REG (op1);
code1 = REG;
}
if (code0 != code1)
return 0;
switch (code0)
{
case CONST_INT:
/* Cannot permit any symbolic constants, even if the consecutive
operand is 0, since a movl really performs sign extension. */
if (code1 != CONST_INT)
return 0;
if ((INTVAL (op0) == 0 && INTVAL (op1) == 0)
|| (INTVAL (op0) == -1 && INTVAL (op1) == -1))
return 3;
if ((INTVAL (op0) == 0 && INTVAL (op1) > 0)
|| (INTVAL (op0) == -1 && INTVAL (op1) < 0))
return 2;
if ((INTVAL (op1) == 0 && INTVAL (op0) > 0)
|| (INTVAL (op1) == -1 && INTVAL (op0) < 0))
return 1;
break;
case REG:
regno_off0 = REGNO (op0) + regno_off0;
regno_off1 = REGNO (op1) + regno_off1;
cnst_diff = regno_off0 - regno_off1;
if (cnst_diff == 1)
{
/* movl with the highest numbered parameter (local) register as
source or destination, doesn't wrap to the lowest numbered local
(temporary) register. */
if (regno_off0 % 16 != 0)
return 1;
else
return 0;
}
else if (cnst_diff == -1)
{
if (regno_off1 % 16 != 0)
return 2;
else
return 0;
}
break;
case MEM:
op0 = XEXP (op0, 0);
op1 = XEXP (op1, 0);
if (GET_CODE (op0) == CONST)
op0 = XEXP (op0, 0);
if (GET_CODE (op1) == CONST)
op1 = XEXP (op1, 0);
cnst_diff = constant_diff (op0, op1);
if (cnst_diff)
{
if (cnst_diff == 4)
return 1;
else if (cnst_diff == -4)
return 2;
}
break;
}
return 0;
}
/* Return the constant difference of the rtx expressions OP0 and OP1,
or 0 if they don't have a constant difference.
This function is used to determine if addresses are consecutive,
and therefore possible to combine to fewer instructions. */
int
constant_diff (op0, op1)
rtx op0, op1;
{
RTX_CODE code0, code1;
int cnst_diff;
code0 = GET_CODE (op0);
code1 = GET_CODE (op1);
if (code0 != code1)
{
if (code0 == PLUS)
{
if (GET_CODE (XEXP (op0, 1)) == CONST_INT
&& rtx_equal_p (op1, XEXP (op0, 0)))
return INTVAL (XEXP (op0, 1));
}
else if (code1 == PLUS)
{
if (GET_CODE (XEXP (op1, 1)) == CONST_INT
&& rtx_equal_p (op0, XEXP (op1, 0)))
return -INTVAL (XEXP (op1, 1));
}
return 0;
}
if (code0 == CONST_INT)
return INTVAL (op0) - INTVAL (op1);
if (code0 == PLUS)
{
cnst_diff = constant_diff (XEXP (op0, 0), XEXP (op1, 0));
if (cnst_diff)
return (rtx_equal_p (XEXP (op0, 1), XEXP (op1, 1)))
? cnst_diff : 0;
cnst_diff = constant_diff (XEXP (op0, 1), XEXP (op1, 1));
if (cnst_diff)
return (rtx_equal_p (XEXP (op0, 0), XEXP (op1, 0)))
? cnst_diff : 0;
}
return 0;
}
int
already_sign_extended (insn, from_mode, op)
rtx insn;
enum machine_mode from_mode;
rtx op;
{
rtx xinsn, xdest, xsrc;
for (;;)
{
insn = PREV_INSN (insn);
if (insn == 0)
return 0;
if (GET_CODE (insn) == NOTE || GET_CODE (insn) == JUMP_INSN)
continue;
if (GET_CODE (insn) == CALL_INSN && ! call_used_regs[REGNO (op)])
continue;
if (GET_CODE (insn) != INSN)
return 0;
xinsn = PATTERN (insn);
if (GET_CODE (xinsn) != SET)
return 0;
xdest = SET_DEST (xinsn);
xsrc = SET_SRC (xinsn);
if (GET_CODE (xdest) == SUBREG)
abort ();
if ( ! REG_P (xdest))
continue;
if (REGNO (op) == REGNO (xdest)
&& ((GET_CODE (xsrc) == SIGN_EXTEND
&& GET_MODE (XEXP (xsrc, 0)) == from_mode)
|| (GET_CODE (xsrc) == MEM
&& GET_MODE (xsrc) == from_mode)))
return 1;
/* The register is modified by another operation. */
if (reg_overlap_mentioned_p (xdest, op))
return 0;
}
}
char *
output_move_double (operands)
rtx *operands;
{
if (GET_CODE (operands[1]) == CONST_DOUBLE)
{
if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT)
{
/* In an integer, the low-order word is in CONST_DOUBLE_LOW. */
rtx const_op = operands[1];
if ((CONST_DOUBLE_HIGH (const_op) == 0
&& CONST_DOUBLE_LOW (const_op) >= 0)
|| (CONST_DOUBLE_HIGH (const_op) == -1
&& CONST_DOUBLE_LOW (const_op) < 0))
{
operands[1] = GEN_INT (CONST_DOUBLE_LOW (const_op));
return "movl %1,%0";
}
operands[1] = GEN_INT (CONST_DOUBLE_HIGH (const_op));
output_asm_insn ("movw %1,%0", operands);
operands[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
operands[1] = GEN_INT (CONST_DOUBLE_LOW (const_op));
return "movw %1,%0";
}
else
{
/* In a real, the low-address word is in CONST_DOUBLE_LOW. */
rtx const_op = operands[1];
if ((CONST_DOUBLE_LOW (const_op) == 0
&& CONST_DOUBLE_HIGH (const_op) >= 0)
|| (CONST_DOUBLE_LOW (const_op) == -1
&& CONST_DOUBLE_HIGH (const_op) < 0))
{
operands[1] = GEN_INT (CONST_DOUBLE_HIGH (const_op));
return "movl %1,%0";
}
operands[1] = GEN_INT (CONST_DOUBLE_LOW (const_op));
output_asm_insn ("movw %1,%0", operands);
operands[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
operands[1] = GEN_INT (CONST_DOUBLE_HIGH (const_op));
return "movw %1,%0";
}
}
return "movl %1,%0";
}
/* Output a shift insns, after having reduced integer arguments to
avoid as warnings. */
char *
output_shift (pattern, op2, mod)
char *pattern;
rtx op2;
int mod;
{
if (GET_CODE (op2) == CONST_INT)
{
int cnt = INTVAL (op2) % mod;
if (cnt == 0)
{
cc_status = cc_prev_status;
return "";
}
op2 = GEN_INT (cnt);
}
return pattern;
}
/* Return non-zero if the code of this rtx pattern is a relop. */
int
relop (op, mode)
rtx op;
enum machine_mode mode;
{
switch (GET_CODE (op))
{
case EQ:
case NE:
case LT:
case LE:
case GE:
case GT:
case LTU:
case LEU:
case GEU:
case GTU:
return 1;
}
return 0;
}
void
notice_update_cc (EXP, INSN)
rtx EXP, INSN;
{
switch (GET_CODE (EXP))
{
case SET:
switch (GET_CODE (SET_DEST (EXP)))
{
case CC0:
cc_status.mdep = 0;
cc_status.flags = 0;
cc_status.value1 = 0;
cc_status.value2 = SET_SRC (EXP);
break;
case PC:
break;
case REG:
switch (GET_CODE (SET_SRC (EXP)))
{
case CALL:
goto call;
case MEM:
if (GET_MODE (SET_SRC (EXP)) == QImode
|| GET_MODE (SET_SRC (EXP)) == HImode)
{
cc_status.mdep = 0;
cc_status.flags = CC_NO_OVERFLOW;
cc_status.value1 = SET_DEST (EXP);
cc_status.value2 = SET_SRC (EXP);
break;
}
/* else: Fall through. */
case CONST_INT:
case SYMBOL_REF:
case LABEL_REF:
case CONST:
case CONST_DOUBLE:
case REG:
if (cc_status.value1
&& reg_overlap_mentioned_p (SET_DEST (EXP),
cc_status.value1))
cc_status.value1 = 0;
if (cc_status.value2
&& reg_overlap_mentioned_p (SET_DEST (EXP),
cc_status.value2))
cc_status.value2 = 0;
break;
case UDIV:
case UMOD:
cc_status.mdep = CC_VALID_FOR_UNSIGNED;
cc_status.flags = CC_NO_OVERFLOW;
cc_status.value1 = SET_DEST (EXP);
cc_status.value2 = SET_SRC (EXP);
break;
default:
cc_status.mdep = 0;
cc_status.flags = CC_NO_OVERFLOW;
cc_status.value1 = SET_DEST (EXP);
cc_status.value2 = SET_SRC (EXP);
break;
}
break;
case MEM:
switch (GET_CODE (SET_SRC (EXP)))
{
case REG:
if (GET_MODE (SET_SRC (EXP)) == QImode
|| GET_MODE (SET_SRC (EXP)) == HImode)
{
cc_status.flags = CC_NO_OVERFLOW;
cc_status.value1 = SET_DEST (EXP);
cc_status.value2 = SET_SRC (EXP);
cc_status.mdep = 0;
break;
}
/* else: Fall through. */
case CONST_INT:
case SYMBOL_REF:
case LABEL_REF:
case CONST:
case CONST_DOUBLE:
case MEM:
/* Need to forget cc_status about memory positions each
time a memory store is made, even if the memory store
insns in question doesn't modify the condition codes. */
if (cc_status.value1 &&
GET_CODE (cc_status.value1) == MEM)
cc_status.value1 = 0;
if (cc_status.value2 &&
GET_CODE (cc_status.value2) == MEM)
cc_status.value2 = 0;
break;
case SIGN_EXTEND:
case FLOAT_EXTEND:
case FLOAT_TRUNCATE:
case FLOAT:
case FIX:
cc_status.flags = CC_NO_OVERFLOW;
cc_status.value1 = SET_DEST (EXP);
cc_status.value2 = SET_SRC (EXP);
cc_status.mdep = 0;
break;
default:
abort ();
}
break;
default:
abort ();
}
break;
case CALL:
call:
CC_STATUS_INIT;
break;
/* Do calls preserve the condition codes? (At least forget
cc_status expressions if they refer to registers
not preserved across calls. Also forget expressions
about memory contents.) */
if (cc_status.value1
&& (refers_to_regno_p (PYR_TREG (0), PYR_TREG (15),
cc_status.value1, 0)
|| GET_CODE (cc_status.value1) == MEM))
cc_status.value1 = 0;
if (cc_status.value2
&& (refers_to_regno_p (PYR_TREG (0), PYR_TREG (15),
cc_status.value2, 0)
|| GET_CODE (cc_status.value2) == MEM))
cc_status.value2 = 0;
break;
default:
CC_STATUS_INIT;
}
}
void
forget_cc_if_dependent (op)
rtx op;
{
cc_status = cc_prev_status;
if (cc_status.value1 && reg_overlap_mentioned_p (op, cc_status.value1))
cc_status.value1 = 0;
if (cc_status.value2 && reg_overlap_mentioned_p (op, cc_status.value2))
cc_status.value2 = 0;
}
/* ??? None of the original definitions ever worked for stdarg.h, or
even for structs or float arguments. Quoting bits of the old
va-pyr.h for historical interest. */
/**
*
* Varargs for PYR/GNU CC
*
* WARNING -- WARNING -- DANGER
*
* The code in this file implements varargs for gcc on a pyr in
* a way that is compatible with code compiled by the Pyramid Technology
* C compiler.
* As such, it depends strongly on the Pyramid conventions for
* parameter passing.ct and independent implementation.
* These (somewhat bizarre) parameter-passing conventions are described
* in the ``OSx Operating System Porting Guide''.
*
* A quick summary is useful:
* 12 of the 48 register-windowed regs available for
* parameter passing. Parameters of a function call that are eligible
* to be passed in registers are assigned registers from TR0/PR0 onwards;
* all other arguments are passed on the stack.
* Structure and union parameters are *never* passed in registers,
* even if they are small enough to fit. They are always passed on
* the stack.
*
* Double-sized parameters cannot be passed in TR11, because
* TR12 is not used for passing parameters. If, in the absence of this
* rule, a double-sized param would have been passed in TR11,
* that parameter is passed on the stack and no parameters are
* passed in TR11.
*
* It is only known to work for passing 32-bit integer quantities
* (ie chars, shorts, ints/enums, longs), doubles, or pointers.
* Passing structures on a Pyramid via varargs is a loser.
* Passing an object larger than 8 bytes on a pyramid via varargs may
* also be a loser.
*
*/
tree
pyr_build_va_list ()
{
typedef struct __va_regs {
__voidptr __stackp,__regp,__count;
__voidptr __pr0,__pr1,__pr2,__pr3,__pr4,__pr5,__pr6,__pr7,__pr8,__pr9,__pr10,__pr11;
} __va_regs;
typedef __va_regs __va_buf;
typedef __va_buf __gnuc_va_list;
}
void
pyr_va_start (stdarg_p, valist, nextarg)
int stdarg_p;
tree valist;
rtx nextarg ATTRIBUTE_UNUSED;
{
#define va_alist \
__va0,__va1,__va2,__va3,__va4,__va5,__va6,__va7,__va8,__va9,__va10,__va11, \
__builtin_va_alist
/* The ... causes current_function_varargs to be set in cc1. */
#define va_dcl __voidptr va_alist; __va_ellipsis
/* __asm ("rcsp %0" : "=r" ( _AP [0]));*/
#define va_start(_AP) \
_AP = ((struct __va_regs) { \
&(_AP.__pr0), (void*)&__builtin_va_alist, (void*)0, \
__va0,__va1,__va2,__va3,__va4,__va5, \
__va6,__va7,__va8,__va9,__va10,__va11})
}
rtx
pyr_va_arg (valist, type)
tree valist, type;
{
#define va_arg(_AP, _MODE) \
__extension__ \
(*({__voidptr *__ap = (__voidptr*)&_AP; \
register int __size = sizeof (_MODE); \
register int __onstack = \
(__size > 8 || ( (int)(__ap[2]) > 11) || \
(__size==8 && (int)(__ap[2])==11)); \
register int* __param_addr = ((int*)((__ap) [__onstack])); \
\
((void *)__ap[__onstack])+=__size; \
if (__onstack==0 || (int)(__ap[2])==11) \
__ap[2]+= (__size >> 2); \
(( _MODE *) (void *) __param_addr); \
}))
}
/* Definitions of target machine parameters for GNU compiler,
for Pyramid 90x, 9000, and MIServer Series.
Copyright (C) 1989, 1995, 1996, 1997, 1998, 1999
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, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/*
* If you're going to change this, and you haven't already,
* you should get and read
* ``OSx Operating System Porting Guide'',
* publication number 4100-0066-A
* Revision A
* Pyramid Technology Corporation.
*
* or whatever the most recent version is. In any case, page and
* section number references given herein refer to this document.
*
* The instruction table for gdb lists the available insns and
* the valid addressing modes.
*
* Any other information on the Pyramid architecture is proprietary
* and hard to get. (Pyramid cc -S and adb are also useful.)
*
*/
/*** Run-time compilation parameters selecting different hardware subsets. ***/
/* Names to predefine in the preprocessor for this target machine. */
#define CPP_PREDEFINES "-Dpyr -Dunix -Asystem(unix) -Acpu(pyr) -Amachine(pyr)"
/* Print subsidiary information on the compiler version in use. */
#define TARGET_VERSION fprintf (stderr, " (pyr)");
extern int target_flags;
/* Nonzero if compiling code that Unix assembler can assemble. */
#define TARGET_UNIX_ASM (target_flags & 1)
/* Implement stdarg in the same fashion used on all other machines. */
#define TARGET_GNU_STDARG (target_flags & 2)
/* Compile using RETD to pop off the args.
This will not work unless you use prototypes at least
for all functions that can take varying numbers of args.
This contravenes the Pyramid calling convention, so we don't
do it yet. */
#define TARGET_RETD (target_flags & 4)
/* Macros used in the machine description to test the flags. */
/* Macro to define tables used to set the flags.
This is a list in braces of pairs in braces,
each pair being { "NAME", VALUE }
where VALUE is the bits to set or minus the bits to clear.
An empty string NAME is used to identify the default VALUE.
-mgnu will be useful if we ever have GAS on a pyramid. */
#define TARGET_SWITCHES \
{ {"unix", 1}, \
{"gnu", -1}, \
{"gnu-stdarg", 2}, \
{"nognu-stdarg", -2}, \
{"retd", 4}, \
{"no-retd", -4}, \
{ "", TARGET_DEFAULT}}
/* Default target_flags if no switches specified.
(equivalent to "-munix -mindex -mgnu-stdarg") */
#ifndef TARGET_DEFAULT
#define TARGET_DEFAULT (1 + 2)
#endif
/* Make GCC agree with types.h. */
#ifdef SIZE_TYPE
#undef SIZE_TYPE
#endif
#define SIZE_TYPE "unsigned int"
/* Assembler does not permit $ in labels */
#define NO_DOLLAR_IN_LABEL
/* Maybe it doesn't permit dot either. */
#define NO_DOT_IN_LABEL
/* Never allow $ in identifiers */
#define DOLLARS_IN_IDENTIFIERS 0
/*** Target machine storage layout ***/
/* Define this to non-zero if most significant bit is lowest
numbered in instructions that operate on numbered bit-fields.
This is not true on the pyramid. */
#define BITS_BIG_ENDIAN 0
/* Define this to non-zero if most significant byte of a word is
the lowest numbered. */
#define BYTES_BIG_ENDIAN 1
/* Define this to non-zero if most significant word of a multiword
number is the lowest numbered. */
#define WORDS_BIG_ENDIAN 1
/* Number of bits in an addressable storage unit */
#define BITS_PER_UNIT 8
/* Width in bits of a "word", which is the contents of a machine register.
Note that this is not necessarily the width of data type `int';
if using 16-bit ints on a 68000, this would still be 32.
But on a machine with 16-bit registers, this would be 16. */
#define BITS_PER_WORD 32
/* Width of a word, in units (bytes). */
#define UNITS_PER_WORD 4
/* Width in bits of a pointer.
See also the macro `Pmode' defined below. */
#define POINTER_SIZE 32
/* Allocation boundary (in *bits*) for storing arguments in argument list. */
#define PARM_BOUNDARY 32
/* Boundary (in *bits*) on which stack pointer should be aligned. */
#define STACK_BOUNDARY 32
/* Allocation boundary (in *bits*) for the code of a function. */
#define FUNCTION_BOUNDARY 32
/* Alignment of field after `int : 0' in a structure. */
#define EMPTY_FIELD_BOUNDARY 32
/* Every structure's size must be a multiple of this. */
#define STRUCTURE_SIZE_BOUNDARY 32
/* No data type wants to be aligned rounder than this. */
#define BIGGEST_ALIGNMENT 32
/* Specified types of bitfields affect alignment of those fields
and of the structure as a whole. */
#define PCC_BITFIELD_TYPE_MATTERS 1
/* Make strings word-aligned so strcpy from constants will be faster.
Pyramid documentation says the best alignment is to align
on the size of a cache line, which is 32 bytes.
Newer pyrs have single insns that do strcmp() and strcpy(), so this
may not actually win anything. */
#define CONSTANT_ALIGNMENT(EXP, ALIGN) \
(TREE_CODE (EXP) == STRING_CST \
&& (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN))
/* Make arrays of chars word-aligned for the same reasons. */
#define DATA_ALIGNMENT(TYPE, ALIGN) \
(TREE_CODE (TYPE) == ARRAY_TYPE \
&& TYPE_MODE (TREE_TYPE (TYPE)) == QImode \
&& (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN))
/* Set this nonzero if move instructions will actually fail to work
when given unaligned data. */
#define STRICT_ALIGNMENT 1
/*** Standard register usage. ***/
/* Number of actual hardware registers.
The hardware registers are assigned numbers for the compiler
from 0 to just below FIRST_PSEUDO_REGISTER.
All registers that the compiler knows about must be given numbers,
even those that are not normally considered general registers. */
/* Nota Bene:
Pyramids have 64 addressable 32-bit registers, arranged as four
groups of sixteen registers each. Pyramid names the groups
global, parameter, local, and temporary.
The sixteen global registers are fairly conventional; the last
four are overloaded with a PSW, frame pointer, stack pointer, and pc.
The non-dedicated global registers used to be reserved for Pyramid
operating systems, and still have cryptic and undocumented uses for
certain library calls. We do not use global registers gr0 through
gr11.
The parameter, local, and temporary registers provide register
windowing. Each procedure call has its own set of these 48
registers, which constitute its call frame. (These frames are
not allocated on the conventional stack, but contiguously
on a separate stack called the control stack.)
Register windowing is a facility whereby the temporary registers
of frame n become the parameter registers of frame n+1, viz.:
0 15 0 15 0 15
+------------+------------+------------+
frame n+1 | | | |
+------------+------------+------------+
Parameter Local Temporary
^
| These 16 regs are the same.
v
0 15 0 15 0 15
+------------+------------+------------+
frame n | | | |
+------------+------------+------------+
Parameter Local Temporary
New frames are automatically allocated on the control stack by the
call instruction and de-allocated by the return insns "ret" and
"retd". The control-stack grows contiguously upward from a
well-known address in memory; programs are free to allocate
a variable sized, conventional frame on the data stack, which
grows downwards in memory from just below the control stack.
Temporary registers are used for parameter passing, and are not
preserved across calls. TR0 through TR11 correspond to
gcc's ``input'' registers; PR0 through TR11 the ``output''
registers. The call insn stores the PC and PSW in PR14 and PR15 of
the frame it creates; the return insns restore these into the PC
and PSW. The same is true for interrupts; TR14 and TR15 of the
current frame are reserved and should never be used, since an
interrupt may occur at any time and clobber them.
An interesting quirk is the ability to take the address of a
variable in a windowed register. This done by adding the memory
address of the base of the current window frame, to the offset
within the frame of the desired register. The resulting address
can be treated just like any other pointer; if a quantity is stored
into that address, the appropriate register also changes.
GCC does not, and according to RMS will not, support this feature,
even though some programs rely on this (mis)feature.
*/
#define PYR_GREG(n) (n)
#define PYR_PREG(n) (16+(n))
#define PYR_LREG(n) (32+(n))
#define PYR_TREG(n) (48+(n))
/* Define this macro if the target machine has "register windows". This
C expression returns the register number as seen by the called function
corresponding to register number OUT as seen by the calling function.
Return OUT if register number OUT is not an outbound register. */
#define INCOMING_REGNO(OUT) \
(((OUT) < 48 || (OUT) > 63) ? (OUT) : (OUT) - 32)
/* Define this macro if the target machine has "register windows". This
C expression returns the register number as seen by the calling function
corresponding to register number IN as seen by the called function.
Return IN if register number IN is not an inbound register. */
#define OUTGOING_REGNO(IN) \
(((IN) < 15 || (IN) > 31) ? (IN) : (IN) + 32)
#define FIRST_PSEUDO_REGISTER 64
/* 1 for registers that have pervasive standard uses
and are not available for the register allocator.
On the pyramid, these are LOGPSW, SP, and PC. */
#define FIXED_REGISTERS \
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, \
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1}
/* 1 for registers not available across function calls.
These must include the FIXED_REGISTERS and also any
registers that can be used without being saved.
The latter must include the registers where values are returned
and the register where structure-value addresses are passed.
Aside from that, you can include as many other registers as you like. */
#define CALL_USED_REGISTERS \
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, \
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
/* #define DEFAULT_CALLER_SAVES */
/* Return number of consecutive hard regs needed starting at reg REGNO
to hold something of mode MODE.
This is ordinarily the length in words of a value of mode MODE
but can be less for certain modes in special long registers.
On the pyramid, all registers are one word long. */
#define HARD_REGNO_NREGS(REGNO, MODE) \
((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE.
On the pyramid, all registers can hold all modes. */
/* -->FIXME: this is not the case for 64-bit quantities in tr11/12 through
--> TR14/15. This should be fixed, but to do it correctly, we also
--> need to fix MODES_TIEABLE_P. Yuk. We ignore this, since GCC should
--> do the "right" thing due to FIXED_REGISTERS. */
#define HARD_REGNO_MODE_OK(REGNO, MODE) 1
/* Value is 1 if it is a good idea to tie two pseudo registers
when one has mode MODE1 and one has mode MODE2.
If HARD_REGNO_MODE_OK could produce different values for MODE1 and MODE2,
for any hard reg, then this must be 0 for correct output. */
#define MODES_TIEABLE_P(MODE1, MODE2) 1
/* Specify the registers used for certain standard purposes.
The values of these macros are register numbers. */
/* Pyramid pc is overloaded on global register 15. */
#define PC_REGNUM PYR_GREG(15)
/* Register to use for pushing function arguments.
--> on Pyramids, the data stack pointer. */
#define STACK_POINTER_REGNUM PYR_GREG(14)
/* Base register for access to local variables of the function.
Pyramid uses CFP (GR13) as both frame pointer and argument pointer. */
#define FRAME_POINTER_REGNUM 13 /* pyr cpp fails on PYR_GREG(13) */
/* Value should be nonzero if functions must have frame pointers.
Zero means the frame pointer need not be set up (and parms
may be accessed via the stack pointer) in functions that seem suitable.
This is computed in `reload', in reload1.c.
Setting this to 1 can't break anything. Since the Pyramid has
register windows, I don't know if defining this to be zero can
win anything. It could changed later, if it wins. */
#define FRAME_POINTER_REQUIRED 1
/* Base register for access to arguments of the function. */
#define ARG_POINTER_REGNUM 13 /* PYR_GREG(13) */
/* Register in which static-chain is passed to a function. */
/* If needed, Pyramid says to use temporary register 12. */
#define STATIC_CHAIN_REGNUM PYR_TREG(12)
/* If register windows are used, STATIC_CHAIN_INCOMING_REGNUM
is the register number as seen by the called function, while
STATIC_CHAIN_REGNUM is the register number as seen by the calling
function. */
#define STATIC_CHAIN_INCOMING_REGNUM PYR_PREG(12)
/* Register in which address to store a structure value
is passed to a function.
On a Pyramid, this is temporary register 0 (TR0). */
#define STRUCT_VALUE_REGNUM PYR_TREG(0)
#define STRUCT_VALUE_INCOMING_REGNUM PYR_PREG(0)
/* Define the classes of registers for register constraints in the
machine description. Also define ranges of constants.
One of the classes must always be named ALL_REGS and include all hard regs.
If there is more than one class, another class must be named NO_REGS
and contain no registers.
The name GENERAL_REGS must be the name of a class (or an alias for
another name such as ALL_REGS). This is the class of registers
that is allowed by "g" or "r" in a register constraint.
Also, registers outside this class are allocated only when
instructions express preferences for them.
The classes must be numbered in nondecreasing order; that is,
a larger-numbered class must never be contained completely
in a smaller-numbered class.
For any two classes, it is very desirable that there be another
class that represents their union. */
/* The pyramid has only one kind of registers, so NO_REGS and ALL_REGS
are the only classes. */
enum reg_class { NO_REGS, ALL_REGS, LIM_REG_CLASSES };
#define N_REG_CLASSES (int) LIM_REG_CLASSES
/* Since GENERAL_REGS is the same class as ALL_REGS,
don't give it a different class number; just make it an alias. */
#define GENERAL_REGS ALL_REGS
/* Give names of register classes as strings for dump file. */
#define REG_CLASS_NAMES \
{"NO_REGS", "ALL_REGS" }
/* Define which registers fit in which classes.
This is an initializer for a vector of HARD_REG_SET
of length N_REG_CLASSES. */
#define REG_CLASS_CONTENTS {{0,0}, {0xffffffff,0xffffffff}}
/* The same information, inverted:
Return the class number of the smallest class containing
reg number REGNO. This could be a conditional expression
or could index an array. */
#define REGNO_REG_CLASS(REGNO) ALL_REGS
/* The class value for index registers, and the one for base regs. */
#define BASE_REG_CLASS ALL_REGS
#define INDEX_REG_CLASS ALL_REGS
/* Get reg_class from a letter such as appears in the machine description. */
#define REG_CLASS_FROM_LETTER(C) NO_REGS
/* Given an rtx X being reloaded into a reg required to be
in class CLASS, return the class of reg to actually use.
In general this is just CLASS; but on some machines
in some cases it is preferable to use a more restrictive class. */
#define PREFERRED_RELOAD_CLASS(X,CLASS) (CLASS)
/* Return the maximum number of consecutive registers
needed to represent mode MODE in a register of class CLASS. */
/* On the pyramid, this is always the size of MODE in words,
since all registers are the same size. */
#define CLASS_MAX_NREGS(CLASS, MODE) \
((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
/* The letters I, J, K, L and M in a register constraint string
can be used to stand for particular ranges of immediate operands.
This macro defines what the ranges are.
C is the letter, and VALUE is a constant value.
Return 1 if VALUE is in the range specified by C.
--> For the Pyramid, 'I' can be used for the 6-bit signed integers
--> (-32 to 31) allowed as immediate short operands in many
--> instructions. 'J' cane be used for any value that doesn't fit
--> in 6 bits. */
#define CONST_OK_FOR_LETTER_P(VALUE, C) \
((C) == 'I' ? (VALUE) >= -32 && (VALUE) < 32 : \
(C) == 'J' ? (VALUE) < -32 || (VALUE) >= 32 : \
(C) == 'K' ? (VALUE) == 0xff || (VALUE) == 0xffff : 0)
/* Similar, but for floating constants, and defining letters G and H.
Here VALUE is the CONST_DOUBLE rtx itself. */
#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) 0
/*** Stack layout; function entry, exit and calling. ***/
/* Define this if pushing a word on the stack
makes the stack pointer a smaller address. */
#define STACK_GROWS_DOWNWARD
/* Define this if the nominal address of the stack frame
is at the high-address end of the local variables;
that is, each additional local variable allocated
goes at a more negative offset in the frame. */
#define FRAME_GROWS_DOWNWARD
/* Offset within stack frame to start allocating local variables at.
If FRAME_GROWS_DOWNWARD, this is the offset to the END of the
first local allocated. Otherwise, it is the offset to the BEGINNING
of the first local allocated. */
/* FIXME: this used to work when defined as 0. But that makes gnu
stdargs clobber the first arg. What gives?? */
#define STARTING_FRAME_OFFSET 0
/* Offset of first parameter from the argument pointer register value. */
#define FIRST_PARM_OFFSET(FNDECL) 0
/* Value is the number of bytes of arguments automatically
popped when returning from a subroutine call.
FUNDECL is the declaration node of the function (as a tree),
FUNTYPE is the data type of the function (as a tree),
or for a library call it is an identifier node for the subroutine name.
SIZE is the number of bytes of arguments passed on the stack.
The Pyramid OSx Porting Guide says we are never to do this;
using RETD in this way violates the Pyramid calling convention.
We may nevertheless provide this as an option. */
#define RETURN_POPS_ARGS(FUNDECL,FUNTYPE,SIZE) \
((TARGET_RETD && (!(FUNDECL) || TREE_CODE (FUNDECL) != IDENTIFIER_NODE) \
&& (TYPE_ARG_TYPES (FUNTYPE) == 0 \
|| (TREE_VALUE (tree_last (TYPE_ARG_TYPES (FUNTYPE))) \
== void_type_node))) \
? (SIZE) : 0)
/* Define how to find the value returned by a function.
VALTYPE is the data type of the value (as a tree).
If the precise function being called is known, FUNC is its FUNCTION_DECL;
otherwise, FUNC is 0. */
/* --> Pyramid has register windows.
--> The caller sees the return value is in TR0(/TR1) regardless of
--> its type. */
#define FUNCTION_VALUE(VALTYPE, FUNC) \
gen_rtx_REG (TYPE_MODE (VALTYPE), PYR_TREG(0))
/* --> but the callee has to leave it in PR0(/PR1) */
#define FUNCTION_OUTGOING_VALUE(VALTYPE, FUNC) \
gen_rtx_REG (TYPE_MODE (VALTYPE), PYR_PREG(0))
/* Define how to find the value returned by a library function
assuming the value has mode MODE. */
/* --> On Pyramid the return value is in TR0/TR1 regardless. */
#define LIBCALL_VALUE(MODE) gen_rtx_REG (MODE, PYR_TREG(0))
/* Define this if PCC uses the nonreentrant convention for returning
structure and union values. */
#define PCC_STATIC_STRUCT_RETURN
/* 1 if N is a possible register number for a function value
as seen by the caller.
On the Pyramid, TR0 is the only register thus used. */
#define FUNCTION_VALUE_REGNO_P(N) ((N) == PYR_TREG(0))
/* 1 if N is a possible register number for function argument passing.
On the Pyramid, the first twelve temporary registers are available. */
/* FIXME FIXME FIXME
it's not clear whether this macro should be defined from the point
of view of the caller or the callee. Since it's never actually used
in GNU CC, the point is somewhat moot :-).
This definition is consistent with register usage in the md's for
other register-window architectures (sparc and spur).
*/
#define FUNCTION_ARG_REGNO_P(N) ((PYR_TREG(0) <= (N)) && ((N) <= PYR_TREG(11)))
/*** Parameter passing: FUNCTION_ARG and FUNCTION_INCOMING_ARG ***/
/* Define a data type for recording info about an argument list
during the scan of that argument list. This data type should
hold all necessary information about the function itself
and about the args processed so far, enough to enable macros
such as FUNCTION_ARG to determine where the next arg should go.
On Pyramids, each parameter is passed either completely on the stack
or completely in registers. No parameter larger than a double may
be passed in a register. Also, no struct or union may be passed in
a register, even if it would fit.
So parameters are not necessarily passed "consecutively".
Thus we need a vector data type: one element to record how many
parameters have been passed in registers and on the stack,
respectively.
((These constraints seem like a gross waste of registers. But if we
ignore the constraint about structs & unions, we won`t be able to
freely mix gcc-compiled code and pyr cc-compiled code. It looks
like better argument passing conventions, and a machine-dependent
flag to enable them, might be a win.)) */
#define CUMULATIVE_ARGS int
/* Define the number of registers that can hold parameters.
This macro is used only in other macro definitions below. */
#define NPARM_REGS 12
/* Decide whether or not a parameter can be put in a register.
(We may still have problems with libcalls. GCC doesn't seem
to know about anything more than the machine mode. I trust
structures are never passed to a libcall...
If compiling with -mgnu-stdarg, this definition should make
functions using the gcc-supplied stdarg, and calls to such
functions (declared with an arglist ending in"..."), work.
But such fns won't be able to call pyr cc-compiled
varargs fns (eg, printf(), _doprnt.)
If compiling with -mnognu-stdarg, this definition should make
calls to pyr cc-compiled functions work. Functions using
the gcc-supplied stdarg will be utterly broken.
There will be no better solution until RMS can be persuaded that
one is needed.
This macro is used only in other macro definitions below.
(well, it may be used in pyr.c, because the damn pyramid cc
can't handle the macro definition of PARAM_SAFE_FOR_REG_P ! */
#define INNER_PARAM_SAFE_HELPER(TYPE) \
((TARGET_GNU_STDARG ? (! TREE_ADDRESSABLE ((tree)TYPE)): 1) \
&& (TREE_CODE ((tree)TYPE) != RECORD_TYPE) \
&& (TREE_CODE ((tree)TYPE) != UNION_TYPE))
#ifdef __GNUC__
#define PARAM_SAFE_HELPER(TYPE) \
INNER_PARAM_SAFE_HELPER((TYPE))
#else
extern int inner_param_safe_helper();
#define PARAM_SAFE_HELPER(TYPE) \
inner_param_safe_helper((tree)(TYPE))
#endif
/* Be careful with the expression (long) (TYPE) == 0.
Writing it in more obvious/correct forms makes the Pyr cc
dump core! */
#define PARAM_SAFE_FOR_REG_P(MODE, TYPE, NAMED) \
(((MODE) != BLKmode) \
&& ((TARGET_GNU_STDARG) ? (NAMED) : 1) \
&& ((((long)(TYPE))==0) || PARAM_SAFE_HELPER((TYPE))))
/* Initialize a variable CUM of type CUMULATIVE_ARGS
for a call to a function whose data type is FNTYPE.
For a library call, FNTYPE is 0. */
#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE,LIBNAME,INDIRECT) \
((CUM) = (FNTYPE && !flag_pcc_struct_return \
&& aggregate_value_p (TREE_TYPE (FNTYPE))))
/* Determine where to put an argument to a function.
Value is zero to push the argument on the stack,
or a hard register in which to store the argument.
MODE is the argument's machine mode.
TYPE is the data type of the argument (as a tree).
This is null for libcalls where that information may
not be available.
CUM is a variable of type CUMULATIVE_ARGS which gives info about
the preceding args and about the function being called.
NAMED is nonzero if this argument is a named parameter
(otherwise it is an extra parameter matching an ellipsis). */
#define FUNCTION_ARG_HELPER(CUM, MODE, TYPE, NAMED) \
(PARAM_SAFE_FOR_REG_P(MODE,TYPE,NAMED) \
? (NPARM_REGS >= ((CUM) \
+ ((MODE) == BLKmode \
? (int_size_in_bytes (TYPE) + 3) / 4 \
: (GET_MODE_SIZE (MODE) + 3) / 4)) \
? gen_rtx_REG ((MODE), PYR_TREG(CUM)) \
: 0) \
: 0)
#ifdef __GNUC__
#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \
FUNCTION_ARG_HELPER(CUM, MODE, TYPE, NAMED)
#else
/***************** Avoid bug in Pyramid OSx compiler... ******************/
#define FUNCTION_ARG (rtx) pyr_function_arg
extern void* pyr_function_arg ();
#endif
/* Define where a function finds its arguments.
This is different from FUNCTION_ARG because of register windows. */
#define FUNCTION_INCOMING_ARG(CUM, MODE, TYPE, NAMED) \
(PARAM_SAFE_FOR_REG_P(MODE,TYPE,NAMED) \
? (NPARM_REGS >= ((CUM) \
+ ((MODE) == BLKmode \
? (int_size_in_bytes (TYPE) + 3) / 4 \
: (GET_MODE_SIZE (MODE) + 3) / 4)) \
? gen_rtx_REG ((MODE), PYR_PREG(CUM)) \
: 0) \
: 0)
/* Update the data in CUM to advance over an argument
of mode MODE and data type TYPE.
(TYPE is null for libcalls where that information may not be available.) */
#define FUNCTION_ARG_ADVANCE(CUM,MODE,TYPE,NAMED) \
((CUM) += (PARAM_SAFE_FOR_REG_P(MODE,TYPE,NAMED) \
? ((MODE) != BLKmode \
? (GET_MODE_SIZE (MODE) + 3) / 4 \
: (int_size_in_bytes (TYPE) + 3) / 4) \
: 0))
/* This macro generates the assembly code for function entry.
FILE is a stdio stream to output the code to.
SIZE is an int: how many units of temporary storage to allocate.
Refer to the array `regs_ever_live' to determine which registers
to save; `regs_ever_live[I]' is nonzero if register number I
is ever used in the function. This macro is responsible for
knowing which registers should not be saved even if used. */
#if FRAME_POINTER_REQUIRED
/* We always have frame pointers */
/* Don't set up a frame pointer if it's not referenced. */
#define FUNCTION_PROLOGUE(FILE, SIZE) \
{ \
int _size = (SIZE) + current_function_pretend_args_size; \
if (_size + current_function_args_size != 0 \
|| current_function_calls_alloca) \
{ \
fprintf (FILE, "\tadsf $%d\n", _size); \
if (current_function_pretend_args_size > 0) \
fprintf (FILE, "\tsubw $%d,cfp\n", \
current_function_pretend_args_size); \
} \
}
#else /* !FRAME_POINTER_REQUIRED */
/* Don't set up a frame pointer if `frame_pointer_needed' tells us
there is no need. Also, don't set up a frame pointer if it's not
referenced. */
/* The definition used to be broken. Write a new one. */
#endif /* !FRAME_POINTER_REQUIRED */
/* the trampoline stuff was taken from convex.h - S.P. */
/* A C statement to output, on the stream FILE, assembler code for a
block of data that contains the constant parts of a trampoline. This
code should not include a label - the label is taken care of
automatically.
We use TR12/PR12 for the static chain.
movew $<STATIC>,pr12 # I2R
jump $<func> # S2R
*/
#define TRAMPOLINE_TEMPLATE(FILE) \
{ ASM_OUTPUT_INT (FILE, GEN_INT (0x2100001C)); \
ASM_OUTPUT_INT (FILE, GEN_INT (0x00000000)); \
ASM_OUTPUT_INT (FILE, GEN_INT (0x40000000)); \
ASM_OUTPUT_INT (FILE, GEN_INT (0x00000000)); }
#define TRAMPOLINE_SIZE 16
#define TRAMPOLINE_ALIGNMENT 32
/* Emit RTL insns to initialize the variable parts of a trampoline.
FNADDR is an RTX for the address of the function's pure code.
CXT is an RTX for the static chain value for the function. */
#define INITIALIZE_TRAMPOLINE(TRAMP, FNADDR, CXT) \
{ emit_move_insn (gen_rtx_MEM (Pmode, plus_constant (TRAMP, 4)), CXT); \
emit_move_insn (gen_rtx (MEM, Pmode, plus_constant (TRAMP, 12)), FNADDR); \
emit_call_insn (gen_call \
(gen_rtx_MEM \
(QImode, \
gen_rtx_SYMBOL_REF (Pmode, "__enable_execute_stack")), \
const0_rtx)); \
}
/* Output assembler code to FILE to increment profiler label # LABELNO
for profiling a function entry. */
#define FUNCTION_PROFILER(FILE, LABELNO) \
fprintf (FILE, "\tmova LP%d,tr0\n\tcall mcount\n", (LABELNO));
/* Output assembler code to FILE to initialize this source file's
basic block profiling info, if that has not already been done.
Don't know if this works on Pyrs. */
#if 0 /* don't do basic_block profiling yet */
#define FUNCTION_BLOCK_PROFILER(FILE, LABELNO) \
fprintf (FILE, \
"\tmtstw LPBX0,tr0\n\tbne LPI%d\n\tmova LP%d,TR0\n\tcall __bb_init_func\nLPI%d:\n", \
LABELNO, LABELNO);
/* Output assembler code to increment the count associated with
the basic block number BLOCKNO. Not sure how to do this on pyrs. */
#define BLOCK_PROFILER(FILE, BLOCKNO) \
fprintf (FILE, "\taddw", 4 * BLOCKNO)
#endif /* don't do basic_block profiling yet */
/* When returning from a function, the stack pointer does not matter
(as long as there is a frame pointer). */
/* This should return non-zero when we really set up a frame pointer.
Otherwise, GCC is directed to preserve sp by returning zero. */
#define EXIT_IGNORE_STACK \
(get_frame_size () + current_function_pretend_args_size \
+ current_function_args_size != 0 \
|| current_function_calls_alloca) \
/* Store in the variable DEPTH the initial difference between the
frame pointer reg contents and the stack pointer reg contents,
as of the start of the function body. This depends on the layout
of the fixed parts of the stack frame and on how registers are saved.
On the Pyramid, FRAME_POINTER_REQUIRED is always 1, so the definition
of this macro doesn't matter. But it must be defined. */
#define INITIAL_FRAME_POINTER_OFFSET(DEPTH) (DEPTH) = 0;
/*** Addressing modes, and classification of registers for them. ***/
/* #define HAVE_POST_INCREMENT 0 */ /* pyramid has none of these */
/* #define HAVE_POST_DECREMENT 0 */
/* #define HAVE_PRE_DECREMENT 0 */
/* #define HAVE_PRE_INCREMENT 0 */
/* Macros to check register numbers against specific register classes. */
/* These assume that REGNO is a hard or pseudo reg number.
They give nonzero only if REGNO is a hard reg of the suitable class
or a pseudo reg currently allocated to a suitable hard reg.
Since they use reg_renumber, they are safe only once reg_renumber
has been allocated, which happens in local-alloc.c. */
/* All registers except gr0 OK as index or base registers. */
#define REGNO_OK_FOR_BASE_P(regno) \
((regno) < FIRST_PSEUDO_REGISTER || reg_renumber[regno] >= 0)
#define REGNO_OK_FOR_INDEX_P(regno) \
((unsigned) (regno) - 1 < FIRST_PSEUDO_REGISTER - 1 \
|| reg_renumber[regno] > 0)
/* Maximum number of registers that can appear in a valid memory address. */
#define MAX_REGS_PER_ADDRESS 2 /* check MAX_REGS_PER_ADDRESS */
/* 1 if X is an rtx for a constant that is a valid address. */
#define CONSTANT_ADDRESS_P(X) \
(GET_CODE (X) == LABEL_REF || GET_CODE (X) == SYMBOL_REF \
|| GET_CODE (X) == CONST_INT || GET_CODE (X) == CONST \
|| GET_CODE (X) == HIGH)
/* Nonzero if the constant value X is a legitimate general operand.
It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE. */
#define LEGITIMATE_CONSTANT_P(X) 1
/* The macros REG_OK_FOR..._P assume that the arg is a REG rtx
and check its validity for a certain class.
We have two alternate definitions for each of them.
The usual definition accepts all pseudo regs; the other rejects
them unless they have been allocated suitable hard regs.
The symbol REG_OK_STRICT causes the latter definition to be used.
Most source files want to accept pseudo regs in the hope that
they will get allocated to the class that the insn wants them to be in.
Source files for reload pass need to be strict.
After reload, it makes no difference, since pseudo regs have
been eliminated by then. */
#ifndef REG_OK_STRICT
/* Nonzero if X is a hard reg that can be used as an index
or if it is a pseudo reg. */
#define REG_OK_FOR_INDEX_P(X) (REGNO (X) > 0)
/* Nonzero if X is a hard reg that can be used as a base reg
or if it is a pseudo reg. */
#define REG_OK_FOR_BASE_P(X) 1
#else
/* Nonzero if X is a hard reg that can be used as an index. */
#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P (REGNO (X))
/* Nonzero if X is a hard reg that can be used as a base reg. */
#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P (REGNO (X))
#endif
/* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression
that is a valid memory address for an instruction.
The MODE argument is the machine mode for the MEM expression
that wants to use this address.
The other macros defined here are used only in GO_IF_LEGITIMATE_ADDRESS,
except for CONSTANT_ADDRESS_P which is actually machine-independent. */
/* Go to ADDR if X is indexable -- i.e., neither indexed nor offset. */
#define GO_IF_INDEXABLE_ADDRESS(X, ADDR) \
{ register rtx xfoob = (X); \
if ((CONSTANT_ADDRESS_P (xfoob)) \
|| (GET_CODE (xfoob) == REG && (REG_OK_FOR_BASE_P (xfoob)))) \
goto ADDR; \
}
/* Go to label ADDR if X is a valid address that doesn't use indexing.
This is so if X is either a simple address, or the contents of a register
plus an offset.
This macro also gets used in output-pyramid.h in the function that
recognizes non-indexed operands. */
#define GO_IF_NONINDEXED_ADDRESS(X, ADDR) \
{ \
if (GET_CODE (X) == REG) \
goto ADDR; \
GO_IF_INDEXABLE_ADDRESS (X, ADDR); \
if (GET_CODE (X) == PLUS) \
{ /* Handle offset(reg) represented with offset on left */ \
if (CONSTANT_ADDRESS_P (XEXP (X, 0))) \
{ if (GET_CODE (XEXP (X, 1)) == REG \
&& REG_OK_FOR_BASE_P (XEXP (X, 1))) \
goto ADDR; \
} \
/* Handle offset(reg) represented with offset on right */ \
if (CONSTANT_ADDRESS_P (XEXP (X, 1))) \
{ if (GET_CODE (XEXP (X, 0)) == REG \
&& REG_OK_FOR_BASE_P (XEXP (X, 0))) \
goto ADDR; \
} \
} \
}
/* 1 if PROD is either a reg or a reg times a valid offset multiplier
(ie, 2, 4, or 8).
This macro's expansion uses the temporary variables xfoo0 and xfoo1
that must be declared in the surrounding context. */
#define INDEX_TERM_P(PROD, MODE) \
((GET_CODE (PROD) == REG && REG_OK_FOR_BASE_P (PROD)) \
|| (GET_CODE (PROD) == MULT \
&& \
(xfoo0 = XEXP (PROD, 0), xfoo1 = XEXP (PROD, 1), \
((GET_CODE (xfoo0) == CONST_INT \
&& (INTVAL (xfoo0) == 1 \
|| INTVAL (xfoo0) == 2 \
|| INTVAL (xfoo0) == 4 \
|| INTVAL (xfoo0) == 8) \
&& GET_CODE (xfoo1) == REG \
&& REG_OK_FOR_INDEX_P (xfoo1)) \
|| \
(GET_CODE (xfoo1) == CONST_INT \
&& (INTVAL (xfoo1) == 1 \
|| INTVAL (xfoo1) == 2 \
|| INTVAL (xfoo1) == 4 \
|| INTVAL (xfoo1) == 8) \
&& GET_CODE (xfoo0) == REG \
&& REG_OK_FOR_INDEX_P (xfoo0))))))
#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \
{ register rtx xone, xtwo, xfoo0, xfoo1; \
GO_IF_NONINDEXED_ADDRESS (X, ADDR); \
if (GET_CODE (X) == PLUS) \
{ \
/* Handle <address>[index] represented with index-sum outermost */\
xone = XEXP (X, 0); \
xtwo = XEXP (X, 1); \
if (INDEX_TERM_P (xone, MODE)) \
{ GO_IF_INDEXABLE_ADDRESS (xtwo, ADDR); } \
/* Handle <address>[index] represented with index-sum innermost */\
if (INDEX_TERM_P (xtwo, MODE)) \
{ GO_IF_INDEXABLE_ADDRESS (xone, ADDR); } \
} \
}
/* Try machine-dependent ways of modifying an illegitimate address
to be legitimate. If we find one, return the new, valid address.
This macro is used in only one place: `memory_address' in explow.c.
OLDX is the address as it was before break_out_memory_refs was called.
In some cases it is useful to look at this to decide what needs to be done.
MODE and WIN are passed so that this macro can use
GO_IF_LEGITIMATE_ADDRESS.
It is always safe for this macro to do nothing. It exists to recognize
opportunities to optimize the output.
--> FIXME: We haven't yet figured out what optimizations are useful
--> on Pyramids. */
#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN) {}
/* Go to LABEL if ADDR (a legitimate address expression)
has an effect that depends on the machine mode it is used for.
There don't seem to be any such modes on pyramids. */
#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL)
/*** Miscellaneous Parameters ***/
/* Specify the machine mode that this machine uses
for the index in the tablejump instruction. */
#define CASE_VECTOR_MODE SImode
/* Define as C expression which evaluates to nonzero if the tablejump
instruction expects the table to contain offsets from the address of the
table.
Do not define this if the table should contain absolute addresses. */
/*#define CASE_VECTOR_PC_RELATIVE 1 */
/* Specify the tree operation to be used to convert reals to integers. */
#define IMPLICIT_FIX_EXPR FIX_ROUND_EXPR
/* This is the kind of divide that is easiest to do in the general case.
It's just a guess. I have no idea of insn cost on pyrs. */
#define EASY_DIV_EXPR TRUNC_DIV_EXPR
/* Define this as 1 if `char' should by default be signed; else as 0. */
#define DEFAULT_SIGNED_CHAR 1
/* This flag, if defined, says the same insns that convert to a signed fixnum
also convert validly to an unsigned one. */
/* This is untrue for pyramid. The cvtdw instruction generates a trap
for input operands that are out-of-range for a signed int. */
/* #define FIXUNS_TRUNC_LIKE_FIX_TRUNC */
/* Define this macro if the preprocessor should silently ignore
'#sccs' directives. */
/* #define SCCS_DIRECTIVE */
/* Define this macro if the preprocessor should silently ignore
'#ident' directives. */
/* #define IDENT_DIRECTIVE */
/* Max number of bytes we can move from memory to memory
in one reasonably fast instruction. */
#define MOVE_MAX 8
/* Define this if zero-extension is slow (more than one real instruction). */
/* #define SLOW_ZERO_EXTEND */
/* number of bits in an 'int' on target machine */
#define INT_TYPE_SIZE 32
/* 1 if byte access requires more than one instruction */
#define SLOW_BYTE_ACCESS 0
/* Define this to be nonzero if shift instructions ignore all but the low-order
few bits. */
#define SHIFT_COUNT_TRUNCATED 1
/* Value is 1 if truncating an integer of INPREC bits to OUTPREC bits
is done just by pretending it is already truncated. */
#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1
/* Define this macro if it is as good or better to call a constant
function address than to call an address kept in a register. */
/* #define NO_FUNCTION_CSE */
/* When a prototype says `char' or `short', really pass an `int'. */
#define PROMOTE_PROTOTYPES 1
/* There are no flag store insns on a pyr. */
/* #define STORE_FLAG_VALUE */
/* Specify the machine mode that pointers have.
After generation of rtl, the compiler makes no further distinction
between pointers and any other objects of this machine mode. */
#define Pmode SImode
/* A function address in a call instruction
is a byte address (for indexing purposes)
so give the MEM rtx a byte's mode. */
#define FUNCTION_MODE QImode
/* Compute the cost of computing a constant rtl expression RTX
whose rtx-code is CODE. The body of this macro is a portion
of a switch statement. If the code is computed here,
return it with a return statement. Otherwise, break from the switch. */
#define CONST_COSTS(RTX,CODE,OUTER_CODE) \
case CONST_INT: \
if (CONST_OK_FOR_LETTER_P (INTVAL (RTX),'I')) return 0; \
case CONST: \
case LABEL_REF: \
case SYMBOL_REF: \
return 4; \
case CONST_DOUBLE: \
return 6;
/* A flag which says to swap the operands of certain insns
when they are output. */
extern int swap_operands;
/*** Condition Code Information ***/
/* Tell final.c how to eliminate redundant test instructions. */
/* Here we define machine-dependent flags and fields in cc_status
(see `conditions.h'). No extra ones are needed for the pyr. */
/* Store in cc_status the expressions
that the condition codes will describe
after execution of an instruction whose pattern is EXP.
Do not alter them if the instruction would not alter the cc's. */
/* This is a very simple definition of NOTICE_UPDATE_CC.
Many cases can be optimized, to improve condition code usage.
Maybe we should handle this entirely in the md, since it complicated
to describe the way pyr sets cc. */
#define TRULY_UNSIGNED_COMPARE_P(X) \
(X == GEU || X == GTU || X == LEU || X == LTU)
#define CC_VALID_FOR_UNSIGNED 2
#define CC_STATUS_MDEP_INIT cc_status.mdep = 0
#define NOTICE_UPDATE_CC(EXP, INSN) \
notice_update_cc(EXP, INSN)
/*** Output of Assembler Code ***/
/* Output at beginning of assembler file. */
#define ASM_FILE_START(FILE) \
fprintf (FILE, ((TARGET_UNIX_ASM)? "" : "#NO_APP\n"));
/* Output to assembler file text saying following lines
may contain character constants, extra white space, comments, etc. */
#define ASM_APP_ON ((TARGET_UNIX_ASM) ? "" : "#APP\n")
/* Output to assembler file text saying following lines
no longer contain unusual constructs. */
#define ASM_APP_OFF ((TARGET_UNIX_ASM) ? "" : "#NO_APP\n")
/* Output before read-only data. */
#define TEXT_SECTION_ASM_OP "\t.text"
/* Output before writable data. */
#define DATA_SECTION_ASM_OP "\t.data"
/* How to refer to registers in assembler output.
This sequence is indexed by compiler's hard-register-number (see above). */
#define REGISTER_NAMES \
{"gr0", "gr1", "gr2", "gr3", "gr4", "gr5", "gr6", "gr7", "gr8", \
"gr9", "gr10", "gr11", "logpsw", "cfp", "sp", "pc", \
"pr0", "pr1", "pr2", "pr3", "pr4", "pr5", "pr6", "pr7", \
"pr8", "pr9", "pr10", "pr11", "pr12", "pr13", "pr14", "pr15", \
"lr0", "lr1", "lr2", "lr3", "lr4", "lr5", "lr6", "lr7", \
"lr8", "lr9", "lr10", "lr11", "lr12", "lr13", "lr14", "lr15", \
"tr0", "tr1", "tr2", "tr3", "tr4", "tr5", "tr6", "tr7", \
"tr8", "tr9", "tr10", "tr11", "tr12", "tr13", "tr14", "tr15"}
/* How to renumber registers for dbx and gdb. */
#define DBX_REGISTER_NUMBER(REGNO) (REGNO)
/* Our preference is for dbx rather than sdb.
Yours may be different. */
#define DBX_DEBUGGING_INFO
/* #define SDB_DEBUGGING_INFO */
/* Don't use the `xsfoo;' construct in DBX output; this system
doesn't support it. */
#define DBX_NO_XREFS 1
/* Do not break .stabs pseudos into continuations. */
#define DBX_CONTIN_LENGTH 0
/* This is the char to use for continuation (in case we need to turn
continuation back on). */
#define DBX_CONTIN_CHAR '?'
/* This is how to output the definition of a user-level label named NAME,
such as the label on a static function or variable NAME. */
#define ASM_OUTPUT_LABEL(FILE,NAME) \
do { assemble_name (FILE, NAME); fputs (":\n", FILE); } while (0)
/* This is how to output a command to make the user-level label named NAME
defined for reference from other files. */
#define ASM_GLOBALIZE_LABEL(FILE,NAME) \
do { fputs (".globl ", FILE); assemble_name (FILE, NAME); fputs ("\n", FILE);} while (0)
/* The prefix to add to user-visible assembler symbols. */
#define USER_LABEL_PREFIX "_"
/* This is how to output an internal numbered label where
PREFIX is the class of label and NUM is the number within the class. */
#define ASM_OUTPUT_INTERNAL_LABEL(FILE,PREFIX,NUM) \
fprintf (FILE, "%s%d:\n", PREFIX, NUM)
/* This is how to store into the string LABEL
the symbol_ref name of an internal numbered label where
PREFIX is the class of label and NUM is the number within the class.
This is suitable for output with `assemble_name'. */
#define ASM_GENERATE_INTERNAL_LABEL(LABEL,PREFIX,NUM) \
sprintf (LABEL, "*%s%d", PREFIX, NUM)
/* This is how to output an assembler line defining a `double' constant. */
#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \
fprintf (FILE, "\t.double 0d%.20e\n", (VALUE))
/* This is how to output an assembler line defining a `float' constant. */
#define ASM_OUTPUT_FLOAT(FILE,VALUE) \
fprintf (FILE, "\t.float 0f%.20e\n", (VALUE))
/* This is how to output an assembler line defining an `int' constant. */
#define ASM_OUTPUT_INT(FILE,VALUE) \
( fprintf (FILE, "\t.word "), \
output_addr_const (FILE, (VALUE)), \
fprintf (FILE, "\n"))
/* Likewise for `char' and `short' constants. */
#define ASM_OUTPUT_SHORT(FILE,VALUE) \
( fprintf (FILE, "\t.half "), \
output_addr_const (FILE, (VALUE)), \
fprintf (FILE, "\n"))
#define ASM_OUTPUT_CHAR(FILE,VALUE) \
( fprintf (FILE, "\t.byte "), \
output_addr_const (FILE, (VALUE)), \
fprintf (FILE, "\n"))
/* This is how to output an assembler line for a numeric constant byte. */
#define ASM_OUTPUT_BYTE(FILE,VALUE) \
fprintf (FILE, "\t.byte 0x%x\n", (VALUE))
/* This is how to output an insn to push a register on the stack.
It need not be very fast code. */
#define ASM_OUTPUT_REG_PUSH(FILE,REGNO) \
fprintf (FILE, "\tsubw $4,sp\n\tmovw %s,(sp)\n", reg_names[REGNO])
/* This is how to output an insn to pop a register from the stack.
It need not be very fast code. */
#define ASM_OUTPUT_REG_POP(FILE,REGNO) \
fprintf (FILE, "\tmovw (sp),%s\n\taddw $4,sp\n", reg_names[REGNO])
/* Store in OUTPUT a string (made with alloca) containing
an assembler-name for a local static variable named NAME.
LABELNO is an integer which is different for each call. */
#define ASM_FORMAT_PRIVATE_NAME(OUTPUT, NAME, LABELNO) \
( (OUTPUT) = (char *) alloca (strlen ((NAME)) + 10), \
sprintf ((OUTPUT), "%s.%d", (NAME), (LABELNO)))
/* This is how to output an element of a case-vector that is absolute. */
#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \
fprintf (FILE, "\t.word L%d\n", VALUE)
/* This is how to output an element of a case-vector that is relative. */
#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \
fprintf (FILE, "\t.word L%d-L%d\n", VALUE, REL)
/* This is how to output an assembler line
that says to advance the location counter
to a multiple of 2**LOG bytes.
On Pyramids, the text segment must always be word aligned.
On Pyramids, .align takes only args between 2 and 5.
*/
#define ASM_OUTPUT_ALIGN(FILE,LOG) \
fprintf (FILE, "\t.align %d\n", (LOG) < 2 ? 2 : (LOG))
#define ASM_OUTPUT_SKIP(FILE,SIZE) \
fprintf (FILE, "\t.space %u\n", (SIZE))
/* This says how to output an assembler line
to define a global common symbol. */
#define ASM_OUTPUT_COMMON(FILE, NAME, SIZE, ROUNDED) \
( fputs (".comm ", (FILE)), \
assemble_name ((FILE), (NAME)), \
fprintf ((FILE), ",%u\n", (ROUNDED)))
/* This says how to output an assembler line
to define a local common symbol. */
#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \
( fputs (".lcomm ", (FILE)), \
assemble_name ((FILE), (NAME)), \
fprintf ((FILE), ",%u\n", (ROUNDED)))
/* Define the parentheses used to group arithmetic operations
in assembler code. */
#define ASM_OPEN_PAREN "("
#define ASM_CLOSE_PAREN ")"
/* Define results of standard character escape sequences. */
#define TARGET_BELL 007
#define TARGET_BS 010
#define TARGET_TAB 011
#define TARGET_NEWLINE 012
#define TARGET_VT 013
#define TARGET_FF 014
#define TARGET_CR 015
/* Print operand X (an rtx) in assembler syntax to file FILE.
CODE is a letter or dot (`z' in `%z0') or 0 if no letter was specified.
For `%' followed by punctuation, CODE is the punctuation and X is null.
On the Pyr, we support the conventional CODE characters:
'f' for float insn (print a CONST_DOUBLE as a float rather than in hex)
which are never used. */
/* FIXME : should be more robust with CONST_DOUBLE. */
#define PRINT_OPERAND(FILE, X, CODE) \
{ if (GET_CODE (X) == REG) \
fprintf (FILE, "%s", reg_names [REGNO (X) + ((CODE) == 'R')]); \
\
else if (GET_CODE (X) == MEM) \
output_address (XEXP (X, 0)); \
\
else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) == SFmode) \
{ union { double d; int i[2]; } u; \
union { float f; int i; } u1; \
u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); \
u1.f = u.d; \
if (CODE == 'f') \
fprintf (FILE, "$0f%.0e", u1.f); \
else \
fprintf (FILE, "$0x%x", u1.i); } \
\
else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) != VOIDmode) \
{ union { double d; int i[2]; } u; \
u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); \
fprintf (FILE, "$0d%.20e", u.d); } \
\
else if (CODE == 'N') \
switch (GET_CODE (X)) \
{ \
case EQ: fputs ("eq", FILE); break; \
case NE: fputs ("ne", FILE); break; \
case GT: \
case GTU: fputs ("gt", FILE); break; \
case LT: \
case LTU: fputs ("lt", FILE); break; \
case GE: \
case GEU: fputs ("ge", FILE); break; \
case LE: \
case LEU: fputs ("le", FILE); break; \
} \
\
else if (CODE == 'C') \
switch (GET_CODE (X)) \
{ \
case EQ: fputs ("ne", FILE); break; \
case NE: fputs ("eq", FILE); break; \
case GT: \
case GTU: fputs ("le", FILE); break; \
case LT: \
case LTU: fputs ("ge", FILE); break; \
case GE: \
case GEU: fputs ("lt", FILE); break; \
case LE: \
case LEU: fputs ("gt", FILE); break; \
} \
\
else if (CODE == 'R') \
switch (GET_CODE (X)) \
{ \
case EQ: fputs ("eq", FILE); break; \
case NE: fputs ("ne", FILE); break; \
case GT: \
case GTU: fputs ("lt", FILE); break; \
case LT: \
case LTU: fputs ("gt", FILE); break; \
case GE: \
case GEU: fputs ("le", FILE); break; \
case LE: \
case LEU: fputs ("ge", FILE); break; \
} \
\
else { putc ('$', FILE); output_addr_const (FILE, X); } \
}
/* Print a memory operand whose address is ADDR, on file FILE. */
/* This is horrendously complicated. */
#define PRINT_OPERAND_ADDRESS(FILE, ADDR) \
{ \
register rtx reg1, reg2, breg, ireg; \
register rtx addr = ADDR; \
rtx offset, scale; \
retry: \
switch (GET_CODE (addr)) \
{ \
case MEM: \
fprintf (stderr, "bad Mem "); debug_rtx (addr); \
addr = XEXP (addr, 0); \
abort (); \
case REG: \
fprintf (FILE, "(%s)", reg_names [REGNO (addr)]); \
break; \
case PLUS: \
reg1 = 0; reg2 = 0; \
ireg = 0; breg = 0; \
offset = 0; \
if (CONSTANT_ADDRESS_P (XEXP (addr, 0)) \
|| GET_CODE (XEXP (addr, 0)) == MEM) \
{ \
offset = XEXP (addr, 0); \
addr = XEXP (addr, 1); \
} \
else if (CONSTANT_ADDRESS_P (XEXP (addr, 1)) \
|| GET_CODE (XEXP (addr, 1)) == MEM) \
{ \
offset = XEXP (addr, 1); \
addr = XEXP (addr, 0); \
} \
if (GET_CODE (addr) != PLUS) ; \
else if (GET_CODE (XEXP (addr, 0)) == MULT) \
{ \
reg1 = XEXP (addr, 0); \
addr = XEXP (addr, 1); \
} \
else if (GET_CODE (XEXP (addr, 1)) == MULT) \
{ \
reg1 = XEXP (addr, 1); \
addr = XEXP (addr, 0); \
} \
else if (GET_CODE (XEXP (addr, 0)) == REG) \
{ \
reg1 = XEXP (addr, 0); \
addr = XEXP (addr, 1); \
} \
else if (GET_CODE (XEXP (addr, 1)) == REG) \
{ \
reg1 = XEXP (addr, 1); \
addr = XEXP (addr, 0); \
} \
if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT) \
{ \
if (reg1 == 0) \
reg1 = addr; \
else \
reg2 = addr; \
addr = 0; \
} \
if (offset != 0) \
{ \
if (addr != 0) { \
fprintf (stderr, "\nBad addr "); debug_rtx (addr); \
abort ();} \
addr = offset; \
} \
if (reg1 != 0 && GET_CODE (reg1) == MULT) \
{ breg = reg2; ireg = reg1; } \
else if (reg2 != 0 && GET_CODE (reg2) == MULT) \
{ breg = reg1; ireg = reg2; } \
else if (reg2 != 0 || GET_CODE (addr) == MEM) \
{ breg = reg2; ireg = reg1; } \
else \
{ breg = reg1; ireg = reg2; } \
if (addr != 0) \
output_address (offset); \
if (breg != 0) \
{ if (GET_CODE (breg) != REG) \
{ \
fprintf (stderr, "bad Breg"); debug_rtx (addr); \
abort (); \
} \
fprintf (FILE, "(%s)", reg_names[REGNO (breg)]); } \
if (ireg != 0) \
{ \
if (GET_CODE (ireg) == MULT) \
{ \
scale = XEXP (ireg, 1); \
ireg = XEXP (ireg, 0); \
if (GET_CODE (ireg) != REG) \
{ register rtx tem; \
tem = ireg; ireg = scale; scale = tem; \
} \
if (GET_CODE (ireg) != REG) { \
fprintf (stderr, "bad idx "); debug_rtx (addr); \
abort (); } \
if ((GET_CODE (scale) == CONST_INT) && (INTVAL(scale) >= 1))\
fprintf (FILE, "[%s*0x%x]", reg_names[REGNO (ireg)], \
INTVAL(scale)); \
else \
fprintf (FILE, "[%s*1]", reg_names[REGNO (ireg)]); \
} \
else if (GET_CODE (ireg) == REG) \
fprintf (FILE, "[%s*1]", reg_names[REGNO (ireg)]); \
else \
{ \
fprintf (stderr, "Not indexed at all!"); debug_rtx (addr);\
abort (); \
} \
} \
break; \
default: \
output_addr_const (FILE, addr); \
} \
}
;; GNU C machine description for Pyramid 90x, 9000, MIServer Series
;; Copyright (C) 1989, 90, 95, 97, 98, 1999 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, 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.
;; Instruction patterns. When multiple patterns apply,
;; the first one in the file is chosen.
;;
;; See file "rtl.def" for documentation on define_insn, match_*, et. al.
;;
;; cpp macro #define NOTICE_UPDATE_CC in file tm.h handles condition code
;; updates for most instructions.
;; These comments are mostly obsolete. Written for gcc version 1.XX.
;; * Try using define_insn instead of some peepholes in more places.
;; * Set REG_NOTES:REG_EQUIV for cvt[bh]w loads. This would make the
;; backward scan in sign_extend needless.
;; * Match (pc) (label_ref) case in peephole patterns.
;; * Should optimize
;; "cmpX op1,op2; b{eq,ne} LY; ucmpX op1.op2; b{lt,le,gt,ge} LZ"
;; to
;; "ucmpX op1,op2; b{eq,ne} LY; b{lt,le,gt,ge} LZ"
;; by pre-scanning insn and running notice_update_cc for them.
;; * Is it necessary to do copy_rtx in the test and compare patterns?
;; * Fix true frame pointer omission.
;; * Make the jump tables contain branches, not addresses! This would
;; save us one instruction.
;; * Could the complicated scheme for compares be simplified, if we had
;; no named cmpqi or cmphi patterns, and instead anonymous patterns for
;; the less-than-word compare cases pyr can handle???
;; * The jump insn seems to accept more than just IR addressing. Would
;; we win by telling GCC? Or can we use movw into the global reg which
;; is a synonym for pc?
;; * More DImode patterns.
;; * Scan backwards in "zero_extendhisi2", "zero_extendqisi2" to find out
;; if the extension can be omitted.
;; * "divmodsi" with Pyramid "ediv" insn. Is it possible in rtl??
;; * Would "rcsp tmpreg; u?cmp[bh] op1_regdispl(tmpreg),op2" win in
;; comparison with the two extensions and single test generated now?
;; The rcsp insn could be expanded, and moved out of loops by the
;; optimizer, making 1 (64 bit) insn of 3 (32 bit) insns in loops.
;; The rcsp insn could be followed by an add insn, making non-displacement
;; IR addressing sufficient.
;______________________________________________________________________
;
; Test and Compare Patterns.
;______________________________________________________________________
; The argument for the rather complicated test and compare expansion
; scheme, is the irregular pyramid instructions for these operations.
; 1) Pyramid has different signed and unsigned compares. 2) HImode
; and QImode integers are memory-memory and immediate-memory only. 3)
; Unsigned HImode compares doesn't exist. 4) Only certain
; combinations of addresses are allowed for memory-memory compares.
; Whenever necessary, in order to fulfill these addressing
; constraints, the compare operands are swapped.
(define_expand "tstsi"
[(set (cc0)
(match_operand:SI 0 "general_operand" ""))]
"" "operands[0] = force_reg (SImode, operands[0]);")
(define_insn ""
[(set (cc0)
(compare (match_operand:SI 0 "memory_operand" "m")
(match_operand:SI 1 "memory_operand" "m")))]
"weird_memory_memory (operands[0], operands[1])"
"*
{
rtx br_insn = NEXT_INSN (insn);
RTX_CODE br_code;
if (GET_CODE (br_insn) != JUMP_INSN)
abort();
br_code = GET_CODE (XEXP (XEXP (PATTERN (br_insn), 1), 0));
weird_memory_memory (operands[0], operands[1]);
if (swap_operands)
{
cc_status.flags = CC_REVERSED;
if (TRULY_UNSIGNED_COMPARE_P (br_code))
{
cc_status.mdep = CC_VALID_FOR_UNSIGNED;
return \"ucmpw %0,%1\";
}
return \"cmpw %0,%1\";
}
if (TRULY_UNSIGNED_COMPARE_P (br_code))
{
cc_status.mdep = CC_VALID_FOR_UNSIGNED;
return \"ucmpw %1,%0\";
}
return \"cmpw %1,%0\";
}")
(define_insn "cmpsi"
[(set (cc0)
(compare (match_operand:SI 0 "nonimmediate_operand" "r,g")
(match_operand:SI 1 "general_operand" "g,r")))]
""
"*
{
rtx br_insn = NEXT_INSN (insn);
RTX_CODE br_code;
if (GET_CODE (br_insn) != JUMP_INSN)
abort();
br_code = GET_CODE (XEXP (XEXP (PATTERN (br_insn), 1), 0));
if (which_alternative != 0)
{
cc_status.flags = CC_REVERSED;
if (TRULY_UNSIGNED_COMPARE_P (br_code))
{
cc_status.mdep = CC_VALID_FOR_UNSIGNED;
return \"ucmpw %0,%1\";
}
return \"cmpw %0,%1\";
}
if (TRULY_UNSIGNED_COMPARE_P (br_code))
{
cc_status.mdep = CC_VALID_FOR_UNSIGNED;
return \"ucmpw %1,%0\";
}
return \"cmpw %1,%0\";
}")
(define_insn ""
[(set (cc0)
(match_operand:SI 0 "nonimmediate_operand" "r"))]
""
"*
{
#if 0
cc_status.flags |= CC_NO_OVERFLOW;
return \"cmpw $0,%0\";
#endif
rtx br_insn = NEXT_INSN (insn);
RTX_CODE br_code;
if (GET_CODE (br_insn) != JUMP_INSN)
abort();
br_code = GET_CODE (XEXP (XEXP (PATTERN (br_insn), 1), 0));
if (TRULY_UNSIGNED_COMPARE_P (br_code))
{
cc_status.mdep = CC_VALID_FOR_UNSIGNED;
return \"ucmpw $0,%0\";
}
return \"mtstw %0,%0\";
}")
(define_expand "cmphi"
[(set (cc0)
(compare (match_operand:HI 0 "nonimmediate_operand" "")
(match_operand:HI 1 "general_operand" "")))]
""
"
{
extern rtx test_op0, test_op1; extern enum machine_mode test_mode;
test_op0 = copy_rtx (operands[0]);
test_op1 = copy_rtx (operands[1]);
test_mode = HImode;
DONE;
}")
(define_expand "tsthi"
[(set (cc0)
(match_operand:HI 0 "nonimmediate_operand" ""))]
""
"
{
extern rtx test_op0; extern enum machine_mode test_mode;
test_op0 = copy_rtx (operands[0]);
test_mode = HImode;
DONE;
}")
(define_insn ""
[(set (cc0)
(compare (match_operand:HI 0 "memory_operand" "m")
(match_operand:HI 1 "memory_operand" "m")))]
"(!TRULY_UNSIGNED_COMPARE_P (GET_CODE (XEXP (SET_SRC (PATTERN (NEXT_INSN (insn))), 0))))
&& weird_memory_memory (operands[0], operands[1])"
"*
{
rtx br_insn = NEXT_INSN (insn);
if (GET_CODE (br_insn) != JUMP_INSN)
abort();
weird_memory_memory (operands[0], operands[1]);
if (swap_operands)
{
cc_status.flags = CC_REVERSED;
return \"cmph %0,%1\";
}
return \"cmph %1,%0\";
}")
(define_insn ""
[(set (cc0)
(compare (match_operand:HI 0 "nonimmediate_operand" "r,m")
(match_operand:HI 1 "nonimmediate_operand" "m,r")))]
"(!TRULY_UNSIGNED_COMPARE_P (GET_CODE (XEXP (SET_SRC (PATTERN (NEXT_INSN (insn))), 0))))
&& ((GET_CODE (operands[0]) == MEM) != (GET_CODE (operands[1]) == MEM))"
"*
{
rtx br_insn = NEXT_INSN (insn);
if (GET_CODE (br_insn) != JUMP_INSN)
abort();
if (which_alternative != 0)
{
cc_status.flags = CC_REVERSED;
return \"cmph %0,%1\";
}
return \"cmph %1,%0\";
}")
(define_expand "cmpqi"
[(set (cc0)
(compare (match_operand:QI 0 "nonimmediate_operand" "")
(match_operand:QI 1 "general_operand" "")))]
""
"
{
extern rtx test_op0, test_op1; extern enum machine_mode test_mode;
test_op0 = copy_rtx (operands[0]);
test_op1 = copy_rtx (operands[1]);
test_mode = QImode;
DONE;
}")
(define_expand "tstqi"
[(set (cc0)
(match_operand:QI 0 "nonimmediate_operand" ""))]
""
"
{
extern rtx test_op0; extern enum machine_mode test_mode;
test_op0 = copy_rtx (operands[0]);
test_mode = QImode;
DONE;
}")
(define_insn ""
[(set (cc0)
(compare (match_operand:QI 0 "memory_operand" "m")
(match_operand:QI 1 "memory_operand" "m")))]
"weird_memory_memory (operands[0], operands[1])"
"*
{
rtx br_insn = NEXT_INSN (insn);
RTX_CODE br_code;
if (GET_CODE (br_insn) != JUMP_INSN)
abort();
br_code = GET_CODE (XEXP (XEXP (PATTERN (br_insn), 1), 0));
weird_memory_memory (operands[0], operands[1]);
if (swap_operands)
{
cc_status.flags = CC_REVERSED;
if (TRULY_UNSIGNED_COMPARE_P (br_code))
{
cc_status.mdep = CC_VALID_FOR_UNSIGNED;
return \"ucmpb %0,%1\";
}
return \"cmpb %0,%1\";
}
if (TRULY_UNSIGNED_COMPARE_P (br_code))
{
cc_status.mdep = CC_VALID_FOR_UNSIGNED;
return \"ucmpb %1,%0\";
}
return \"cmpb %1,%0\";
}")
(define_insn ""
[(set (cc0)
(compare (match_operand:QI 0 "nonimmediate_operand" "r,m")
(match_operand:QI 1 "nonimmediate_operand" "m,r")))]
"((GET_CODE (operands[0]) == MEM) != (GET_CODE (operands[1]) == MEM))"
"*
{
rtx br_insn = NEXT_INSN (insn);
RTX_CODE br_code;
if (GET_CODE (br_insn) != JUMP_INSN)
abort();
br_code = GET_CODE (XEXP (XEXP (PATTERN (br_insn), 1), 0));
if (which_alternative != 0)
{
cc_status.flags = CC_REVERSED;
if (TRULY_UNSIGNED_COMPARE_P (br_code))
{
cc_status.mdep = CC_VALID_FOR_UNSIGNED;
return \"ucmpb %0,%1\";
}
return \"cmpb %0,%1\";
}
if (TRULY_UNSIGNED_COMPARE_P (br_code))
{
cc_status.mdep = CC_VALID_FOR_UNSIGNED;
return \"ucmpb %1,%0\";
}
return \"cmpb %1,%0\";
}")
(define_expand "bgt"
[(set (pc) (if_then_else (gt (cc0) (const_int 0))
(label_ref (match_operand 0 "" "")) (pc)))]
"" "extend_and_branch (SIGN_EXTEND);")
(define_expand "blt"
[(set (pc) (if_then_else (lt (cc0) (const_int 0))
(label_ref (match_operand 0 "" "")) (pc)))]
"" "extend_and_branch (SIGN_EXTEND);")
(define_expand "bge"
[(set (pc) (if_then_else (ge (cc0) (const_int 0))
(label_ref (match_operand 0 "" "")) (pc)))]
"" "extend_and_branch (SIGN_EXTEND);")
(define_expand "ble"
[(set (pc) (if_then_else (le (cc0) (const_int 0))
(label_ref (match_operand 0 "" "")) (pc)))]
"" "extend_and_branch (SIGN_EXTEND);")
(define_expand "beq"
[(set (pc) (if_then_else (eq (cc0) (const_int 0))
(label_ref (match_operand 0 "" "")) (pc)))]
"" "extend_and_branch (SIGN_EXTEND);")
(define_expand "bne"
[(set (pc) (if_then_else (ne (cc0) (const_int 0))
(label_ref (match_operand 0 "" "")) (pc)))]
"" "extend_and_branch (SIGN_EXTEND);")
(define_expand "bgtu"
[(set (pc) (if_then_else (gtu (cc0) (const_int 0))
(label_ref (match_operand 0 "" "")) (pc)))]
"" "extend_and_branch (ZERO_EXTEND);")
(define_expand "bltu"
[(set (pc) (if_then_else (ltu (cc0) (const_int 0))
(label_ref (match_operand 0 "" "")) (pc)))]
"" "extend_and_branch (ZERO_EXTEND);")
(define_expand "bgeu"
[(set (pc) (if_then_else (geu (cc0) (const_int 0))
(label_ref (match_operand 0 "" "")) (pc)))]
"" "extend_and_branch (ZERO_EXTEND);")
(define_expand "bleu"
[(set (pc) (if_then_else (leu (cc0) (const_int 0))
(label_ref (match_operand 0 "" "")) (pc)))]
"" "extend_and_branch (ZERO_EXTEND);")
(define_insn "cmpdf"
[(set (cc0)
(compare (match_operand:DF 0 "register_operand" "r")
(match_operand:DF 1 "register_operand" "r")))]
""
"cmpd %1,%0")
(define_insn "cmpsf"
[(set (cc0)
(compare (match_operand:SF 0 "register_operand" "r")
(match_operand:SF 1 "register_operand" "r")))]
""
"cmpf %1,%0")
(define_insn "tstdf"
[(set (cc0)
(match_operand:DF 0 "register_operand" "r"))]
""
"mtstd %0,%0")
(define_insn "tstsf"
[(set (cc0)
(match_operand:SF 0 "register_operand" "r"))]
""
"mtstf %0,%0")
;______________________________________________________________________
;
; Fixed-point Arithmetic.
;______________________________________________________________________
(define_insn "addsi3"
[(set (match_operand:SI 0 "register_operand" "=r,!r")
(plus:SI (match_operand:SI 1 "general_operand" "%0,r")
(match_operand:SI 2 "general_operand" "g,rJ")))]
""
"*
{
if (which_alternative == 0)
return (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 32
? \"subw %n2,%0\" : \"addw %2,%0\");
else
{
forget_cc_if_dependent (operands[0]);
return \"mova %a2[%1*1],%0\";
}
}")
(define_insn "subsi3"
[(set (match_operand:SI 0 "register_operand" "=r,r")
(minus:SI (match_operand:SI 1 "general_operand" "0,g")
(match_operand:SI 2 "general_operand" "g,0")))]
""
"* return (which_alternative == 0) ? \"subw %2,%0\" : \"rsubw %1,%0\";")
(define_insn "mulsi3"
[(set (match_operand:SI 0 "register_operand" "=r")
(mult:SI (match_operand:SI 1 "general_operand" "%0")
(match_operand:SI 2 "general_operand" "g")))]
""
"mulw %2,%0")
(define_insn "divsi3"
[(set (match_operand:SI 0 "register_operand" "=r,r")
(div:SI (match_operand:SI 1 "general_operand" "0,g")
(match_operand:SI 2 "general_operand" "g,0")))]
""
"* return (which_alternative == 0) ? \"divw %2,%0\" : \"rdivw %1,%0\";")
(define_insn "udivsi3"
[(set (match_operand:SI 0 "register_operand" "=r")
(udiv:SI (match_operand:SI 1 "register_operand" "0")
(match_operand:SI 2 "general_operand" "g")))]
""
"udivw %2,%0")
(define_insn "modsi3"
[(set (match_operand:SI 0 "register_operand" "=r")
(mod:SI (match_operand:SI 1 "register_operand" "0")
(match_operand:SI 2 "general_operand" "g")))]
""
"modw %2,%0")
(define_insn "umodsi3"
[(set (match_operand:SI 0 "register_operand" "=r")
(umod:SI (match_operand:SI 1 "register_operand" "0")
(match_operand:SI 2 "general_operand" "g")))]
""
"umodw %2,%0")
(define_insn "negsi2"
[(set (match_operand:SI 0 "register_operand" "=r")
(neg:SI (match_operand:SI 1 "nonimmediate_operand" "rm")))]
""
"mnegw %1,%0")
(define_insn "one_cmplsi2"
[(set (match_operand:SI 0 "register_operand" "=r")
(not:SI (match_operand:SI 1 "nonimmediate_operand" "rm")))]
""
"mcomw %1,%0")
(define_insn "abssi2"
[(set (match_operand:SI 0 "register_operand" "=r")
(abs:SI (match_operand:SI 1 "nonimmediate_operand" "rm")))]
""
"mabsw %1,%0")
;______________________________________________________________________
;
; Floating-point Arithmetic.
;______________________________________________________________________
(define_insn "adddf3"
[(set (match_operand:DF 0 "register_operand" "=r")
(plus:DF (match_operand:DF 1 "register_operand" "%0")
(match_operand:DF 2 "register_operand" "r")))]
""
"addd %2,%0")
(define_insn "addsf3"
[(set (match_operand:SF 0 "register_operand" "=r")
(plus:SF (match_operand:SF 1 "register_operand" "%0")
(match_operand:SF 2 "register_operand" "r")))]
""
"addf %2,%0")
(define_insn "subdf3"
[(set (match_operand:DF 0 "register_operand" "=r")
(minus:DF (match_operand:DF 1 "register_operand" "0")
(match_operand:DF 2 "register_operand" "r")))]
""
"subd %2,%0")
(define_insn "subsf3"
[(set (match_operand:SF 0 "register_operand" "=r")
(minus:SF (match_operand:SF 1 "register_operand" "0")
(match_operand:SF 2 "register_operand" "r")))]
""
"subf %2,%0")
(define_insn "muldf3"
[(set (match_operand:DF 0 "register_operand" "=r")
(mult:DF (match_operand:DF 1 "register_operand" "%0")
(match_operand:DF 2 "register_operand" "r")))]
""
"muld %2,%0")
(define_insn "mulsf3"
[(set (match_operand:SF 0 "register_operand" "=r")
(mult:SF (match_operand:SF 1 "register_operand" "%0")
(match_operand:SF 2 "register_operand" "r")))]
""
"mulf %2,%0")
(define_insn "divdf3"
[(set (match_operand:DF 0 "register_operand" "=r")
(div:DF (match_operand:DF 1 "register_operand" "0")
(match_operand:DF 2 "register_operand" "r")))]
""
"divd %2,%0")
(define_insn "divsf3"
[(set (match_operand:SF 0 "register_operand" "=r")
(div:SF (match_operand:SF 1 "register_operand" "0")
(match_operand:SF 2 "register_operand" "r")))]
""
"divf %2,%0")
(define_insn "negdf2"
[(set (match_operand:DF 0 "register_operand" "=r")
(neg:DF (match_operand:DF 1 "register_operand" "r")))]
""
"mnegd %1,%0")
(define_insn "negsf2"
[(set (match_operand:SF 0 "register_operand" "=r")
(neg:SF (match_operand:SF 1 "register_operand" "r")))]
""
"mnegf %1,%0")
(define_insn "absdf2"
[(set (match_operand:DF 0 "register_operand" "=r")
(abs:DF (match_operand:DF 1 "register_operand" "r")))]
""
"mabsd %1,%0")
(define_insn "abssf2"
[(set (match_operand:SF 0 "register_operand" "=r")
(abs:SF (match_operand:SF 1 "register_operand" "r")))]
""
"mabsf %1,%0")
;______________________________________________________________________
;
; Logical and Shift Instructions.
;______________________________________________________________________
(define_insn ""
[(set (cc0)
(and:SI (match_operand:SI 0 "general_operand" "%r")
(match_operand:SI 1 "general_operand" "g")))]
""
"*
{
cc_status.flags |= CC_NO_OVERFLOW;
return \"bitw %1,%0\";
}")
(define_insn "andsi3"
[(set (match_operand:SI 0 "register_operand" "=r,r")
(and:SI (match_operand:SI 1 "general_operand" "%0,r")
(match_operand:SI 2 "general_operand" "g,K")))]
""
"*
{
if (which_alternative == 0)
return \"andw %2,%0\";
cc_status.flags = CC_NOT_NEGATIVE;
return (INTVAL (operands[2]) == 255
? \"movzbw %1,%0\" : \"movzhw %1,%0\");
}")
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(and:SI (not:SI (match_operand:SI 1 "general_operand" "g"))
(match_operand:SI 2 "register_operand" "0")))]
""
"bicw %1,%0")
(define_insn "iorsi3"
[(set (match_operand:SI 0 "register_operand" "=r")
(ior:SI (match_operand:SI 1 "general_operand" "%0")
(match_operand:SI 2 "general_operand" "g")))]
""
"orw %2,%0")
(define_insn "xorsi3"
[(set (match_operand:SI 0 "register_operand" "=r")
(xor:SI (match_operand:SI 1 "general_operand" "%0")
(match_operand:SI 2 "general_operand" "g")))]
""
"xorw %2,%0")
; The arithmetic left shift instructions work strangely on pyramids.
; They fail to modify the sign bit. Therefore, use logic shifts.
(define_insn "ashlsi3"
[(set (match_operand:SI 0 "register_operand" "=r")
(ashift:SI (match_operand:SI 1 "register_operand" "0")
(match_operand:SI 2 "general_operand" "rnm")))]
""
"*
{
extern char *output_shift ();
return output_shift (\"lshlw %2,%0\", operands[2], 32);
}")
(define_insn "ashrsi3"
[(set (match_operand:SI 0 "register_operand" "=r")
(ashiftrt:SI (match_operand:SI 1 "register_operand" "0")
(match_operand:SI 2 "general_operand" "rnm")))]
""
"*
{
extern char *output_shift ();
return output_shift (\"ashrw %2,%0\", operands[2], 32);
}")
(define_insn "ashrdi3"
[(set (match_operand:DI 0 "register_operand" "=r")
(ashiftrt:DI (match_operand:DI 1 "register_operand" "0")
(match_operand:SI 2 "general_operand" "rnm")))]
""
"*
{
extern char *output_shift ();
return output_shift (\"ashrl %2,%0\", operands[2], 64);
}")
(define_insn "lshrsi3"
[(set (match_operand:SI 0 "register_operand" "=r")
(lshiftrt:SI (match_operand:SI 1 "register_operand" "0")
(match_operand:SI 2 "general_operand" "rnm")))]
""
"*
{
extern char *output_shift ();
return output_shift (\"lshrw %2,%0\", operands[2], 32);
}")
(define_insn "rotlsi3"
[(set (match_operand:SI 0 "register_operand" "=r")
(rotate:SI (match_operand:SI 1 "register_operand" "0")
(match_operand:SI 2 "general_operand" "rnm")))]
""
"*
{
extern char *output_shift ();
return output_shift (\"rotlw %2,%0\", operands[2], 32);
}")
(define_insn "rotrsi3"
[(set (match_operand:SI 0 "register_operand" "=r")
(rotatert:SI (match_operand:SI 1 "register_operand" "0")
(match_operand:SI 2 "general_operand" "rnm")))]
""
"*
{
extern char *output_shift ();
return output_shift (\"rotrw %2,%0\", operands[2], 32);
}")
;______________________________________________________________________
;
; Fixed and Floating Moves.
;______________________________________________________________________
;; If the destination is a memory operand, indexed source operands are
;; disallowed. Big DImode constants are always loaded into a reg pair,
;; although offsettable memory addresses really could be dealt with.
(define_insn ""
[(set (match_operand:DI 0 "memory_operand" "=m")
(match_operand:DI 1 "nonindexed_operand" "gF"))]
"(GET_CODE (operands[1]) == CONST_DOUBLE
? ((CONST_DOUBLE_HIGH (operands[1]) == 0
&& CONST_DOUBLE_LOW (operands[1]) >= 0)
|| (CONST_DOUBLE_HIGH (operands[1]) == -1
&& CONST_DOUBLE_LOW (operands[1]) < 0))
: 1)"
"*
{
if (GET_CODE (operands[1]) == CONST_DOUBLE)
operands[1] = GEN_INT (CONST_DOUBLE_LOW (operands[1]));
return \"movl %1,%0\";
}")
;; Force the destination to a register, so all source operands are allowed.
(define_insn "movdi"
[(set (match_operand:DI 0 "general_operand" "=r")
(match_operand:DI 1 "general_operand" "gF"))]
""
"*
{
extern char *output_move_double ();
return output_move_double (operands);
}")
;; If the destination is a memory address, indexed source operands are
;; disallowed.
(define_insn ""
[(set (match_operand:SI 0 "memory_operand" "=m")
(match_operand:SI 1 "nonindexed_operand" "g"))]
""
"movw %1,%0")
;; Force the destination to a register, so all source operands are allowed.
(define_insn "movsi"
[(set (match_operand:SI 0 "general_operand" "=r")
(match_operand:SI 1 "general_operand" "g"))]
""
"movw %1,%0")
;; If the destination is a memory address, indexed source operands are
;; disallowed.
(define_insn ""
[(set (match_operand:HI 0 "memory_operand" "=m")
(match_operand:HI 1 "nonindexed_operand" "g"))]
""
"*
{
if (REG_P (operands[1]))
return \"cvtwh %1,%0\"; /* reg -> mem */
else
return \"movh %1,%0\"; /* mem imm -> mem */
}")
;; Force the destination to a register, so all source operands are allowed.
(define_insn "movhi"
[(set (match_operand:HI 0 "general_operand" "=r")
(match_operand:HI 1 "general_operand" "g"))]
""
"*
{
if (GET_CODE (operands[1]) != MEM)
return \"movw %1,%0\"; /* reg imm -> reg */
return \"cvthw %1,%0\"; /* mem -> reg */
}")
;; If the destination is a memory address, indexed source operands are
;; disallowed.
(define_insn ""
[(set (match_operand:QI 0 "memory_operand" "=m")
(match_operand:QI 1 "nonindexed_operand" "g"))]
""
"*
{
if (REG_P (operands[1]))
return \"cvtwb %1,%0\"; /* reg -> mem */
else
return \"movb %1,%0\"; /* mem imm -> mem */
}")
;; Force the destination to a register, so all source operands are allowed.
(define_insn "movqi"
[(set (match_operand:QI 0 "general_operand" "=r")
(match_operand:QI 1 "general_operand" "g"))]
""
"*
{
if (GET_CODE (operands[1]) != MEM)
return \"movw %1,%0\"; /* reg imm -> reg */
return \"cvtbw %1,%0\"; /* mem -> reg */
}")
;; If the destination is a memory address, indexed source operands are
;; disallowed.
(define_insn ""
[(set (match_operand:DF 0 "memory_operand" "=m")
(match_operand:DF 1 "nonindexed_operand" "g"))]
"GET_CODE (operands[1]) != CONST_DOUBLE"
"movl %1,%0")
;; Force the destination to a register, so all source operands are allowed.
(define_insn "movdf"
[(set (match_operand:DF 0 "general_operand" "=r")
(match_operand:DF 1 "general_operand" "gF"))]
""
"*
{
extern char *output_move_double ();
return output_move_double (operands);
}")
;; If the destination is a memory address, indexed source operands are
;; disallowed.
(define_insn ""
[(set (match_operand:SF 0 "memory_operand" "=m")
(match_operand:SF 1 "nonindexed_operand" "g"))]
""
"movw %1,%0")
;; Force the destination to a register, so all source operands are allowed.
(define_insn "movsf"
[(set (match_operand:SF 0 "general_operand" "=r")
(match_operand:SF 1 "general_operand" "g"))]
""
"movw %1,%0")
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(match_operand:QI 1 "address_operand" "p"))]
""
"*
{
forget_cc_if_dependent (operands[0]);
return \"mova %a1,%0\";
}")
;______________________________________________________________________
;
; Conversion patterns.
;______________________________________________________________________
;; The trunc patterns are used only when non compile-time constants are used.
(define_insn "truncsiqi2"
[(set (match_operand:QI 0 "register_operand" "=r")
(truncate:QI (match_operand:SI 1 "nonimmediate_operand" "rm")))]
""
"*
{
if (REG_P (operands[0]) && REG_P (operands[1])
&& REGNO (operands[0]) == REGNO (operands[1]))
{
cc_status = cc_prev_status;
return \"\";
}
forget_cc_if_dependent (operands[0]);
return \"movw %1,%0\";
}")
(define_insn "truncsihi2"
[(set (match_operand:HI 0 "register_operand" "=r")
(truncate:HI (match_operand:SI 1 "nonimmediate_operand" "rm")))]
""
"*
{
if (REG_P (operands[0]) && REG_P (operands[1])
&& REGNO (operands[0]) == REGNO (operands[1]))
{
cc_status = cc_prev_status;
return \"\";
}
forget_cc_if_dependent (operands[0]);
return \"movw %1,%0\";
}")
(define_insn "extendhisi2"
[(set (match_operand:SI 0 "general_operand" "=r,m")
(sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "rm,r")))]
""
"*
{
if (optimize && REG_P (operands[0]) && REG_P (operands[1])
&& REGNO (operands[0]) == REGNO (operands[1])
&& already_sign_extended (insn, HImode, operands[0]))
{
cc_status = cc_prev_status;
return \"\";
}
return \"cvthw %1,%0\";
}")
(define_insn "extendqisi2"
[(set (match_operand:SI 0 "general_operand" "=r,m")
(sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "rm,r")))]
""
"*
{
if (optimize && REG_P (operands[0]) && REG_P (operands[1])
&& REGNO (operands[0]) == REGNO (operands[1])
&& already_sign_extended (insn, QImode, operands[0]))
{
cc_status = cc_prev_status;
return \"\";
}
return \"cvtbw %1,%0\";
}")
; Pyramid doesn't have insns *called* "cvtbh" or "movzbh".
; But we can cvtbw/movzbw into a register, where there is no distinction
; between words and halfwords.
(define_insn "extendqihi2"
[(set (match_operand:HI 0 "register_operand" "=r")
(sign_extend:HI (match_operand:QI 1 "nonimmediate_operand" "rm")))]
""
"cvtbw %1,%0")
(define_insn "zero_extendhisi2"
[(set (match_operand:SI 0 "register_operand" "=r")
(zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "rm")))]
""
"*
{
cc_status.flags = CC_NOT_NEGATIVE;
return \"movzhw %1,%0\";
}")
(define_insn "zero_extendqisi2"
[(set (match_operand:SI 0 "register_operand" "=r")
(zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "rm")))]
""
"*
{
cc_status.flags = CC_NOT_NEGATIVE;
return \"movzbw %1,%0\";
}")
(define_insn "zero_extendqihi2"
[(set (match_operand:HI 0 "register_operand" "=r")
(zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "rm")))]
""
"*
{
cc_status.flags = CC_NOT_NEGATIVE;
return \"movzbw %1,%0\";
}")
(define_insn "extendsfdf2"
[(set (match_operand:DF 0 "general_operand" "=&r,m")
(float_extend:DF (match_operand:SF 1 "nonimmediate_operand" "rm,r")))]
""
"cvtfd %1,%0")
(define_insn "truncdfsf2"
[(set (match_operand:SF 0 "general_operand" "=&r,m")
(float_truncate:SF (match_operand:DF 1 "nonimmediate_operand" "rm,r")))]
""
"cvtdf %1,%0")
(define_insn "floatsisf2"
[(set (match_operand:SF 0 "general_operand" "=&r,m")
(float:SF (match_operand:SI 1 "nonimmediate_operand" "rm,r")))]
""
"cvtwf %1,%0")
(define_insn "floatsidf2"
[(set (match_operand:DF 0 "general_operand" "=&r,m")
(float:DF (match_operand:SI 1 "nonimmediate_operand" "rm,r")))]
""
"cvtwd %1,%0")
(define_insn "fix_truncsfsi2"
[(set (match_operand:SI 0 "general_operand" "=&r,m")
(fix:SI (fix:SF (match_operand:SF 1 "nonimmediate_operand" "rm,r"))))]
""
"cvtfw %1,%0")
(define_insn "fix_truncdfsi2"
[(set (match_operand:SI 0 "general_operand" "=&r,m")
(fix:SI (fix:DF (match_operand:DF 1 "nonimmediate_operand" "rm,r"))))]
""
"cvtdw %1,%0")
;______________________________________________________________________
;
; Flow Control Patterns.
;______________________________________________________________________
;; Prefer "br" to "jump" for unconditional jumps, since it's faster.
;; (The assembler can manage with out-of-range branches.)
(define_insn "jump"
[(set (pc)
(label_ref (match_operand 0 "" "")))]
""
"br %l0")
(define_insn ""
[(set (pc)
(if_then_else (match_operator 0 "relop" [(cc0) (const_int 0)])
(label_ref (match_operand 1 "" ""))
(pc)))]
""
"*
{
if (optimize)
switch (GET_CODE (operands[0]))
{
case EQ: case NE:
break;
case LT: case LE: case GE: case GT:
if (cc_prev_status.mdep == CC_VALID_FOR_UNSIGNED)
return 0;
break;
case LTU: case LEU: case GEU: case GTU:
if (cc_prev_status.mdep != CC_VALID_FOR_UNSIGNED)
return 0;
break;
}
return \"b%N0 %l1\";
}")
(define_insn ""
[(set (pc)
(if_then_else (match_operator 0 "relop" [(cc0) (const_int 0)])
(pc)
(label_ref (match_operand 1 "" ""))))]
""
"*
{
if (optimize)
switch (GET_CODE (operands[0]))
{
case EQ: case NE:
break;
case LT: case LE: case GE: case GT:
if (cc_prev_status.mdep == CC_VALID_FOR_UNSIGNED)
return 0;
break;
case LTU: case LEU: case GEU: case GTU:
if (cc_prev_status.mdep != CC_VALID_FOR_UNSIGNED)
return 0;
break;
}
return \"b%C0 %l1\";
}")
(define_insn "call"
[(call (match_operand:QI 0 "memory_operand" "m")
(match_operand:SI 1 "immediate_operand" "n"))]
""
"call %0")
(define_insn "call_value"
[(set (match_operand 0 "" "=r")
(call (match_operand:QI 1 "memory_operand" "m")
(match_operand:SI 2 "immediate_operand" "n")))]
;; Operand 2 not really used on Pyramid architecture.
""
"call %1")
(define_insn "return"
[(return)]
""
"*
{
if (get_frame_size () + current_function_pretend_args_size
+ current_function_args_size != 0
|| current_function_calls_alloca)
{
int dealloc_size = current_function_pretend_args_size;
if (current_function_pops_args)
dealloc_size += current_function_args_size;
operands[0] = GEN_INT (dealloc_size);
return \"retd %0\";
}
else
return \"ret\";
}")
(define_insn "tablejump"
[(set (pc) (match_operand:SI 0 "register_operand" "r"))
(use (label_ref (match_operand 1 "" "")))]
""
"jump (%0)")
(define_insn "nop"
[(const_int 0)]
""
"movw gr0,gr0 # nop")
;______________________________________________________________________
;
; Peep-hole Optimization Patterns.
;______________________________________________________________________
;; Optimize fullword move followed by a test of the moved value.
(define_peephole
[(set (match_operand:SI 0 "register_operand" "=r")
(match_operand:SI 1 "nonimmediate_operand" "rm"))
(set (cc0) (match_operand:SI 2 "nonimmediate_operand" "rm"))]
"rtx_equal_p (operands[2], operands[0])
|| rtx_equal_p (operands[2], operands[1])"
"*
cc_status.flags |= CC_NO_OVERFLOW;
return \"mtstw %1,%0\";
")
;; Optimize loops with an incremented/decremented variable.
(define_peephole
[(set (match_operand:SI 0 "register_operand" "=r")
(plus:SI (match_dup 0)
(const_int -1)))
(set (cc0)
(compare (match_operand:SI 1 "register_operand" "r")
(match_operand:SI 2 "nonmemory_operand" "ri")))
(set (pc)
(if_then_else (match_operator:SI 3 "signed_comparison"
[(cc0) (const_int 0)])
(label_ref (match_operand 4 "" ""))
(pc)))]
"(GET_CODE (operands[2]) == CONST_INT
? (unsigned)INTVAL (operands[2]) + 32 >= 64
: 1) && (rtx_equal_p (operands[0], operands[1])
|| rtx_equal_p (operands[0], operands[2]))"
"*
if (rtx_equal_p (operands[0], operands[1]))
{
output_asm_insn (\"dcmpw %2,%0\", operands);
return \"b%N3 %l4\";
}
else
{
output_asm_insn (\"dcmpw %1,%0\", operands);
return \"b%R3 %l4\";
}
")
(define_peephole
[(set (match_operand:SI 0 "register_operand" "=r")
(plus:SI (match_dup 0)
(const_int 1)))
(set (cc0)
(compare (match_operand:SI 1 "register_operand" "r")
(match_operand:SI 2 "nonmemory_operand" "ri")))
(set (pc)
(if_then_else (match_operator:SI 3 "signed_comparison"
[(cc0) (const_int 0)])
(label_ref (match_operand 4 "" ""))
(pc)))]
"(GET_CODE (operands[2]) == CONST_INT
? (unsigned)INTVAL (operands[2]) + 32 >= 64
: 1) && (rtx_equal_p (operands[0], operands[1])
|| rtx_equal_p (operands[0], operands[2]))"
"*
if (rtx_equal_p (operands[0], operands[1]))
{
output_asm_insn (\"icmpw %2,%0\", operands);
return \"b%N3 %l4\";
}
else
{
output_asm_insn (\"icmpw %1,%0\", operands);
return \"b%R3 %l4\";
}
")
;; Combine two word moves with consecutive operands into one long move.
;; Also combines immediate moves, if the high-order destination operand
;; is loaded with 0 or -1 and the low-order destination operand is loaded
;; with a constant with the same sign.
(define_peephole
[(set (match_operand:SI 0 "general_operand" "=g")
(match_operand:SI 1 "general_operand" "g"))
(set (match_operand:SI 2 "general_operand" "=g")
(match_operand:SI 3 "general_operand" "g"))]
"movdi_possible (operands)"
"*
{
output_asm_insn (\"# COMBINE movw %1,%0\", operands);
output_asm_insn (\"# COMBINE movw %3,%2\", operands);
movdi_possible (operands);
if (CONSTANT_P (operands[1]))
return (swap_operands ? \"movl %3,%0\" : \"movl %1,%2\");
return (swap_operands ? \"movl %1,%0\" : \"movl %3,%2\");
}")
;; Optimize certain tests after memory stores.
(define_peephole
[(set (match_operand 0 "memory_operand" "=m")
(match_operand 1 "register_operand" "r"))
(set (match_operand:SI 2 "register_operand" "=r")
(sign_extend:SI (match_dup 1)))
(set (cc0)
(match_dup 2))]
"dead_or_set_p (insn, operands[2])"
"*
cc_status.flags |= CC_NO_OVERFLOW;
if (GET_MODE (operands[0]) == QImode)
return \"cvtwb %1,%0\";
else
return \"cvtwh %1,%0\";
")
;______________________________________________________________________
;
; DImode Patterns.
;______________________________________________________________________
(define_expand "extendsidi2"
[(set (subreg:SI (match_operand:DI 0 "register_operand" "=r") 1)
(match_operand:SI 1 "general_operand" "g"))
(set (subreg:SI (match_dup 0) 0)
(subreg:SI (match_dup 0) 1))
(set (subreg:SI (match_dup 0) 0)
(ashiftrt:SI (subreg:SI (match_dup 0) 0)
(const_int 31)))]
""
"")
(define_insn "adddi3"
[(set (match_operand:DI 0 "register_operand" "=r")
(plus:DI (match_operand:DI 1 "nonmemory_operand" "%0")
(match_operand:DI 2 "nonmemory_operand" "rF")))]
""
"*
{
rtx xoperands[2];
CC_STATUS_INIT;
xoperands[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
if (REG_P (operands[2]))
xoperands[1] = gen_rtx_REG (SImode, REGNO (operands[2]) + 1);
else
{
xoperands[1] = GEN_INT (CONST_DOUBLE_LOW (operands[2]));
operands[2] = GEN_INT (CONST_DOUBLE_HIGH (operands[2]));
}
output_asm_insn (\"addw %1,%0\", xoperands);
return \"addwc %2,%0\";
}")
(define_insn "subdi3"
[(set (match_operand:DI 0 "register_operand" "=r")
(minus:DI (match_operand:DI 1 "register_operand" "0")
(match_operand:DI 2 "nonmemory_operand" "rF")))]
""
"*
{
rtx xoperands[2];
CC_STATUS_INIT;
xoperands[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
if (REG_P (operands[2]))
xoperands[1] = gen_rtx_REG (SImode, REGNO (operands[2]) + 1);
else
{
xoperands[1] = GEN_INT (CONST_DOUBLE_LOW (operands[2]));
operands[2] = GEN_INT (CONST_DOUBLE_HIGH (operands[2]));
}
output_asm_insn (\"subw %1,%0\", xoperands);
return \"subwb %2,%0\";
}")
(define_insn "iordi3"
[(set (match_operand:DI 0 "register_operand" "=r")
(ior:DI (match_operand:DI 1 "nonmemory_operand" "%0")
(match_operand:DI 2 "nonmemory_operand" "rF")))]
""
"*
{
rtx xoperands[2];
CC_STATUS_INIT;
xoperands[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
if (REG_P (operands[2]))
xoperands[1] = gen_rtx_REG (SImode, REGNO (operands[2]) + 1);
else
{
xoperands[1] = GEN_INT (CONST_DOUBLE_LOW (operands[2]));
operands[2] = GEN_INT (CONST_DOUBLE_HIGH (operands[2]));
}
output_asm_insn (\"orw %1,%0\", xoperands);
return \"orw %2,%0\";
}")
(define_insn "anddi3"
[(set (match_operand:DI 0 "register_operand" "=r")
(and:DI (match_operand:DI 1 "nonmemory_operand" "%0")
(match_operand:DI 2 "nonmemory_operand" "rF")))]
""
"*
{
rtx xoperands[2];
CC_STATUS_INIT;
xoperands[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
if (REG_P (operands[2]))
xoperands[1] = gen_rtx_REG (SImode, REGNO (operands[2]) + 1);
else
{
xoperands[1] = GEN_INT (CONST_DOUBLE_LOW (operands[2]));
operands[2] = GEN_INT (CONST_DOUBLE_HIGH (operands[2]));
}
output_asm_insn (\"andw %1,%0\", xoperands);
return \"andw %2,%0\";
}")
(define_insn "xordi3"
[(set (match_operand:DI 0 "register_operand" "=r")
(xor:DI (match_operand:DI 1 "nonmemory_operand" "%0")
(match_operand:DI 2 "nonmemory_operand" "rF")))]
""
"*
{
rtx xoperands[2];
CC_STATUS_INIT;
xoperands[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
if (REG_P (operands[2]))
xoperands[1] = gen_rtx_REG (SImode, REGNO (operands[2]) + 1);
else
{
xoperands[1] = GEN_INT (CONST_DOUBLE_LOW (operands[2]));
operands[2] = GEN_INT (CONST_DOUBLE_HIGH (operands[2]));
}
output_asm_insn (\"xorw %1,%0\", xoperands);
return \"xorw %2,%0\";
}")
;; My version, modelled after Jonathan Stone's and "tablejump" - S.P.
(define_insn "indirect_jump"
[(set (pc) (match_operand:SI 0 "general_operand" "r"))]
""
"jump (%0)")
CLIB=-lc /usr/.attlib/libPW.a
/* Configuration for GNU compiler, for Pyramid 90x, 9000, and MIServer Series.
Copyright (C) 1989, 1993 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, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* #defines that need visibility everywhere. */
#define FALSE 0
#define TRUE 1
/* target machine dependencies.
tm.h is a symbolic link to the actual target specific file. */
#include "tm.h"
/* This describes the machine the compiler is hosted on. */
#define HOST_BITS_PER_CHAR 8
#define HOST_BITS_PER_SHORT 16
#define HOST_BITS_PER_INT 32
#define HOST_BITS_PER_LONG 32
#define HOST_BITS_PER_LONGLONG 64
#define HOST_WORDS_BIG_ENDIAN
/* Arguments to use with `exit'. */
#define SUCCESS_EXIT_CODE 0
#define FATAL_EXIT_CODE 33
/* Subroutines for insn-output.c for SPUR. Adapted from routines for
the Motorola 68000 family.
Copyright (C) 1988, 1991, 1997, 1998, 1999 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, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include "config.h"
#include "system.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 "function.h"
#include "insn-attr.h"
static rtx find_addr_reg ();
char *
output_compare (operands, opcode, exchange_opcode,
neg_opcode, neg_exchange_opcode)
rtx *operands;
char *opcode;
char *exchange_opcode;
char *neg_opcode;
char *neg_exchange_opcode;
{
static char buf[100];
operands[2] = operands[0];
if (GET_CODE (cc_prev_status.value1) == CONST_INT)
{
operands[1] = cc_prev_status.value1;
operands[0] = cc_prev_status.value2;
opcode = exchange_opcode, neg_opcode = neg_exchange_opcode;
}
else
{
operands[0] = cc_prev_status.value1;
operands[1] = cc_prev_status.value2;
}
if (TARGET_LONG_JUMPS)
sprintf (buf,
"cmp_br_delayed %s,%%0,%%1,1f\n\tnop\n\tjump %%l2\n\tnop\n1:",
neg_opcode);
else
sprintf (buf, "cmp_br_delayed %s,%%0,%%1,%%l2\n\tnop", opcode);
return buf;
}
/* Return the best assembler insn template
for moving operands[1] into operands[0] as a fullword. */
static char *
singlemove_string (operands)
rtx *operands;
{
if (GET_CODE (operands[0]) == MEM)
return "st_32 %r1,%0";
if (GET_CODE (operands[1]) == MEM)
return "ld_32 %0,%1\n\tnop";
if (GET_CODE (operands[1]) == REG)
return "add_nt %0,%1,$0";
return "add_nt %0,r0,%1";
}
/* 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 (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 (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 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)
{
latehalf[1] = GEN_INT (CONST_DOUBLE_HIGH (operands[1]));
operands[1] = GEN_INT (CONST_DOUBLE_LOW (operands[1]));
}
else if (CONSTANT_P (operands[1]))
latehalf[1] = const0_rtx;
}
else
latehalf[1] = operands[1];
/* If 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 == REGOP && optype1 == REGOP
&& REGNO (operands[0]) == REGNO (latehalf[1]))
{
/* Make any unoffsettable addresses point at high-numbered word. */
if (addreg0)
output_asm_insn ("add_nt %0,%0,$4", &addreg0);
if (addreg1)
output_asm_insn ("add_nt %0,%0,$4", &addreg1);
/* Do that word. */
output_asm_insn (singlemove_string (latehalf), latehalf);
/* Undo the adds we just did. */
if (addreg0)
output_asm_insn ("add_nt %0,%0,$-4", &addreg0);
if (addreg1)
output_asm_insn ("add_nt %0,%0,$-4", &addreg0);
/* 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 ("add_nt %0,%0,$4", &addreg0);
if (addreg1)
output_asm_insn ("add_nt %0,%0,$4", &addreg1);
/* Do that word. */
output_asm_insn (singlemove_string (latehalf), latehalf);
/* Undo the adds we just did. */
if (addreg0)
output_asm_insn ("add_nt %0,%0,$-4", &addreg0);
if (addreg1)
output_asm_insn ("add_nt %0,%0,$-4", &addreg1);
return "";
}
static char *
output_fp_move_double (operands)
rtx *operands;
{
if (FP_REG_P (operands[0]))
{
if (FP_REG_P (operands[1]))
return "fmov %0,%1";
if (GET_CODE (operands[1]) == REG)
{
rtx xoperands[2];
int offset = - get_frame_size () - 8;
xoperands[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1);
xoperands[0] = GEN_INT (offset + 4);
output_asm_insn ("st_32 %1,r25,%0", xoperands);
xoperands[1] = operands[1];
xoperands[0] = GEN_INT (offset);
output_asm_insn ("st_32 %1,r25,%0", xoperands);
xoperands[1] = operands[0];
output_asm_insn ("ld_dbl %1,r25,%0\n\tnop", xoperands);
return "";
}
return "ld_dbl %0,%1\n\tnop";
}
else if (FP_REG_P (operands[1]))
{
if (GET_CODE (operands[0]) == REG)
{
rtx xoperands[2];
int offset = - get_frame_size () - 8;
xoperands[0] = GEN_INT (offset);
xoperands[1] = operands[1];
output_asm_insn ("st_dbl %1,r25,%0", xoperands);
xoperands[1] = operands[0];
output_asm_insn ("ld_32 %1,r25,%0\n\tnop", xoperands);
xoperands[1] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
xoperands[0] = GEN_INT (offset + 4);
output_asm_insn ("ld_32 %1,r25,%0\n\tnop", xoperands);
return "";
}
return "st_dbl %1,%0";
}
}
/* 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 ();
}
/* Generate code to add a large integer constant to register, reg, storing
* the result in a register, target. Offset must be 27-bit signed quantity */
static char *
output_add_large_offset (target, reg, offset)
rtx target, reg;
int offset;
{
rtx operands[3];
int high, n, i;
operands[0] = target, operands[1] = reg;
for (high = offset, n = 0;
(unsigned) (high + 0x2000) >= 0x4000;
high >>= 1, n += 1)
;
operands[2] = GEN_INT (high);
output_asm_insn ("add_nt r2,r0,%2", operands);
i = n;
while (i >= 3)
output_asm_insn ("sll r2,r2,$3", operands), i -= 3;
if (i == 2)
output_asm_insn ("sll r2,r2,$2", operands);
else if (i == 1)
output_asm_insn ("sll r2,r2,$1", operands);
output_asm_insn ("add_nt %0,r2,%1", operands);
if (offset - (high << n) != 0)
{
operands[2] = GEN_INT (offset - (high << n));
output_asm_insn ("add_nt %0,%0,%2", operands);
}
return "";
}
/* Additional TESTFN for matching. Like immediate_operand, but matches big
* constants */
int
big_immediate_operand (op, mode)
rtx op;
enum machine_mode mode;
{
return (GET_CODE (op) == CONST_INT);
}
/* ??? None of the original definitions ever worked for stdarg.h, and
the port never updated for gcc2. Quoting bits of the old va-spur.h
for historical interest. */
tree
spur_build_va_list ()
{
typedef struct {
int __pnt;
char *__regs;
char *__stack;
} va_list;
}
void
spur_va_start (stdarg_p, valist, nextarg)
int stdarg_p;
tree valist;
rtx nextarg ATTRIBUTE_UNUSED;
{
struct __va_struct { char __regs[20]; };
#define va_alist __va_regs, __va_stack
#define va_dcl struct __va_struct __va_regs; int __va_stack;
#define va_start(pvar) \
((pvar).__pnt = 0, (pvar).__regs = __va_regs.__regs, \
(pvar).__stack = (char *) &__va_stack)
}
rtx
spur_va_arg (valist, type)
tree valist, type;
{
#define va_arg(pvar,type) \
__extension__ \
(*({ type *__va_result; \
if ((pvar).__pnt >= 20) { \
__va_result = ( (type *) ((pvar).__stack + (pvar).__pnt - 20)); \
(pvar).__pnt += (sizeof(type) + 7) & ~7; \
} \
else if ((pvar).__pnt + sizeof(type) > 20) { \
__va_result = (type *) (pvar).__stack; \
(pvar).__pnt = 20 + ( (sizeof(type) + 7) & ~7); \
} \
else if (sizeof(type) == 8) { \
union {double d; int i[2];} __u; \
__u.i[0] = *(int *) ((pvar).__regs + (pvar).__pnt); \
__u.i[1] = *(int *) ((pvar).__regs + (pvar).__pnt + 4); \
__va_result = (type *) &__u; \
(pvar).__pnt += 8; \
} \
else { \
__va_result = (type *) ((pvar).__regs + (pvar).__pnt); \
(pvar).__pnt += (sizeof(type) + 3) & ~3; \
} \
__va_result; }))
}
/* Definitions of target machine for GNU compiler, for SPUR chip.
Copyright (C) 1988, 1995, 1996, 1998, 1999, 2000 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, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* Note that some other tm.h files include this one and then override
many of the definitions that relate to assembler syntax. */
/* Names to predefine in the preprocessor for this target machine. */
#define CPP_PREDEFINES "-Dspur -Acpu(spur) -Amachine(spur)"
/* Link with libg.a when debugging, for dbx's sake. */
#define LIB_SPEC "%{g:-lg} %{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p} "
/* Print subsidiary information on the compiler version in use. */
#define TARGET_VERSION fprintf (stderr, " (spur)");
/* Run-time compilation parameters selecting different hardware subsets.
On the SPUR, we don't yet need any. */
extern int target_flags;
/* Nonzero if we should generate code to use the fpu. */
#define TARGET_FPU (target_flags & 1)
/* Nonzero if we should expand constant shifts into series of shift
instructions. */
#define TARGET_EXPAND_SHIFTS (target_flags & 2)
/* Nonzero if we should generate long jumps for compares. */
#define TARGET_LONG_JUMPS (target_flags & 4)
/* Macro to define tables used to set the flags.
This is a list in braces of pairs in braces,
each pair being { "NAME", VALUE }
where VALUE is the bits to set or minus the bits to clear.
An empty string NAME is used to identify the default VALUE. */
#define TARGET_SWITCHES \
{ {"fpu", 1}, \
{"soft-float", -1}, \
{"expand-shifts", 2}, \
{"lib-shifts", -2}, \
{"long-jumps", 4}, \
{"short-jumps", -4}, \
{ "", TARGET_DEFAULT}}
#define TARGET_DEFAULT 0
/* target machine storage layout */
/* Define this if most significant bit is lowest numbered
in instructions that operate on numbered bit-fields.
This is a moot question on the SPUR due to the lack of bit-field insns. */
#define BITS_BIG_ENDIAN 0
/* Define this if most significant byte of a word is the lowest numbered. */
/* That is not true on SPUR. */
#define BYTES_BIG_ENDIAN 0
/* Define this if most significant word of a multiword number is the lowest
numbered. */
/* For SPUR we can decide arbitrarily
since there are no machine instructions for them. */
#define WORDS_BIG_ENDIAN 0
/* number of bits in an addressable storage unit */
#define BITS_PER_UNIT 8
/* Width in bits of a "word", which is the contents of a machine register.
Note that this is not necessarily the width of data type `int';
if using 16-bit ints on a 68000, this would still be 32.
But on a machine with 16-bit registers, this would be 16. */
#define BITS_PER_WORD 32
/* Width of a word, in units (bytes). */
#define UNITS_PER_WORD 4
/* Width in bits of a pointer.
See also the macro `Pmode' defined below. */
#define POINTER_SIZE 32
/* Allocation boundary (in *bits*) for storing arguments in argument list. */
#define PARM_BOUNDARY 64
/* Boundary (in *bits*) on which stack pointer should be aligned. */
#define STACK_BOUNDARY 64
/* Allocation boundary (in *bits*) for the code of a function. */
#define FUNCTION_BOUNDARY 32
/* Alignment of field after `int : 0' in a structure. */
#define EMPTY_FIELD_BOUNDARY 32
/* Every structure's size must be a multiple of this. */
#define STRUCTURE_SIZE_BOUNDARY 32
/* No data type wants to be aligned rounder than this. */
#define BIGGEST_ALIGNMENT 64
/* Set this nonzero if move instructions will actually fail to work
when given unaligned data. */
#define STRICT_ALIGNMENT 1
/* Standard register usage. */
/* Number of actual hardware registers.
The hardware registers are assigned numbers for the compiler
from 0 to just below FIRST_PSEUDO_REGISTER.
All registers that the compiler knows about must be given numbers,
even those that are not normally considered general registers.
SPUR has 32 fullword registers and 15 floating point registers. */
#define FIRST_PSEUDO_REGISTER 47
/* 1 for registers that have pervasive standard uses
and are not available for the register allocator.
On SPUR, this includes all the global registers
and the callee return address register. */
#define FIXED_REGISTERS \
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
1, 0, 0, 0, 0, 0, \
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, \
1, 0, 0, 0, 0, 0, \
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
/* 1 for registers not available across function calls.
These must include the FIXED_REGISTERS and also any
registers that can be used without being saved.
The latter must include the registers where values are returned
and the register where structure-value addresses are passed.
Aside from that, you can include as many other registers as you like. */
#define CALL_USED_REGISTERS \
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
1, 0, 0, 0, 0, 0, \
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, \
1, 1, 1, 1, 1, 1, \
1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0}
/* Return number of consecutive hard regs needed starting at reg REGNO
to hold something of mode MODE.
This is ordinarily the length in words of a value of mode MODE
but can be less for certain modes in special long registers.
On SPUR, ordinary registers hold 32 bits worth;
a single floating point register is always enough for
anything that can be stored in them at all. */
#define HARD_REGNO_NREGS(REGNO, MODE) \
((REGNO) >= 32 ? GET_MODE_NUNITS ((MODE)) \
: ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD))
/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE.
On SPUR, the cpu registers can hold any mode but the float registers
can hold only floating point. And they can't hold anything if use
of hardware floating point is disabled. */
#define HARD_REGNO_MODE_OK(REGNO, MODE) \
(((REGNO) < 32 \
&& (REGNO) + ((GET_MODE_UNIT_SIZE ((MODE)) + 3) / 4) <= 32) \
|| (TARGET_FPU && ((MODE) == SFmode || (MODE) == DFmode \
|| (MODE) == SCmode || (MODE) == DCmode)))
/* Value is 1 if it is a good idea to tie two pseudo registers
when one has mode MODE1 and one has mode MODE2.
If HARD_REGNO_MODE_OK could produce different values for MODE1 and MODE2,
for any hard reg, then this must be 0 for correct output. */
#define MODES_TIEABLE_P(MODE1, MODE2) \
(((MODE1) == SFmode || (MODE1) == DFmode \
|| (MODE1) == SCmode || (MODE1) == DCmode) \
== ((MODE2) == SFmode || (MODE2) == DFmode \
|| (MODE2) == SCmode || (MODE2) == DCmode))
/* Specify the registers used for certain standard purposes.
The values of these macros are register numbers. */
/* SPUR pc isn't overloaded on a register that the compiler knows about. */
/* #define PC_REGNUM */
/* Register to use for pushing function arguments. */
#define STACK_POINTER_REGNUM 4
/* Base register for access to local variables of the function. */
#define FRAME_POINTER_REGNUM 25
/* Value should be nonzero if functions must have frame pointers.
Zero means the frame pointer need not be set up (and parms
may be accessed via the stack pointer) in functions that seem suitable.
This is computed in `reload', in reload1.c. */
#define FRAME_POINTER_REQUIRED 1
/* Base register for access to arguments of the function. */
#define ARG_POINTER_REGNUM 25
/* Register in which static-chain is passed to a function. */
/* ??? */
#define STATIC_CHAIN_REGNUM 8
/* Register in which address to store a structure value
is passed to a function. */
#define STRUCT_VALUE_REGNUM 27
#define STRUCT_VALUE_INCOMING_REGNUM 11
/* Define the classes of registers for register constraints in the
machine description. Also define ranges of constants.
One of the classes must always be named ALL_REGS and include all hard regs.
If there is more than one class, another class must be named NO_REGS
and contain no registers.
The name GENERAL_REGS must be the name of a class (or an alias for
another name such as ALL_REGS). This is the class of registers
that is allowed by "g" or "r" in a register constraint.
Also, registers outside this class are allocated only when
instructions express preferences for them.
The classes must be numbered in nondecreasing order; that is,
a larger-numbered class must never be contained completely
in a smaller-numbered class.
For any two classes, it is very desirable that there be another
class that represents their union. */
/* The 68000 has two kinds of registers, hence four classes. */
enum reg_class { NO_REGS, GENERAL_REGS, FP_REGS, ALL_REGS, LIM_REG_CLASSES };
#define N_REG_CLASSES (int) LIM_REG_CLASSES
/* Give names of register classes as strings for dump file. */
#define REG_CLASS_NAMES \
{"NO_REGS", "GENERAL_REGS", "FP_REGS", "ALL_REGS" }
/* Define which registers fit in which classes.
This is an initializer for a vector of HARD_REG_SET
of length N_REG_CLASSES. */
#define REG_CLASS_CONTENTS {{0, 0}, {-1, 0}, {0, 0x7fff}, {-1, 0x7fff}}
/* The same information, inverted:
Return the class number of the smallest class containing
reg number REGNO. This could be a conditional expression
or could index an array. */
#define REGNO_REG_CLASS(REGNO) \
((REGNO) >= 32 ? FP_REGS : GENERAL_REGS)
/* The class value for index registers, and the one for base regs. */
#define INDEX_REG_CLASS GENERAL_REGS
#define BASE_REG_CLASS GENERAL_REGS
/* Get reg_class from a letter such as appears in the machine description. */
#define REG_CLASS_FROM_LETTER(C) \
((C) == 'f' ? FP_REGS : NO_REGS)
/* The letters I, J, K, L and M in a register constraint string
can be used to stand for particular ranges of immediate operands.
This macro defines what the ranges are.
C is the letter, and VALUE is a constant value.
Return 1 if VALUE is in the range specified by C.
For SPUR, `I' is used for the range of constants an insn
can actually contain.
`J' is used for the range which is just zero (since that is R0).
`K' is used for the 5-bit operand of a compare insns. */
#define CONST_OK_FOR_LETTER_P(VALUE, C) \
((C) == 'I' ? (unsigned) ((VALUE) + 0x2000) < 0x4000 \
: (C) == 'J' ? (VALUE) == 0 \
: (C) == 'K' ? (unsigned) (VALUE) < 0x20 \
: 0)
/* Similar, but for floating constants, and defining letters G and H.
Here VALUE is the CONST_DOUBLE rtx itself. */
#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) \
((C) == 'G' && CONST_DOUBLE_HIGH (VALUE) == 0 \
&& CONST_DOUBLE_LOW (VALUE) == 0)
/* Given an rtx X being reloaded into a reg required to be
in class CLASS, return the class of reg to actually use.
In general this is just CLASS; but on some machines
in some cases it is preferable to use a more restrictive class. */
#define PREFERRED_RELOAD_CLASS(X,CLASS) (CLASS)
/* Return the maximum number of consecutive registers
needed to represent mode MODE in a register of class CLASS. */
/* On SPUR, this is the size of MODE in words,
except in the FP regs, where a single reg is always enough. */
#define CLASS_MAX_NREGS(CLASS, MODE) \
((CLASS) == FP_REGS ? 1 \
: ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD))
/* Stack layout; function entry, exit and calling. */
/* Define this if pushing a word on the stack
makes the stack pointer a smaller address. */
#define STACK_GROWS_DOWNWARD
/* Define this if the nominal address of the stack frame
is at the high-address end of the local variables;
that is, each additional local variable allocated
goes at a more negative offset in the frame. */
#define FRAME_GROWS_DOWNWARD
/* Offset within stack frame to start allocating local variables at.
If FRAME_GROWS_DOWNWARD, this is the offset to the END of the
first local allocated. Otherwise, it is the offset to the BEGINNING
of the first local allocated. */
#define STARTING_FRAME_OFFSET 0
/* If we generate an insn to push BYTES bytes,
this says how many the stack pointer really advances by.
On SPUR, don't define this because there are no push insns. */
/* #define PUSH_ROUNDING(BYTES) */
/* Offset of first parameter from the argument pointer register value. */
#define FIRST_PARM_OFFSET(FNDECL) 0
/* Value is the number of bytes of arguments automatically
popped when returning from a subroutine call.
FUNDECL is the declaration node of the function (as a tree),
FUNTYPE is the data type of the function (as a tree),
or for a library call it is an identifier node for the subroutine name.
SIZE is the number of bytes of arguments passed on the stack. */
#define RETURN_POPS_ARGS(FUNDECL,FUNTYPE,SIZE) 0
/* Define how to find the value returned by a function.
VALTYPE is the data type of the value (as a tree).
If the precise function being called is known, FUNC is its FUNCTION_DECL;
otherwise, FUNC is 0. */
/* On SPUR the value is found in the second "output" register. */
#define FUNCTION_VALUE(VALTYPE, FUNC) \
gen_rtx_REG (TYPE_MODE (VALTYPE), 27)
/* But the called function leaves it in the second "input" register. */
#define FUNCTION_OUTGOING_VALUE(VALTYPE, FUNC) \
gen_rtx_REG (TYPE_MODE (VALTYPE), 11)
/* Define how to find the value returned by a library function
assuming the value has mode MODE. */
#define LIBCALL_VALUE(MODE) gen_rtx_REG (MODE, 27)
/* 1 if N is a possible register number for a function value
as seen by the caller.
On SPUR, the first "output" reg is the only register thus used. */
#define FUNCTION_VALUE_REGNO_P(N) ((N) == 27)
/* 1 if N is a possible register number for function argument passing.
On SPUR, these are the "output" registers. */
#define FUNCTION_ARG_REGNO_P(N) ((N) < 32 && (N) > 26)
/* Define this macro if the target machine has "register windows". This
C expression returns the register number as seen by the called function
corresponding to register number OUT as seen by the calling function.
Return OUT if register number OUT is not an outbound register. */
#define INCOMING_REGNO(OUT) \
(((OUT) < 27 || (OUT) > 31) ? (OUT) : (OUT) - 16)
/* Define this macro if the target machine has "register windows". This
C expression returns the register number as seen by the calling function
corresponding to register number IN as seen by the called function.
Return IN if register number IN is not an inbound register. */
#define OUTGOING_REGNO(IN) \
(((IN) < 11 || (IN) > 15) ? (IN) : (IN) + 16)
/* Define a data type for recording info about an argument list
during the scan of that argument list. This data type should
hold all necessary information about the function itself
and about the args processed so far, enough to enable macros
such as FUNCTION_ARG to determine where the next arg should go.
On SPUR, this is a single integer, which is a number of words
of arguments scanned so far (including the invisible argument,
if any, which holds the structure-value-address).
Thus 5 or more means all following args should go on the stack. */
#define CUMULATIVE_ARGS int
/* Initialize a variable CUM of type CUMULATIVE_ARGS
for a call to a function whose data type is FNTYPE.
For a library call, FNTYPE is 0.
On SPUR, the offset normally starts at 0, but starts at 4 bytes
when the function gets a structure-value-address as an
invisible first argument. */
#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE,LIBNAME,INDIRECT) \
((CUM) = ((FNTYPE) != 0 && aggregate_value_p (TREE_TYPE ((FNTYPE)))))
/* Update the data in CUM to advance over an argument
of mode MODE and data type TYPE.
(TYPE is null for libcalls where that information may not be available.) */
#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \
((CUM) += ((MODE) != BLKmode \
? (GET_MODE_SIZE (MODE) + 3) / 4 \
: (int_size_in_bytes (TYPE) + 3) / 4))
/* Determine where to put an argument to a function.
Value is zero to push the argument on the stack,
or a hard register in which to store the argument.
MODE is the argument's machine mode.
TYPE is the data type of the argument (as a tree).
This is null for libcalls where that information may
not be available.
CUM is a variable of type CUMULATIVE_ARGS which gives info about
the preceding args and about the function being called.
NAMED is nonzero if this argument is a named parameter
(otherwise it is an extra parameter matching an ellipsis). */
/* On SPUR the first five words of args are normally in registers
and the rest are pushed. But any arg that won't entirely fit in regs
is pushed. */
#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \
(5 >= ((CUM) \
+ ((MODE) == BLKmode \
? (int_size_in_bytes (TYPE) + 3) / 4 \
: (GET_MODE_SIZE (MODE) + 3) / 4)) \
? gen_rtx_REG ((MODE), 27 + (CUM)) \
: 0)
/* Define where a function finds its arguments.
This is different from FUNCTION_ARG because of register windows. */
#define FUNCTION_INCOMING_ARG(CUM, MODE, TYPE, NAMED) \
(5 >= ((CUM) \
+ ((MODE) == BLKmode \
? (int_size_in_bytes (TYPE) + 3) / 4 \
: (GET_MODE_SIZE (MODE) + 3) / 4)) \
? gen_rtx_REG ((MODE), 11 + (CUM)) \
: 0)
/* For an arg passed partly in registers and partly in memory,
this is the number of registers used.
For args passed entirely in registers or entirely in memory, zero. */
#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) 0
/* This macro generates the assembly code for function entry.
FILE is a stdio stream to output the code to.
SIZE is an int: how many units of temporary storage to allocate.
Refer to the array `regs_ever_live' to determine which registers
to save; `regs_ever_live[I]' is nonzero if register number I
is ever used in the function. This macro is responsible for
knowing which registers should not be saved even if used. */
/* On spur, move-double insns between fpu and cpu need an 8-byte block
of memory. If any fpu reg is used in the function, we allocate
such a block here, at the bottom of the frame, just in case it's needed. */
#define FUNCTION_PROLOGUE(FILE, SIZE) \
{ \
extern char call_used_regs[]; \
int fsize = ((SIZE) + 7) & ~7; \
int nregs, i, fp_used = 0; \
for (i = 32, nregs = 0; i < FIRST_PSEUDO_REGISTER; i++) \
{ \
if (regs_ever_live[i] && ! call_used_regs[i]) \
nregs++; \
if (regs_ever_live[i]) fp_used = 1; \
} \
if (fp_used) fsize += 8; \
fprintf (FILE, "0:\trd_special r24,pc\n"); \
fprintf (FILE, "\tand r24,r24,$~0x3\n"); \
fprintf (FILE, "\tadd_nt r25,r4,$%d\n", \
- current_function_pretend_args_size); \
if (fsize + nregs != 0 || current_function_pretend_args_size > 0)\
{ \
int n = - fsize - nregs * 16; \
if (n >= -8192) \
fprintf (FILE, "\tadd_nt r4,r25,$%d\n", n); \
else \
{ \
fprintf (FILE, "\tadd_nt r4,r25,$-8192\n"); \
n += 8192; \
while (n < -8192) \
fprintf (FILE, "\tadd_nt r4,r4,$-8192\n"), n += 8192; \
if (n != 0) \
fprintf (FILE, "\tadd_nt r4,r4,$%d\n", n); \
} \
} \
for (i = 32, nregs = 0; i < FIRST_PSEUDO_REGISTER; i++) \
if (regs_ever_live[i] && ! call_used_regs[i]) \
{ \
fprintf (FILE, "\tst_ext1 %s,r4,$%d\n", \
reg_names[i], 8 * nregs++); \
fprintf (FILE, "\tst_ext2 %s,r4,$%d\n", \
reg_names[i], 8 * nregs++); \
} \
}
/* Output assembler code to FILE to increment profiler label # LABELNO
for profiling a function entry. */
#define FUNCTION_PROFILER(FILE, LABELNO) \
abort ();
/* EXIT_IGNORE_STACK should be nonzero if, when returning from a function,
the stack pointer does not matter. The value is tested only in
functions that have frame pointers.
No definition is equivalent to always zero. */
#define EXIT_IGNORE_STACK \
(get_frame_size () != 0 \
|| current_function_calls_alloca || current_function_pretend_args_size)
/* This macro generates the assembly code for function exit,
on machines that need it. If FUNCTION_EPILOGUE is not defined
then individual return instructions are generated for each
return statement. Args are same as for FUNCTION_PROLOGUE.
The function epilogue should not depend on the current stack pointer!
It should use the frame pointer only. This is mandatory because
of alloca; we also take advantage of it to omit stack adjustments
before returning. */
#define FUNCTION_EPILOGUE(FILE, SIZE) \
{ \
extern char call_used_regs[]; \
int fsize = ((SIZE) + 7) & ~7; \
int nregs, i, fp_used = 0; \
for (i = 32, nregs = 0; i < FIRST_PSEUDO_REGISTER; i++) \
{ \
if (regs_ever_live[i] && ! call_used_regs[i]) \
nregs++; \
if (regs_ever_live[i]) fp_used = 1; \
} \
if (fp_used) fsize += 8; \
if (nregs != 0) \
{ \
fprintf (FILE, "\tadd_nt r4,r25,$%d\n", - fsize - nregs * 16); \
for (i = 32, nregs = 0; i < FIRST_PSEUDO_REGISTER; i++) \
if (regs_ever_live[i] && ! call_used_regs[i]) \
{ \
fprintf (FILE, "\tld_ext1 %s,r4,$%d\n\tnop\n", \
reg_names[i], 8 * nregs++); \
fprintf (FILE, "\tld_ext2 %s,r4,$%d\n\tnop\n", \
reg_names[i], 8 * nregs++); \
} \
} \
if (fsize != 0 || nregs != 0 || current_function_calls_alloca \
|| current_function_pretend_args_size > 0) \
fprintf (FILE, "\tadd_nt r4,r25,$%d\n", \
current_function_pretend_args_size); \
fprintf (FILE, "\treturn r10,$8\n\tnop\n"); \
}
/* Addressing modes, and classification of registers for them. */
/* #define HAVE_POST_INCREMENT 0 */
/* #define HAVE_POST_DECREMENT 0 */
/* #define HAVE_PRE_DECREMENT 0 */
/* #define HAVE_PRE_INCREMENT 0 */
/* Macros to check register numbers against specific register classes. */
/* These assume that REGNO is a hard or pseudo reg number.
They give nonzero only if REGNO is a hard reg of the suitable class
or a pseudo reg currently allocated to a suitable hard reg.
Since they use reg_renumber, they are safe only once reg_renumber
has been allocated, which happens in local-alloc.c. */
#define REGNO_OK_FOR_INDEX_P(REGNO) \
((REGNO) < 32 || (unsigned) reg_renumber[REGNO] < 32)
#define REGNO_OK_FOR_BASE_P(REGNO) \
((REGNO) < 32 || (unsigned) reg_renumber[REGNO] < 32)
#define REGNO_OK_FOR_FP_P(REGNO) \
(((REGNO) ^ 0x20) < 14 || (unsigned) (reg_renumber[REGNO] ^ 0x20) < 14)
/* Now macros that check whether X is a register and also,
strictly, whether it is in a specified class.
These macros are specific to the SPUR, and may be used only
in code for printing assembler insns and in conditions for
define_optimization. */
/* 1 if X is an fp register. */
#define FP_REG_P(X) (REG_P (X) && REGNO_OK_FOR_FP_P (REGNO (X)))
/* Maximum number of registers that can appear in a valid memory address. */
#define MAX_REGS_PER_ADDRESS 2
/* Recognize any constant value that is a valid address. */
#define CONSTANT_ADDRESS_P(X) \
(GET_CODE (X) == LABEL_REF || GET_CODE (X) == SYMBOL_REF \
|| GET_CODE (X) == CONST_INT || GET_CODE (X) == CONST \
|| GET_CODE (X) == HIGH)
/* Nonzero if the constant value X is a legitimate general operand.
It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE. */
#define LEGITIMATE_CONSTANT_P(X) \
((GET_CODE (X) == CONST_INT \
&& (unsigned) (INTVAL (X) + 0x2000) < 0x4000)\
|| (GET_CODE (X) == SYMBOL_REF && (X)->unchanging))
/* The macros REG_OK_FOR..._P assume that the arg is a REG rtx
and check its validity for a certain class.
We have two alternate definitions for each of them.
The usual definition accepts all pseudo regs; the other rejects
them unless they have been allocated suitable hard regs.
The symbol REG_OK_STRICT causes the latter definition to be used.
Most source files want to accept pseudo regs in the hope that
they will get allocated to the class that the insn wants them to be in.
Source files for reload pass need to be strict.
After reload, it makes no difference, since pseudo regs have
been eliminated by then. */
#ifndef REG_OK_STRICT
/* Nonzero if X is a hard reg that can be used as an index
or if it is a pseudo reg. */
#define REG_OK_FOR_INDEX_P(X) (((unsigned) REGNO (X)) - 32 >= 14)
/* Nonzero if X is a hard reg that can be used as a base reg
or if it is a pseudo reg. */
#define REG_OK_FOR_BASE_P(X) (((unsigned) REGNO (X)) - 32 >= 14)
#else
/* Nonzero if X is a hard reg that can be used as an index. */
#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P (REGNO (X))
/* Nonzero if X is a hard reg that can be used as a base reg. */
#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P (REGNO (X))
#endif
/* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression
that is a valid memory address for an instruction.
The MODE argument is the machine mode for the MEM expression
that wants to use this address.
On SPUR, the actual legitimate addresses must be REG+SMALLINT or REG+REG.
Actually, REG+REG is not legitimate for stores, so
it is obtained only by combination on loads.
We can treat a SYMBOL_REF as legitimate if it is part of this
function's constant-pool, because such addresses can actually
be output as REG+SMALLINT. */
#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \
{ if (GET_CODE (X) == REG \
&& REG_OK_FOR_BASE_P (X)) \
goto ADDR; \
if (GET_CODE (X) == SYMBOL_REF && (X)->unchanging) \
goto ADDR; \
if (GET_CODE (X) == PLUS \
&& GET_CODE (XEXP (X, 0)) == REG \
&& REG_OK_FOR_BASE_P (XEXP (X, 0))) \
{ \
if (GET_CODE (XEXP (X, 1)) == CONST_INT \
&& INTVAL (XEXP (X, 1)) >= -0x2000 \
&& INTVAL (XEXP (X, 1)) < 0x2000) \
goto ADDR; \
} \
}
/* Try machine-dependent ways of modifying an illegitimate address
to be legitimate. If we find one, return the new, valid address.
This macro is used in only one place: `memory_address' in explow.c.
OLDX is the address as it was before break_out_memory_refs was called.
In some cases it is useful to look at this to decide what needs to be done.
MODE and WIN are passed so that this macro can use
GO_IF_LEGITIMATE_ADDRESS.
It is always safe for this macro to do nothing. It exists to recognize
opportunities to optimize the output. */
/* On SPUR, change REG+N into REG+REG, and REG+(X*Y) into REG+REG. */
#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN) \
{ if (GET_CODE (X) == PLUS && CONSTANT_ADDRESS_P (XEXP (X, 1))) \
(X) = gen_rtx_PLUS (SImode, XEXP (X, 0), \
copy_to_mode_reg (SImode, XEXP (X, 1))); \
if (GET_CODE (X) == PLUS && CONSTANT_ADDRESS_P (XEXP (X, 0))) \
(X) = gen_rtx_PLUS (SImode, XEXP (X, 1), \
copy_to_mode_reg (SImode, XEXP (X, 0))); \
if (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 0)) == MULT) \
(X) = gen_rtx_PLUS (SImode, XEXP (X, 1), \
force_operand (XEXP (X, 0), 0)); \
if (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 1)) == MULT) \
(X) = gen_rtx_PLUS (SImode, XEXP (X, 0), \
force_operand (XEXP (X, 1), 0)); \
if (memory_address_p (MODE, X)) \
goto WIN; }
/* Go to LABEL if ADDR (a legitimate address expression)
has an effect that depends on the machine mode it is used for.
On the SPUR this is never true. */
#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL)
/* Specify the machine mode that this machine uses
for the index in the tablejump instruction. */
#define CASE_VECTOR_MODE SImode
/* Define as C expression which evaluates to nonzero if the tablejump
instruction expects the table to contain offsets from the address of the
table.
Do not define this if the table should contain absolute addresses. */
/* #define CASE_VECTOR_PC_RELATIVE 1 */
/* Specify the tree operation to be used to convert reals to integers. */
#define IMPLICIT_FIX_EXPR FIX_ROUND_EXPR
/* This is the kind of divide that is easiest to do in the general case. */
#define EASY_DIV_EXPR TRUNC_DIV_EXPR
/* Define this as 1 if `char' should by default be signed; else as 0. */
#define DEFAULT_SIGNED_CHAR 0
/* Max number of bytes we can move from memory to memory
in one reasonably fast instruction. */
#define MOVE_MAX 4
/* Nonzero if access to memory by bytes is slow and undesirable. */
#define SLOW_BYTE_ACCESS 1
/* This is BSD, so it wants DBX format. */
#define DBX_DEBUGGING_INFO
/* Do not break .stabs pseudos into continuations. */
#define DBX_CONTIN_LENGTH 0
/* Don't try to use the `x' type-cross-reference character in DBX data.
Also has the consequence of putting each struct, union or enum
into a separate .stabs, containing only cross-refs to the others. */
#define DBX_NO_XREFS
/* Value is 1 if truncating an integer of INPREC bits to OUTPREC bits
is done just by pretending it is already truncated. */
#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1
/* Specify the machine mode that pointers have.
After generation of rtl, the compiler makes no further distinction
between pointers and any other objects of this machine mode. */
#define Pmode SImode
/* A function address in a call instruction
is a byte address (for indexing purposes)
so give the MEM rtx a byte's mode. */
#define FUNCTION_MODE SImode
/* Define this if addresses of constant functions
shouldn't be put through pseudo regs where they can be cse'd.
Desirable on machines where ordinary constants are expensive
but a CALL with constant address is cheap. */
#define NO_FUNCTION_CSE
/* Compute the cost of computing a constant rtl expression RTX
whose rtx-code is CODE. The body of this macro is a portion
of a switch statement. If the code is computed here,
return it with a return statement. Otherwise, break from the switch. */
#define CONST_COSTS(RTX,CODE,OUTER_CODE) \
case CONST_INT: \
if (INTVAL (RTX) < 0x2000 && INTVAL (RTX) >= -0x2000) return 1; \
case CONST: \
case LABEL_REF: \
case SYMBOL_REF: \
return 2; \
case CONST_DOUBLE: \
return 4;
/* Tell final.c how to eliminate redundant test instructions. */
/* Here we define machine-dependent flags and fields in cc_status
(see `conditions.h'). */
/* (None are needed on SPUR.) */
/* Store in cc_status the expressions
that the condition codes will describe
after execution of an instruction whose pattern is EXP.
Do not alter them if the instruction would not alter the cc's. */
/* The SPUR does not really have a condition code. */
#define NOTICE_UPDATE_CC(EXP, INSN) \
{ CC_STATUS_INIT; }
/* Control the assembler format that we output. */
/* Output at beginning of assembler file. */
#define ASM_FILE_START(FILE)
/* Output to assembler file text saying following lines
may contain character constants, extra white space, comments, etc. */
#define ASM_APP_ON ""
/* Output to assembler file text saying following lines
no longer contain unusual constructs. */
#define ASM_APP_OFF ""
/* Output before read-only data. */
#define TEXT_SECTION_ASM_OP "\t.text"
/* Output before writable data. */
#define DATA_SECTION_ASM_OP "\t.data"
/* How to refer to registers in assembler output.
This sequence is indexed by compiler's hard-register-number (see above). */
#define REGISTER_NAMES \
{"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", \
"r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", \
"r20", "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", \
"r30", "r31", \
"f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", \
"f10", "f11", "f12", "f13", "f14" }
/* How to renumber registers for dbx and gdb. */
#define DBX_REGISTER_NUMBER(REGNO) (REGNO)
/* This is how to output the definition of a user-level label named NAME,
such as the label on a static function or variable NAME. */
#define ASM_OUTPUT_LABEL(FILE,NAME) \
do { assemble_name (FILE, NAME); fputs (":\n", FILE); } while (0)
/* This is how to output a command to make the user-level label named NAME
defined for reference from other files. */
#define ASM_GLOBALIZE_LABEL(FILE,NAME) \
do { fputs (".globl ", FILE); assemble_name (FILE, NAME); fputs ("\n", FILE);} while (0)
/* The prefix to add to user-visible assembler symbols. */
#define USER_LABEL_PREFIX "_"
/* This is how to output an internal numbered label where
PREFIX is the class of label and NUM is the number within the class. */
#define ASM_OUTPUT_INTERNAL_LABEL(FILE,PREFIX,NUM) \
fprintf (FILE, "%s%d:\n", PREFIX, NUM)
/* This is how to store into the string LABEL
the symbol_ref name of an internal numbered label where
PREFIX is the class of label and NUM is the number within the class.
This is suitable for output with `assemble_name'. */
#define ASM_GENERATE_INTERNAL_LABEL(LABEL,PREFIX,NUM) \
sprintf (LABEL, "*%s%d", PREFIX, NUM)
/* This is how to output an assembler line defining a `double' constant. */
#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \
fprintf (FILE, "\t.double %.20e\n", (VALUE))
/* This is how to output an assembler line defining a `float' constant. */
#define ASM_OUTPUT_FLOAT(FILE,VALUE) \
fprintf (FILE, "\t.single %.12e\n", (VALUE))
/* This is how to output an assembler line defining an `int' constant. */
#define ASM_OUTPUT_INT(FILE,VALUE) \
( fprintf (FILE, "\t.long "), \
output_addr_const (FILE, (VALUE)), \
fprintf (FILE, "\n"))
/* Likewise for `char' and `short' constants. */
#define ASM_OUTPUT_SHORT(FILE,VALUE) \
( fprintf (FILE, "\t.word "), \
output_addr_const (FILE, (VALUE)), \
fprintf (FILE, "\n"))
#define ASM_OUTPUT_CHAR(FILE,VALUE) \
( fprintf (FILE, "\t.byte "), \
output_addr_const (FILE, (VALUE)), \
fprintf (FILE, "\n"))
/* This is how to output an assembler line for a numeric constant byte. */
#define ASM_OUTPUT_BYTE(FILE,VALUE) \
fprintf (FILE, "\t.byte 0x%x\n", (VALUE))
/* This is how to output code to push a register on the stack.
It need not be very fast code. */
#define ASM_OUTPUT_REG_PUSH(FILE,REGNO) \
fprintf (FILE, "\tadd_nt r4,r4,$-4\n\tst_32 %s,r4,$0\n", reg_names[REGNO])
/* This is how to output an insn to pop a register from the stack.
It need not be very fast code. */
#define ASM_OUTPUT_REG_POP(FILE,REGNO) \
fprintf (FILE, "\tld_32 %s,r4,$0\n\tadd_nt r4,r4,$4\n", reg_names[REGNO])
/* This is how to output an element of a case-vector that is absolute. */
#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \
fprintf (FILE, "\t.long L%d\n", VALUE)
/* This is how to output an element of a case-vector that is relative.
(SPUR does not use such vectors,
but we must define this macro anyway.) */
#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \
fprintf (FILE, "\t.word L%d-L%d\n", VALUE, REL)
/* This is how to output an assembler line
that says to advance the location counter
to a multiple of 2**LOG bytes. */
#define ASM_OUTPUT_ALIGN(FILE,LOG) \
if ((LOG) != 0) \
fprintf (FILE, "\t.align %d\n", (LOG))
#define ASM_OUTPUT_SKIP(FILE,SIZE) \
fprintf (FILE, "\t.space %u\n", (SIZE))
/* This says how to output an assembler line
to define a global common symbol. */
#define ASM_OUTPUT_COMMON(FILE, NAME, SIZE, ROUNDED) \
( fputs (".comm ", (FILE)), \
assemble_name ((FILE), (NAME)), \
fprintf ((FILE), ",%u\n", (ROUNDED)))
/* This says how to output an assembler line
to define a local common symbol. */
#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \
( fputs (".lcomm ", (FILE)), \
assemble_name ((FILE), (NAME)), \
fprintf ((FILE), ",%u\n", (ROUNDED)))
/* Store in OUTPUT a string (made with alloca) containing
an assembler-name for a local static variable named NAME.
LABELNO is an integer which is different for each call. */
#define ASM_FORMAT_PRIVATE_NAME(OUTPUT, NAME, LABELNO) \
( (OUTPUT) = (char *) alloca (strlen ((NAME)) + 10), \
sprintf ((OUTPUT), "%s.%d", (NAME), (LABELNO)))
/* Define the parentheses used to group arithmetic operations
in assembler code. */
#define ASM_OPEN_PAREN "("
#define ASM_CLOSE_PAREN ")"
/* Define results of standard character escape sequences. */
#define TARGET_BELL 007
#define TARGET_BS 010
#define TARGET_TAB 011
#define TARGET_NEWLINE 012
#define TARGET_VT 013
#define TARGET_FF 014
#define TARGET_CR 015
/* Print operand X (an rtx) in assembler syntax to file FILE.
CODE is a letter or dot (`z' in `%z0') or 0 if no letter was specified.
For `%' followed by punctuation, CODE is the punctuation and X is null.
On SPUR, the CODE can be `r', meaning this is a register-only operand
and an immediate zero should be represented as `r0'. */
#define PRINT_OPERAND(FILE, X, CODE) \
{ if (GET_CODE (X) == REG) \
fprintf (FILE, "%s", reg_names[REGNO (X)]); \
else if (GET_CODE (X) == MEM) \
output_address (XEXP (X, 0)); \
else if (GET_CODE (X) == CONST_DOUBLE) \
abort (); \
else if ((CODE) == 'r' && (X) == const0_rtx) \
fprintf (FILE, "r0"); \
else { putc ('$', FILE); output_addr_const (FILE, X); }}
/* Print a memory address as an operand to reference that memory location. */
#define PRINT_OPERAND_ADDRESS(FILE, ADDR) \
{ register rtx base, index = 0; \
int offset = 0; \
register rtx addr = ADDR; \
if (GET_CODE (addr) == REG) \
{ \
fprintf (FILE, "%s,$0", reg_names[REGNO (addr)]); \
} \
else if (GET_CODE (addr) == PLUS) \
{ \
if (GET_CODE (XEXP (addr, 0)) == CONST_INT) \
offset = INTVAL (XEXP (addr, 0)), base = XEXP (addr, 1);\
else if (GET_CODE (XEXP (addr, 1)) == CONST_INT) \
offset = INTVAL (XEXP (addr, 1)), base = XEXP (addr, 0);\
else \
base = XEXP (addr, 0), index = XEXP (addr, 1); \
fprintf (FILE, "%s,", reg_names[REGNO (base)]); \
if (index == 0) \
fprintf (FILE, "$%d", offset); \
else \
fprintf (FILE, "%s,", reg_names[REGNO (index)]); \
} \
else \
{ \
fprintf (FILE, "r24,$("); \
output_addr_const (FILE, addr); \
fprintf (FILE, "-0b)"); \
} \
}
;;- Machine description for SPUR chip for GNU C compiler
;; Copyright (C) 1988, 1998, 1999 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, 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.
;;- See file "rtl.def" for documentation on define_insn, match_*, et. al.
;;- cpp macro #define NOTICE_UPDATE_CC in file tm.h handles condition code
;;- updates for most instructions.
;;- Operand classes for the register allocator:
;; Compare instructions.
;; This pattern is used for generating an "insn"
;; which does just a compare and sets a (fictitious) condition code.
;; The actual SPUR insns are compare-and-conditional-jump.
;; The define_peephole's below recognize the combinations of
;; compares and jumps, and output each pair as a single assembler insn.
;; This controls RTL generation and register allocation.
(define_insn "cmpsi"
[(set (cc0)
(compare (match_operand:SI 0 "register_operand" "rK")
(match_operand:SI 1 "nonmemory_operand" "rK")))]
""
"*
{
cc_status.value1 = operands[0], cc_status.value2 = operands[1];
return \"\";
}")
;; We have to have this because cse can optimize the previous pattern
;; into this one.
(define_insn "tstsi"
[(set (cc0)
(match_operand:SI 0 "register_operand" "r"))]
""
"*
{
cc_status.value1 = operands[0], cc_status.value2 = const0_rtx;
return \"\";
}")
;; These control RTL generation for conditional jump insns
;; and match them for register allocation.
(define_insn "beq"
[(set (pc)
(if_then_else (eq (cc0)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"* return output_compare (operands, \"eq\", \"eq\", \"ne\", \"ne\"); ")
(define_insn "bne"
[(set (pc)
(if_then_else (ne (cc0)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"* return output_compare (operands, \"ne\", \"ne\", \"eq\", \"eq\"); ")
(define_insn "bgt"
[(set (pc)
(if_then_else (gt (cc0)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"* return output_compare (operands, \"gt\", \"lt\", \"le\", \"ge\"); ")
(define_insn "bgtu"
[(set (pc)
(if_then_else (gtu (cc0)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"* return output_compare (operands, \"ugt\", \"ult\", \"ule\", \"uge\"); ")
(define_insn "blt"
[(set (pc)
(if_then_else (lt (cc0)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"* return output_compare (operands, \"lt\", \"gt\", \"ge\", \"le\"); ")
(define_insn "bltu"
[(set (pc)
(if_then_else (ltu (cc0)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"* return output_compare (operands, \"ult\", \"ugt\", \"uge\", \"ule\"); ")
(define_insn "bge"
[(set (pc)
(if_then_else (ge (cc0)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"* return output_compare (operands, \"ge\", \"le\", \"lt\", \"gt\"); ")
(define_insn "bgeu"
[(set (pc)
(if_then_else (geu (cc0)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"* return output_compare (operands, \"uge\", \"ule\", \"ult\", \"ugt\"); ")
(define_insn "ble"
[(set (pc)
(if_then_else (le (cc0)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"* return output_compare (operands, \"le\", \"ge\", \"gt\", \"lt\"); ")
(define_insn "bleu"
[(set (pc)
(if_then_else (leu (cc0)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"* return output_compare (operands, \"ule\", \"uge\", \"ugt\", \"ult\"); ")
;; These match inverted jump insns for register allocation.
(define_insn ""
[(set (pc)
(if_then_else (eq (cc0)
(const_int 0))
(pc)
(label_ref (match_operand 0 "" ""))))]
""
"* return output_compare (operands, \"ne\", \"ne\", \"eq\", \"eq\"); ")
(define_insn ""
[(set (pc)
(if_then_else (ne (cc0)
(const_int 0))
(pc)
(label_ref (match_operand 0 "" ""))))]
""
"* return output_compare (operands, \"eq\", \"eq\", \"ne\", \"ne\"); ")
(define_insn ""
[(set (pc)
(if_then_else (gt (cc0)
(const_int 0))
(pc)
(label_ref (match_operand 0 "" ""))))]
""
"* return output_compare (operands, \"le\", \"ge\", \"gt\", \"lt\"); ")
(define_insn ""
[(set (pc)
(if_then_else (gtu (cc0)
(const_int 0))
(pc)
(label_ref (match_operand 0 "" ""))))]
""
"* return output_compare (operands, \"ule\", \"uge\", \"ugt\", \"ult\"); ")
(define_insn ""
[(set (pc)
(if_then_else (lt (cc0)
(const_int 0))
(pc)
(label_ref (match_operand 0 "" ""))))]
""
"* return output_compare (operands, \"ge\", \"le\", \"lt\", \"gt\"); ")
(define_insn ""
[(set (pc)
(if_then_else (ltu (cc0)
(const_int 0))
(pc)
(label_ref (match_operand 0 "" ""))))]
""
"* return output_compare (operands, \"uge\", \"ule\", \"ult\", \"ugt\"); ")
(define_insn ""
[(set (pc)
(if_then_else (ge (cc0)
(const_int 0))
(pc)
(label_ref (match_operand 0 "" ""))))]
""
"* return output_compare (operands, \"lt\", \"gt\", \"ge\", \"le\"); ")
(define_insn ""
[(set (pc)
(if_then_else (geu (cc0)
(const_int 0))
(pc)
(label_ref (match_operand 0 "" ""))))]
""
"* return output_compare (operands, \"ult\", \"ugt\", \"uge\", \"ule\"); ")
(define_insn ""
[(set (pc)
(if_then_else (le (cc0)
(const_int 0))
(pc)
(label_ref (match_operand 0 "" ""))))]
""
"* return output_compare (operands, \"gt\", \"lt\", \"le\", \"ge\"); ")
(define_insn ""
[(set (pc)
(if_then_else (leu (cc0)
(const_int 0))
(pc)
(label_ref (match_operand 0 "" ""))))]
""
"* return output_compare (operands, \"ugt\", \"ult\", \"ule\", \"uge\"); ")
;; Move instructions
(define_insn "movsi"
[(set (match_operand:SI 0 "general_operand" "=r,m")
(match_operand:SI 1 "general_operand" "rmi,rJ"))]
""
"*
{
if (GET_CODE (operands[0]) == MEM)
return \"st_32 %r1,%0\";
if (GET_CODE (operands[1]) == MEM)
return \"ld_32 %0,%1\;nop\";
if (GET_CODE (operands[1]) == REG)
return \"add_nt %0,%1,$0\";
if (GET_CODE (operands[1]) == SYMBOL_REF && operands[1]->unchanging)
return \"add_nt %0,r24,$(%1-0b)\";
return \"add_nt %0,r0,%1\";
}")
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(mem:SI (plus:SI (match_operand:SI 1 "register_operand" "r")
(match_operand:SI 2 "register_operand" "r"))))]
""
"ld_32 %0,%1,%2\;nop")
;; Generate insns for moving single bytes.
(define_expand "movqi"
[(set (match_operand:QI 0 "general_operand" "")
(match_operand:QI 1 "general_operand" ""))]
""
"
{
if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM)
operands[1] = copy_to_reg (operands[1]);
if (GET_CODE (operands[1]) == MEM)
{
rtx tem = gen_reg_rtx (SImode);
rtx addr = force_reg (SImode, XEXP (operands[1], 0));
rtx subreg;
emit_move_insn (tem, gen_rtx_MEM (SImode, addr));
if (GET_CODE (operands[0]) == SUBREG)
subreg = gen_rtx_SUBREG (SImode, SUBREG_REG (operands[0]),
SUBREG_WORD (operands[0]));
else
subreg = gen_rtx_SUBREG (SImode, operands[0], 0);
emit_insn (gen_rtx_SET (VOIDmode, subreg,
gen_rtx_ZERO_EXTRACT (SImode, tem,
GEN_INT (8),
addr)));
}
else if (GET_CODE (operands[0]) == MEM)
{
rtx tem = gen_reg_rtx (SImode);
rtx addr = force_reg (SImode, XEXP (operands[0], 0));
rtx subreg;
emit_move_insn (tem, gen_rtx_MEM (SImode, addr));
if (! CONSTANT_ADDRESS_P (operands[1]))
{
if (GET_CODE (operands[1]) == SUBREG)
subreg = gen_rtx_SUBREG (SImode, SUBREG_REG (operands[1]),
SUBREG_WORD (operands[1]));
else
subreg = gen_rtx_SUBREG (SImode, operands[1], 0);
}
emit_insn (gen_rtx_SET (VOIDmode,
gen_rtx_ZERO_EXTRACT (SImode, tem,
GEN_INT (8),
addr),
subreg));
emit_move_insn (gen_rtx_MEM (SImode, addr), tem);
}
else
{
emit_insn (gen_rtx_SET (VOIDmode, operands[0], operands[1]));
}
DONE;
}")
;; Recognize insns generated for moving single bytes.
(define_insn ""
[(set (match_operand:QI 0 "general_operand" "=r,m")
(match_operand:QI 1 "general_operand" "rmi,r"))]
""
"*
{
if (GET_CODE (operands[0]) == MEM)
return \"st_32 %1,%0\";
if (GET_CODE (operands[1]) == MEM)
return \"ld_32 %0,%1\;nop\";
if (GET_CODE (operands[1]) == REG)
return \"add_nt %0,%1,$0\";
return \"add_nt %0,r0,%1\";
}")
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(zero_extract:SI (match_operand:SI 1 "register_operand" "r")
(const_int 8)
(match_operand:SI 2 "nonmemory_operand" "rI")))]
""
"extract %0,%1,%2")
(define_insn ""
[(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+r")
(const_int 8)
(match_operand:SI 1 "nonmemory_operand" "rI"))
(match_operand:SI 2 "nonmemory_operand" "ri"))]
""
"wr_insert %1\;insert %0,%0,%2")
;; Constant propagation can optimize the previous pattern into this pattern.
;[Not any more. It could when the position-operand contains a MULT.]
;(define_insn ""
; [(set (zero_extract:QI (match_operand:SI 0 "register_operand" "+r")
; (const_int 8)
; (match_operand:SI 1 "immediate_operand" "I"))
; (match_operand:QI 2 "register_operand" "r"))]
; "GET_CODE (operands[1]) == CONST_INT
; && INTVAL (operands[1]) % 8 == 0
; && (unsigned) INTVAL (operands[1]) < 32"
; "*
;{
; operands[1] = GEN_INT (INTVAL (operands[1]) / 8);
; return \"wr_insert 0,0,%1\;insert %0,%0,%2\";
;}")
;; The three define_expand patterns on this page
;; serve as subroutines of "movhi".
;; Generate code to fetch an aligned halfword from memory.
;; Operand 0 is the destination register (HImode).
;; Operand 1 is the memory address (SImode).
;; Operand 2 is a temporary (SImode).
;; Operand 3 is a temporary (SImode).
;; Operand 4 is a temporary (QImode).
;; Operand 5 is an internal temporary (HImode).
(define_expand "loadhi"
[(set (match_operand:SI 2 "register_operand" "")
(mem:SI (match_operand:SI 1 "register_operand" "")))
;; Extract the low byte.
(set (subreg:SI (match_dup 5) 0)
(zero_extract:SI (match_dup 2) (const_int 8) (match_dup 1)))
;; Form address of high byte.
(set (match_operand:SI 3 "register_operand" "")
(plus:SI (match_dup 1) (const_int 1)))
;; Extract the high byte.
(set (subreg:SI (match_operand:QI 4 "register_operand" "") 0)
(zero_extract:SI (match_dup 2) (const_int 8) (match_dup 3)))
;; Put the high byte in with the low one.
(set (zero_extract:SI (match_dup 5) (const_int 8) (const_int 1))
(subreg:SI (match_dup 4) 0))
(set (match_operand:HI 0 "register_operand" "") (match_dup 5))]
""
"operands[5] = gen_reg_rtx (HImode);")
;; Generate code to store an aligned halfword into memory.
;; Operand 0 is the destination address (SImode).
;; Operand 1 is the source register (HImode, not constant).
;; Operand 2 is a temporary (SImode).
;; Operand 3 is a temporary (SImode).
;; Operand 4 is a temporary (QImode).
;; Operand 5 is an internal variable made from operand 1.
(define_expand "storehi"
[(set (match_operand:SI 2 "register_operand" "")
(mem:SI (match_operand:SI 0 "register_operand" "")))
;; Insert the low byte.
(set (zero_extract:SI (match_dup 2) (const_int 8) (match_dup 0))
(match_dup 5))
;; Form address of high byte.
(set (match_operand:SI 3 "register_operand" "")
(plus:SI (match_dup 0) (const_int 1)))
;; Extract the high byte from the source.
(set (subreg:SI (match_operand:QI 4 "register_operand" "") 0)
(zero_extract:SI (match_operand:HI 1 "register_operand" "")
(const_int 8) (const_int 1)))
;; Store high byte into the memory word
(set (zero_extract:SI (match_dup 2) (const_int 8) (match_dup 3))
(subreg:SI (match_dup 4) 0))
;; Put memory word back into memory.
(set (mem:SI (match_dup 0))
(match_dup 2))]
""
"
{
if (GET_CODE (operands[1]) == SUBREG)
operands[5] = gen_rtx_SUBREG (SImode, SUBREG_REG (operands[1]),
SUBREG_WORD (operands[1]));
else
operands[5] = gen_rtx_SUBREG (SImode, operands[1], 0);
}")
;; Like storehi but operands[1] is a CONST_INT.
(define_expand "storeinthi"
[(set (match_operand:SI 2 "register_operand" "")
(mem:SI (match_operand:SI 0 "register_operand" "")))
;; Insert the low byte.
(set (zero_extract:SI (match_dup 2) (const_int 8) (match_dup 0))
(match_dup 5))
;; Form address of high byte.
(set (match_operand:SI 3 "register_operand" "")
(plus:SI (match_dup 0) (const_int 1)))
;; Store high byte into the memory word
(set (zero_extract:SI (match_dup 2) (const_int 8) (match_dup 3))
(match_dup 6))
;; Put memory word back into memory.
(set (mem:SI (match_dup 0))
(match_dup 2))]
""
" operands[5] = GEN_INT (INTVAL (operands[1]) & 255);
operands[6] = GEN_INT (INTVAL (operands[1]) >> 8) & 255);
")
;; Main entry for generating insns to move halfwords.
(define_expand "movhi"
[(set (match_operand:HI 0 "general_operand" "")
(match_operand:HI 1 "general_operand" ""))]
""
"
{
if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM)
operands[1] = copy_to_reg (operands[1]);
if (GET_CODE (operands[1]) == MEM)
{
rtx insn =
emit_insn (gen_loadhi (operands[0],
force_reg (SImode, XEXP (operands[1], 0)),
gen_reg_rtx (SImode), gen_reg_rtx (SImode),
gen_reg_rtx (QImode)));
/* Tell cse what value the loadhi produces, so it detect duplicates. */
REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL, operands[1],
REG_NOTES (insn));
}
else if (GET_CODE (operands[0]) == MEM)
{
if (GET_CODE (operands[1]) == CONST_INT)
emit_insn (gen_storeinthi (force_reg (SImode, XEXP (operands[0], 0)),
operands[1],
gen_reg_rtx (SImode), gen_reg_rtx (SImode),
gen_reg_rtx (QImode)));
else
{
if (CONSTANT_P (operands[1]))
operands[1] = force_reg (HImode, operands[1]);
emit_insn (gen_storehi (force_reg (SImode, XEXP (operands[0], 0)),
operands[1],
gen_reg_rtx (SImode), gen_reg_rtx (SImode),
gen_reg_rtx (QImode)));
}
}
else
emit_insn (gen_rtx_SET (VOIDmode, operands[0], operands[1]));
DONE;
}")
;; Recognize insns generated for moving halfwords.
;; (Note that the extract and insert patterns for single-byte moves
;; are also involved in recognizing some of the insns used for this purpose.)
(define_insn ""
[(set (match_operand:HI 0 "general_operand" "=r,m")
(match_operand:HI 1 "general_operand" "rmi,r"))]
""
"*
{
if (GET_CODE (operands[0]) == MEM)
return \"st_32 %1,%0\";
if (GET_CODE (operands[1]) == MEM)
return \"ld_32 %0,%1\;nop\";
if (GET_CODE (operands[1]) == REG)
return \"add_nt %0,%1,$0\";
return \"add_nt %0,r0,%1\";
}")
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(zero_extract:SI (match_operand:HI 1 "register_operand" "r")
(const_int 8)
(match_operand:SI 2 "nonmemory_operand" "rI")))]
""
"extract %0,%1,%2")
(define_insn ""
[(set (zero_extract:SI (match_operand:HI 0 "register_operand" "+r")
(const_int 8)
(match_operand:SI 1 "nonmemory_operand" "rI"))
(match_operand:SI 2 "nonmemory_operand" "ri"))]
""
"wr_insert %1\;insert %0,%0,%2")
;; Constant propagation can optimize the previous pattern into this pattern.
;(define_insn ""
; [(set (zero_extract:QI (match_operand:HI 0 "register_operand" "+r")
; (const_int 8)
; (match_operand:SI 1 "immediate_operand" "I"))
; (match_operand:QI 2 "register_operand" "r"))]
; "GET_CODE (operands[1]) == CONST_INT
; && INTVAL (operands[1]) % 8 == 0
; && (unsigned) INTVAL (operands[1]) < 32"
; "*
;{
; operands[1] = GEN_INT (INTVAL (operands[1]) / 8);
; return \"wr_insert 0,0,%1\;insert %0,%0,%2\";
;}")
;; This pattern forces (set (reg:DF ...) (const_double ...))
;; to be reloaded by putting the constant into memory.
;; It must come before the more general movdf pattern.
(define_insn ""
[(set (match_operand:DF 0 "general_operand" "=&r,f,&o")
(match_operand:DF 1 "" "mG,m,G"))]
"GET_CODE (operands[1]) == CONST_DOUBLE"
"*
{
if (FP_REG_P (operands[0]))
return output_fp_move_double (operands);
if (operands[1] == CONST0_RTX (DFmode) && GET_CODE (operands[0]) == REG)
{
operands[1] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
return \"add_nt %0,r0,$0\;add_nt %1,r0,$0\";
}
if (operands[1] == CONST0_RTX (DFmode) && GET_CODE (operands[0]) == MEM)
{
operands[1] = adj_offsettable_operand (operands[0], 4);
return \"st_32 r0,%0\;st_32 r0,%1\";
}
return output_move_double (operands);
}
")
(define_insn "movdf"
[(set (match_operand:DF 0 "general_operand" "=r,&r,m,?f,?rm")
(match_operand:DF 1 "general_operand" "r,m,r,rfm,f"))]
""
"*
{
if (FP_REG_P (operands[0]) || FP_REG_P (operands[1]))
return output_fp_move_double (operands);
return output_move_double (operands);
}
")
(define_insn "movdi"
[(set (match_operand:DI 0 "general_operand" "=r,&r,m,?f,?rm")
(match_operand:DI 1 "general_operand" "r,m,r,rfm,f"))]
""
"*
{
if (FP_REG_P (operands[0]) || FP_REG_P (operands[1]))
return output_fp_move_double (operands);
return output_move_double (operands);
}
")
(define_insn "movsf"
[(set (match_operand:SF 0 "general_operand" "=rf,m")
(match_operand:SF 1 "general_operand" "rfm,rf"))]
""
"*
{
if (FP_REG_P (operands[0]))
{
if (FP_REG_P (operands[1]))
return \"fmov %0,%1\";
if (GET_CODE (operands[1]) == REG)
{
rtx xoperands[2];
int offset = - get_frame_size () - 8;
xoperands[1] = operands[1];
xoperands[0] = GEN_INT (offset);
output_asm_insn (\"st_32 %1,r25,%0\", xoperands);
xoperands[1] = operands[0];
output_asm_insn (\"ld_sgl %1,r25,%0\;nop\", xoperands);
return \"\";
}
return \"ld_sgl %0,%1\;nop\";
}
if (FP_REG_P (operands[1]))
{
if (GET_CODE (operands[0]) == REG)
{
rtx xoperands[2];
int offset = - get_frame_size () - 8;
xoperands[0] = GEN_INT (offset);
xoperands[1] = operands[1];
output_asm_insn (\"st_sgl %1,r25,%0\", xoperands);
xoperands[1] = operands[0];
output_asm_insn (\"ld_32 %1,r25,%0\;nop\", xoperands);
return \"\";
}
return \"st_sgl %1,%0\";
}
if (GET_CODE (operands[0]) == MEM)
return \"st_32 %r1,%0\";
if (GET_CODE (operands[1]) == MEM)
return \"ld_32 %0,%1\;nop\";
if (GET_CODE (operands[1]) == REG)
return \"add_nt %0,%1,$0\";
return \"add_nt %0,r0,%1\";
}")
;;- truncation instructions
(define_insn "truncsiqi2"
[(set (match_operand:QI 0 "register_operand" "=r")
(truncate:QI
(match_operand:SI 1 "register_operand" "r")))]
""
"add_nt %0,%1,$0")
(define_insn "trunchiqi2"
[(set (match_operand:QI 0 "register_operand" "=r")
(truncate:QI
(match_operand:HI 1 "register_operand" "r")))]
""
"add_nt %0,%1,$0")
(define_insn "truncsihi2"
[(set (match_operand:HI 0 "register_operand" "=r")
(truncate:HI
(match_operand:SI 1 "register_operand" "r")))]
""
"add_nt %0,%1,$0")
;;- zero extension instructions
;; Note that the one starting from HImode comes before those for QImode
;; so that a constant operand will match HImode, not QImode.
(define_expand "zero_extendhisi2"
[(set (match_operand:SI 0 "register_operand" "")
(and:SI (match_operand:HI 1 "register_operand" "") ;Changed to SI below
;; This constant is invalid, but reloading will handle it.
;; It's useless to generate here the insns to construct it
;; because constant propagation would simplify them anyway.
(match_dup 2)))]
""
"
{
if (GET_CODE (operands[1]) == SUBREG)
operands[1] = gen_rtx_SUBREG (SImode, SUBREG_REG (operands[1]),
SUBREG_WORD (operands[1]));
else
operands[1] = gen_rtx_SUBREG (SImode, operands[1], 0);
operands[2] = force_reg (SImode, GEN_INT (65535));
}")
(define_insn "zero_extendqihi2"
[(set (match_operand:HI 0 "register_operand" "=r")
(zero_extend:HI
(match_operand:QI 1 "register_operand" "r")))]
""
"extract %0,%1,$0")
(define_insn "zero_extendqisi2"
[(set (match_operand:SI 0 "register_operand" "=r")
(zero_extend:SI
(match_operand:QI 1 "register_operand" "r")))]
""
"extract %0,%1,$0")
;;- sign extension instructions
;; Note that the one starting from HImode comes before those for QImode
;; so that a constant operand will match HImode, not QImode.
(define_expand "extendhisi2"
[(set (match_dup 2)
(and:SI (match_operand:HI 1 "register_operand" "") ;Changed to SI below
(match_dup 4)))
(set (match_dup 3) (plus:SI (match_dup 2) (match_dup 5)))
(set (match_operand:SI 0 "register_operand" "")
(xor:SI (match_dup 3) (match_dup 5)))]
""
"
{
if (GET_CODE (operands[1]) == SUBREG)
operands[1] = gen_rtx_SUBREG (SImode, SUBREG_REG (operands[1]),
SUBREG_WORD (operands[1]));
else
operands[1] = gen_rtx_SUBREG (SImode, operands[1], 0);
operands[2] = gen_reg_rtx (SImode);
operands[3] = gen_reg_rtx (SImode);
operands[4] = force_reg (SImode, GEN_INT (65535));
operands[5] = force_reg (SImode, GEN_INT (-32768));
}")
(define_expand "extendqihi2"
[(set (match_dup 2)
(and:HI (match_operand:QI 1 "register_operand" "") ;Changed to SI below
(const_int 255)))
(set (match_dup 3)
(plus:SI (match_dup 2) (const_int -128)))
(set (match_operand:HI 0 "register_operand" "")
(xor:SI (match_dup 3) (const_int -128)))]
""
"
{
if (GET_CODE (operands[1]) == SUBREG)
operands[1] = gen_rtx_SUBREG (HImode, SUBREG_REG (operands[1]),
SUBREG_WORD (operands[1]));
else
operands[1] = gen_rtx_SUBREG (HImode, operands[1], 0);
operands[2] = gen_reg_rtx (HImode);
operands[3] = gen_reg_rtx (HImode);
}")
(define_expand "extendqisi2"
[(set (match_dup 2)
(and:SI (match_operand:QI 1 "register_operand" "") ;Changed to SI below
(const_int 255)))
(set (match_dup 3) (plus:SI (match_dup 2) (const_int -128)))
(set (match_operand:SI 0 "register_operand" "")
(xor:SI (match_dup 3) (const_int -128)))]
""
"
{
if (GET_CODE (operands[1]) == SUBREG)
operands[1] = gen_rtx_SUBREG (SImode, SUBREG_REG (operands[1]),
SUBREG_WORD (operands[1]));
else
operands[1] = gen_rtx_SUBREG (SImode, operands[1], 0);
operands[2] = gen_reg_rtx (SImode);
operands[3] = gen_reg_rtx (SImode);
}")
;;- arithmetic instructions
(define_insn "addsi3"
[(set (match_operand:SI 0 "register_operand" "=r")
(plus:SI (match_operand:SI 1 "nonmemory_operand" "%r")
(match_operand:SI 2 "nonmemory_operand" "rI")))]
""
"add %0,%1,%2")
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(plus:SI (match_operand:SI 1 "nonmemory_operand" "%r")
(match_operand:SI 2 "big_immediate_operand" "g")))]
"GET_CODE (operands[2]) == CONST_INT
&& (unsigned) (INTVAL (operands[2]) + 0x8000000) < 0x10000000"
"*
{
return
output_add_large_offset (operands[0], operands[1], INTVAL (operands[2]));
}")
(define_insn "subsi3"
[(set (match_operand:SI 0 "register_operand" "=r")
(minus:SI (match_operand:SI 1 "register_operand" "r")
(match_operand:SI 2 "nonmemory_operand" "rI")))]
""
"sub %0,%1,%2")
(define_insn "andsi3"
[(set (match_operand:SI 0 "register_operand" "=r")
(and:SI (match_operand:SI 1 "nonmemory_operand" "%r")
(match_operand:SI 2 "nonmemory_operand" "rI")))]
""
"and %0,%1,%2")
(define_insn "iorsi3"
[(set (match_operand:SI 0 "register_operand" "=r")
(ior:SI (match_operand:SI 1 "nonmemory_operand" "%r")
(match_operand:SI 2 "nonmemory_operand" "rI")))]
""
"or %0,%1,%2")
(define_insn "xorsi3"
[(set (match_operand:SI 0 "register_operand" "=r")
(xor:SI (match_operand:SI 1 "nonmemory_operand" "%r")
(match_operand:SI 2 "nonmemory_operand" "rI")))]
""
"xor %0,%1,%2")
(define_insn "negsi2"
[(set (match_operand:SI 0 "register_operand" "=r")
(neg:SI (match_operand:SI 1 "nonmemory_operand" "rI")))]
""
"sub %0,r0,%1")
(define_insn "one_cmplsi2"
[(set (match_operand:SI 0 "register_operand" "=r")
(not:SI (match_operand:SI 1 "register_operand" "r")))]
""
"xor %0,%1,$-1")
;; Floating point arithmetic instructions.
(define_insn "adddf3"
[(set (match_operand:DF 0 "register_operand" "=f")
(plus:DF (match_operand:DF 1 "register_operand" "f")
(match_operand:DF 2 "register_operand" "f")))]
"TARGET_FPU"
"fadd %0,%1,%2")
(define_insn "addsf3"
[(set (match_operand:SF 0 "register_operand" "=f")
(plus:SF (match_operand:SF 1 "register_operand" "f")
(match_operand:SF 2 "register_operand" "f")))]
"TARGET_FPU"
"fadd %0,%1,%2")
(define_insn "subdf3"
[(set (match_operand:DF 0 "register_operand" "=f")
(minus:DF (match_operand:DF 1 "register_operand" "f")
(match_operand:DF 2 "register_operand" "f")))]
"TARGET_FPU"
"fsub %0,%1,%2")
(define_insn "subsf3"
[(set (match_operand:SF 0 "register_operand" "=f")
(minus:SF (match_operand:SF 1 "register_operand" "f")
(match_operand:SF 2 "register_operand" "f")))]
"TARGET_FPU"
"fsub %0,%1,%2")
(define_insn "muldf3"
[(set (match_operand:DF 0 "register_operand" "=f")
(mult:DF (match_operand:DF 1 "register_operand" "f")
(match_operand:DF 2 "register_operand" "f")))]
"TARGET_FPU"
"fmul %0,%1,%2")
(define_insn "mulsf3"
[(set (match_operand:SF 0 "register_operand" "=f")
(mult:SF (match_operand:SF 1 "register_operand" "f")
(match_operand:SF 2 "register_operand" "f")))]
"TARGET_FPU"
"fmul %0,%1,%2")
(define_insn "divdf3"
[(set (match_operand:DF 0 "register_operand" "=f")
(div:DF (match_operand:DF 1 "register_operand" "f")
(match_operand:DF 2 "register_operand" "f")))]
"TARGET_FPU"
"fdiv %0,%1,%2")
(define_insn "divsf3"
[(set (match_operand:SF 0 "register_operand" "=f")
(div:SF (match_operand:SF 1 "register_operand" "f")
(match_operand:SF 2 "register_operand" "f")))]
"TARGET_FPU"
"fdiv %0,%1,%2")
(define_insn "negdf2"
[(set (match_operand:DF 0 "register_operand" "=f")
(neg:DF (match_operand:DF 1 "nonmemory_operand" "f")))]
"TARGET_FPU"
"fneg %0,%1")
(define_insn "negsf2"
[(set (match_operand:SF 0 "register_operand" "=f")
(neg:SF (match_operand:SF 1 "nonmemory_operand" "f")))]
"TARGET_FPU"
"fneg %0,%1")
(define_insn "absdf2"
[(set (match_operand:DF 0 "register_operand" "=f")
(abs:DF (match_operand:DF 1 "nonmemory_operand" "f")))]
"TARGET_FPU"
"fabs %0,%1")
(define_insn "abssf2"
[(set (match_operand:SF 0 "register_operand" "=f")
(abs:SF (match_operand:SF 1 "nonmemory_operand" "f")))]
"TARGET_FPU"
"fabs %0,%1")
;; Shift instructions
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(ashift:SI (match_operand:SI 1 "register_operand" "r")
(match_operand:SI 2 "immediate_operand" "I")))]
"GET_CODE (operands[2]) == CONST_INT"
"*
{
unsigned int amount = INTVAL (operands[2]);
switch (amount)
{
case 0:
return \"add_nt %0,%1,$0\";
case 1:
return \"sll %0,%1,$1\";
case 2:
return \"sll %0,%1,$2\";
default:
output_asm_insn (\"sll %0,%1,$3\", operands);
for (amount -= 3; amount >= 3; amount -= 3)
output_asm_insn (\"sll %0,%0,$3\", operands);
if (amount > 0)
output_asm_insn (amount == 1 ? \"sll %0,%0,$1\" : \"sll %0,%0,$2\",
operands);
return \"\";
}
}")
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(ashiftrt:SI (match_operand:SI 1 "register_operand" "r")
(match_operand:SI 2 "immediate_operand" "I")))]
"GET_CODE (operands[2]) == CONST_INT"
"*
{
unsigned int amount = INTVAL (operands[2]);
if (amount == 0)
return \"add_nt %0,%1,$0\";
else
output_asm_insn (\"sra %0,%1,$1\", operands);
for (amount -= 1; amount > 0; amount -= 1)
output_asm_insn (\"sra %0,%0,$1\", operands);
return \"\";
}")
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(lshiftrt:SI (match_operand:SI 1 "register_operand" "r")
(match_operand:SI 2 "immediate_operand" "I")))]
"GET_CODE (operands[2]) == CONST_INT"
"*
{
unsigned int amount = INTVAL (operands[2]);
if (amount == 0)
return \"add_nt %0,%1,$0\";
else
output_asm_insn (\"srl %0,%1,$1\", operands);
for (amount -= 1; amount > 0; amount -= 1)
output_asm_insn (\"srl %0,%0,$1\", operands);
return \"\";
}")
(define_expand "ashlsi3"
[(set (match_operand:SI 0 "register_operand" "")
(ashift:SI (match_operand:SI 1 "register_operand" "")
(match_operand:SI 2 "nonmemory_operand" "")))]
""
"
{
if (GET_CODE (operands[2]) != CONST_INT
|| (! TARGET_EXPAND_SHIFTS && (unsigned) INTVAL (operands[2]) > 3))
FAIL;
}")
(define_expand "ashrsi3"
[(set (match_operand:SI 0 "register_operand" "")
(ashiftrt:SI (match_operand:SI 1 "register_operand" "")
(match_operand:SI 2 "nonmemory_operand" "")))]
""
"
{
if (GET_CODE (operands[2]) != CONST_INT
|| (! TARGET_EXPAND_SHIFTS && (unsigned) INTVAL (operands[2]) > 1))
FAIL;
}")
(define_expand "lshrsi3"
[(set (match_operand:SI 0 "register_operand" "")
(lshiftrt:SI (match_operand:SI 1 "register_operand" "")
(match_operand:SI 2 "nonmemory_operand" "")))]
""
"
{
if (GET_CODE (operands[2]) != CONST_INT
|| (! TARGET_EXPAND_SHIFTS && (unsigned) INTVAL (operands[2]) > 1))
FAIL;
}")
;; Unconditional and other jump instructions
(define_insn "jump"
[(set (pc)
(label_ref (match_operand 0 "" "")))]
""
"jump %l0\;nop")
(define_insn "tablejump"
[(set (pc) (match_operand:SI 0 "register_operand" "r"))
(use (label_ref (match_operand 1 "" "")))]
""
"jump_reg r0,%0\;nop")
;;- jump to subroutine
(define_insn "call"
[(call (match_operand:SI 0 "memory_operand" "m")
(match_operand:SI 1 "general_operand" "g"))]
;;- Don't use operand 1 for most machines.
""
"add_nt r2,%0\;call .+8\;jump_reg r0,r2\;nop")
(define_insn "call_value"
[(set (match_operand 0 "" "=g")
(call (match_operand:SI 1 "memory_operand" "m")
(match_operand:SI 2 "general_operand" "g")))]
;;- Don't use operand 1 for most machines.
""
"add_nt r2,%1\;call .+8\;jump_reg r0,r2\;nop")
;; A memory ref with constant address is not normally valid.
;; But it is valid in a call insns. This pattern allows the
;; loading of the address to combine with the call.
(define_insn ""
[(call (mem:SI (match_operand:SI 0 "" "i"))
(match_operand:SI 1 "general_operand" "g"))]
;;- Don't use operand 1 for most machines.
"GET_CODE (operands[0]) == SYMBOL_REF"
"call %0\;nop")
(define_insn ""
[(set (match_operand 0 "" "=g")
(call (mem:SI (match_operand:SI 1 "" "i"))
(match_operand:SI 2 "general_operand" "g")))]
;;- Don't use operand 1 for most machines.
"GET_CODE (operands[1]) == SYMBOL_REF"
"call %1\;nop")
(define_insn "nop"
[(const_int 0)]
""
"nop")
/* Configuration for GNU C-compiler for Berkeley SPUR processor.
Copyright (C) 1988, 1993 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, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* #defines that need visibility everywhere. */
#define FALSE 0
#define TRUE 1
/* This describes the machine the compiler is hosted on. */
#define HOST_BITS_PER_CHAR 8
#define HOST_BITS_PER_SHORT 16
#define HOST_BITS_PER_INT 32
#define HOST_BITS_PER_LONG 32
#define HOST_BITS_PER_LONGLONG 64
/* target machine dependencies.
tm.h is a symbolic link to the actual target specific file. */
#include "tm.h"
/* Arguments to use with `exit'. */
#define SUCCESS_EXIT_CODE 0
#define FATAL_EXIT_CODE 33
/* Definitions of target machine for GNU compiler. Harris tahoe version.
Copyright (C) 1989, 1993 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, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include "tahoe/tahoe.h"
#undef CPP_PREDEFINES
#define CPP_PREDEFINES "-Dtahoe -Dunix -Dhcx -Asystem(unix) -Acpu(tahoe) -Amachine(tahoe)"
#undef DBX_DEBUGGING_INFO
#define SDB_DEBUGGING_INFO
#undef LIB_SPEC
#undef TARGET_DEFAULT
#define TARGET_DEFAULT 1
/* urem and udiv don't exist on this system. */
#undef UDIVSI3_LIBCALL
#undef UMODSI3_LIBCALL
/* Operand of .align is not logarithmic. */
#undef ASM_OUTPUT_ALIGN
#define ASM_OUTPUT_ALIGN(FILE,LOG) \
LOG ? fprintf (FILE, "\t.align %d\n", 1 << (LOG)) : 0
/* For the same reason, we need .align 2 after casesi. */
#undef PRINT_OPERAND
#define PRINT_OPERAND(FILE, X, CODE) \
{ if (CODE == '@') \
putc ('2', FILE); \
else if (GET_CODE (X) == REG) \
fprintf (FILE, "%s", reg_names[REGNO (X)]); \
else if (GET_CODE (X) == MEM) \
output_address (XEXP (X, 0)); \
else { putc ('$', FILE); output_addr_const (FILE, X); }}
#undef ASM_OUTPUT_LOCAL
#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \
( fputs (".bss ", (FILE)), \
assemble_name ((FILE), (NAME)), \
fprintf ((FILE), ",%u,4\n", (ROUNDED)))
/* Output at beginning of assembler file. */
/* The .file command should always begin the output. */
#undef ASM_FILE_START
#define ASM_FILE_START(FILE) \
output_file_directive ((FILE), main_input_filename);
#define ASM_OUTPUT_ASCII(FILE, PTR, SIZE) \
do { \
const unsigned char *_p = (PTR); \
int _thissize = (SIZE); \
fprintf ((FILE), "\t.ascii \""); \
for (i = 0; i < _thissize; i++) \
{ \
register int c = _p[i]; \
if (c >= ' ' && c < 0177 && c != '\"' && c != '\\') \
putc (c, (FILE)); \
else \
{ \
fprintf ((FILE), "\\%o", c); \
if (i < _thissize - 1 \
&& _p[i + 1] >= '0' && _p[i + 1] <= '9') \
fprintf ((FILE), "\"\n\t.ascii \""); \
} \
} \
fprintf ((FILE), "\"\n"); \
} while (0)
/* Subroutines for insn-output.c for Tahoe.
Copyright (C) 1989, 1991, 1997, 1998, 1999 Free Software Foundation, Inc.
Contributed by the University of Buffalo (Devon Bowen, Dale Wiles
and Kevin Zachmann.
Changes for HCX by Piet van Oostrum, University of Utrecht,
The Netherlands (piet@cs.ruu.nl)
Speed tweaks by Michael Tiemann (tiemann@lurch.stanford.edu).
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, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include "config.h"
#include "system.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 "function.h"
#include "output.h"
#include "insn-attr.h"
#include "ggc.h"
/* On tahoe, you have to go to memory to convert a register
from sub-word to word. */
rtx tahoe_reg_conversion_loc;
int
extensible_operand (op, mode)
rtx op;
enum machine_mode mode;
{
if ((GET_CODE (op) == REG
|| (GET_CODE (op) == SUBREG
&& GET_CODE (SUBREG_REG (op)) == REG))
&& tahoe_reg_conversion_loc == 0)
{
tahoe_reg_conversion_loc
= assign_stack_local (SImode, GET_MODE_SIZE (SImode));
ggc_add_rtx_root (&tahoe_reg_conversion_loc, 1);
}
return general_operand (op, mode);
}
/* Most of the print_operand_address function was taken from the VAX since
the modes are basically the same. I had to add a special case, though, for
symbol references with offsets. */
print_operand_address (file, addr)
FILE *file;
register rtx addr;
{
register rtx reg1, reg2, breg, ireg;
rtx offset;
static char *reg_name[] = REGISTER_NAMES;
retry:
switch (GET_CODE (addr))
{
case MEM:
fprintf (file, "*");
addr = XEXP (addr, 0);
goto retry;
case REG:
fprintf (file, "(%s)", reg_name [REGNO (addr)]);
break;
case PRE_DEC:
fprintf (file, "-(%s)", reg_name [REGNO (XEXP (addr, 0))]);
break;
case POST_INC:
fprintf (file, "(%s)+", reg_name [REGNO (XEXP (addr, 0))]);
break;
case PLUS:
reg1 = 0, reg2 = 0;
ireg = 0, breg = 0;
offset = 0;
if (CONSTANT_ADDRESS_P (XEXP (addr, 0))
&& GET_CODE (XEXP (addr, 1)) == CONST_INT)
output_addr_const (file, addr);
if (CONSTANT_ADDRESS_P (XEXP (addr, 1))
&& GET_CODE (XEXP (addr, 0)) == CONST_INT)
output_addr_const (file, addr);
if (CONSTANT_ADDRESS_P (XEXP (addr, 0))
|| GET_CODE (XEXP (addr, 0)) == MEM)
offset = XEXP (addr, 0), addr = XEXP (addr, 1);
else if (CONSTANT_ADDRESS_P (XEXP (addr, 1))
|| GET_CODE (XEXP (addr, 1)) == MEM)
offset = XEXP (addr, 1), addr = XEXP (addr, 0);
if (GET_CODE (addr) != PLUS)
;
else if (GET_CODE (XEXP (addr, 0)) == MULT)
reg1 = XEXP (addr, 0), addr = XEXP (addr, 1);
else if (GET_CODE (XEXP (addr, 1)) == MULT)
reg1 = XEXP (addr, 1), addr = XEXP (addr, 0);
else if (GET_CODE (XEXP (addr, 0)) == REG)
reg1 = XEXP (addr, 0), addr = XEXP (addr, 1);
else if (GET_CODE (XEXP (addr, 1)) == REG)
reg1 = XEXP (addr, 1), addr = XEXP (addr, 0);
if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT)
{
if (reg1 == 0)
reg1 = addr;
else
reg2 = addr;
addr = 0;
}
if (offset != 0)
{
if (addr != 0)
abort ();
addr = offset;
}
if (reg1 != 0 && GET_CODE (reg1) == MULT)
breg = reg2, ireg = reg1;
else if (reg2 != 0 && GET_CODE (reg2) == MULT)
breg = reg1, ireg = reg2;
else if (reg2 != 0 || GET_CODE (addr) == MEM)
breg = reg2, ireg = reg1;
else
breg = reg1, ireg = reg2;
if (addr != 0)
output_address (offset);
if (breg != 0)
{
if (GET_CODE (breg) != REG)
abort ();
fprintf (file, "(%s)", reg_name[REGNO (breg)]);
}
if (ireg != 0)
{
if (GET_CODE (ireg) == MULT)
ireg = XEXP (ireg, 0);
if (GET_CODE (ireg) != REG)
abort ();
fprintf (file, "[%s]", reg_name[REGNO (ireg)]);
}
break;
default:
output_addr_const (file, addr);
}
}
/* Do a quick check and find out what the best way to do the mini-move is.
Could be a push or a move..... */
static char *
singlemove_string (operands)
rtx *operands;
{
if (operands[1] == const0_rtx)
return "clrl %0";
if (push_operand (operands[0], SImode))
return "pushl %1";
return "movl %1,%0";
}
/* Given the rtx for an address, return true if the given register number is
used in the address somewhere. */
int
regisused (addr, regnum)
rtx addr;
int regnum;
{
if (GET_CODE (addr) == REG)
return REGNO (addr) == regnum;
else if (GET_CODE (addr) == MEM)
return regisused (XEXP (addr, 0), regnum);
else if (GET_CODE (addr) == MULT || GET_CODE (addr) == PLUS)
return (regisused (XEXP (addr, 0), regnum)
|| regisused (XEXP (addr, 1), regnum));
return 0;
}
/* Given some rtx, traverse it and return the register used in a index. If no
index is found, return 0. */
rtx
index_reg (addr)
rtx addr;
{
rtx temp;
if (GET_CODE (addr) == MEM)
return index_reg (XEXP (addr, 0));
else if (GET_CODE (addr) == MULT)
{
if (GET_CODE (XEXP (addr, 0)) == REG)
return XEXP (addr, 0);
else
return XEXP (addr, 1);
}
else if (GET_CODE (addr) == PLUS)
{
if ((temp = index_reg (XEXP (addr, 0))) != 0)
return temp;
else
return index_reg (XEXP (addr, 1));
}
return 0;
}
/* Simulate the move double by generating two movl's. We need to be careful
about mixing modes here. */
char *
output_move_double (operands)
rtx *operands;
{
enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, INDOP, CNSTOP, RNDOP }
optype0, optype1;
rtx latehalf[2];
rtx shftreg0 = 0, shftreg1 = 0;
rtx temp0 = 0, temp1 = 0;
rtx addreg0 = 0, addreg1 = 0;
int dohighfirst = 0;
/* First classify both operands. */
if (REG_P (operands[0]))
optype0 = REGOP;
else if (GET_CODE (operands[0]) == MEM
&& (shftreg0 = index_reg (operands[0])) != 0)
optype0 = INDOP;
else if (offsettable_memref_p (operands[0]))
optype0 = OFFSOP;
else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
{
optype0 = PUSHOP;
dohighfirst++;
}
else if (GET_CODE (operands[0]) == MEM)
optype0 = MEMOP;
else
optype0 = RNDOP;
if (REG_P (operands[1]))
optype1 = REGOP;
else if (GET_CODE (operands[1]) == MEM
&& (shftreg1 = index_reg (operands[1])) !+ 0)
optype1 = INDOP;
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 (operands[1]) == MEM)
optype1 = MEMOP;
else if (CONSTANT_P (operands[1]))
optype1 = CNSTOP;
else
optype1 = RNDOP;
/* Set up for the high byte move for operand zero */
switch (optype0)
{
/* If it's a register, just use the next highest in the high address
move. */
case REGOP:
latehalf[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
break;
/* For an offsettable address, use the GCC function to modify the
operand to get an offset of 4 higher for the second move. */
case OFFSOP:
latehalf[0] = adj_offsettable_operand (operands[0], 4);
break;
/* If the operand is MEMOP type, it must be a pointer to a pointer.
So just remember to increase the mem location and use the same
operand. */
case MEMOP:
latehalf[0] = operands[0];
addreg0 = XEXP(operands[0],0);
break;
/* If we're dealing with a push instruction, just leave the operand
alone since it auto-increments. */
case PUSHOP:
latehalf[0] = operands[0];
break;
/* Indexed addressing. If the address is considered offsettable, use
the offset in the high part. Otherwise find what exactly is being
added to the multiplication. If it's a mem reference, increment that
with the high part being unchanged to cause the shift. If it's a
reg, do the same. If we can't identify it, abort. Remember that the
shift register was already set during identification. */
case INDOP:
if (offsettable_memref_p (operands[0]))
{
latehalf[0] = adj_offsettable_operand (operands[0], 4);
break;
}
latehalf[0] = operands[0];
temp0 = XEXP (XEXP (operands[0], 0), 0);
if (GET_CODE(temp0) == MULT)
{
temp1 = temp0;
temp0 = XEXP (XEXP (operands[0], 0), 1);
}
else
{
temp1 = XEXP (XEXP (operands[0], 0), 1);
if (GET_CODE (temp1) != MULT)
abort();
}
if (GET_CODE (temp0) == MEM)
addreg0 = temp0;
else if (GET_CODE (temp0) == REG)
addreg0 = temp0;
else
abort();
break;
case RNDOP:
default:
abort();
}
/* Do the same setup for operand one. */
switch (optype1)
{
case REGOP:
latehalf[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1);
break;
case OFFSOP:
latehalf[1] = adj_offsettable_operand (operands[1], 4);
break;
case MEMOP:
latehalf[1] = operands[1];
addreg1 = XEXP (operands[1], 0);
break;
case POPOP:
latehalf[1] = operands[1];
break;
case INDOP:
if (offsettable_memref_p (operands[1]))
{
latehalf[1] = adj_offsettable_operand (operands[1], 4);
break;
}
latehalf[1] = operands[1];
temp0 = XEXP (XEXP (operands[1], 0), 0);
if (GET_CODE (temp0) == MULT)
{
temp1 = temp0;
temp0 = XEXP (XEXP (operands[1], 0), 1);
}
else
{
temp1 = XEXP (XEXP (operands[1], 0), 1);
if (GET_CODE (temp1) != MULT)
abort();
}
if (GET_CODE (temp0) == MEM)
addreg1 = temp0;
else if (GET_CODE (temp0) == REG)
addreg1 = temp0;
else
abort();
break;
case CNSTOP:
if (GET_CODE (operands[1]) == CONST_DOUBLE)
split_double (operands[1], &operands[1], &latehalf[1]);
else if (CONSTANT_P (operands[1]))
latehalf[1] = const0_rtx;
else
abort ();
break;
case RNDOP:
default:
abort ();
}
/* Double the register used for shifting in both of the operands but make
sure the same register isn't doubled twice! */
if (shftreg0 != 0 && shftreg1 != 0 && rtx_equal_p (shftreg0, shftreg1))
output_asm_insn ("addl2 %0,%0", &shftreg0);
else
{
if (shftreg0 != 0)
output_asm_insn ("addl2 %0,%0", &shftreg0);
if (shftreg1!= 0)
output_asm_insn ("addl2 %0,%0", &shftreg1);
}
/* If the destination is a register and that register is needed in the
source addressing mode, swap the order of the moves since we don't want
this destroyed til last. If both regs are used, not much we can do, so
abort. If these becomes a problem, maybe we can do it on the stack? */
if (GET_CODE (operands[0]) == REG
&& regisused (operands[1], REGNO (operands[0])))
{
if (regisused (latehalf[1], REGNO(latehalf[0])))
;
else
dohighfirst++;
}
/* If we're pushing, do the high address part first. */
if (dohighfirst)
{
if (addreg0 != 0 && addreg1 != 0 && rtx_equal_p (addreg0, addreg1))
output_asm_insn ("addl2 $4,%0", &addreg0);
else
{
if (addreg0 != 0)
output_asm_insn ("addl2 $4,%0", &addreg0);
if (addreg1 != 0)
output_asm_insn ("addl2 $4,%0", &addreg1);
}
output_asm_insn (singlemove_string (latehalf), latehalf);
if (addreg0 != 0 && addreg1 != 0 && rtx_equal_p (addreg0, addreg1))
output_asm_insn ("subl2 $4,%0", &addreg0);
else
{
if (addreg0 != 0)
output_asm_insn ("subl2 $4,%0", &addreg0);
if (addreg1 != 0)
output_asm_insn ("subl2 $4,%0", &addreg1);
}
return singlemove_string (operands);
}
output_asm_insn (singlemove_string(operands), operands);
if (addreg0 != 0 && addreg1 != 0 && rtx_equal_p (addreg0, addreg1))
output_asm_insn ("addl2 $4,%0", &addreg0);
else
{
if (addreg0 != 0)
output_asm_insn ("addl2 $4,%0", &addreg0);
if (addreg1 != 0)
output_asm_insn ("addl2 $4,%0", &addreg1);
}
output_asm_insn (singlemove_string (latehalf), latehalf);
if (addreg0 != 0 && addreg1 != 0 && rtx_equal_p(addreg0, addreg1))
output_asm_insn ("subl2 $4,%0", &addreg0);
else
{
if (addreg0 != 0)
output_asm_insn ("subl2 $4,%0", &addreg0);
if (addreg1 != 0)
output_asm_insn ("subl2 $4,%0", &addreg1);
}
if (shftreg0 != 0 && shftreg1 != 0 && rtx_equal_p (shftreg0, shftreg1))
output_asm_insn ("shar $1,%0,%0", &shftreg0);
else
{
if (shftreg0 != 0)
output_asm_insn ("shar $1,%0,%0", &shftreg0);
if (shftreg1 != 0)
output_asm_insn ("shar $1,%0,%0", &shftreg1);
}
return "";
}
/* This checks if a zero_extended cmp[bw] can be replaced by a sign_extended
cmp[bw]. This can be done if the operand is a constant that fits in a
byte/word or a memory operand. Besides that the next instruction must be an
unsigned compare. Some of these tests are done by the machine description */
int
tahoe_cmp_check (insn, op, max)
rtx insn, op;
int max;
{
register rtx next = NEXT_INSN (insn);
if (GET_CODE (op) == CONST_INT
&& (INTVAL (op) < 0 || INTVAL (op) > max))
return 0;
if (INSN_P (next))
{
next = PATTERN (next);
if (GET_CODE (next) == SET
&& SET_DEST (next) == pc_rtx
&& GET_CODE (SET_SRC (next)) == IF_THEN_ELSE)
switch (GET_CODE (XEXP (SET_SRC (next), 0)))
{
case EQ:
case NE:
case LTU:
case GTU:
case LEU:
case GEU:
return 1;
}
}
return 0;
}
/* Definitions of target machine for GNU compiler. Tahoe version.
Copyright (C) 1989, 93, 94, 95, 96, 1998, 1999, 2000 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, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/*
* Original port made at the University of Buffalo by Devon Bowen,
* Dale Wiles and Kevin Zachmann.
*
* HCX/UX version by Piet van Oostrum (piet@cs.ruu.nl)
*
* Performance hacking by Michael Tiemann (tiemann@cygnus.com)
*/
/* define this for the HCX/UX version */
/* #define HCX_UX */
/*
* Run-time Target Specification
*/
#ifdef HCX_UX
/* no predefines, see Makefile and hcx-universe.c */
/* have cc1 print that this is the hcx version */
#define TARGET_VERSION printf (" (hcx)");
#else
/* we want "tahoe" and "unix" defined for all future compilations */
#define CPP_PREDEFINES "-Dtahoe -Dunix -Asystem(unix) -Acpu(tahoe) -Amachine(tahoe)"
/* have cc1 print that this is the tahoe version */
#define TARGET_VERSION printf (" (tahoe)");
#endif
/* this is required in all tm files to hold flags */
extern int target_flags;
/* Zero if it is safe to output .dfloat and .float pseudos. */
#define TARGET_HEX_FLOAT (target_flags & 1)
#define TARGET_DEFAULT 1
#define TARGET_SWITCHES \
{ {"hex-float", 1}, \
{"no-hex-float", -1}, \
{ "", TARGET_DEFAULT} }
/*
* Storage Layout
*/
/* This symbol was previously not mentioned, so apparently the tahoe
is little-endian for bits, or else doesn't care. */
#define BITS_BIG_ENDIAN 0
/* tahoe uses a big endian byte order */
#define BYTES_BIG_ENDIAN 1
/* tahoe uses a big endian word order */
#define WORDS_BIG_ENDIAN 1
/* standard byte size is usable on tahoe */
#define BITS_PER_UNIT 8
/* longs on the tahoe are 4 byte groups */
#define BITS_PER_WORD 32
/* from the last two params we get 4 bytes per word */
#define UNITS_PER_WORD 4
/* addresses are 32 bits (one word) */
#define POINTER_SIZE 32
/* all parameters line up on 32 boundaries */
#define PARM_BOUNDARY 32
/* stack should line up on 32 boundaries */
#define STACK_BOUNDARY 32
/* line functions up on 32 bits */
#define FUNCTION_BOUNDARY 32
/* the biggest alignment the tahoe needs in 32 bits */
#define BIGGEST_ALIGNMENT 32
/* we have to align after an 'int : 0' in a structure */
#define EMPTY_FIELD_BOUNDARY 32
#ifdef HCX_UX
/* structures must be made of full words */
#define STRUCTURE_SIZE_BOUNDARY 32
#else
/* structures must be made of full bytes */
#define STRUCTURE_SIZE_BOUNDARY 8
#endif
/* tahoe is picky about data alignment */
#define STRICT_ALIGNMENT 1
/* keep things standard with pcc */
#define PCC_BITFIELD_TYPE_MATTERS 1
/* this section is borrowed from the vax version since the */
/* formats are the same in both of the architectures */
#define CHECK_FLOAT_VALUE(MODE, D, OVERFLOW) \
if (OVERFLOW) \
(D) = 1.7014117331926443e+38; \
else if ((MODE) == SFmode) \
{ \
if ((D) > 1.7014117331926443e+38) \
(OVERFLOW) = 1, (D) = 1.7014117331926443e+38; \
else if ((D) < -1.7014117331926443e+38) \
(OVERFLOW) = 1, (D) = -1.7014117331926443e+38; \
else if (((D) > 0) && ((D) < 2.9387358770557188e-39)) \
(OVERFLOW) = 1, (D) = 0.0; \
else if (((D) < 0) && ((D) > -2.9387358770557188e-39)) \
(OVERFLOW) = 1, (D) = 0.0; \
}
/*
* Register Usage
*/
/* define 15 general regs plus one for the floating point reg (FPP) */
#define FIRST_PSEUDO_REGISTER 17
/* let the compiler know what the fp, sp and pc are */
#define FIXED_REGISTERS {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0}
/* lots of regs aren't guaranteed to return from a call. The FPP reg */
/* must be included in these since it can't be saved by the reg mask */
#define CALL_USED_REGISTERS {1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1}
/* A single fp reg can handle any type of float.
CPU regs hold just 32 bits. */
#define HARD_REGNO_NREGS(REGNO, MODE) \
(REGNO != 16 ? ((GET_MODE_SIZE(MODE)+UNITS_PER_WORD-1) / UNITS_PER_WORD) \
: GET_MODE_NUNITS ((MODE)))
/* any mode greater than 4 bytes (doubles) can only go in an even regs */
/* and the FPP can only hold SFmode and DFmode */
#define HARD_REGNO_MODE_OK(REGNO, MODE) \
(REGNO != 16 \
? (GET_MODE_UNIT_SIZE (MODE) <= 4 ? 1 : (REGNO % 2 - 1)) \
: ((MODE) == SFmode || (MODE) == DFmode \
|| (MODE) == SCmode || (MODE) == DCmode))
/* if mode1 or mode2, but not both, are doubles then modes cannot be tied */
#define MODES_TIEABLE_P(MODE1, MODE2) \
(((MODE1) == DFmode || (MODE1) == DCmode) \
== ((MODE2) == DFmode || (MODE2) == DCmode))
/* return nonzero if register variable of mode MODE is not
a priori a bad idea. Used only if defined. */
#define MODE_OK_FOR_USERVAR(MODE) \
((MODE) == SImode)
/* the program counter is reg 15 */
#define PC_REGNUM 15
/* the stack pointer is reg 14 */
#define STACK_POINTER_REGNUM 14
/* the frame pointer is reg 13 */
#define FRAME_POINTER_REGNUM 13
/* tahoe does require an fp */
#define FRAME_POINTER_REQUIRED 1
/* since tahoe doesn't have a argument pointer, make it the fp */
#define ARG_POINTER_REGNUM 13
/* this isn't currently used since C doesn't support this feature */
#define STATIC_CHAIN_REGNUM 0
/* we'll use reg 1 for structure passing cause the destination */
/* of the eventual movblk requires it to be there anyway. */
#define STRUCT_VALUE_REGNUM 1
/*
* Register Classes
*/
/* tahoe has two types of regs. GENERAL_REGS are all the regs up */
/* to number 15. FPP_REG is the special floating point processor */
/* register class (only one reg). */
enum reg_class {NO_REGS,GENERAL_REGS,FPP_REG,ALL_REGS,LIM_REG_CLASSES};
/* defines the number of reg classes. */
#define N_REG_CLASSES (int) LIM_REG_CLASSES
/* this defines what the classes are officially named for debugging */
#define REG_CLASS_NAMES \
{"NO_REGS","GENERAL_REGS","FPP_REG","ALL_REGS"}
/* set general regs to be the first 16 regs and the fpp reg to be 17th */
#define REG_CLASS_CONTENTS {0,0xffff,0x10000,0x1ffff}
/* register class for the fpp reg is FPP_REG, all others are GENERAL_REGS */
#define REGNO_REG_CLASS(REGNO) (REGNO == 16 ? FPP_REG : GENERAL_REGS)
/* only general registers can be used as a base reg */
#define BASE_REG_CLASS GENERAL_REGS
/* only general registers can be used to index */
#define INDEX_REG_CLASS GENERAL_REGS
/* 'a' as a constraint in the md file means the FFP_REG class */
#define REG_CLASS_FROM_LETTER(C) (C == 'a' ? FPP_REG : NO_REGS)
/* any general reg but the fpp can be a base reg */
#define REGNO_OK_FOR_BASE_P(regno) \
((regno) < FIRST_PSEUDO_REGISTER - 1 || reg_renumber[regno] >= 0)
/* any general reg except the pc and fpp can be an index reg */
#define REGNO_OK_FOR_INDEX_P(regno) \
((regno) < FIRST_PSEUDO_REGISTER - 2 || reg_renumber[regno] >= 0)
/* if your loading a floating point constant, it can't be done */
/* through a register. Force it to be a memory constant. */
#define PREFERRED_RELOAD_CLASS(X,CLASS) \
((GET_CODE (X) == CONST_DOUBLE) ? NO_REGS : CLASS)
/* for the fpp reg, all modes fit; for any others, you need two for doubles */
#define CLASS_MAX_NREGS(CLASS, MODE) \
(CLASS != FPP_REG ? ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) : 1)
/* we don't define any special constant sizes so all should fail */
#define CONST_OK_FOR_LETTER_P(VALUE, C) 0
/* we don't define any special double sizes so all should fail */
#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) 0
/*
* Describing Stack Layout
*/
/* tahoe stack grows from high to low memory */
#define STACK_GROWS_DOWNWARD
/* Define this if longjmp restores from saved registers
rather than from what setjmp saved. */
#define LONGJMP_RESTORE_FROM_STACK
/* tahoe call frames grow from high to low memory on the stack */
#define FRAME_GROWS_DOWNWARD
/* the tahoe fp points to the *top* of the frame instead of the */
/* bottom, so we have to make this offset a constant large enough */
/* to jump over the biggest frame possible. */
#define STARTING_FRAME_OFFSET -52
/* tahoe always pushes 4 bytes unless it's a double in which case */
/* it pushes a full 8 bytes. */
#define PUSH_ROUNDING(BYTES) (BYTES <= 4 ? 4 : 8)
/* the first parameter in a function is at the fp + 4 */
#define FIRST_PARM_OFFSET(FNDECL) 4
/* the tahoe return function takes care of everything on the stack */
#define RETURN_POPS_ARGS(FUNDECL,FUNTYPE,SIZE) (SIZE)
/* function values for all types are returned in register 0 */
#define FUNCTION_VALUE(VALTYPE, FUNC) \
gen_rtx_REG (TYPE_MODE (VALTYPE), 0)
/* library routines also return things in reg 0 */
#define LIBCALL_VALUE(MODE) gen_rtx_REG (MODE, 0)
/* Tahoe doesn't return structures in a reentrant way */
#define PCC_STATIC_STRUCT_RETURN
/* we only return values from a function in reg 0 */
#define FUNCTION_VALUE_REGNO_P(N) ((N) == 0)
/* we never pass args through a register */
#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) 0
/* int is fine to hold the argument summary in FUNCTION_ARG */
#define CUMULATIVE_ARGS int
/* we just set CUM to 0 before the FUNCTION_ARG call. No matter what */
/* we make it, FUNCTION_ARG will return 0 anyway */
#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE,LIBNAME,INDIRECT) \
((CUM) = 0)
/* all modes push their size rounded to the nearest word boundary */
/* except block which is the size of the block rounded up */
#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \
((CUM) += ((MODE) != BLKmode \
? (GET_MODE_SIZE (MODE) + 3) & ~3 \
: (int_size_in_bytes (TYPE) + 3) & ~3))
/* this is always false since we never pass params in regs */
#define FUNCTION_ARG_REGNO_P(N) 0
/* this code calculates the register entry mask and sets up */
/* the stack pointer for the function. The stack is set down */
/* far enough from the fp to jump over any push regs and local */
/* vars. This is a problem since the tahoe has the fp pointing */
/* to the top of the frame and the compiler must know the off- */
/* set off the fp to the local vars. */
#define FUNCTION_PROLOGUE(FILE, SIZE) \
{ register int regno; \
register int mask = 0; \
extern char call_used_regs[]; \
for (regno = 0; regno < FIRST_PSEUDO_REGISTER-1; regno++) \
if (regs_ever_live[regno] && !call_used_regs[regno]) \
mask |= 1 << regno; \
fprintf (FILE, "\t.word 0x%x\n", mask); \
if (SIZE != 0) fprintf (FILE, "\tsubl3 $%d,fp,sp\n", (SIZE) - STARTING_FRAME_OFFSET); }
/* Zero out global variable in case it was used in this function. */
#define FUNCTION_EPILOGUE(FILE, SIZE) \
{ extern rtx tahoe_reg_conversion_loc; \
tahoe_reg_conversion_loc = 0; \
}
#ifdef HCX_UX
/* to call the profiler, the address of the counter var is placed */
/* on the stack and then passed into mcount this way */
#define FUNCTION_PROFILER(FILE, LABELNO) \
fprintf (FILE, "\tpushal LP%d\n\tcallf $8,mcount\n", (LABELNO));
#else
/* to call the profiler, push the variable value onto the stack */
/* and call mcount like a regular function. */
#define FUNCTION_PROFILER(FILE, LABELNO) \
fprintf (FILE, "\tpushl $LP%d\n\tcallf $8,mcount\n", (LABELNO));
#endif
/* all stack handling at the end of a function is handled by the */
/* return command. */
#define EXIT_IGNORE_STACK 1
/*
* Library Subroutine Names
*/
/* udiv is a valid C library routine in libc.a, so we call that */
#define UDIVSI3_LIBCALL "*udiv"
/* urem is a valid C library routine in libc.a, so we call that */
/* but not so on hcx/ux */
#ifdef HCX_UX
#undef UMODSI3_LIBCALL
#else
#define UMODSI3_LIBCALL "*urem"
#endif
/*
* Addressing Modes
*/
/* constant addresses can be treated exactly the same as normal constants */
#define CONSTANT_ADDRESS_P(X) \
(GET_CODE (X) == LABEL_REF || GET_CODE (X) == SYMBOL_REF \
|| GET_CODE (X) == CONST_INT || GET_CODE (X) == CONST \
|| GET_CODE (X) == HIGH)
/* we can have as many as two regs in any given address */
#define MAX_REGS_PER_ADDRESS 2
/* The following is all the code for GO_IF_LEGITIMATE_ADDRESS */
/* most of this taken directly from the vax tm file since the */
/* tahoe and vax addressing modes are nearly identical. */
/* Is x an indirectable address? */
#define INDIRECTABLE_ADDRESS_P(X) \
(CONSTANT_ADDRESS_P (X) \
|| (GET_CODE (X) == REG && REG_OK_FOR_BASE_P (X)) \
|| (GET_CODE (X) == PLUS \
&& GET_CODE (XEXP (X, 0)) == REG \
&& REG_OK_FOR_BASE_P (XEXP (X, 0)) \
&& CONSTANT_ADDRESS_P (XEXP (X, 1))))
/* If x is a non-indexed-address, go to ADDR. */
#define GO_IF_NONINDEXED_ADDRESS(X, ADDR) \
{ register rtx xfoob = (X); \
if (GET_CODE (xfoob) == REG) goto ADDR; \
if (INDIRECTABLE_ADDRESS_P (xfoob)) goto ADDR; \
xfoob = XEXP (X, 0); \
if (GET_CODE (X) == MEM && INDIRECTABLE_ADDRESS_P (xfoob)) \
goto ADDR; \
if ((GET_CODE (X) == PRE_DEC || GET_CODE (X) == POST_INC) \
&& GET_CODE (xfoob) == REG && REGNO (xfoob) == 14) \
goto ADDR; }
/* Is PROD an index term in mode MODE. */
#define INDEX_TERM_P(PROD, MODE) \
(GET_MODE_SIZE (MODE) == 1 \
? (GET_CODE (PROD) == REG && REG_OK_FOR_BASE_P (PROD)) \
: (GET_CODE (PROD) == MULT \
&& \
(xfoo0 = XEXP (PROD, 0), xfoo1 = XEXP (PROD, 1), \
((GET_CODE (xfoo0) == CONST_INT \
&& INTVAL (xfoo0) == GET_MODE_SIZE (MODE) \
&& GET_CODE (xfoo1) == REG \
&& REG_OK_FOR_INDEX_P (xfoo1)) \
|| \
(GET_CODE (xfoo1) == CONST_INT \
&& INTVAL (xfoo1) == GET_MODE_SIZE (MODE) \
&& GET_CODE (xfoo0) == REG \
&& REG_OK_FOR_INDEX_P (xfoo0))))))
/* Is the addition to the index a reg? */
#define GO_IF_REG_PLUS_INDEX(X, MODE, ADDR) \
{ register rtx xfooa; \
if (GET_CODE (X) == PLUS) \
{ if (GET_CODE (XEXP (X, 0)) == REG \
&& REG_OK_FOR_BASE_P (XEXP (X, 0)) \
&& (xfooa = XEXP (X, 1), \
INDEX_TERM_P (xfooa, MODE))) \
goto ADDR; \
if (GET_CODE (XEXP (X, 1)) == REG \
&& REG_OK_FOR_BASE_P (XEXP (X, 1)) \
&& (xfooa = XEXP (X, 0), \
INDEX_TERM_P (xfooa, MODE))) \
goto ADDR; } }
/* Is the rtx X a valid memory address for operand of mode MODE? */
/* If it is, go to ADDR */
#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \
{ register rtx xfoo, xfoo0, xfoo1; \
GO_IF_NONINDEXED_ADDRESS (X, ADDR); \
if (GET_CODE (X) == PLUS) \
{ xfoo = XEXP (X, 0); \
if (INDEX_TERM_P (xfoo, MODE)) \
{ GO_IF_NONINDEXED_ADDRESS (XEXP (X, 1), ADDR); } \
xfoo = XEXP (X, 1); \
if (INDEX_TERM_P (xfoo, MODE)) \
{ GO_IF_NONINDEXED_ADDRESS (XEXP (X, 0), ADDR); } \
if (CONSTANT_ADDRESS_P (XEXP (X, 0))) \
{ if (GET_CODE (XEXP (X, 1)) == REG \
&& REG_OK_FOR_BASE_P (XEXP (X, 1))) \
goto ADDR; \
GO_IF_REG_PLUS_INDEX (XEXP (X, 1), MODE, ADDR); } \
if (CONSTANT_ADDRESS_P (XEXP (X, 1))) \
{ if (GET_CODE (XEXP (X, 0)) == REG \
&& REG_OK_FOR_BASE_P (XEXP (X, 0))) \
goto ADDR; \
GO_IF_REG_PLUS_INDEX (XEXP (X, 0), MODE, ADDR); } } }
/* Register 16 can never be used for index or base */
#ifndef REG_OK_STRICT
#define REG_OK_FOR_INDEX_P(X) (REGNO(X) != 16)
#define REG_OK_FOR_BASE_P(X) (REGNO(X) != 16)
#else
#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P (REGNO (X))
#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P (REGNO (X))
#endif
/* Addressing is too simple to allow optimizing here */
#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN) {}
/* Post_inc and pre_dec always adds 4 */
#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL) \
{ if (GET_CODE(ADDR) == POST_INC || GET_CODE(ADDR) == PRE_DEC) \
goto LABEL; \
if (GET_CODE (ADDR) == PLUS) \
{ if (CONSTANT_ADDRESS_P (XEXP (ADDR, 0)) \
&& GET_CODE (XEXP (ADDR, 1)) == REG); \
else if (CONSTANT_ADDRESS_P (XEXP (ADDR, 1)) \
&& GET_CODE (XEXP (ADDR, 0)) == REG); \
else goto LABEL; }}
/* Double's are not legitimate as immediate operands */
#define LEGITIMATE_CONSTANT_P(X) \
(GET_CODE (X) != CONST_DOUBLE)
/*
* Miscellaneous Parameters
*/
/* the elements in the case jump table are all words */
#define CASE_VECTOR_MODE HImode
/* Define as C expression which evaluates to nonzero if the tablejump
instruction expects the table to contain offsets from the address of the
table.
Do not define this if the table should contain absolute addresses. */
#define CASE_VECTOR_PC_RELATIVE 1
/* tahoe case instructions just fall through to the next instruction */
/* if not satisfied. It doesn't support a default action */
#define CASE_DROPS_THROUGH
/* the standard answer is given here and work ok */
#define IMPLICIT_FIX_EXPR FIX_ROUND_EXPR
/* in a general div case, it's easiest to use TRUNC_DIV_EXPR */
#define EASY_DIV_EXPR TRUNC_DIV_EXPR
/* the standard seems to be leaving char's as signed so we left it */
/* this way even though we think they should be unsigned! */
#define DEFAULT_SIGNED_CHAR 1
/* the most we can move without cutting down speed is 4 bytes */
#define MOVE_MAX 4
/* our int is 32 bits */
#define INT_TYPE_SIZE 32
/* byte access isn't really slower than anything else */
#define SLOW_BYTE_ACCESS 0
/* zero extension is more than one instruction so try to avoid it */
#define SLOW_ZERO_EXTEND
/* any bits higher than the low 4 are ignored in the shift count */
/* so don't bother zero extending or sign extending them */
#define SHIFT_COUNT_TRUNCATED 1
/* we don't need to officially convert from one fixed type to another */
/* in order to use it as that type. We can just assume it's the same */
#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1
/* pass chars as ints */
#define PROMOTE_PROTOTYPES 1
/* pointers can be represented by an si mode expression */
#define Pmode SImode
/* function addresses are made by specifying a byte address */
#define FUNCTION_MODE QImode
/* Define this if addresses of constant functions
shouldn't be put through pseudo regs where they can be cse'd.
On the tahoe a call with a constant address is much faster than one with a
register. */
#define NO_FUNCTION_CSE
/* specify the costs of various sorts of constants,
and also indicate that multiplication is cheap on this machine. */
#define CONST_COSTS(RTX,CODE,OUTER_CODE) \
case CONST_INT: \
/* Constant zero is super cheap due to clr instruction. */ \
if (RTX == const0_rtx) return 0; \
if ((unsigned) INTVAL (RTX) < 077) return 1; \
if (INTVAL (RTX) <= 127 && INTVAL (RTX) >= -128) return 2; \
case CONST: \
case LABEL_REF: \
case SYMBOL_REF: \
return 3; \
case CONST_DOUBLE: \
return 5; \
case MULT: \
total = 2;
/*
* Condition Code Information
*/
/* Nonzero if the results of the previous comparison are
in the floating point condition code register. */
#define CC_UNCHANGED 04000
#define NOTICE_UPDATE_CC(EXP, INSN) \
{ if (cc_status.flags & CC_UNCHANGED) \
/* Happens for cvtld and a few other insns. */ \
cc_status.flags &= ~CC_UNCHANGED; \
else if (GET_CODE (EXP) == SET) \
{ if (GET_CODE (SET_SRC (EXP)) == CALL) \
CC_STATUS_INIT; \
else if (GET_CODE (SET_DEST (EXP)) != PC) \
{ cc_status.flags = 0; \
cc_status.value1 = SET_DEST (EXP); \
cc_status.value2 = SET_SRC (EXP); } } \
else if (GET_CODE (EXP) == PARALLEL \
&& GET_CODE (XVECEXP (EXP, 0, 0)) == SET \
&& GET_CODE (SET_DEST (XVECEXP (EXP, 0, 0))) != PC) \
{ cc_status.flags = 0; \
cc_status.value1 = SET_DEST (XVECEXP (EXP, 0, 0)); \
cc_status.value2 = SET_SRC (XVECEXP (EXP, 0, 0)); } \
/* PARALLELs whose first element sets the PC are aob, sob insns. \
They do change the cc's. So drop through and forget the cc's. */ \
else CC_STATUS_INIT; \
if (cc_status.value1 && GET_CODE (cc_status.value1) == REG \
&& cc_status.value2 \
&& reg_overlap_mentioned_p (cc_status.value1, cc_status.value2)) \
cc_status.value2 = 0; \
if (cc_status.value1 && GET_CODE (cc_status.value1) == MEM \
&& cc_status.value2 \
&& GET_CODE (cc_status.value2) == MEM) \
cc_status.value2 = 0; }
/* Actual condition, one line up, should be that value2's address
depends on value1, but that is too much of a pain. */
/*
* Output of Assembler Code
*/
/* print which tahoe version compiled this code and print a directive */
/* to the gnu assembler to say that the following is normal assembly */
#ifdef HCX_UX
#define ASM_FILE_START(FILE) \
{ fprintf (FILE, "#gcc hcx 1.0\n\n"); \
output_file_directive ((FILE), main_input_filename);} while (0)
#else
#define ASM_FILE_START(FILE) fprintf (FILE, "#gcc tahoe 1.0\n#NO_APP\n");
#endif
/* the instruction that turns on the APP for the gnu assembler */
#define ASM_APP_ON "#APP\n"
/* the instruction that turns off the APP for the gnu assembler */
#define ASM_APP_OFF "#NO_APP\n"
/* what to output before read-only data. */
#define TEXT_SECTION_ASM_OP "\t.text"
/* what to output before writable data. */
#define DATA_SECTION_ASM_OP "\t.data"
/* this is what we call each of the regs. notice that the FPP reg is */
/* called "ac". This should never get used due to the way we've set */
/* up FPP instructions in the md file. But we call it "ac" here to */
/* fill the list. */
#define REGISTER_NAMES \
{"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", \
"r9", "r10", "r11", "r12", "fp", "sp", "pc", "ac"}
#ifdef HCX_UX
/* allow generation of sdb info in the assembly */
#define SDB_DEBUGGING_INFO
#else
/* allow generation of dbx info in the assembly */
#define DBX_DEBUGGING_INFO
/* our dbx doesn't support this */
#define DBX_NO_XREFS
/* we don't want symbols broken up */
#define DBX_CONTIN_LENGTH 0
/* this'll really never be used, but we'll leave it at this */
#define DBX_CONTIN_CHAR '?'
#endif /* HCX_UX */
/* registers are called the same thing in dbx anything else */
/* This is necessary even if we generate SDB output */
#define DBX_REGISTER_NUMBER(REGNO) (REGNO)
/* labels are the label followed by a colon and a newline */
/* must be a statement, so surround it in a null loop */
#define ASM_OUTPUT_LABEL(FILE,NAME) \
do { assemble_name (FILE, NAME); fputs (":\n", FILE); } while (0)
/* use the .globl directive to make labels global for the linker */
#define ASM_GLOBALIZE_LABEL(FILE,NAME) \
do { fputs (".globl ", FILE); assemble_name (FILE, NAME); fputs ("\n", FILE);} while (0)
/* The prefix to add to user-visible assembler symbols. */
#define USER_LABEL_PREFIX "_"
/* use the standard format for printing internal labels */
#define ASM_OUTPUT_INTERNAL_LABEL(FILE,PREFIX,NUM) \
fprintf (FILE, "%s%d:\n", PREFIX, NUM)
/* a * is used for label indirection in unix assembly */
#define ASM_GENERATE_INTERNAL_LABEL(LABEL,PREFIX,NUM) \
sprintf (LABEL, "*%s%d", PREFIX, NUM)
/* outputting a double is easy cause we only have one kind */
#ifdef HCX_UX
#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \
fprintf (FILE, "\t.double 0d%.20e\n", (VALUE))
#else
#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \
{ \
union { int i[2]; double d;} temp; \
temp.d = (VALUE); \
if (TARGET_HEX_FLOAT) \
fprintf ((FILE), "\t.long 0x%x,0x%x # %.20e\n", \
temp.i[0], temp.i[1], temp.d); \
else \
fprintf (FILE, "\t.dfloat 0d%.20e\n", temp.d); \
}
#endif
/* This is how to output an assembler line defining a `float' constant. */
#ifdef HCX_UX
#define ASM_OUTPUT_FLOAT(FILE,VALUE) \
fprintf (FILE, "\t.float 0f%.20e\n", (VALUE))
#else
#define ASM_OUTPUT_FLOAT(FILE,VALUE) \
{ \
union { int i; float f;} temp; \
temp.f = (float) (VALUE); \
if (TARGET_HEX_FLOAT) \
fprintf ((FILE), "\t.long 0x%x # %.20e\n", \
temp.i, temp.f); \
else \
fprintf (FILE, "\t.float 0f%.20e\n", temp.f); \
}
#endif
/* This is how to output an assembler line defining an `int' constant. */
#define ASM_OUTPUT_INT(FILE,VALUE) \
( fprintf (FILE, "\t.long "), \
output_addr_const (FILE, (VALUE)), \
fprintf (FILE, "\n"))
/* Likewise for `char' and `short' constants. */
#define ASM_OUTPUT_SHORT(FILE,VALUE) \
( fprintf (FILE, "\t.word "), \
output_addr_const (FILE, (VALUE)), \
fprintf (FILE, "\n"))
#define ASM_OUTPUT_CHAR(FILE,VALUE) \
( fprintf (FILE, "\t.byte "), \
output_addr_const (FILE, (VALUE)), \
fprintf (FILE, "\n"))
#ifdef HCX_UX
/* This is how to output an assembler line for an ASCII string. */
#define ASM_OUTPUT_ASCII(FILE, p, size) \
do { register int i; \
fprintf ((FILE), "\t.ascii \""); \
for (i = 0; i < (size); i++) \
{ \
register int c = (p)[i]; \
if (c == '\'' || c == '\\') \
putc ('\\', (FILE)); \
if (c >= ' ' && c < 0177 && c != '\"') \
putc (c, (FILE)); \
else \
{ \
fprintf ((FILE), "\\%03o", c); \
} \
} \
fprintf ((FILE), "\"\n"); } while (0)
#endif
/* This is how to output an assembler line for a numeric constant byte. */
#define ASM_OUTPUT_BYTE(FILE,VALUE) \
fprintf (FILE, "\t.byte 0x%x\n", (VALUE))
/* this is the insn to push a register onto the stack */
#define ASM_OUTPUT_REG_PUSH(FILE,REGNO) \
fprintf (FILE, "\tpushl %s\n", reg_names[REGNO])
/* this is the insn to pop a register from the stack */
#define ASM_OUTPUT_REG_POP(FILE,REGNO) \
fprintf (FILE, "\tmovl (sp)+,%s\n", reg_names[REGNO])
/* this is required even thought tahoe doesn't support it */
/* cause the C code expects it to be defined */
#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \
fprintf (FILE, "\t.long L%d\n", VALUE)
/* This is how to output an element of a case-vector that is relative. */
#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \
fprintf (FILE, "\t.word L%d-L%d\n", VALUE, REL)
/* This is how to output an assembler line
that says to advance the location counter
to a multiple of 2**LOG bytes. */
#ifdef HCX_UX
#define CASE_ALIGNMENT 2
#define ASM_OUTPUT_ALIGN(FILE,LOG) \
if ((LOG)!=0) fprintf ((FILE), "\t.align %d\n", 1<<(LOG))
#else
#define CASE_ALIGNMENT 1
#define ASM_OUTPUT_ALIGN(FILE,LOG) \
LOG ? fprintf (FILE, "\t.align %d\n", (LOG)) : 0
#endif
/* This is how to skip over some space */
#define ASM_OUTPUT_SKIP(FILE,SIZE) \
fprintf (FILE, "\t.space %u\n", (SIZE))
/* This defines common variables across files */
#ifdef HCX_UX
#define ASM_OUTPUT_COMMON(FILE, NAME, SIZE, ROUNDED) \
( fputs (".comm ", (FILE)), \
assemble_name ((FILE), (NAME)), \
fprintf ((FILE), ",%u\n", (SIZE)))
#else
#define ASM_OUTPUT_COMMON(FILE, NAME, SIZE, ROUNDED) \
( fputs (".comm ", (FILE)), \
assemble_name ((FILE), (NAME)), \
fprintf ((FILE), ",%u\n", (ROUNDED)))
#endif
/* This says how to output an assembler line
to define a local common symbol. */
#ifdef HCX_UX
#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \
( fputs ("\t.bss ", (FILE)), \
assemble_name ((FILE), (NAME)), \
fprintf ((FILE), ",%u,4\n", (SIZE),(ROUNDED)))
#else
#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \
( fputs (".lcomm ", (FILE)), \
assemble_name ((FILE), (NAME)), \
fprintf ((FILE), ",%u\n", (ROUNDED)))
#endif
/* code to generate a label */
#define ASM_FORMAT_PRIVATE_NAME(OUTPUT, NAME, LABELNO) \
( (OUTPUT) = (char *) alloca (strlen ((NAME)) + 10), \
sprintf ((OUTPUT), "%s.%d", (NAME), (LABELNO)))
/* Define the parentheses used to group arithmetic operations
in assembler code. */
#define ASM_OPEN_PAREN "("
#define ASM_CLOSE_PAREN ")"
/* Define results of standard character escape sequences. */
#define TARGET_BELL 007
#define TARGET_BS 010
#define TARGET_TAB 011
#define TARGET_NEWLINE 012
#define TARGET_VT 013
#define TARGET_FF 014
#define TARGET_CR 015
/* Print an instruction operand X on file FILE.
CODE is the code from the %-spec that requested printing this operand;
if `%z3' was used to print operand 3, then CODE is 'z'.
On the Vax, the only code used is `#', indicating that either
`d' or `g' should be printed, depending on whether we're using dfloat
or gfloat. */
/* Print an operand. Some difference from the vax code,
since the tahoe can't support immediate floats and doubles.
%@ means print the proper alignment operand for aligning after a casesi.
This depends on the assembler syntax.
This is 1 for our assembler, since .align is logarithmic.
%s means the number given is supposed to be a shift value, but on
the tahoe it should be converted to a number that can be used as a
multiplicative constant (cause multiplication is a whole lot faster
than shifting). So make the number 2^n instead. */
#define PRINT_OPERAND_PUNCT_VALID_P(CODE) \
((CODE) == '@')
#define PRINT_OPERAND(FILE, X, CODE) \
{ if (CODE == '@') \
putc ('0' + CASE_ALIGNMENT, FILE); \
else if (CODE == 's') \
fprintf (FILE, "$%d", 1 << INTVAL(X)); \
else if (GET_CODE (X) == REG) \
fprintf (FILE, "%s", reg_names[REGNO (X)]); \
else if (GET_CODE (X) == MEM) \
output_address (XEXP (X, 0)); \
else { putc ('$', FILE); output_addr_const (FILE, X); }}
/* When the operand is an address, call print_operand_address to */
/* do the work from output-tahoe.c. */
#define PRINT_OPERAND_ADDRESS(FILE, ADDR) \
print_operand_address (FILE, ADDR)
/* This is for G++ */
#define CRT0_DUMMIES
#define DOT_GLOBAL_START
#ifdef HCX_UX
#define NO_GNU_LD /* because of COFF format */
#define LINK_SPEC "-L/usr/staff/lib"
#endif
;; Machine description for GNU compiler, Tahoe version
;; Copyright (C) 1989, 1994, 1996, 1997, 1998, 1999
;; 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, 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.
; File: tahoe.md
;
; Original port made at the University of Buffalo by Devon Bowen,
; Dale Wiles and Kevin Zachmann.
;
; Piet van Oostrum (piet@cs.ruu.nl) made changes for HCX/UX, fixed
; some bugs and made some improvements (hopefully).
;
; Mail bugs reports or fixes to: gcc@cs.buffalo.edu
; movdi must call the output_move_double routine to move it around since
; the tahoe doesn't efficiently support 8 bit moves.
(define_insn "movdi"
[(set (match_operand:DI 0 "general_operand" "=g")
(match_operand:DI 1 "general_operand" "g"))]
""
"*
{
CC_STATUS_INIT;
return output_move_double (operands);
}")
; the trick in the movsi is accessing the contents of the sp register. The
; tahoe doesn't allow you to access it directly so you have to access the
; address of the top of the stack instead.
(define_insn "movsi"
[(set (match_operand:SI 0 "general_operand" "=g")
(match_operand:SI 1 "general_operand" "g"))]
""
"*
{
rtx link;
if (operands[1] == const1_rtx
&& (link = find_reg_note (insn, REG_WAS_0, 0))
&& ! INSN_DELETED_P (XEXP (link, 0))
&& GET_CODE (XEXP (link, 0)) != NOTE
&& no_labels_between_p (XEXP (link, 0), insn)
/* Make sure the reg hasn't been clobbered. */
&& ! reg_set_between_p (operands[0], XEXP (link, 0), insn))
return \"incl %0\";
if (GET_CODE (operands[1]) == SYMBOL_REF || GET_CODE (operands[1]) == CONST)
{
if (push_operand (operands[0], SImode))
return \"pushab %a1\";
return \"movab %a1,%0\";
}
if (operands[1] == const0_rtx)
return \"clrl %0\";
if (push_operand (operands[0], SImode))
return \"pushl %1\";
if (GET_CODE(operands[1]) == REG && REGNO(operands[1]) == 14)
return \"moval (sp),%0\";
return \"movl %1,%0\";
}")
(define_insn "movhi"
[(set (match_operand:HI 0 "general_operand" "=g")
(match_operand:HI 1 "general_operand" "g"))]
""
"*
{
rtx link;
if (operands[1] == const1_rtx
&& (link = find_reg_note (insn, REG_WAS_0, 0))
&& ! INSN_DELETED_P (XEXP (link, 0))
&& GET_CODE (XEXP (link, 0)) != NOTE
&& no_labels_between_p (XEXP (link, 0), insn)
/* Make sure the reg hasn't been clobbered. */
&& ! reg_set_between_p (operands[0], XEXP (link, 0), insn))
return \"incw %0\";
if (operands[1] == const0_rtx)
return \"clrw %0\";
return \"movw %1,%0\";
}")
(define_insn "movqi"
[(set (match_operand:QI 0 "general_operand" "=g")
(match_operand:QI 1 "general_operand" "g"))]
""
"*
{
if (operands[1] == const0_rtx)
return \"clrb %0\";
return \"movb %1,%0\";
}")
; movsf has three cases since they can move from one place to another
; or to/from the fpp and since different instructions are needed for
; each case. The fpp related instructions don't set the flags properly.
(define_insn "movsf"
[(set (match_operand:SF 0 "general_operand" "=g,=a,=g")
(match_operand:SF 1 "general_operand" "g,g,a"))]
""
"*
{
CC_STATUS_INIT;
switch (which_alternative)
{
case 0: return \"movl %1,%0\";
case 1: return \"ldf %1\";
case 2: return \"stf %0\";
}
}")
; movdf has a number of different cases. If it's going to or from
; the fpp, use the special instructions to do it. If not, use the
; output_move_double function.
(define_insn "movdf"
[(set (match_operand:DF 0 "general_operand" "=a,=g,?=g")
(match_operand:DF 1 "general_operand" "g,a,g"))]
""
"*
{
CC_STATUS_INIT;
switch (which_alternative)
{
case 0:
return \"ldd %1\";
case 1:
if (push_operand (operands[0], DFmode))
return \"pushd\";
else
return \"std %0\";
case 2:
return output_move_double (operands);
}
}")
;========================================================================
; The tahoe has the following semantics for byte (and similar for word)
; operands: if the operand is a register or immediate, it takes the full 32
; bit operand, if the operand is memory, it sign-extends the byte. The
; operation is performed on the 32 bit values. If the destination is a
; register, the full 32 bit result is stored, if the destination is memory,
; of course only the low part is stored. The condition code is based on the
; 32 bit operation. Only on the movz instructions the byte from memory is
; zero-extended rather than sign-extended.
; This means that for arithmetic instructions we can use addb etc. to
; perform a long add from a signed byte from memory to a register. Of
; course this would also work for logical operations, but that doesn't seem
; very useful.
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(plus:SI (sign_extend:SI (match_operand:QI 1 "memory_operand" "m"))
(sign_extend:SI (match_operand:QI 2 "memory_operand" "m"))))]
""
"addb3 %1,%2,%0")
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(plus:SI (match_operand:SI 1 "nonmemory_operand" "%ri")
(sign_extend:SI (match_operand:QI 2 "memory_operand" "m"))))]
""
"*
{
if (rtx_equal_p (operands[0], operands[1]))
return \"addb2 %2,%0\";
return \"addb3 %1,%2,%0\";
}")
; We can also consider the result to be a half integer
(define_insn ""
[(set (match_operand:HI 0 "register_operand" "=r")
(plus:HI (sign_extend:HI (match_operand:QI 1 "memory_operand" "m"))
(sign_extend:HI (match_operand:QI 2 "memory_operand" "m"))))]
""
"addb3 %1,%2,%0")
(define_insn ""
[(set (match_operand:HI 0 "register_operand" "=r")
(plus:HI (match_operand:HI 1 "nonmemory_operand" "%ri")
(sign_extend:HI (match_operand:QI 2 "memory_operand" "m"))))]
""
"*
{
if (rtx_equal_p (operands[0], operands[1]))
return \"addb2 %2,%0\";
return \"addb3 %1,%2,%0\";
}")
; The same applies to words (HI)
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(plus:SI (sign_extend:SI (match_operand:HI 1 "memory_operand" "m"))
(sign_extend:SI (match_operand:HI 2 "memory_operand" "m"))))]
""
"addw3 %1,%2,%0")
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(plus:SI (match_operand:SI 1 "nonmemory_operand" "%ri")
(sign_extend:SI (match_operand:HI 2 "memory_operand" "m"))))]
""
"*
{
if (rtx_equal_p (operands[0], operands[1]))
return \"addw2 %2,%0\";
return \"addw3 %1,%2,%0\";
}")
; ======================= Now for subtract ==============================
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(minus:SI (sign_extend:SI (match_operand:QI 1 "memory_operand" "m"))
(sign_extend:SI (match_operand:QI 2 "memory_operand" "m"))))]
""
"subb3 %2,%1,%0")
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(minus:SI (match_operand:SI 1 "nonmemory_operand" "ri")
(sign_extend:SI (match_operand:QI 2 "memory_operand" "m"))))]
""
"*
{
if (rtx_equal_p (operands[0], operands[1]))
return \"subb2 %2,%0\";
return \"subb3 %2,%1,%0\";
}")
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(minus:SI (sign_extend:SI (match_operand:QI 1 "memory_operand" "m"))
(match_operand:SI 2 "nonmemory_operand" "ri")))]
""
"subb3 %2,%1,%0")
; We can also consider the result to be a half integer
(define_insn ""
[(set (match_operand:HI 0 "register_operand" "=r")
(minus:HI (sign_extend:HI (match_operand:QI 1 "memory_operand" "m"))
(sign_extend:HI (match_operand:QI 2 "memory_operand" "m"))))]
""
"subb3 %2,%1,%0")
(define_insn ""
[(set (match_operand:HI 0 "register_operand" "=r")
(minus:HI (match_operand:HI 1 "nonmemory_operand" "%ri")
(sign_extend:HI (match_operand:QI 2 "memory_operand" "m"))))]
""
"*
{
if (rtx_equal_p (operands[0], operands[1]))
return \"subb2 %2,%0\";
return \"subb3 %2,%1,%0\";
}")
(define_insn ""
[(set (match_operand:HI 0 "register_operand" "=r")
(minus:HI (sign_extend:HI (match_operand:QI 1 "memory_operand" "m"))
(match_operand:HI 2 "nonmemory_operand" "ri")))]
""
"subb3 %2,%1,%0")
; The same applies to words (HI)
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(minus:SI (sign_extend:SI (match_operand:HI 1 "memory_operand" "m"))
(sign_extend:SI (match_operand:HI 2 "memory_operand" "m"))))]
""
"subw3 %2,%1,%0")
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(minus:SI (match_operand:SI 1 "nonmemory_operand" "ri")
(sign_extend:SI (match_operand:HI 2 "memory_operand" "m"))))]
""
"*
{
if (rtx_equal_p (operands[0], operands[1]))
return \"subw2 %2,%0\";
return \"subw3 %2,%1,%0\";
}")
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(minus:SI (sign_extend:SI (match_operand:HI 1 "memory_operand" "m"))
(match_operand:SI 2 "nonmemory_operand" "ri")))]
""
"subw3 %2,%1,%0")
; ======================= Now for neg ==============================
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(neg:SI (sign_extend:SI (match_operand:QI 1 "memory_operand" "m"))))]
""
"mnegb %1,%0")
(define_insn ""
[(set (match_operand:HI 0 "register_operand" "=r")
(neg:HI (sign_extend:HI (match_operand:QI 1 "memory_operand" "m"))))]
""
"mnegb %1,%0")
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(neg:SI (sign_extend:SI (match_operand:HI 1 "memory_operand" "m"))))]
""
"mnegw %1,%0")
;========================================================================
(define_insn "addsi3"
[(set (match_operand:SI 0 "general_operand" "=g")
(plus:SI (match_operand:SI 1 "general_operand" "g")
(match_operand:SI 2 "general_operand" "g")))]
""
"*
{
if (rtx_equal_p (operands[0], operands[1]))
{
if (operands[2] == const1_rtx)
return \"incl %0\";
if (GET_CODE (operands[2]) == CONST_INT
&& INTVAL (operands[2]) == -1)
return \"decl %0\";
if (GET_CODE (operands[2]) == CONST_INT
&& (unsigned) (- INTVAL (operands[2])) < 64)
return \"subl2 $%n2,%0\";
return \"addl2 %2,%0\";
}
if (rtx_equal_p (operands[0], operands[2]))
return \"addl2 %1,%0\";
if (GET_CODE (operands[2]) == CONST_INT
&& GET_CODE (operands[1]) == REG)
{
if (push_operand (operands[0], SImode))
return \"pushab %c2(%1)\";
return \"movab %c2(%1),%0\";
}
if (GET_CODE (operands[2]) == CONST_INT
&& (unsigned) (- INTVAL (operands[2])) < 64)
return \"subl3 $%n2,%1,%0\";
return \"addl3 %1,%2,%0\";
}")
(define_insn "addhi3"
[(set (match_operand:HI 0 "general_operand" "=g")
(plus:HI (match_operand:HI 1 "general_operand" "g")
(match_operand:HI 2 "general_operand" "g")))]
""
"*
{
if (rtx_equal_p (operands[0], operands[1]))
{
if (operands[2] == const1_rtx)
return \"incw %0\";
if (GET_CODE (operands[2]) == CONST_INT
&& INTVAL (operands[2]) == -1)
return \"decw %0\";
if (GET_CODE (operands[2]) == CONST_INT
&& (unsigned) (- INTVAL (operands[2])) < 64)
return \"subw2 $%n2,%0\";
return \"addw2 %2,%0\";
}
if (rtx_equal_p (operands[0], operands[2]))
return \"addw2 %1,%0\";
if (GET_CODE (operands[2]) == CONST_INT
&& (unsigned) (- INTVAL (operands[2])) < 64)
return \"subw3 $%n2,%1,%0\";
return \"addw3 %1,%2,%0\";
}")
(define_insn "addqi3"
[(set (match_operand:QI 0 "general_operand" "=g")
(plus:QI (match_operand:QI 1 "general_operand" "g")
(match_operand:QI 2 "general_operand" "g")))]
""
"*
{
if (rtx_equal_p (operands[0], operands[1]))
{
if (operands[2] == const1_rtx)
return \"incb %0\";
if (GET_CODE (operands[2]) == CONST_INT
&& INTVAL (operands[2]) == -1)
return \"decb %0\";
if (GET_CODE (operands[2]) == CONST_INT
&& (unsigned) (- INTVAL (operands[2])) < 64)
return \"subb2 $%n2,%0\";
return \"addb2 %2,%0\";
}
if (rtx_equal_p (operands[0], operands[2]))
return \"addb2 %1,%0\";
if (GET_CODE (operands[2]) == CONST_INT
&& (unsigned) (- INTVAL (operands[2])) < 64)
return \"subb3 $%n2,%1,%0\";
return \"addb3 %1,%2,%0\";
}")
; addsf3 can only add into the fpp register since the fpp is treated
; as a separate unit in the machine. It also doesn't set the flags at
; all.
(define_insn "addsf3"
[(set (match_operand:SF 0 "register_operand" "=a")
(plus:SF (match_operand:SF 1 "register_operand" "%0")
(match_operand:SF 2 "general_operand" "g")))]
""
"*
{
CC_STATUS_INIT;
return \"addf %2\";
}")
; adddf3 can only add into the fpp reg since the fpp is treated as a
; separate entity. Doubles can only be read from a register or memory
; since a double is not an immediate mode. Flags are not set by this
; instruction.
(define_insn "adddf3"
[(set (match_operand:DF 0 "register_operand" "=a")
(plus:DF (match_operand:DF 1 "register_operand" "%0")
(match_operand:DF 2 "general_operand" "rm")))]
""
"*
{
CC_STATUS_INIT;
return \"addd %2\";
}")
; Subtraction from the sp (needed by the built in alloc function) needs
; to be different since the sp cannot be directly read on the tahoe.
; If it's a simple constant, you just use displacement. Otherwise, you
; push the sp, and then do the subtraction off the stack.
(define_insn "subsi3"
[(set (match_operand:SI 0 "general_operand" "=g")
(minus:SI (match_operand:SI 1 "general_operand" "g")
(match_operand:SI 2 "general_operand" "g")))]
""
"*
{
if (rtx_equal_p (operands[0], operands[1]))
{
if (operands[2] == const1_rtx)
return \"decl %0\";
if (GET_CODE(operands[0]) == REG && REGNO(operands[0]) == 14)
{
if (GET_CODE(operands[2]) == CONST_INT)
return \"movab %n2(sp),sp\";
else
return \"pushab (sp)\;subl3 %2,(sp),sp\";
}
return \"subl2 %2,%0\";
}
if (rtx_equal_p (operands[1], operands[2]))
return \"clrl %0\";
return \"subl3 %2,%1,%0\";
}")
(define_insn "subhi3"
[(set (match_operand:HI 0 "general_operand" "=g")
(minus:HI (match_operand:HI 1 "general_operand" "g")
(match_operand:HI 2 "general_operand" "g")))]
""
"*
{
if (rtx_equal_p (operands[0], operands[1]))
{
if (operands[2] == const1_rtx)
return \"decw %0\";
return \"subw2 %2,%0\";
}
if (rtx_equal_p (operands[1], operands[2]))
return \"clrw %0\";
return \"subw3 %2,%1,%0\";
}")
(define_insn "subqi3"
[(set (match_operand:QI 0 "general_operand" "=g")
(minus:QI (match_operand:QI 1 "general_operand" "g")
(match_operand:QI 2 "general_operand" "g")))]
""
"*
{
if (rtx_equal_p (operands[0], operands[1]))
{
if (operands[2] == const1_rtx)
return \"decb %0\";
return \"subb2 %2,%0\";
}
if (rtx_equal_p (operands[1], operands[2]))
return \"clrb %0\";
return \"subb3 %2,%1,%0\";
}")
; subsf3 can only subtract into the fpp accumulator due to the way
; the fpp reg is limited by the instruction set. This also doesn't
; bother setting up flags.
(define_insn "subsf3"
[(set (match_operand:SF 0 "register_operand" "=a")
(minus:SF (match_operand:SF 1 "register_operand" "0")
(match_operand:SF 2 "general_operand" "g")))]
""
"*
{
CC_STATUS_INIT;
return \"subf %2\";
}")
; subdf3 is set up to subtract into the fpp reg due to limitations
; of the fpp instruction set. Doubles can not be immediate. This
; instruction does not set the flags.
(define_insn "subdf3"
[(set (match_operand:DF 0 "register_operand" "=a")
(minus:DF (match_operand:DF 1 "register_operand" "0")
(match_operand:DF 2 "general_operand" "rm")))]
""
"*
{
CC_STATUS_INIT;
return \"subd %2\";
}")
(define_insn "mulsi3"
[(set (match_operand:SI 0 "general_operand" "=g")
(mult:SI (match_operand:SI 1 "general_operand" "g")
(match_operand:SI 2 "general_operand" "g")))]
""
"*
{
if (rtx_equal_p (operands[0], operands[1]))
return \"mull2 %2,%0\";
if (rtx_equal_p (operands[0], operands[2]))
return \"mull2 %1,%0\";
return \"mull3 %1,%2,%0\";
}")
; mulsf3 can only multiply into the fpp accumulator due to limitations
; of the fpp. It also does not set the condition codes properly.
(define_insn "mulsf3"
[(set (match_operand:SF 0 "register_operand" "=a")
(mult:SF (match_operand:SF 1 "register_operand" "%0")
(match_operand:SF 2 "general_operand" "g")))]
""
"*
{
CC_STATUS_INIT;
return \"mulf %2\";
}")
; muldf3 can only multiply into the fpp reg since the fpp is limited
; from the rest. Doubles may not be immediate mode. This does not set
; the flags like gcc would expect.
(define_insn "muldf3"
[(set (match_operand:DF 0 "register_operand" "=a")
(mult:DF (match_operand:DF 1 "register_operand" "%0")
(match_operand:DF 2 "general_operand" "rm")))]
""
"*
{
CC_STATUS_INIT;
return \"muld %2\";
}")
(define_insn "divsi3"
[(set (match_operand:SI 0 "general_operand" "=g")
(div:SI (match_operand:SI 1 "general_operand" "g")
(match_operand:SI 2 "general_operand" "g")))]
""
"*
{
if (rtx_equal_p (operands[1], operands[2]))
return \"movl $1,%0\";
if (operands[1] == const0_rtx)
return \"clrl %0\";
if (GET_CODE (operands[2]) == CONST_INT
&& INTVAL (operands[2]) == -1)
return \"mnegl %1,%0\";
if (rtx_equal_p (operands[0], operands[1]))
return \"divl2 %2,%0\";
return \"divl3 %2,%1,%0\";
}")
; divsf3 must divide into the fpp accumulator. Flags are not set by
; this instruction, so they are cleared.
(define_insn "divsf3"
[(set (match_operand:SF 0 "register_operand" "=a")
(div:SF (match_operand:SF 1 "register_operand" "0")
(match_operand:SF 2 "general_operand" "g")))]
""
"*
{
CC_STATUS_INIT;
return \"divf %2\";
}")
; divdf3 also must divide into the fpp reg so optimization isn't
; possible. Note that doubles cannot be immediate. The flags here
; are not set correctly so they must be ignored.
(define_insn "divdf3"
[(set (match_operand:DF 0 "register_operand" "=a")
(div:DF (match_operand:DF 1 "register_operand" "0")
(match_operand:DF 2 "general_operand" "rm")))]
""
"*
{
CC_STATUS_INIT;
return \"divd %2\";
}")
(define_insn "andsi3"
[(set (match_operand:SI 0 "general_operand" "=g")
(and:SI (match_operand:SI 1 "general_operand" "g")
(match_operand:SI 2 "general_operand" "g")))]
""
"*
{
if (rtx_equal_p (operands[0], operands[1]))
return \"andl2 %2,%0\";
if (rtx_equal_p (operands[0], operands[2]))
return \"andl2 %1,%0\";
return \"andl3 %2,%1,%0\";
}")
(define_insn "andhi3"
[(set (match_operand:HI 0 "general_operand" "=g")
(and:HI (match_operand:HI 1 "general_operand" "g")
(match_operand:HI 2 "general_operand" "g")))]
""
"*
{
if (rtx_equal_p (operands[0], operands[1]))
return \"andw2 %2,%0\";
if (rtx_equal_p (operands[0], operands[2]))
return \"andw2 %1,%0\";
return \"andw3 %2,%1,%0\";
}")
(define_insn "andqi3"
[(set (match_operand:QI 0 "general_operand" "=g")
(and:QI (match_operand:QI 1 "general_operand" "g")
(match_operand:QI 2 "general_operand" "g")))]
""
"*
{
if (rtx_equal_p (operands[0], operands[1]))
return \"andb2 %2,%0\";
if (rtx_equal_p (operands[0], operands[2]))
return \"andb2 %1,%0\";
return \"andb3 %2,%1,%0\";
}")
(define_insn "iorsi3"
[(set (match_operand:SI 0 "general_operand" "=g")
(ior:SI (match_operand:SI 1 "general_operand" "g")
(match_operand:SI 2 "general_operand" "g")))]
""
"*
{
if (rtx_equal_p (operands[0], operands[1]))
return \"orl2 %2,%0\";
if (rtx_equal_p (operands[0], operands[2]))
return \"orl2 %1,%0\";
return \"orl3 %2,%1,%0\";
}")
(define_insn "iorhi3"
[(set (match_operand:HI 0 "general_operand" "=g")
(ior:HI (match_operand:HI 1 "general_operand" "g")
(match_operand:HI 2 "general_operand" "g")))]
""
"*
{
if (rtx_equal_p (operands[0], operands[1]))
return \"orw2 %2,%0\";
if (rtx_equal_p (operands[0], operands[2]))
return \"orw2 %1,%0\";
return \"orw3 %2,%1,%0\";
}")
(define_insn "iorqi3"
[(set (match_operand:QI 0 "general_operand" "=g")
(ior:QI (match_operand:QI 1 "general_operand" "g")
(match_operand:QI 2 "general_operand" "g")))]
""
"*
{
if (rtx_equal_p (operands[0], operands[1]))
return \"orb2 %2,%0\";
if (rtx_equal_p (operands[0], operands[2]))
return \"orb2 %1,%0\";
return \"orb3 %2,%1,%0\";
}")
(define_insn "xorsi3"
[(set (match_operand:SI 0 "general_operand" "=g")
(xor:SI (match_operand:SI 1 "general_operand" "g")
(match_operand:SI 2 "general_operand" "g")))]
""
"*
{
if (rtx_equal_p (operands[0], operands[1]))
return \"xorl2 %2,%0\";
if (rtx_equal_p (operands[0], operands[2]))
return \"xorl2 %1,%0\";
return \"xorl3 %2,%1,%0\";
}")
(define_insn "xorhi3"
[(set (match_operand:HI 0 "general_operand" "=g")
(xor:HI (match_operand:HI 1 "general_operand" "g")
(match_operand:HI 2 "general_operand" "g")))]
""
"*
{
if (rtx_equal_p (operands[0], operands[1]))
return \"xorw2 %2,%0\";
if (rtx_equal_p (operands[0], operands[2]))
return \"xorw2 %1,%0\";
return \"xorw3 %2,%1,%0\";
}")
(define_insn "xorqi3"
[(set (match_operand:QI 0 "general_operand" "=g")
(xor:QI (match_operand:QI 1 "general_operand" "g")
(match_operand:QI 2 "general_operand" "g")))]
""
"*
{
if (rtx_equal_p (operands[0], operands[1]))
return \"xorb2 %2,%0\";
if (rtx_equal_p (operands[0], operands[2]))
return \"xorb2 %1,%0\";
return \"xorb3 %2,%1,%0\";
}")
; shifts on the tahoe are expensive, try some magic first...
(define_insn "ashlsi3"
[(set (match_operand:SI 0 "general_operand" "=g")
(ashift:SI (match_operand:SI 1 "general_operand" "g")
(match_operand:QI 2 "general_operand" "g")))]
""
"*
{
if (GET_CODE(operands[2]) == REG)
return \"mull3 ___shtab[%2],%1,%0\";
/* if (GET_CODE(operands[2]) == REG)
if (rtx_equal_p (operands[0], operands[1]))
return \"mull2 ___shtab[%2],%1\";
else
return \"mull3 ___shtab[%2],%1,%0\"; */
if (GET_CODE(operands[1]) == REG)
{
if (operands[2] == const1_rtx)
{
CC_STATUS_INIT;
return \"movaw 0[%1],%0\";
}
if (GET_CODE(operands[2]) == CONST_INT && INTVAL(operands[2]) == 2)
{
CC_STATUS_INIT;
return \"moval 0[%1],%0\";
}
}
if (GET_CODE(operands[2]) != CONST_INT || INTVAL(operands[2]) == 1)
return \"shal %2,%1,%0\";
if (rtx_equal_p (operands[0], operands[1]))
return \"mull2 %s2,%1\";
else
return \"mull3 %s2,%1,%0\";
}")
(define_insn "ashrsi3"
[(set (match_operand:SI 0 "general_operand" "=g")
(ashiftrt:SI (match_operand:SI 1 "general_operand" "g")
(match_operand:QI 2 "general_operand" "g")))]
""
"shar %2,%1,%0")
; shifts are very expensive, try some magic first...
(define_insn "lshrsi3"
[(set (match_operand:SI 0 "general_operand" "=g")
(lshiftrt:SI (match_operand:SI 1 "general_operand" "g")
(match_operand:QI 2 "general_operand" "g")))]
""
"shrl %2,%1,%0")
(define_insn "negsi2"
[(set (match_operand:SI 0 "general_operand" "=g")
(neg:SI (match_operand:SI 1 "general_operand" "g")))]
""
"mnegl %1,%0")
(define_insn "neghi2"
[(set (match_operand:HI 0 "general_operand" "=g")
(neg:HI (match_operand:HI 1 "general_operand" "g")))]
""
"mnegw %1,%0")
(define_insn "negqi2"
[(set (match_operand:QI 0 "general_operand" "=g")
(neg:QI (match_operand:QI 1 "general_operand" "g")))]
""
"mnegb %1,%0")
; negsf2 can only negate the value already in the fpp accumulator.
; The value remains in the fpp accumulator. No flags are set.
(define_insn "negsf2"
[(set (match_operand:SF 0 "register_operand" "=a,=a")
(neg:SF (match_operand:SF 1 "register_operand" "a,g")))]
""
"*
{
CC_STATUS_INIT;
switch (which_alternative)
{
case 0: return \"negf\";
case 1: return \"lnf %1\";
}
}")
; negdf2 can only negate the value already in the fpp accumulator.
; The value remains in the fpp accumulator. No flags are set.
(define_insn "negdf2"
[(set (match_operand:DF 0 "register_operand" "=a,=a")
(neg:DF (match_operand:DF 1 "register_operand" "a,g")))]
""
"*
{
CC_STATUS_INIT;
switch (which_alternative)
{
case 0: return \"negd\";
case 1: return \"lnd %1\";
}
}")
; sqrtsf2 tahoe can calculate the square root of a float in the
; fpp accumulator. The answer remains in the fpp accumulator. No
; flags are set by this function.
(define_insn "sqrtsf2"
[(set (match_operand:SF 0 "register_operand" "=a")
(sqrt:SF (match_operand:SF 1 "register_operand" "0")))]
""
"*
{
CC_STATUS_INIT;
return \"sqrtf\";
}")
; ffssi2 tahoe instruction gives one less than gcc desired result for
; any given input. So the increment is necessary here.
(define_insn "ffssi2"
[(set (match_operand:SI 0 "general_operand" "=g")
(ffs:SI (match_operand:SI 1 "general_operand" "g")))]
""
"*
{
if (push_operand(operands[0], SImode))
return \"ffs %1,%0\;incl (sp)\";
return \"ffs %1,%0\;incl %0\";
}")
(define_insn "one_cmplsi2"
[(set (match_operand:SI 0 "general_operand" "=g")
(not:SI (match_operand:SI 1 "general_operand" "g")))]
""
"mcoml %1,%0")
(define_insn "one_cmplhi2"
[(set (match_operand:HI 0 "general_operand" "=g")
(not:HI (match_operand:HI 1 "general_operand" "g")))]
""
"mcomw %1,%0")
(define_insn "one_cmplqi2"
[(set (match_operand:QI 0 "general_operand" "=g")
(not:QI (match_operand:QI 1 "general_operand" "g")))]
""
"mcomb %1,%0")
; cmpsi works fine, but due to microcode problems, the tahoe doesn't
; properly compare hi's and qi's. Leaving them out seems to be acceptable
; to the compiler, so they were left out. Compares of the stack are
; possible, though.
; There are optimized cases possible, however. These follow first.
(define_insn ""
[(set (cc0)
(compare (sign_extend:SI (match_operand:HI 0 "memory_operand" "m"))
(sign_extend:SI (match_operand:HI 1 "memory_operand" "m"))))]
""
"cmpw %0,%1")
(define_insn ""
[(set (cc0)
(compare (match_operand:SI 0 "nonmemory_operand" "ri")
(sign_extend:SI (match_operand:HI 1 "memory_operand" "m"))))]
""
"cmpw %0,%1")
(define_insn ""
[(set (cc0)
(compare (sign_extend:SI (match_operand:HI 0 "memory_operand" "m"))
(match_operand:SI 1 "nonmemory_operand" "ri")))]
""
"cmpw %0,%1")
; zero-extended compares give the same result as sign-extended compares, if
; the compare is unsigned. Just see: if both operands are <65536 they are the
; same in both cases. If both are >=65536 the you effectively compare x+D
; with y+D, where D=2**32-2**16, so the result is the same. if x<65536 and
; y>=65536 then you compare x with y+D, and in both cases the result is x<y.
(define_insn ""
[(set (cc0)
(compare (zero_extend:SI (match_operand:HI 0 "memory_operand" "m"))
(zero_extend:SI (match_operand:HI 1 "memory_operand" "m"))))]
"tahoe_cmp_check (insn, operands[0], 0)"
"cmpw %0,%1")
(define_insn ""
[(set (cc0)
(compare (zero_extend:SI (match_operand:HI 0 "memory_operand" "m"))
(match_operand:SI 1 "immediate_operand" "i")))]
"tahoe_cmp_check(insn, operands[1], 65535)"
"*
{
if (INTVAL (operands[1]) > 32767)
operands[1] = GEN_INT (INTVAL (operands[1]) + 0xffff0000);
return \"cmpw %0,%1\";
}")
(define_insn ""
[(set (cc0)
(compare (sign_extend:SI (match_operand:QI 0 "memory_operand" "m"))
(sign_extend:SI (match_operand:QI 1 "memory_operand" "m"))))]
""
"cmpb %0,%1")
(define_insn ""
[(set (cc0)
(compare (match_operand:SI 0 "nonmemory_operand" "ri")
(sign_extend:SI (match_operand:QI 1 "memory_operand" "m"))))]
""
"cmpb %0,%1")
(define_insn ""
[(set (cc0)
(compare (sign_extend:SI (match_operand:QI 0 "memory_operand" "m"))
(match_operand:SI 1 "nonmemory_operand" "ri")))]
""
"cmpb %0,%1")
; zero-extended compares give the same result as sign-extended compares, if
; the compare is unsigned. Just see: if both operands are <128 they are the
; same in both cases. If both are >=128 the you effectively compare x+D
; with y+D, where D=2**32-2**8, so the result is the same. if x<128 and
; y>=128 then you compare x with y+D, and in both cases the result is x<y.
(define_insn ""
[(set (cc0)
(compare (zero_extend:SI (match_operand:QI 0 "memory_operand" "m"))
(zero_extend:SI (match_operand:QI 1 "memory_operand" "m"))))]
"tahoe_cmp_check (insn, operands[0], 0)"
"cmpb %0,%1")
(define_insn ""
[(set (cc0)
(compare (zero_extend:SI (match_operand:QI 0 "memory_operand" "m"))
(match_operand:SI 1 "immediate_operand" "i")))]
"tahoe_cmp_check(insn, operands[1], 255)"
"*
{
if (INTVAL (operands[1]) > 127)
operands[1] = GEN_INT (INTVAL (operands[1]) + 0xffffff00);
return \"cmpb %0,%1\";
}")
(define_insn "cmpsi"
[(set (cc0)
(compare (match_operand:SI 0 "nonimmediate_operand" "g")
(match_operand:SI 1 "general_operand" "g")))]
""
"cmpl %0,%1")
; cmpsf similar to vax, but first operand is expected to be in the
; fpp accumulator.
(define_insn "cmpsf"
[(set (cc0)
(compare (match_operand:SF 0 "general_operand" "a,g")
(match_operand:SF 1 "general_operand" "g,g")))]
""
"*
{
switch (which_alternative)
{
case 0: return \"cmpf %1\";
case 1: return \"cmpf2 %0,%1\";
}
}")
; cmpdf similar to vax, but first operand is expected to be in the
; fpp accumulator. Immediate doubles not allowed.
(define_insn "cmpdf"
[(set (cc0)
(compare (match_operand:DF 0 "general_operand" "a,rm")
(match_operand:DF 1 "general_operand" "rm,rm")))]
""
"*
{
switch (which_alternative)
{
case 0: return \"cmpd %1\";
case 1: return \"cmpd2 %0,%1\";
}
}")
;; We don't want to allow a constant operand for test insns because
;; (set (cc0) (const_int foo)) has no mode information. Such insns will
;; be folded while optimizing anyway.
(define_insn "tstsi"
[(set (cc0)
(match_operand:SI 0 "nonimmediate_operand" "g"))]
""
"tstl %0")
; small tests from memory are normal, but testing from registers doesn't
; expand the data properly. So test in this case does a convert and tests
; the new register data from the stack.
; First some special cases that do work
(define_insn ""
[(set (cc0)
(sign_extend:SI (match_operand:HI 0 "memory_operand" "m")))]
""
"tstw %0")
(define_insn ""
[(set (cc0)
(zero_extend:SI (match_operand:HI 0 "memory_operand" "m")))]
"tahoe_cmp_check (insn, operands[0], 0)"
"tstw %0")
(define_insn "tsthi"
[(set (cc0)
(match_operand:HI 0 "extensible_operand" "m,!r"))]
"GET_MODE (operands[0]) != VOIDmode"
"*
{
rtx xoperands[2];
extern rtx tahoe_reg_conversion_loc;
switch (which_alternative)
{
case 0:
return \"tstw %0\";
case 1:
xoperands[0] = operands[0];
xoperands[1] = tahoe_reg_conversion_loc;
output_asm_insn (\"movl %0,%1\", xoperands);
xoperands[1] = plus_constant (XEXP (tahoe_reg_conversion_loc, 0), 2);
output_asm_insn (\"tstw %a1\", xoperands);
return \"\";
}
}")
(define_insn ""
[(set (cc0)
(sign_extend:SI (match_operand:QI 0 "memory_operand" "m")))]
""
"tstb %0")
(define_insn ""
[(set (cc0)
(zero_extend:SI (match_operand:QI 0 "memory_operand" "m")))]
"tahoe_cmp_check (insn, operands[0], 0)"
"tstb %0")
(define_insn "tstqi"
[(set (cc0)
(match_operand:QI 0 "extensible_operand" "m,!r"))]
"GET_MODE (operands[0]) != VOIDmode"
"*
{
rtx xoperands[2];
extern rtx tahoe_reg_conversion_loc;
switch (which_alternative)
{
case 0:
return \"tstb %0\";
case 1:
xoperands[0] = operands[0];
xoperands[1] = tahoe_reg_conversion_loc;
output_asm_insn (\"movl %0,%1\", xoperands);
xoperands[1] = plus_constant (XEXP (tahoe_reg_conversion_loc, 0), 3);
output_asm_insn (\"tstb %a1\", xoperands);
return \"\";
}
}")
; tstsf compares a given value to a value already in the fpp accumulator.
; No flags are set by this so ignore them.
(define_insn "tstsf"
[(set (cc0)
(match_operand:SF 0 "register_operand" "a"))]
""
"tstf")
; tstdf compares a given value to a value already in the fpp accumulator.
; immediate doubles not allowed. Flags are ignored after this.
(define_insn "tstdf"
[(set (cc0)
(match_operand:DF 0 "register_operand" "a"))]
""
"tstd")
; movstrhi tahoe instruction does not load registers by itself like
; the vax counterpart does. registers 0-2 must be primed by hand.
; we have loaded the registers in the order: dst, src, count.
(define_insn "movstrhi"
[(set (match_operand:BLK 0 "general_operand" "p")
(match_operand:BLK 1 "general_operand" "p"))
(use (match_operand:HI 2 "general_operand" "g"))
(clobber (reg:SI 0))
(clobber (reg:SI 1))
(clobber (reg:SI 2))]
""
"movab %0,r1\;movab %1,r0\;movl %2,r2\;movblk")
; floatsisf2 on tahoe converts the long from reg/mem into the fpp
; accumulator. There are no hi and qi counterparts. Flags are not
; set correctly here.
(define_insn "floatsisf2"
[(set (match_operand:SF 0 "register_operand" "=a")
(float:SF (match_operand:SI 1 "general_operand" "g")))]
""
"*
{
CC_STATUS_INIT;
return \"cvlf %1\";
}")
; floatsidf2 on tahoe converts the long from reg/mem into the fpp
; accumulator. There are no hi and qi counterparts. Flags are not
; set correctly here.
(define_insn "floatsidf2"
[(set (match_operand:DF 0 "register_operand" "=a")
(float:DF (match_operand:SI 1 "general_operand" "g")))]
""
"*
{
CC_STATUS_INIT;
return \"cvld %1\";
}")
; fix_truncsfsi2 to convert a float to long, tahoe must have the float
; in the fpp accumulator. Flags are not set here.
(define_insn "fix_truncsfsi2"
[(set (match_operand:SI 0 "general_operand" "=g")
(fix:SI (fix:SF (match_operand:SF 1 "register_operand" "a"))))]
""
"*
{
CC_STATUS_INIT;
return \"cvfl %0\";
}")
; fix_truncsfsi2 to convert a double to long, tahoe must have the double
; in the fpp accumulator. Flags are not set here.
(define_insn "fix_truncdfsi2"
[(set (match_operand:SI 0 "general_operand" "=g")
(fix:SI (fix:DF (match_operand:DF 1 "register_operand" "a"))))]
""
"*
{
CC_STATUS_INIT;
return \"cvdl %0\";
}")
(define_insn "truncsihi2"
[(set (match_operand:HI 0 "general_operand" "=g")
(truncate:HI (match_operand:SI 1 "general_operand" "g")))]
""
"cvtlw %1,%0")
(define_insn "truncsiqi2"
[(set (match_operand:QI 0 "general_operand" "=g")
(truncate:QI (match_operand:SI 1 "general_operand" "g")))]
""
"cvtlb %1,%0")
(define_insn "trunchiqi2"
[(set (match_operand:QI 0 "general_operand" "=g")
(truncate:QI (match_operand:HI 1 "general_operand" "g")))]
""
"cvtwb %1,%0")
; The fpp related instructions don't set flags, so ignore them
; after this instruction.
(define_insn "truncdfsf2"
[(set (match_operand:SF 0 "register_operand" "=a")
(float_truncate:SF (match_operand:DF 1 "register_operand" "0")))]
""
"*
{
CC_STATUS_INIT;
return \"cvdf\";
}")
; This monster is to cover for the Tahoe's nasty habit of not extending
; a number if the source is in a register. (It just moves it!) Case 0 is
; a normal extend from memory. Case 1 does the extension from the top of
; the stack. Extension from the stack doesn't set the flags right since
; the moval changes them.
(define_insn "extendhisi2"
[(set (match_operand:SI 0 "general_operand" "=g,?=g")
(sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "m,r")))]
""
"*
{
switch (which_alternative)
{
case 0:
return \"cvtwl %1,%0\";
case 1:
if (push_operand (operands[0], SImode))
return \"pushl %1\;cvtwl 2(sp),(sp)\";
else
{
CC_STATUS_INIT;
return \"pushl %1\;cvtwl 2(sp),%0\;moval 4(sp),sp\";
}
}
}")
; This monster is to cover for the Tahoe's nasty habit of not extending
; a number if the source is in a register. (It just moves it!) Case 0 is
; a normal extend from memory. Case 1 does the extension from the top of
; the stack. Extension from the stack doesn't set the flags right since
; the moval changes them.
(define_insn "extendqisi2"
[(set (match_operand:SI 0 "general_operand" "=g,?=g")
(sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "m,r")))]
""
"*
{
switch (which_alternative)
{
case 0:
return \"cvtbl %1,%0\";
case 1:
if (push_operand (operands[0], SImode))
return \"pushl %1\;cvtbl 3(sp),(sp)\";
else
{
CC_STATUS_INIT;
return \"pushl %1\;cvtbl 3(sp),%0\;moval 4(sp),sp\";
}
}
}")
; This monster is to cover for the Tahoe's nasty habit of not extending
; a number if the source is in a register. (It just moves it!) Case 0 is
; a normal extend from memory. Case 1 does the extension from the top of
; the stack. Extension from the stack doesn't set the flags right since
; the moval changes them.
(define_insn "extendqihi2"
[(set (match_operand:HI 0 "general_operand" "=g,?=g")
(sign_extend:HI (match_operand:QI 1 "nonimmediate_operand" "m,r")))]
""
"*
{
switch (which_alternative)
{
case 0:
return \"cvtbw %1,%0\";
case 1:
if (push_operand (operands[0], SImode))
return \"pushl %1\;cvtbw 3(sp),(sp)\";
else
{
CC_STATUS_INIT;
return \"pushl %1\;cvtbw 3(sp),%0\;moval 4(sp),sp\";
}
}
}")
; extendsfdf2 tahoe uses the fpp accumulator to do the extension.
; It takes a float and loads it up directly as a double.
(define_insn "extendsfdf2"
[(set (match_operand:DF 0 "register_operand" "=a")
(float_extend:DF (match_operand:SF 1 "general_operand" "g")))]
""
"*
{
CC_STATUS_INIT;
return \"ldfd %1\";
}")
; movz works fine from memory but not from register for the same reasons
; the cvt instructions don't work right. So we use the normal instruction
; from memory and we use an and to simulate it from register. This is faster
; than pulling it off the stack.
(define_insn "zero_extendhisi2"
[(set (match_operand:SI 0 "general_operand" "=g,?=g")
(zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "m,r")))]
""
"*
{
switch (which_alternative)
{
case 0: return \"movzwl %1,%0\";
case 1: return \"andl3 $0xffff,%1,%0\";
}
}")
; movz works fine from memory but not from register for the same reasons
; the cvt instructions don't work right. So we use the normal instruction
; from memory and we use an and to simulate it from register. This is faster
; than pulling it off the stack.
(define_insn "zero_extendqihi2"
[(set (match_operand:HI 0 "general_operand" "=g,?=g")
(zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "m,r")))]
""
"*
{
switch (which_alternative)
{
case 0: return \"movzbw %1,%0\";
case 1: return \"andw3 $0xff,%1,%0\";
}
}")
; movz works fine from memory but not from register for the same reasons
; the cvt instructions don't work right. So we use the normal instruction
; from memory and we use an and to simulate it from register. This is faster
; than pulling it off the stack.
(define_insn "zero_extendqisi2"
[(set (match_operand:SI 0 "general_operand" "=g,?=g")
(zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "m,r")))]
""
"*
{
switch (which_alternative)
{
case 0: return \"movzbl %1,%0\";
case 1: return \"andl3 $0xff,%1,%0\";
}
}")
(define_insn "beq"
[(set (pc)
(if_then_else (eq (cc0)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"jeql %l0")
(define_insn "bne"
[(set (pc)
(if_then_else (ne (cc0)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"jneq %l0")
(define_insn "bgt"
[(set (pc)
(if_then_else (gt (cc0)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"jgtr %l0")
(define_insn "bgtu"
[(set (pc)
(if_then_else (gtu (cc0)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"jgtru %l0")
(define_insn "blt"
[(set (pc)
(if_then_else (lt (cc0)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"jlss %l0")
(define_insn "bltu"
[(set (pc)
(if_then_else (ltu (cc0)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"jlssu %l0")
(define_insn "bge"
[(set (pc)
(if_then_else (ge (cc0)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"jgeq %l0")
(define_insn "bgeu"
[(set (pc)
(if_then_else (geu (cc0)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"jgequ %l0")
(define_insn "ble"
[(set (pc)
(if_then_else (le (cc0)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"jleq %l0")
(define_insn "bleu"
[(set (pc)
(if_then_else (leu (cc0)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"jlequ %l0")
; gcc does not account for register mask/argc longword. Thus the number
; for the call = number bytes for args + 4
(define_insn "call"
[(call (match_operand:QI 0 "memory_operand" "m")
(match_operand:QI 1 "general_operand" "g"))]
""
"*
{
operands[1] = GEN_INT (INTVAL (operands[1]) + 4);
if (GET_CODE(operands[0]) == MEM
&& CONSTANT_ADDRESS_P (XEXP(operands[0], 0))
&& INTVAL (operands[1]) < 64)
return \"callf %1,%0\"; /* this is much faster */
return \"calls %1,%0\";
}")
; gcc does not account for register mask/argc longword. Thus the number
; for the call = number bytes for args + 4
(define_insn "call_value"
[(set (match_operand 0 "" "=g")
(call (match_operand:QI 1 "memory_operand" "m")
(match_operand:QI 2 "general_operand" "g")))]
""
"*
{
operands[2] = GEN_INT (INTVAL (operands[2]) + 4));
if (GET_CODE(operands[1]) == MEM
&& CONSTANT_ADDRESS_P (XEXP(operands[1], 0))
&& INTVAL (operands[2]) < 64)
return \"callf %2,%1\"; /* this is much faster */
return \"calls %2,%1\";
}")
(define_insn "return"
[(return)]
""
"ret")
(define_insn "nop"
[(const_int 0)]
""
"nop")
; casesi this code extracted from the vax code. The instructions are
; very similar. Tahoe requires that the table be word aligned. GCC
; places the table immediately after, thus the alignment directive.
(define_insn "casesi"
[(set (pc)
(if_then_else (le (minus:SI (match_operand:SI 0 "general_operand" "g")
(match_operand:SI 1 "general_operand" "g"))
(match_operand:SI 2 "general_operand" "g"))
(plus:SI (sign_extend:SI
(mem:HI (plus:SI (pc)
(minus:SI (match_dup 0)
(match_dup 1)))))
(label_ref:SI (match_operand 3 "" "")))
(pc)))]
""
"casel %0,%1,%2\;.align %@")
(define_insn "jump"
[(set (pc)
(label_ref (match_operand 0 "" "")))]
""
"jbr %l0")
;; This is the list of all the non-standard insn patterns
; This is used to access the address of a byte. This is similar to
; movqi, but the second operand had to be "address_operand" type, so
; it had to be an unnamed one.
(define_insn ""
[(set (match_operand:SI 0 "general_operand" "=g")
(match_operand:QI 1 "address_operand" "p"))]
""
"*
{
if (push_operand (operands[0], SImode))
return \"pushab %a1\";
return \"movab %a1,%0\";
}")
; This is used to access the address of a word. This is similar to
; movhi, but the second operand had to be "address_operand" type, so
; it had to be an unnamed one.
(define_insn ""
[(set (match_operand:SI 0 "general_operand" "=g")
(match_operand:HI 1 "address_operand" "p"))]
""
"*
{
if (push_operand (operands[0], SImode))
return \"pushaw %a1\";
return \"movaw %a1,%0\";
}")
; This is used to access the address of a long. This is similar to
; movsi, but the second operand had to be "address_operand" type, so
; it had to be an unnamed one.
(define_insn ""
[(set (match_operand:SI 0 "general_operand" "=g")
(match_operand:SI 1 "address_operand" "p"))]
""
"*
{
if (push_operand (operands[0], SImode))
return \"pushal %a1\";
return \"moval %a1,%0\";
}")
; bit test longword instruction, same as vax
(define_insn ""
[(set (cc0)
(and:SI (match_operand:SI 0 "general_operand" "g")
(match_operand:SI 1 "general_operand" "g")))]
""
"bitl %0,%1")
; bit test word instructions, same as vax
(define_insn ""
[(set (cc0)
(and:HI (match_operand:HI 0 "general_operand" "g")
(match_operand:HI 1 "general_operand" "g")))]
""
"bitw %0,%1")
; bit test instructions, same as vax
(define_insn ""
[(set (cc0)
(and:QI (match_operand:QI 0 "general_operand" "g")
(match_operand:QI 1 "general_operand" "g")))]
""
"bitb %0,%1")
; bne counterpart. in case gcc reverses the conditional.
(define_insn ""
[(set (pc)
(if_then_else (eq (cc0)
(const_int 0))
(pc)
(label_ref (match_operand 0 "" ""))))]
""
"jneq %l0")
; beq counterpart. in case gcc reverses the conditional.
(define_insn ""
[(set (pc)
(if_then_else (ne (cc0)
(const_int 0))
(pc)
(label_ref (match_operand 0 "" ""))))]
""
"jeql %l0")
; ble counterpart. in case gcc reverses the conditional.
(define_insn ""
[(set (pc)
(if_then_else (gt (cc0)
(const_int 0))
(pc)
(label_ref (match_operand 0 "" ""))))]
""
"jleq %l0")
; bleu counterpart. in case gcc reverses the conditional.
(define_insn ""
[(set (pc)
(if_then_else (gtu (cc0)
(const_int 0))
(pc)
(label_ref (match_operand 0 "" ""))))]
""
"jlequ %l0")
; bge counterpart. in case gcc reverses the conditional.
(define_insn ""
[(set (pc)
(if_then_else (lt (cc0)
(const_int 0))
(pc)
(label_ref (match_operand 0 "" ""))))]
""
"jgeq %l0")
; bgeu counterpart. in case gcc reverses the conditional.
(define_insn ""
[(set (pc)
(if_then_else (ltu (cc0)
(const_int 0))
(pc)
(label_ref (match_operand 0 "" ""))))]
""
"jgequ %l0")
; blt counterpart. in case gcc reverses the conditional.
(define_insn ""
[(set (pc)
(if_then_else (ge (cc0)
(const_int 0))
(pc)
(label_ref (match_operand 0 "" ""))))]
""
"jlss %l0")
; bltu counterpart. in case gcc reverses the conditional.
(define_insn ""
[(set (pc)
(if_then_else (geu (cc0)
(const_int 0))
(pc)
(label_ref (match_operand 0 "" ""))))]
""
"jlssu %l0")
; bgt counterpart. in case gcc reverses the conditional.
(define_insn ""
[(set (pc)
(if_then_else (le (cc0)
(const_int 0))
(pc)
(label_ref (match_operand 0 "" ""))))]
""
"jgtr %l0")
; bgtu counterpart. in case gcc reverses the conditional.
(define_insn ""
[(set (pc)
(if_then_else (leu (cc0)
(const_int 0))
(pc)
(label_ref (match_operand 0 "" ""))))]
""
"jgtru %l0")
; casesi alternate form as found in vax code. this form is to
; compensate for the table's offset being no distance (0 displacement)
(define_insn ""
[(set (pc)
(if_then_else (le (match_operand:SI 0 "general_operand" "g")
(match_operand:SI 1 "general_operand" "g"))
(plus:SI (sign_extend:SI
(mem:HI (plus:SI (pc)
(minus:SI (match_dup 0)
(const_int 0)))))
(label_ref:SI (match_operand 3 "" "")))
(pc)))]
""
"casel %0,$0,%1\;.align %@")
; casesi alternate form as found in vax code. another form to
; compensate for the table's offset being no distance (0 displacement)
(define_insn ""
[(set (pc)
(if_then_else (le (match_operand:SI 0 "general_operand" "g")
(match_operand:SI 1 "general_operand" "g"))
(plus:SI (sign_extend:SI
(mem:HI (plus:SI (pc)
(match_dup 0))))
(label_ref:SI (match_operand 3 "" "")))
(pc)))]
""
"casel %0,$0,%1 \;.align %@")
(define_insn ""
[(set (pc)
(if_then_else
(lt (plus:SI (match_operand:SI 0 "general_operand" "+g")
(const_int 1))
(match_operand:SI 1 "general_operand" "g"))
(label_ref (match_operand 2 "" ""))
(pc)))
(set (match_dup 0)
(plus:SI (match_dup 0)
(const_int 1)))]
""
"aoblss %1,%0,%l2")
(define_insn ""
[(set (pc)
(if_then_else
(le (plus:SI (match_operand:SI 0 "general_operand" "+g")
(const_int 1))
(match_operand:SI 1 "general_operand" "g"))
(label_ref (match_operand 2 "" ""))
(pc)))
(set (match_dup 0)
(plus:SI (match_dup 0)
(const_int 1)))]
""
"aobleq %1,%0,%l2")
(define_insn ""
[(set (pc)
(if_then_else
(ge (plus:SI (match_operand:SI 0 "general_operand" "+g")
(const_int 1))
(match_operand:SI 1 "general_operand" "g"))
(pc)
(label_ref (match_operand 2 "" ""))))
(set (match_dup 0)
(plus:SI (match_dup 0)
(const_int 1)))]
""
"aoblss %1,%0,%l2")
(define_insn ""
[(set (pc)
(if_then_else
(gt (plus:SI (match_operand:SI 0 "general_operand" "+g")
(const_int 1))
(match_operand:SI 1 "general_operand" "g"))
(pc)
(label_ref (match_operand 2 "" ""))))
(set (match_dup 0)
(plus:SI (match_dup 0)
(const_int 1)))]
""
"aobleq %1,%0,%l2")
; bbs/bbc
(define_insn ""
[(set (pc)
(if_then_else
(ne (sign_extract:SI (match_operand:SI 0 "register_operand" "rm")
(const_int 1)
(subreg:QI (match_operand:SI 1 "general_operand" "g") 0))
(const_int 0))
(label_ref (match_operand 2 "" ""))
(pc)))]
""
"bbs %1,%0,%l2")
(define_insn ""
[(set (pc)
(if_then_else
(eq (sign_extract:SI (match_operand:SI 0 "register_operand" "rm")
(const_int 1)
(subreg:QI (match_operand:SI 1 "general_operand" "g") 0))
(const_int 0))
(label_ref (match_operand 2 "" ""))
(pc)))]
""
"bbc %1,%0,%l2")
(define_insn ""
[(set (pc)
(if_then_else
(ne (sign_extract:SI (match_operand:SI 0 "register_operand" "rm")
(const_int 1)
(subreg:QI (match_operand:SI 1 "general_operand" "g") 0))
(const_int 0))
(pc)
(label_ref (match_operand 2 "" ""))))]
""
"bbc %1,%0,%l2")
(define_insn ""
[(set (pc)
(if_then_else
(eq (sign_extract:SI (match_operand:SI 0 "register_operand" "rm")
(const_int 1)
(subreg:QI (match_operand:SI 1 "general_operand" "g") 0))
(const_int 0))
(pc)
(label_ref (match_operand 2 "" ""))))]
""
"bbs %1,%0,%l2")
; if the shift count is a byte in a register we can use it as a long
(define_insn ""
[(set (pc)
(if_then_else
(ne (sign_extract:SI (match_operand:SI 0 "register_operand" "rm")
(const_int 1)
(match_operand:QI 1 "register_operand" "r"))
(const_int 0))
(label_ref (match_operand 2 "" ""))
(pc)))]
""
"bbs %1,%0,%l2")
(define_insn ""
[(set (pc)
(if_then_else
(eq (sign_extract:SI (match_operand:SI 0 "register_operand" "rm")
(const_int 1)
(match_operand:QI 1 "register_operand" "r"))
(const_int 0))
(label_ref (match_operand 2 "" ""))
(pc)))]
""
"bbc %1,%0,%l2")
(define_insn ""
[(set (pc)
(if_then_else
(ne (sign_extract:SI (match_operand:SI 0 "register_operand" "rm")
(const_int 1)
(match_operand:QI 1 "register_operand" "r"))
(const_int 0))
(pc)
(label_ref (match_operand 2 "" ""))))]
""
"bbc %1,%0,%l2")
(define_insn ""
[(set (pc)
(if_then_else
(eq (sign_extract:SI (match_operand:SI 0 "register_operand" "rm")
(const_int 1)
(match_operand:QI 1 "register_operand" "r"))
(const_int 0))
(pc)
(label_ref (match_operand 2 "" ""))))]
""
"bbs %1,%0,%l2")
; special case for 1 << constant. We don't do these because they are slower
; than the bitl instruction
;(define_insn ""
; [(set (pc)
; (if_then_else
; (ne (and:SI (match_operand:SI 0 "nonimmediate_operand" "%rm")
; (match_operand:SI 1 "immediate_operand" "i"))
; (const_int 0))
; (label_ref (match_operand 2 "" ""))
; (pc)))]
; "GET_CODE (operands[1]) == CONST_INT
; && exact_log2 (INTVAL (operands[1])) >= 0"
; "*
;{
; operands[1] = GEN_INT (exact_log2 (INTVAL (operands[1])));
; return \"bbs %1,%0,%l2\";
;}")
;
;(define_insn ""
; [(set (pc)
; (if_then_else
; (eq (and:SI (match_operand:SI 0 "nonimmediate_operand" "%rm")
; (match_operand:SI 1 "immediate_operand" "i"))
; (const_int 0))
; (label_ref (match_operand 2 "" ""))
; (pc)))]
; "GET_CODE (operands[1]) == CONST_INT
; && exact_log2 (INTVAL (operands[1])) >= 0"
; "*
;{
; operands[1] = GEN_INT (exact_log2 (INTVAL (operands[1])));
; return \"bbc %1,%0,%l2\";
;}")
;
;(define_insn ""
; [(set (pc)
; (if_then_else
; (ne (and:SI (match_operand:SI 0 "nonimmediate_operand" "%rm")
; (match_operand:SI 1 "immediate_operand" "i"))
; (const_int 0))
; (pc)
; (label_ref (match_operand 2 "" ""))))]
; "GET_CODE (operands[1]) == CONST_INT
; && exact_log2 (INTVAL (operands[1])) >= 0"
; "*
;{
; operands[1] = GEN_INT (exact_log2 (INTVAL (operands[1])));
; return \"bbc %1,%0,%l2\";
;}")
;
;(define_insn ""
; [(set (pc)
; (if_then_else
; (eq (and:SI (match_operand:SI 0 "nonimmediate_operand" "%rm")
; (match_operand:SI 1 "immediate_operand" "i"))
; (const_int 0))
; (pc)
; (label_ref (match_operand 2 "" ""))))]
; "GET_CODE (operands[1]) == CONST_INT
; && exact_log2 (INTVAL (operands[1])) >= 0"
; "*
;{
; operands[1]
; = GEN_INT (exact_log2 (INTVAL (operands[1])));
; return \"bbs %1,%0,%l2\";
;}")
/* Configuration for GNU C-compiler for Tahoe.
Copyright (C) 1987, 1993 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, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/*
* File: xm-tahoe.h
*
* Original port made at the University of Buffalo by Devon Bowen,
* Dale Wiles and Kevin Zachmann.
*
* Changes for HCX by Piet van Oostrum,
* University of Utrecht, The Netherlands (piet@cs.ruu.nl)
*
* Mail bugs reports or fixes to: gcc@cs.buffalo.edu
*/
/* This file has the same stuff the vax version does */
/* defines that need visibility everywhere */
#define FALSE 0
#define TRUE 1
/* target machine dependencies
tm.h is a symbolic link to the actual target specific file. */
#include "tm.h"
/* This describes the machine the compiler is hosted on. */
#define HOST_BITS_PER_CHAR 8
#define HOST_BITS_PER_SHORT 16
#define HOST_BITS_PER_INT 32
#define HOST_BITS_PER_LONG 32
#define HOST_BITS_PER_LONGLONG 64
#define HOST_WORDS_BIG_ENDIAN
/* Arguments to use with `exit'. */
#define SUCCESS_EXIT_CODE 0
#define FATAL_EXIT_CODE 33
...@@ -4148,9 +4148,6 @@ for machine in $build $host $target; do ...@@ -4148,9 +4148,6 @@ for machine in $build $host $target; do
tmake_file=fr30/t-fr30 tmake_file=fr30/t-fr30
extra_parts="crti.o crtn.o crtbegin.o crtend.o" extra_parts="crti.o crtn.o crtbegin.o crtend.o"
;; ;;
# This hasn't been upgraded to GCC 2.
# fx80-alliant-*) # Alliant FX/80
# ;;
h8300-*-*) h8300-*-*)
float_format=i32 float_format=i32
;; ;;
...@@ -6111,13 +6108,6 @@ for machine in $build $host $target; do ...@@ -6111,13 +6108,6 @@ for machine in $build $host $target; do
tm_file=ns32k/tek6200.h tm_file=ns32k/tek6200.h
use_collect2=yes use_collect2=yes
;; ;;
# This has not been updated to GCC 2.
# ns32k-ns-genix*)
# xm_defines=USG
# xmake_file=ns32k/x-genix
# tm_file=ns32k/genix.h
# use_collect2=yes
# ;;
ns32k-merlin-*) ns32k-merlin-*)
tm_file=ns32k/merlin.h tm_file=ns32k/merlin.h
use_collect2=yes use_collect2=yes
...@@ -6149,13 +6139,6 @@ for machine in $build $host $target; do ...@@ -6149,13 +6139,6 @@ for machine in $build $host $target; do
ns32k-*-openbsd*) ns32k-*-openbsd*)
# Nothing special # Nothing special
;; ;;
# This has not been updated to GCC 2.
# pyramid-*-*)
# cpu_type=pyr
# xmake_file=pyr/x-pyr
# use_collect2=yes
# ;;
pj*-linux*) pj*-linux*)
tm_file="svr4.h pj/linux.h ${tm_file}" tm_file="svr4.h pj/linux.h ${tm_file}"
;; ;;
...@@ -6642,24 +6625,12 @@ for machine in $build $host $target; do ...@@ -6642,24 +6625,12 @@ for machine in $build $host $target; do
fi fi
float_format=sparc float_format=sparc
;; ;;
# This hasn't been upgraded to GCC 2.
# tahoe-harris-*) # Harris tahoe, using COFF.
# tm_file=tahoe/harris.h
# ;;
# tahoe-*-bsd*) # tahoe running BSD
# ;;
thumb*-*-*) thumb*-*-*)
{ echo "configure: error: { echo "configure: error:
*** The Thumb targets have been depreciated. The equivalent *** The Thumb targets have been depreciated. The equivalent
*** ARM based toolchain can now generated Thumb instructions *** ARM based toolchain can now generated Thumb instructions
*** when the -mthumb switch is given to the compiler." 1>&2; exit 1; } *** when the -mthumb switch is given to the compiler." 1>&2; exit 1; }
;; ;;
# This hasn't been upgraded to GCC 2.
# tron-*-*)
# cpu_type=gmicro
# use_collect2=yes
# ;;
v850-*-rtems*) v850-*-rtems*)
cpu_type=v850 cpu_type=v850
tm_file="v850/rtems.h" tm_file="v850/rtems.h"
...@@ -7184,7 +7155,7 @@ fi ...@@ -7184,7 +7155,7 @@ fi
echo $ac_n "checking for strerror in -lcposix""... $ac_c" 1>&6 echo $ac_n "checking for strerror in -lcposix""... $ac_c" 1>&6
echo "configure:7188: checking for strerror in -lcposix" >&5 echo "configure:7159: checking for strerror in -lcposix" >&5
ac_lib_var=`echo cposix'_'strerror | sed 'y%./+-%__p_%'` ac_lib_var=`echo cposix'_'strerror | sed 'y%./+-%__p_%'`
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
...@@ -7192,7 +7163,7 @@ else ...@@ -7192,7 +7163,7 @@ else
ac_save_LIBS="$LIBS" ac_save_LIBS="$LIBS"
LIBS="-lcposix $LIBS" LIBS="-lcposix $LIBS"
cat > conftest.$ac_ext <<EOF cat > conftest.$ac_ext <<EOF
#line 7196 "configure" #line 7167 "configure"
#include "confdefs.h" #include "confdefs.h"
/* Override any gcc2 internal prototype to avoid an error. */ /* Override any gcc2 internal prototype to avoid an error. */
/* We use char because int might match the return type of a gcc2 /* We use char because int might match the return type of a gcc2
...@@ -7203,7 +7174,7 @@ int main() { ...@@ -7203,7 +7174,7 @@ int main() {
strerror() strerror()
; return 0; } ; return 0; }
EOF EOF
if { (eval echo configure:7207: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then if { (eval echo configure:7178: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest* rm -rf conftest*
eval "ac_cv_lib_$ac_lib_var=yes" eval "ac_cv_lib_$ac_lib_var=yes"
else else
...@@ -7226,12 +7197,12 @@ fi ...@@ -7226,12 +7197,12 @@ fi
echo $ac_n "checking for working const""... $ac_c" 1>&6 echo $ac_n "checking for working const""... $ac_c" 1>&6
echo "configure:7230: checking for working const" >&5 echo "configure:7201: checking for working const" >&5
if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
else else
cat > conftest.$ac_ext <<EOF cat > conftest.$ac_ext <<EOF
#line 7235 "configure" #line 7206 "configure"
#include "confdefs.h" #include "confdefs.h"
int main() { int main() {
...@@ -7280,7 +7251,7 @@ ccp = (char const *const *) p; ...@@ -7280,7 +7251,7 @@ ccp = (char const *const *) p;
; return 0; } ; return 0; }
EOF EOF
if { (eval echo configure:7284: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then if { (eval echo configure:7255: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest* rm -rf conftest*
ac_cv_c_const=yes ac_cv_c_const=yes
else else
...@@ -7301,12 +7272,12 @@ EOF ...@@ -7301,12 +7272,12 @@ EOF
fi fi
echo $ac_n "checking for off_t""... $ac_c" 1>&6 echo $ac_n "checking for off_t""... $ac_c" 1>&6
echo "configure:7305: checking for off_t" >&5 echo "configure:7276: checking for off_t" >&5
if eval "test \"`echo '$''{'ac_cv_type_off_t'+set}'`\" = set"; then if eval "test \"`echo '$''{'ac_cv_type_off_t'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
else else
cat > conftest.$ac_ext <<EOF cat > conftest.$ac_ext <<EOF
#line 7310 "configure" #line 7281 "configure"
#include "confdefs.h" #include "confdefs.h"
#include <sys/types.h> #include <sys/types.h>
#if STDC_HEADERS #if STDC_HEADERS
...@@ -7334,12 +7305,12 @@ EOF ...@@ -7334,12 +7305,12 @@ EOF
fi fi
echo $ac_n "checking for size_t""... $ac_c" 1>&6 echo $ac_n "checking for size_t""... $ac_c" 1>&6
echo "configure:7338: checking for size_t" >&5 echo "configure:7309: checking for size_t" >&5
if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
else else
cat > conftest.$ac_ext <<EOF cat > conftest.$ac_ext <<EOF
#line 7343 "configure" #line 7314 "configure"
#include "confdefs.h" #include "confdefs.h"
#include <sys/types.h> #include <sys/types.h>
#if STDC_HEADERS #if STDC_HEADERS
...@@ -7369,19 +7340,19 @@ fi ...@@ -7369,19 +7340,19 @@ fi
# The Ultrix 4.2 mips builtin alloca declared by alloca.h only works # The Ultrix 4.2 mips builtin alloca declared by alloca.h only works
# for constant arguments. Useless! # for constant arguments. Useless!
echo $ac_n "checking for working alloca.h""... $ac_c" 1>&6 echo $ac_n "checking for working alloca.h""... $ac_c" 1>&6
echo "configure:7373: checking for working alloca.h" >&5 echo "configure:7344: checking for working alloca.h" >&5
if eval "test \"`echo '$''{'ac_cv_header_alloca_h'+set}'`\" = set"; then if eval "test \"`echo '$''{'ac_cv_header_alloca_h'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
else else
cat > conftest.$ac_ext <<EOF cat > conftest.$ac_ext <<EOF
#line 7378 "configure" #line 7349 "configure"
#include "confdefs.h" #include "confdefs.h"
#include <alloca.h> #include <alloca.h>
int main() { int main() {
char *p = alloca(2 * sizeof(int)); char *p = alloca(2 * sizeof(int));
; return 0; } ; return 0; }
EOF EOF
if { (eval echo configure:7385: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then if { (eval echo configure:7356: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest* rm -rf conftest*
ac_cv_header_alloca_h=yes ac_cv_header_alloca_h=yes
else else
...@@ -7402,12 +7373,12 @@ EOF ...@@ -7402,12 +7373,12 @@ EOF
fi fi
echo $ac_n "checking for alloca""... $ac_c" 1>&6 echo $ac_n "checking for alloca""... $ac_c" 1>&6
echo "configure:7406: checking for alloca" >&5 echo "configure:7377: checking for alloca" >&5
if eval "test \"`echo '$''{'ac_cv_func_alloca_works'+set}'`\" = set"; then if eval "test \"`echo '$''{'ac_cv_func_alloca_works'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
else else
cat > conftest.$ac_ext <<EOF cat > conftest.$ac_ext <<EOF
#line 7411 "configure" #line 7382 "configure"
#include "confdefs.h" #include "confdefs.h"
#ifdef __GNUC__ #ifdef __GNUC__
...@@ -7435,7 +7406,7 @@ int main() { ...@@ -7435,7 +7406,7 @@ int main() {
char *p = (char *) alloca(1); char *p = (char *) alloca(1);
; return 0; } ; return 0; }
EOF EOF
if { (eval echo configure:7439: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then if { (eval echo configure:7410: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest* rm -rf conftest*
ac_cv_func_alloca_works=yes ac_cv_func_alloca_works=yes
else else
...@@ -7467,12 +7438,12 @@ EOF ...@@ -7467,12 +7438,12 @@ EOF
echo $ac_n "checking whether alloca needs Cray hooks""... $ac_c" 1>&6 echo $ac_n "checking whether alloca needs Cray hooks""... $ac_c" 1>&6
echo "configure:7471: checking whether alloca needs Cray hooks" >&5 echo "configure:7442: checking whether alloca needs Cray hooks" >&5
if eval "test \"`echo '$''{'ac_cv_os_cray'+set}'`\" = set"; then if eval "test \"`echo '$''{'ac_cv_os_cray'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
else else
cat > conftest.$ac_ext <<EOF cat > conftest.$ac_ext <<EOF
#line 7476 "configure" #line 7447 "configure"
#include "confdefs.h" #include "confdefs.h"
#if defined(CRAY) && ! defined(CRAY2) #if defined(CRAY) && ! defined(CRAY2)
webecray webecray
...@@ -7497,12 +7468,12 @@ echo "$ac_t""$ac_cv_os_cray" 1>&6 ...@@ -7497,12 +7468,12 @@ echo "$ac_t""$ac_cv_os_cray" 1>&6
if test $ac_cv_os_cray = yes; then if test $ac_cv_os_cray = yes; then
for ac_func in _getb67 GETB67 getb67; do for ac_func in _getb67 GETB67 getb67; do
echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
echo "configure:7501: checking for $ac_func" >&5 echo "configure:7472: checking for $ac_func" >&5
if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
else else
cat > conftest.$ac_ext <<EOF cat > conftest.$ac_ext <<EOF
#line 7506 "configure" #line 7477 "configure"
#include "confdefs.h" #include "confdefs.h"
/* System header to define __stub macros and hopefully few prototypes, /* System header to define __stub macros and hopefully few prototypes,
which can conflict with char $ac_func(); below. */ which can conflict with char $ac_func(); below. */
...@@ -7525,7 +7496,7 @@ $ac_func(); ...@@ -7525,7 +7496,7 @@ $ac_func();
; return 0; } ; return 0; }
EOF EOF
if { (eval echo configure:7529: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then if { (eval echo configure:7500: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest* rm -rf conftest*
eval "ac_cv_func_$ac_func=yes" eval "ac_cv_func_$ac_func=yes"
else else
...@@ -7552,7 +7523,7 @@ done ...@@ -7552,7 +7523,7 @@ done
fi fi
echo $ac_n "checking stack direction for C alloca""... $ac_c" 1>&6 echo $ac_n "checking stack direction for C alloca""... $ac_c" 1>&6
echo "configure:7556: checking stack direction for C alloca" >&5 echo "configure:7527: checking stack direction for C alloca" >&5
if eval "test \"`echo '$''{'ac_cv_c_stack_direction'+set}'`\" = set"; then if eval "test \"`echo '$''{'ac_cv_c_stack_direction'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
else else
...@@ -7560,7 +7531,7 @@ else ...@@ -7560,7 +7531,7 @@ else
ac_cv_c_stack_direction=0 ac_cv_c_stack_direction=0
else else
cat > conftest.$ac_ext <<EOF cat > conftest.$ac_ext <<EOF
#line 7564 "configure" #line 7535 "configure"
#include "confdefs.h" #include "confdefs.h"
find_stack_direction () find_stack_direction ()
{ {
...@@ -7579,7 +7550,7 @@ main () ...@@ -7579,7 +7550,7 @@ main ()
exit (find_stack_direction() < 0); exit (find_stack_direction() < 0);
} }
EOF EOF
if { (eval echo configure:7583: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null if { (eval echo configure:7554: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
then then
ac_cv_c_stack_direction=1 ac_cv_c_stack_direction=1
else else
...@@ -7606,17 +7577,17 @@ unistd.h sys/param.h ...@@ -7606,17 +7577,17 @@ unistd.h sys/param.h
do do
ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
echo "configure:7610: checking for $ac_hdr" >&5 echo "configure:7581: checking for $ac_hdr" >&5
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
else else
cat > conftest.$ac_ext <<EOF cat > conftest.$ac_ext <<EOF
#line 7615 "configure" #line 7586 "configure"
#include "confdefs.h" #include "confdefs.h"
#include <$ac_hdr> #include <$ac_hdr>
EOF EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
{ (eval echo configure:7620: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } { (eval echo configure:7591: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then if test -z "$ac_err"; then
rm -rf conftest* rm -rf conftest*
...@@ -7646,12 +7617,12 @@ done ...@@ -7646,12 +7617,12 @@ done
strdup __argz_count __argz_stringify __argz_next strdup __argz_count __argz_stringify __argz_next
do do
echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
echo "configure:7650: checking for $ac_func" >&5 echo "configure:7621: checking for $ac_func" >&5
if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
else else
cat > conftest.$ac_ext <<EOF cat > conftest.$ac_ext <<EOF
#line 7655 "configure" #line 7626 "configure"
#include "confdefs.h" #include "confdefs.h"
/* System header to define __stub macros and hopefully few prototypes, /* System header to define __stub macros and hopefully few prototypes,
which can conflict with char $ac_func(); below. */ which can conflict with char $ac_func(); below. */
...@@ -7674,7 +7645,7 @@ $ac_func(); ...@@ -7674,7 +7645,7 @@ $ac_func();
; return 0; } ; return 0; }
EOF EOF
if { (eval echo configure:7678: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then if { (eval echo configure:7649: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest* rm -rf conftest*
eval "ac_cv_func_$ac_func=yes" eval "ac_cv_func_$ac_func=yes"
else else
...@@ -7703,12 +7674,12 @@ done ...@@ -7703,12 +7674,12 @@ done
for ac_func in stpcpy for ac_func in stpcpy
do do
echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
echo "configure:7707: checking for $ac_func" >&5 echo "configure:7678: checking for $ac_func" >&5
if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
else else
cat > conftest.$ac_ext <<EOF cat > conftest.$ac_ext <<EOF
#line 7712 "configure" #line 7683 "configure"
#include "confdefs.h" #include "confdefs.h"
/* System header to define __stub macros and hopefully few prototypes, /* System header to define __stub macros and hopefully few prototypes,
which can conflict with char $ac_func(); below. */ which can conflict with char $ac_func(); below. */
...@@ -7731,7 +7702,7 @@ $ac_func(); ...@@ -7731,7 +7702,7 @@ $ac_func();
; return 0; } ; return 0; }
EOF EOF
if { (eval echo configure:7735: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then if { (eval echo configure:7706: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest* rm -rf conftest*
eval "ac_cv_func_$ac_func=yes" eval "ac_cv_func_$ac_func=yes"
else else
...@@ -7765,19 +7736,19 @@ EOF ...@@ -7765,19 +7736,19 @@ EOF
if test $ac_cv_header_locale_h = yes; then if test $ac_cv_header_locale_h = yes; then
echo $ac_n "checking for LC_MESSAGES""... $ac_c" 1>&6 echo $ac_n "checking for LC_MESSAGES""... $ac_c" 1>&6
echo "configure:7769: checking for LC_MESSAGES" >&5 echo "configure:7740: checking for LC_MESSAGES" >&5
if eval "test \"`echo '$''{'am_cv_val_LC_MESSAGES'+set}'`\" = set"; then if eval "test \"`echo '$''{'am_cv_val_LC_MESSAGES'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
else else
cat > conftest.$ac_ext <<EOF cat > conftest.$ac_ext <<EOF
#line 7774 "configure" #line 7745 "configure"
#include "confdefs.h" #include "confdefs.h"
#include <locale.h> #include <locale.h>
int main() { int main() {
return LC_MESSAGES return LC_MESSAGES
; return 0; } ; return 0; }
EOF EOF
if { (eval echo configure:7781: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then if { (eval echo configure:7752: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest* rm -rf conftest*
am_cv_val_LC_MESSAGES=yes am_cv_val_LC_MESSAGES=yes
else else
...@@ -7798,7 +7769,7 @@ EOF ...@@ -7798,7 +7769,7 @@ EOF
fi fi
fi fi
echo $ac_n "checking whether NLS is requested""... $ac_c" 1>&6 echo $ac_n "checking whether NLS is requested""... $ac_c" 1>&6
echo "configure:7802: checking whether NLS is requested" >&5 echo "configure:7773: checking whether NLS is requested" >&5
# Check whether --enable-nls or --disable-nls was given. # Check whether --enable-nls or --disable-nls was given.
if test "${enable_nls+set}" = set; then if test "${enable_nls+set}" = set; then
enableval="$enable_nls" enableval="$enable_nls"
...@@ -7818,7 +7789,7 @@ fi ...@@ -7818,7 +7789,7 @@ fi
EOF EOF
echo $ac_n "checking whether included gettext is requested""... $ac_c" 1>&6 echo $ac_n "checking whether included gettext is requested""... $ac_c" 1>&6
echo "configure:7822: checking whether included gettext is requested" >&5 echo "configure:7793: checking whether included gettext is requested" >&5
# Check whether --with-included-gettext or --without-included-gettext was given. # Check whether --with-included-gettext or --without-included-gettext was given.
if test "${with_included_gettext+set}" = set; then if test "${with_included_gettext+set}" = set; then
withval="$with_included_gettext" withval="$with_included_gettext"
...@@ -7837,17 +7808,17 @@ fi ...@@ -7837,17 +7808,17 @@ fi
ac_safe=`echo "libintl.h" | sed 'y%./+-%__p_%'` ac_safe=`echo "libintl.h" | sed 'y%./+-%__p_%'`
echo $ac_n "checking for libintl.h""... $ac_c" 1>&6 echo $ac_n "checking for libintl.h""... $ac_c" 1>&6
echo "configure:7841: checking for libintl.h" >&5 echo "configure:7812: checking for libintl.h" >&5
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
else else
cat > conftest.$ac_ext <<EOF cat > conftest.$ac_ext <<EOF
#line 7846 "configure" #line 7817 "configure"
#include "confdefs.h" #include "confdefs.h"
#include <libintl.h> #include <libintl.h>
EOF EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
{ (eval echo configure:7851: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } { (eval echo configure:7822: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then if test -z "$ac_err"; then
rm -rf conftest* rm -rf conftest*
...@@ -7864,19 +7835,19 @@ fi ...@@ -7864,19 +7835,19 @@ fi
if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
echo "$ac_t""yes" 1>&6 echo "$ac_t""yes" 1>&6
echo $ac_n "checking for gettext in libc""... $ac_c" 1>&6 echo $ac_n "checking for gettext in libc""... $ac_c" 1>&6
echo "configure:7868: checking for gettext in libc" >&5 echo "configure:7839: checking for gettext in libc" >&5
if eval "test \"`echo '$''{'gt_cv_func_gettext_libc'+set}'`\" = set"; then if eval "test \"`echo '$''{'gt_cv_func_gettext_libc'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
else else
cat > conftest.$ac_ext <<EOF cat > conftest.$ac_ext <<EOF
#line 7873 "configure" #line 7844 "configure"
#include "confdefs.h" #include "confdefs.h"
#include <libintl.h> #include <libintl.h>
int main() { int main() {
return (int) gettext ("") return (int) gettext ("")
; return 0; } ; return 0; }
EOF EOF
if { (eval echo configure:7880: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then if { (eval echo configure:7851: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest* rm -rf conftest*
gt_cv_func_gettext_libc=yes gt_cv_func_gettext_libc=yes
else else
...@@ -7892,7 +7863,7 @@ echo "$ac_t""$gt_cv_func_gettext_libc" 1>&6 ...@@ -7892,7 +7863,7 @@ echo "$ac_t""$gt_cv_func_gettext_libc" 1>&6
if test "$gt_cv_func_gettext_libc" != "yes"; then if test "$gt_cv_func_gettext_libc" != "yes"; then
echo $ac_n "checking for bindtextdomain in -lintl""... $ac_c" 1>&6 echo $ac_n "checking for bindtextdomain in -lintl""... $ac_c" 1>&6
echo "configure:7896: checking for bindtextdomain in -lintl" >&5 echo "configure:7867: checking for bindtextdomain in -lintl" >&5
ac_lib_var=`echo intl'_'bindtextdomain | sed 'y%./+-%__p_%'` ac_lib_var=`echo intl'_'bindtextdomain | sed 'y%./+-%__p_%'`
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
...@@ -7900,7 +7871,7 @@ else ...@@ -7900,7 +7871,7 @@ else
ac_save_LIBS="$LIBS" ac_save_LIBS="$LIBS"
LIBS="-lintl $LIBS" LIBS="-lintl $LIBS"
cat > conftest.$ac_ext <<EOF cat > conftest.$ac_ext <<EOF
#line 7904 "configure" #line 7875 "configure"
#include "confdefs.h" #include "confdefs.h"
/* Override any gcc2 internal prototype to avoid an error. */ /* Override any gcc2 internal prototype to avoid an error. */
/* We use char because int might match the return type of a gcc2 /* We use char because int might match the return type of a gcc2
...@@ -7911,7 +7882,7 @@ int main() { ...@@ -7911,7 +7882,7 @@ int main() {
bindtextdomain() bindtextdomain()
; return 0; } ; return 0; }
EOF EOF
if { (eval echo configure:7915: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then if { (eval echo configure:7886: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest* rm -rf conftest*
eval "ac_cv_lib_$ac_lib_var=yes" eval "ac_cv_lib_$ac_lib_var=yes"
else else
...@@ -7927,12 +7898,12 @@ fi ...@@ -7927,12 +7898,12 @@ fi
if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
echo "$ac_t""yes" 1>&6 echo "$ac_t""yes" 1>&6
echo $ac_n "checking for gettext in libintl""... $ac_c" 1>&6 echo $ac_n "checking for gettext in libintl""... $ac_c" 1>&6
echo "configure:7931: checking for gettext in libintl" >&5 echo "configure:7902: checking for gettext in libintl" >&5
if eval "test \"`echo '$''{'gt_cv_func_gettext_libintl'+set}'`\" = set"; then if eval "test \"`echo '$''{'gt_cv_func_gettext_libintl'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
else else
echo $ac_n "checking for gettext in -lintl""... $ac_c" 1>&6 echo $ac_n "checking for gettext in -lintl""... $ac_c" 1>&6
echo "configure:7936: checking for gettext in -lintl" >&5 echo "configure:7907: checking for gettext in -lintl" >&5
ac_lib_var=`echo intl'_'gettext | sed 'y%./+-%__p_%'` ac_lib_var=`echo intl'_'gettext | sed 'y%./+-%__p_%'`
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
...@@ -7940,7 +7911,7 @@ else ...@@ -7940,7 +7911,7 @@ else
ac_save_LIBS="$LIBS" ac_save_LIBS="$LIBS"
LIBS="-lintl $LIBS" LIBS="-lintl $LIBS"
cat > conftest.$ac_ext <<EOF cat > conftest.$ac_ext <<EOF
#line 7944 "configure" #line 7915 "configure"
#include "confdefs.h" #include "confdefs.h"
/* Override any gcc2 internal prototype to avoid an error. */ /* Override any gcc2 internal prototype to avoid an error. */
/* We use char because int might match the return type of a gcc2 /* We use char because int might match the return type of a gcc2
...@@ -7951,7 +7922,7 @@ int main() { ...@@ -7951,7 +7922,7 @@ int main() {
gettext() gettext()
; return 0; } ; return 0; }
EOF EOF
if { (eval echo configure:7955: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then if { (eval echo configure:7926: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest* rm -rf conftest*
eval "ac_cv_lib_$ac_lib_var=yes" eval "ac_cv_lib_$ac_lib_var=yes"
else else
...@@ -7990,7 +7961,7 @@ EOF ...@@ -7990,7 +7961,7 @@ EOF
# Extract the first word of "msgfmt", so it can be a program name with args. # Extract the first word of "msgfmt", so it can be a program name with args.
set dummy msgfmt; ac_word=$2 set dummy msgfmt; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
echo "configure:7994: checking for $ac_word" >&5 echo "configure:7965: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_path_MSGFMT'+set}'`\" = set"; then if eval "test \"`echo '$''{'ac_cv_path_MSGFMT'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
else else
...@@ -8024,12 +7995,12 @@ fi ...@@ -8024,12 +7995,12 @@ fi
for ac_func in dcgettext for ac_func in dcgettext
do do
echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
echo "configure:8028: checking for $ac_func" >&5 echo "configure:7999: checking for $ac_func" >&5
if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
else else
cat > conftest.$ac_ext <<EOF cat > conftest.$ac_ext <<EOF
#line 8033 "configure" #line 8004 "configure"
#include "confdefs.h" #include "confdefs.h"
/* System header to define __stub macros and hopefully few prototypes, /* System header to define __stub macros and hopefully few prototypes,
which can conflict with char $ac_func(); below. */ which can conflict with char $ac_func(); below. */
...@@ -8052,7 +8023,7 @@ $ac_func(); ...@@ -8052,7 +8023,7 @@ $ac_func();
; return 0; } ; return 0; }
EOF EOF
if { (eval echo configure:8056: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then if { (eval echo configure:8027: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest* rm -rf conftest*
eval "ac_cv_func_$ac_func=yes" eval "ac_cv_func_$ac_func=yes"
else else
...@@ -8079,7 +8050,7 @@ done ...@@ -8079,7 +8050,7 @@ done
# Extract the first word of "gmsgfmt", so it can be a program name with args. # Extract the first word of "gmsgfmt", so it can be a program name with args.
set dummy gmsgfmt; ac_word=$2 set dummy gmsgfmt; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
echo "configure:8083: checking for $ac_word" >&5 echo "configure:8054: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_path_GMSGFMT'+set}'`\" = set"; then if eval "test \"`echo '$''{'ac_cv_path_GMSGFMT'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
else else
...@@ -8115,7 +8086,7 @@ fi ...@@ -8115,7 +8086,7 @@ fi
# Extract the first word of "xgettext", so it can be a program name with args. # Extract the first word of "xgettext", so it can be a program name with args.
set dummy xgettext; ac_word=$2 set dummy xgettext; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
echo "configure:8119: checking for $ac_word" >&5 echo "configure:8090: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_path_XGETTEXT'+set}'`\" = set"; then if eval "test \"`echo '$''{'ac_cv_path_XGETTEXT'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
else else
...@@ -8147,7 +8118,7 @@ else ...@@ -8147,7 +8118,7 @@ else
fi fi
cat > conftest.$ac_ext <<EOF cat > conftest.$ac_ext <<EOF
#line 8151 "configure" #line 8122 "configure"
#include "confdefs.h" #include "confdefs.h"
int main() { int main() {
...@@ -8155,7 +8126,7 @@ extern int _nl_msg_cat_cntr; ...@@ -8155,7 +8126,7 @@ extern int _nl_msg_cat_cntr;
return _nl_msg_cat_cntr return _nl_msg_cat_cntr
; return 0; } ; return 0; }
EOF EOF
if { (eval echo configure:8159: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then if { (eval echo configure:8130: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest* rm -rf conftest*
CATOBJEXT=.gmo CATOBJEXT=.gmo
DATADIRNAME=share DATADIRNAME=share
...@@ -8178,7 +8149,7 @@ fi ...@@ -8178,7 +8149,7 @@ fi
if test "$CATOBJEXT" = "NONE"; then if test "$CATOBJEXT" = "NONE"; then
echo $ac_n "checking whether catgets can be used""... $ac_c" 1>&6 echo $ac_n "checking whether catgets can be used""... $ac_c" 1>&6
echo "configure:8182: checking whether catgets can be used" >&5 echo "configure:8153: checking whether catgets can be used" >&5
# Check whether --with-catgets or --without-catgets was given. # Check whether --with-catgets or --without-catgets was given.
if test "${with_catgets+set}" = set; then if test "${with_catgets+set}" = set; then
withval="$with_catgets" withval="$with_catgets"
...@@ -8191,7 +8162,7 @@ fi ...@@ -8191,7 +8162,7 @@ fi
if test "$nls_cv_use_catgets" = "yes"; then if test "$nls_cv_use_catgets" = "yes"; then
echo $ac_n "checking for main in -li""... $ac_c" 1>&6 echo $ac_n "checking for main in -li""... $ac_c" 1>&6
echo "configure:8195: checking for main in -li" >&5 echo "configure:8166: checking for main in -li" >&5
ac_lib_var=`echo i'_'main | sed 'y%./+-%__p_%'` ac_lib_var=`echo i'_'main | sed 'y%./+-%__p_%'`
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
...@@ -8199,14 +8170,14 @@ else ...@@ -8199,14 +8170,14 @@ else
ac_save_LIBS="$LIBS" ac_save_LIBS="$LIBS"
LIBS="-li $LIBS" LIBS="-li $LIBS"
cat > conftest.$ac_ext <<EOF cat > conftest.$ac_ext <<EOF
#line 8203 "configure" #line 8174 "configure"
#include "confdefs.h" #include "confdefs.h"
int main() { int main() {
main() main()
; return 0; } ; return 0; }
EOF EOF
if { (eval echo configure:8210: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then if { (eval echo configure:8181: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest* rm -rf conftest*
eval "ac_cv_lib_$ac_lib_var=yes" eval "ac_cv_lib_$ac_lib_var=yes"
else else
...@@ -8234,12 +8205,12 @@ else ...@@ -8234,12 +8205,12 @@ else
fi fi
echo $ac_n "checking for catgets""... $ac_c" 1>&6 echo $ac_n "checking for catgets""... $ac_c" 1>&6
echo "configure:8238: checking for catgets" >&5 echo "configure:8209: checking for catgets" >&5
if eval "test \"`echo '$''{'ac_cv_func_catgets'+set}'`\" = set"; then if eval "test \"`echo '$''{'ac_cv_func_catgets'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
else else
cat > conftest.$ac_ext <<EOF cat > conftest.$ac_ext <<EOF
#line 8243 "configure" #line 8214 "configure"
#include "confdefs.h" #include "confdefs.h"
/* System header to define __stub macros and hopefully few prototypes, /* System header to define __stub macros and hopefully few prototypes,
which can conflict with char catgets(); below. */ which can conflict with char catgets(); below. */
...@@ -8262,7 +8233,7 @@ catgets(); ...@@ -8262,7 +8233,7 @@ catgets();
; return 0; } ; return 0; }
EOF EOF
if { (eval echo configure:8266: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then if { (eval echo configure:8237: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest* rm -rf conftest*
eval "ac_cv_func_catgets=yes" eval "ac_cv_func_catgets=yes"
else else
...@@ -8284,7 +8255,7 @@ EOF ...@@ -8284,7 +8255,7 @@ EOF
# Extract the first word of "gencat", so it can be a program name with args. # Extract the first word of "gencat", so it can be a program name with args.
set dummy gencat; ac_word=$2 set dummy gencat; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
echo "configure:8288: checking for $ac_word" >&5 echo "configure:8259: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_path_GENCAT'+set}'`\" = set"; then if eval "test \"`echo '$''{'ac_cv_path_GENCAT'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
else else
...@@ -8320,7 +8291,7 @@ fi ...@@ -8320,7 +8291,7 @@ fi
# Extract the first word of "gmsgfmt", so it can be a program name with args. # Extract the first word of "gmsgfmt", so it can be a program name with args.
set dummy gmsgfmt; ac_word=$2 set dummy gmsgfmt; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
echo "configure:8324: checking for $ac_word" >&5 echo "configure:8295: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_path_GMSGFMT'+set}'`\" = set"; then if eval "test \"`echo '$''{'ac_cv_path_GMSGFMT'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
else else
...@@ -8357,7 +8328,7 @@ fi ...@@ -8357,7 +8328,7 @@ fi
# Extract the first word of "msgfmt", so it can be a program name with args. # Extract the first word of "msgfmt", so it can be a program name with args.
set dummy msgfmt; ac_word=$2 set dummy msgfmt; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
echo "configure:8361: checking for $ac_word" >&5 echo "configure:8332: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_path_GMSGFMT'+set}'`\" = set"; then if eval "test \"`echo '$''{'ac_cv_path_GMSGFMT'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
else else
...@@ -8396,7 +8367,7 @@ fi ...@@ -8396,7 +8367,7 @@ fi
# Extract the first word of "xgettext", so it can be a program name with args. # Extract the first word of "xgettext", so it can be a program name with args.
set dummy xgettext; ac_word=$2 set dummy xgettext; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
echo "configure:8400: checking for $ac_word" >&5 echo "configure:8371: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_path_XGETTEXT'+set}'`\" = set"; then if eval "test \"`echo '$''{'ac_cv_path_XGETTEXT'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
else else
...@@ -8454,7 +8425,7 @@ fi ...@@ -8454,7 +8425,7 @@ fi
# Extract the first word of "msgfmt", so it can be a program name with args. # Extract the first word of "msgfmt", so it can be a program name with args.
set dummy msgfmt; ac_word=$2 set dummy msgfmt; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
echo "configure:8458: checking for $ac_word" >&5 echo "configure:8429: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_path_MSGFMT'+set}'`\" = set"; then if eval "test \"`echo '$''{'ac_cv_path_MSGFMT'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
else else
...@@ -8488,7 +8459,7 @@ fi ...@@ -8488,7 +8459,7 @@ fi
# Extract the first word of "gmsgfmt", so it can be a program name with args. # Extract the first word of "gmsgfmt", so it can be a program name with args.
set dummy gmsgfmt; ac_word=$2 set dummy gmsgfmt; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
echo "configure:8492: checking for $ac_word" >&5 echo "configure:8463: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_path_GMSGFMT'+set}'`\" = set"; then if eval "test \"`echo '$''{'ac_cv_path_GMSGFMT'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
else else
...@@ -8528,7 +8499,7 @@ fi ...@@ -8528,7 +8499,7 @@ fi
# Extract the first word of "xgettext", so it can be a program name with args. # Extract the first word of "xgettext", so it can be a program name with args.
set dummy xgettext; ac_word=$2 set dummy xgettext; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
echo "configure:8532: checking for $ac_word" >&5 echo "configure:8503: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_path_XGETTEXT'+set}'`\" = set"; then if eval "test \"`echo '$''{'ac_cv_path_XGETTEXT'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
else else
...@@ -8623,7 +8594,7 @@ fi ...@@ -8623,7 +8594,7 @@ fi
LINGUAS= LINGUAS=
else else
echo $ac_n "checking for catalogs to be installed""... $ac_c" 1>&6 echo $ac_n "checking for catalogs to be installed""... $ac_c" 1>&6
echo "configure:8627: checking for catalogs to be installed" >&5 echo "configure:8598: checking for catalogs to be installed" >&5
if test "x$LINGUAS" = "x"; then if test "x$LINGUAS" = "x"; then
LINGUAS=$ALL_LINGUAS LINGUAS=$ALL_LINGUAS
else else
...@@ -8655,17 +8626,17 @@ echo "configure:8627: checking for catalogs to be installed" >&5 ...@@ -8655,17 +8626,17 @@ echo "configure:8627: checking for catalogs to be installed" >&5
if test "$CATOBJEXT" = ".cat"; then if test "$CATOBJEXT" = ".cat"; then
ac_safe=`echo "linux/version.h" | sed 'y%./+-%__p_%'` ac_safe=`echo "linux/version.h" | sed 'y%./+-%__p_%'`
echo $ac_n "checking for linux/version.h""... $ac_c" 1>&6 echo $ac_n "checking for linux/version.h""... $ac_c" 1>&6
echo "configure:8659: checking for linux/version.h" >&5 echo "configure:8630: checking for linux/version.h" >&5
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
else else
cat > conftest.$ac_ext <<EOF cat > conftest.$ac_ext <<EOF
#line 8664 "configure" #line 8635 "configure"
#include "confdefs.h" #include "confdefs.h"
#include <linux/version.h> #include <linux/version.h>
EOF EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
{ (eval echo configure:8669: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } { (eval echo configure:8640: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then if test -z "$ac_err"; then
rm -rf conftest* rm -rf conftest*
...@@ -8740,7 +8711,7 @@ fi ...@@ -8740,7 +8711,7 @@ fi
echo $ac_n "checking whether windows registry support is requested""... $ac_c" 1>&6 echo $ac_n "checking whether windows registry support is requested""... $ac_c" 1>&6
echo "configure:8744: checking whether windows registry support is requested" >&5 echo "configure:8715: checking whether windows registry support is requested" >&5
if test x$enable_win32_registry != xno; then if test x$enable_win32_registry != xno; then
cat >> confdefs.h <<\EOF cat >> confdefs.h <<\EOF
#define ENABLE_WIN32_REGISTRY 1 #define ENABLE_WIN32_REGISTRY 1
...@@ -8769,7 +8740,7 @@ esac ...@@ -8769,7 +8740,7 @@ esac
if test x$enable_win32_registry != xno; then if test x$enable_win32_registry != xno; then
echo $ac_n "checking registry key on windows hosts""... $ac_c" 1>&6 echo $ac_n "checking registry key on windows hosts""... $ac_c" 1>&6
echo "configure:8773: checking registry key on windows hosts" >&5 echo "configure:8744: checking registry key on windows hosts" >&5
cat >> confdefs.h <<EOF cat >> confdefs.h <<EOF
#define WIN32_REGISTRY_KEY "$gcc_cv_win32_registry_key" #define WIN32_REGISTRY_KEY "$gcc_cv_win32_registry_key"
EOF EOF
...@@ -8963,7 +8934,7 @@ fi ...@@ -8963,7 +8934,7 @@ fi
# Figure out what assembler we will be using. # Figure out what assembler we will be using.
echo $ac_n "checking what assembler to use""... $ac_c" 1>&6 echo $ac_n "checking what assembler to use""... $ac_c" 1>&6
echo "configure:8967: checking what assembler to use" >&5 echo "configure:8938: checking what assembler to use" >&5
gcc_cv_as= gcc_cv_as=
gcc_cv_gas_major_version= gcc_cv_gas_major_version=
gcc_cv_gas_minor_version= gcc_cv_gas_minor_version=
...@@ -9048,7 +9019,7 @@ fi ...@@ -9048,7 +9019,7 @@ fi
# Figure out what nm we will be using. # Figure out what nm we will be using.
echo $ac_n "checking what nm to use""... $ac_c" 1>&6 echo $ac_n "checking what nm to use""... $ac_c" 1>&6
echo "configure:9052: checking what nm to use" >&5 echo "configure:9023: checking what nm to use" >&5
if test -x nm$host_exeext; then if test -x nm$host_exeext; then
gcc_cv_nm=./nm$host_exeext gcc_cv_nm=./nm$host_exeext
elif test x$host = x$target; then elif test x$host = x$target; then
...@@ -9059,7 +9030,7 @@ echo "$ac_t""$gcc_cv_nm" 1>&6 ...@@ -9059,7 +9030,7 @@ echo "$ac_t""$gcc_cv_nm" 1>&6
# Figure out what assembler alignment features are present. # Figure out what assembler alignment features are present.
echo $ac_n "checking assembler alignment features""... $ac_c" 1>&6 echo $ac_n "checking assembler alignment features""... $ac_c" 1>&6
echo "configure:9063: checking assembler alignment features" >&5 echo "configure:9034: checking assembler alignment features" >&5
gcc_cv_as_alignment_features= gcc_cv_as_alignment_features=
if test x$gcc_cv_gas_major_version != x -a x$gcc_cv_gas_minor_version != x; then if test x$gcc_cv_gas_major_version != x -a x$gcc_cv_gas_minor_version != x; then
# Gas version 2.6 and later support for .balign and .p2align. # Gas version 2.6 and later support for .balign and .p2align.
...@@ -9107,7 +9078,7 @@ fi ...@@ -9107,7 +9078,7 @@ fi
echo "$ac_t""$gcc_cv_as_alignment_features" 1>&6 echo "$ac_t""$gcc_cv_as_alignment_features" 1>&6
echo $ac_n "checking assembler subsection support""... $ac_c" 1>&6 echo $ac_n "checking assembler subsection support""... $ac_c" 1>&6
echo "configure:9111: checking assembler subsection support" >&5 echo "configure:9082: checking assembler subsection support" >&5
gcc_cv_as_subsections= gcc_cv_as_subsections=
if test x$gcc_cv_gas_major_version != x -a x$gcc_cv_gas_minor_version != x; then if test x$gcc_cv_gas_major_version != x -a x$gcc_cv_gas_minor_version != x; then
if test "$gcc_cv_gas_major_version" -eq 2 -a "$gcc_cv_gas_minor_version" -ge 9 -o "$gcc_cv_gas_major_version" -gt 2 && grep 'obj_format = elf' ../gas/Makefile > /dev/null; then if test "$gcc_cv_gas_major_version" -eq 2 -a "$gcc_cv_gas_minor_version" -ge 9 -o "$gcc_cv_gas_major_version" -gt 2 && grep 'obj_format = elf' ../gas/Makefile > /dev/null; then
...@@ -9147,7 +9118,7 @@ fi ...@@ -9147,7 +9118,7 @@ fi
echo "$ac_t""$gcc_cv_as_subsections" 1>&6 echo "$ac_t""$gcc_cv_as_subsections" 1>&6
echo $ac_n "checking assembler weak support""... $ac_c" 1>&6 echo $ac_n "checking assembler weak support""... $ac_c" 1>&6
echo "configure:9151: checking assembler weak support" >&5 echo "configure:9122: checking assembler weak support" >&5
gcc_cv_as_weak= gcc_cv_as_weak=
if test x$gcc_cv_gas_major_version != x -a x$gcc_cv_gas_minor_version != x; then if test x$gcc_cv_gas_major_version != x -a x$gcc_cv_gas_minor_version != x; then
if test "$gcc_cv_gas_major_version" -eq 2 -a "$gcc_cv_gas_minor_version" -ge 2 -o "$gcc_cv_gas_major_version" -gt 2; then if test "$gcc_cv_gas_major_version" -eq 2 -a "$gcc_cv_gas_minor_version" -ge 2 -o "$gcc_cv_gas_major_version" -gt 2; then
...@@ -9170,7 +9141,7 @@ fi ...@@ -9170,7 +9141,7 @@ fi
echo "$ac_t""$gcc_cv_as_weak" 1>&6 echo "$ac_t""$gcc_cv_as_weak" 1>&6
echo $ac_n "checking assembler hidden support""... $ac_c" 1>&6 echo $ac_n "checking assembler hidden support""... $ac_c" 1>&6
echo "configure:9174: checking assembler hidden support" >&5 echo "configure:9145: checking assembler hidden support" >&5
gcc_cv_as_hidden= gcc_cv_as_hidden=
if test x$gcc_cv_gas_major_version != x -a x$gcc_cv_gas_minor_version != x; then if test x$gcc_cv_gas_major_version != x -a x$gcc_cv_gas_minor_version != x; then
if test "$gcc_cv_gas_major_version" -eq 2 -a "$gcc_cv_gas_minor_version" -ge 10 -o "$gcc_cv_gas_major_version" -gt 2 && grep 'obj_format = elf' ../gas/Makefile > /dev/null; then if test "$gcc_cv_gas_major_version" -eq 2 -a "$gcc_cv_gas_minor_version" -ge 10 -o "$gcc_cv_gas_major_version" -gt 2 && grep 'obj_format = elf' ../gas/Makefile > /dev/null; then
...@@ -9196,7 +9167,7 @@ echo "$ac_t""$gcc_cv_as_hidden" 1>&6 ...@@ -9196,7 +9167,7 @@ echo "$ac_t""$gcc_cv_as_hidden" 1>&6
case "$target" in case "$target" in
sparc*-*-*) sparc*-*-*)
echo $ac_n "checking assembler .register pseudo-op support""... $ac_c" 1>&6 echo $ac_n "checking assembler .register pseudo-op support""... $ac_c" 1>&6
echo "configure:9200: checking assembler .register pseudo-op support" >&5 echo "configure:9171: checking assembler .register pseudo-op support" >&5
if eval "test \"`echo '$''{'gcc_cv_as_register_pseudo_op'+set}'`\" = set"; then if eval "test \"`echo '$''{'gcc_cv_as_register_pseudo_op'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
else else
...@@ -9224,7 +9195,7 @@ EOF ...@@ -9224,7 +9195,7 @@ EOF
fi fi
echo $ac_n "checking assembler supports -relax""... $ac_c" 1>&6 echo $ac_n "checking assembler supports -relax""... $ac_c" 1>&6
echo "configure:9228: checking assembler supports -relax" >&5 echo "configure:9199: checking assembler supports -relax" >&5
if eval "test \"`echo '$''{'gcc_cv_as_relax_opt'+set}'`\" = set"; then if eval "test \"`echo '$''{'gcc_cv_as_relax_opt'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
else else
...@@ -9254,7 +9225,7 @@ EOF ...@@ -9254,7 +9225,7 @@ EOF
case "$tm_file" in case "$tm_file" in
*64*) *64*)
echo $ac_n "checking for 64 bit support in assembler ($gcc_cv_as)""... $ac_c" 1>&6 echo $ac_n "checking for 64 bit support in assembler ($gcc_cv_as)""... $ac_c" 1>&6
echo "configure:9258: checking for 64 bit support in assembler ($gcc_cv_as)" >&5 echo "configure:9229: checking for 64 bit support in assembler ($gcc_cv_as)" >&5
if eval "test \"`echo '$''{'gcc_cv_as_flags64'+set}'`\" = set"; then if eval "test \"`echo '$''{'gcc_cv_as_flags64'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
else else
...@@ -9299,7 +9270,7 @@ EOF ...@@ -9299,7 +9270,7 @@ EOF
if test "x$gcc_cv_as_flags64" != xno; then if test "x$gcc_cv_as_flags64" != xno; then
echo $ac_n "checking for assembler offsetable %lo() support""... $ac_c" 1>&6 echo $ac_n "checking for assembler offsetable %lo() support""... $ac_c" 1>&6
echo "configure:9303: checking for assembler offsetable %lo() support" >&5 echo "configure:9274: checking for assembler offsetable %lo() support" >&5
if eval "test \"`echo '$''{'gcc_cv_as_offsetable_lo10'+set}'`\" = set"; then if eval "test \"`echo '$''{'gcc_cv_as_offsetable_lo10'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
else else
...@@ -9338,7 +9309,7 @@ EOF ...@@ -9338,7 +9309,7 @@ EOF
i[34567]86-*-*) i[34567]86-*-*)
echo $ac_n "checking assembler instructions""... $ac_c" 1>&6 echo $ac_n "checking assembler instructions""... $ac_c" 1>&6
echo "configure:9342: checking assembler instructions" >&5 echo "configure:9313: checking assembler instructions" >&5
gcc_cv_as_instructions= gcc_cv_as_instructions=
if test x$gcc_cv_gas_major_version != x -a x$gcc_cv_gas_minor_version != x; then if test x$gcc_cv_gas_major_version != x -a x$gcc_cv_gas_minor_version != x; then
if test "$gcc_cv_gas_major_version" -eq 2 -a "$gcc_cv_gas_minor_version" -ge 9 -o "$gcc_cv_gas_major_version" -gt 2; then if test "$gcc_cv_gas_major_version" -eq 2 -a "$gcc_cv_gas_minor_version" -ge 9 -o "$gcc_cv_gas_major_version" -gt 2; then
...@@ -9488,7 +9459,7 @@ fi ...@@ -9488,7 +9459,7 @@ fi
# Build a new-libstdc++ system (ie libstdc++-v3) # Build a new-libstdc++ system (ie libstdc++-v3)
echo $ac_n "checking for libstdc++ to install""... $ac_c" 1>&6 echo $ac_n "checking for libstdc++ to install""... $ac_c" 1>&6
echo "configure:9492: checking for libstdc++ to install" >&5 echo "configure:9463: checking for libstdc++ to install" >&5
# Check whether --enable-libstdcxx-v3 or --disable-libstdcxx-v3 was given. # Check whether --enable-libstdcxx-v3 or --disable-libstdcxx-v3 was given.
if test "${enable_libstdcxx_v3+set}" = set; then if test "${enable_libstdcxx_v3+set}" = set; then
enableval="$enable_libstdcxx_v3" enableval="$enable_libstdcxx_v3"
...@@ -9512,7 +9483,7 @@ EOF ...@@ -9512,7 +9483,7 @@ EOF
echo $ac_n "checking whether to enable maintainer-specific portions of Makefiles""... $ac_c" 1>&6 echo $ac_n "checking whether to enable maintainer-specific portions of Makefiles""... $ac_c" 1>&6
echo "configure:9516: checking whether to enable maintainer-specific portions of Makefiles" >&5 echo "configure:9487: checking whether to enable maintainer-specific portions of Makefiles" >&5
# Check whether --enable-maintainer-mode or --disable-maintainer-mode was given. # Check whether --enable-maintainer-mode or --disable-maintainer-mode was given.
if test "${enable_maintainer_mode+set}" = set; then if test "${enable_maintainer_mode+set}" = set; then
enableval="$enable_maintainer_mode" enableval="$enable_maintainer_mode"
......
...@@ -1031,9 +1031,6 @@ changequote([,])dnl ...@@ -1031,9 +1031,6 @@ changequote([,])dnl
tmake_file=fr30/t-fr30 tmake_file=fr30/t-fr30
extra_parts="crti.o crtn.o crtbegin.o crtend.o" extra_parts="crti.o crtn.o crtbegin.o crtend.o"
;; ;;
# This hasn't been upgraded to GCC 2.
# fx80-alliant-*) # Alliant FX/80
# ;;
h8300-*-*) h8300-*-*)
float_format=i32 float_format=i32
;; ;;
...@@ -3112,13 +3109,6 @@ changequote([,])dnl ...@@ -3112,13 +3109,6 @@ changequote([,])dnl
tm_file=ns32k/tek6200.h tm_file=ns32k/tek6200.h
use_collect2=yes use_collect2=yes
;; ;;
# This has not been updated to GCC 2.
# ns32k-ns-genix*)
# xm_defines=USG
# xmake_file=ns32k/x-genix
# tm_file=ns32k/genix.h
# use_collect2=yes
# ;;
ns32k-merlin-*) ns32k-merlin-*)
tm_file=ns32k/merlin.h tm_file=ns32k/merlin.h
use_collect2=yes use_collect2=yes
...@@ -3150,13 +3140,6 @@ changequote([,])dnl ...@@ -3150,13 +3140,6 @@ changequote([,])dnl
ns32k-*-openbsd*) ns32k-*-openbsd*)
# Nothing special # Nothing special
;; ;;
# This has not been updated to GCC 2.
# pyramid-*-*)
# cpu_type=pyr
# xmake_file=pyr/x-pyr
# use_collect2=yes
# ;;
pj*-linux*) pj*-linux*)
tm_file="svr4.h pj/linux.h ${tm_file}" tm_file="svr4.h pj/linux.h ${tm_file}"
;; ;;
...@@ -3659,24 +3642,12 @@ changequote([,])dnl ...@@ -3659,24 +3642,12 @@ changequote([,])dnl
fi fi
float_format=sparc float_format=sparc
;; ;;
# This hasn't been upgraded to GCC 2.
# tahoe-harris-*) # Harris tahoe, using COFF.
# tm_file=tahoe/harris.h
# ;;
# tahoe-*-bsd*) # tahoe running BSD
# ;;
thumb*-*-*) thumb*-*-*)
AC_MSG_ERROR([ AC_MSG_ERROR([
*** The Thumb targets have been depreciated. The equivalent *** The Thumb targets have been depreciated. The equivalent
*** ARM based toolchain can now generated Thumb instructions *** ARM based toolchain can now generated Thumb instructions
*** when the -mthumb switch is given to the compiler.]) *** when the -mthumb switch is given to the compiler.])
;; ;;
# This hasn't been upgraded to GCC 2.
# tron-*-*)
# cpu_type=gmicro
# use_collect2=yes
# ;;
v850-*-rtems*) v850-*-rtems*)
cpu_type=v850 cpu_type=v850
tm_file="v850/rtems.h" tm_file="v850/rtems.h"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment