V.4 support.

From-SVN: r10152
This commit is contained in:
Michael Meissner 1995-07-21 18:15:38 +00:00
parent b3ae05da16
commit 4697a36cef
13 changed files with 1523 additions and 465 deletions

View File

@ -47,6 +47,29 @@ Boston, MA 02111-1307, USA. */
%{mcpu=603: -mppc} \
%{mcpu=604: -mppc}"
/* Define the options for the binder: Start text at 512, align all segments
to 512 bytes, and warn if there is text relocation.
The -bhalt:4 option supposedly changes the level at which ld will abort,
but it also suppresses warnings about multiply defined symbols and is
used by the AIX cc command. So we use it here.
-bnodelcsect undoes a poor choice of default relating to multiply-defined
csects. See AIX documentation for more information about this.
-bM:SRE tells the linker that the output file is Shared REusable. Note
that to actually build a shared library you will also need to specify an
export list with the -Wl,-bE option.
If -mcpu=common, export the architecture dependent multiply/divide routines
as per README.RS6000. */
#undef LINK_SPEC
#define LINK_SPEC "-T512 -H512 %{!r:-btextro} -bhalt:4 -bnodelcsect\
%{static:-bnso -bI:/lib/syscalls.exp} \
%{mcpu=common: milli.exp%s} \
%{!shared:%{g*:-bexport:/usr/lib/libg.exp}} %{shared:-bM:SRE}"
/* These are not necessary when we pass -u to the assembler, and undefining
them saves a great deal of space in object files. */

View File

@ -27,6 +27,12 @@
.Lgot2e = .-.LCTOC1
.long _GOT2_END_ # -mrelocatable GOT pointers end
.Lfixups = .-.LCTOC1
.long _FIXUP_START_ # start of .fixup section
.Lfixupe = .-.LCTOC1
.long _FIXUP_END_ # end of .fixup section
.text
.Lptr:
.long .LCTOC1-.Laddr # PC relative pointer to .got2
@ -64,16 +70,36 @@ __eabi: mflr 0
add 4,12,4
cmpw 1,3,4 # any pointers to adjust
bc 12,6,.Ldone
bc 12,6,.Lfix
.Lloop:
lwz 11,0(3) # next pointer
add 11,11,12 # adjust
stw 11,0(3)
lwz 5,0(3) # next pointer
add 5,5,12 # adjust
stw 5,0(3)
addi 3,3,4 # bump to next word
cmpw 1,3,4 # more pointers to adjust?
bc 4,6,.Lloop
# Fixup any user initialized pointers now (the compiler drops pointers to
# each of the relocs that it does in the .fixup section). Note, the pointers
# themselves have already been fixed up by the previous loop.
.Lfix:
lwz 3,.Lfixups(11) # fixup pointers start
lwz 4,.Lfixupe(11) # fixup pointers end
cmpw 1,3,4 # any user pointers to adjust
bc 12,6,.Ldone
.Lfloop:
lwz 5,0(3) # next pointer
lwz 6,0(5) # get the pointer it points to
add 6,6,12 # adjust
stw 6,0(5)
addi 3,3,4 # bump to next word
cmpw 1,3,4 # more pointers to adjust?
bc 4,6,.Lfloop
# Done adjusting pointers, return
.Ldone:

View File

@ -50,6 +50,11 @@ Boston, MA 02111-1307, USA. */
#define MINIMAL_TOC_SECTION_ASM_OP \
((TARGET_RELOCATABLE) ? "\t.section\t\".got2\",\"aw\"" : "\t.section\t\".got1\",\"aw\"")
/* Put relocatable data in .data, not .rodata so initialized pointers can be updated */
#undef CONST_SECTION_ASM_OP
#define CONST_SECTION_ASM_OP \
((TARGET_RELOCATABLE) ? "\t.section\t\".data\"\t# .rodata" : "\t.section\t\".rodata\"")
/* Invoke an initializer function to set up the GOT */
#define NAME__MAIN "__eabi"
#define INVOKE__main 1
@ -74,3 +79,43 @@ Boston, MA 02111-1307, USA. */
#undef ENDFILE_SPEC
#define ENDFILE_SPEC ""
/* This is how to output an assembler line defining an `int' constant.
For -mrelocatable, we mark all addresses that need to be fixed up
in the .fixup section. */
#undef ASM_OUTPUT_INT
#define ASM_OUTPUT_INT(FILE,VALUE) \
do { \
static int recurse = 0; \
if (TARGET_RELOCATABLE \
&& in_section != in_toc \
&& in_section != in_text \
&& in_section != in_ctors \
&& in_section != in_dtors \
&& !recurse \
&& GET_CODE (VALUE) != CONST_INT \
&& GET_CODE (VALUE) != CONST_DOUBLE) \
{ \
static int labelno = 0; \
char buf[256], *p; \
\
recurse = 1; \
ASM_GENERATE_INTERNAL_LABEL (buf, "LCP", labelno++); \
STRIP_NAME_ENCODING (p, buf); \
fprintf (FILE, "%s:\n", p); \
fprintf (FILE, "\t.long ("); \
output_addr_const (FILE, (VALUE)); \
fprintf (FILE, ")@fixup\n"); \
fprintf (FILE, "\t.section\t\".fixup\",\"aw\"\n"); \
ASM_OUTPUT_ALIGN (FILE, 2); \
fprintf (FILE, "\t.long\t%s\n", p); \
fprintf (FILE, "\t.previous\n"); \
recurse = 0; \
} \
else \
{ \
fprintf (FILE, "\t.long "); \
output_addr_const (FILE, (VALUE)); \
fprintf (FILE, "\n"); \
} \
} while (0)

View File

@ -0,0 +1,53 @@
/* Embedded ELF system support, using old AIX based calling sequence.
Copyright (C) 1995 Free Software Foundation, Inc.
Contributed by Cygnus Support.
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 "rs6000/eabi.h"
#undef TARGET_DEFAULT
#define TARGET_DEFAULT (MASK_POWERPC | MASK_NEW_MNEMONICS | MASK_AIX_CALLS)
#undef CPP_SPEC
#define CPP_SPEC "\
%{posix: -D_POSIX_SOURCE} \
%{mrelocatable: -D_RELOCATABLE} \
%{mcall-sysv: -D_CALL_SYSV} %{mcall-aix: -D_CALL_AIX} %{!mcall-sysv: %{!mcall-aix: -D_CALL_AIX}} \
%{msoft-float: -D_SOFT_FLOAT} %{mcpu=403: -D_SOFT_FLOAT} \
%{mlittle: -D_LITTLE_ENDIAN -Amachine(littleendian)} \
%{mlittle-endian: -D_LITTLE_ENDIAN -Amachine(littleendian)} \
%{!mlittle: %{!mlittle-endian: -D_BIG_ENDIAN -Amachine(bigendian)}} \
%{!mcpu*: \
%{mpower: %{!mpower2: -D_ARCH_PWR}} \
%{mpower2: -D_ARCH_PWR2} \
%{mpowerpc*: -D_ARCH_PPC} \
%{mno-powerpc: %{!mpower: %{!mpower2: -D_ARCH_COM}}} \
%{!mno-powerpc: -D_ARCH_PPC}} \
%{mcpu=common: -D_ARCH_COM} \
%{mcpu=power: -D_ARCH_PWR} \
%{mcpu=powerpc: -D_ARCH_PPC} \
%{mcpu=rios: -D_ARCH_PWR} \
%{mcpu=rios1: -D_ARCH_PWR} \
%{mcpu=rios2: -D_ARCH_PWR2} \
%{mcpu=rsc: -D_ARCH_PWR} \
%{mcpu=rsc1: -D_ARCH_PWR} \
%{mcpu=403: -D_ARCH_PPC} \
%{mcpu=601: -D_ARCH_PPC -D_ARCH_PWR} \
%{mcpu=603: -D_ARCH_PPC} \
%{mcpu=604: -D_ARCH_PPC}"

View File

@ -29,6 +29,8 @@ Boston, MA 02111-1307, USA. */
#define CPP_SPEC "\
%{posix: -D_POSIX_SOURCE} \
%{mrelocatable: -D_RELOCATABLE} \
%{mcall-sysv: -D_CALL_SYSV} %{mcall-aix: -D_CALL_AIX} %{!mcall-sysv: %{!mcall-aix: -D_CALL_SYSV}} \
%{msoft-float: -D_SOFT_FLOAT} %{mcpu=403: -D_SOFT_FLOAT} \
%{mbig: -D_BIG_ENDIAN -Amachine(bigendian)} \
%{mbig-endian: -D_BIG_ENDIAN -Amachine(bigendian)} \
%{!mbig: %{!mbig-endian: -D_LITTLE_ENDIAN -Amachine(littleendian)}} \

View File

@ -0,0 +1,7 @@
#!
__mulh 0x3100
__mull 0x3180
__divss 0x3200
__divus 0x3280
__quoss 0x3300
__quous 0x3380

File diff suppressed because it is too large Load Diff

View File

@ -150,6 +150,10 @@ extern int target_flags;
#define MASK_STRING 0x4000
#define MASK_STRING_SET 0x8000
/* Temporary debug switches */
#define MASK_DEBUG_STACK 0x10000
#define MASK_DEBUG_ARG 0x20000
#define TARGET_POWER (target_flags & MASK_POWER)
#define TARGET_POWER2 (target_flags & MASK_POWER2)
#define TARGET_POWERPC (target_flags & MASK_POWERPC)
@ -166,9 +170,23 @@ extern int target_flags;
#define TARGET_MULTIPLE_SET (target_flags & MASK_MULTIPLE_SET)
#define TARGET_STRING (target_flags & MASK_STRING)
#define TARGET_STRING_SET (target_flags & MASK_STRING_SET)
#define TARGET_DEBUG_STACK (target_flags & MASK_DEBUG_STACK)
#define TARGET_DEBUG_ARG (target_flags & MASK_DEBUG_ARG)
#define TARGET_HARD_FLOAT (! TARGET_SOFT_FLOAT)
/* Pseudo target to indicate whether the object format is ELF
(to get around not having conditional compilation in the md file) */
#ifndef TARGET_ELF
#define TARGET_ELF 0
#endif
/* If this isn't V.4, don't support -mno-toc. */
#ifndef TARGET_NO_TOC
#define TARGET_NO_TOC 0
#define TARGET_TOC 1
#endif
/* Run-time compilation parameters selecting different hardware subsets.
Macro to define tables used to set the flags.
@ -215,6 +233,8 @@ extern int target_flags;
{"string", MASK_STRING | MASK_STRING_SET}, \
{"no-string", - MASK_STRING}, \
{"no-string", MASK_STRING_SET}, \
{"debug-stack", MASK_DEBUG_STACK}, \
{"debug-arg", MASK_DEBUG_ARG}, \
SUBTARGET_SWITCHES \
{"", TARGET_DEFAULT}}
@ -833,6 +853,32 @@ enum reg_class { NO_REGS, BASE_REGS, GENERAL_REGS, FLOAT_REGS,
/* Stack layout; function entry, exit and calling. */
/* Structure used to define the rs6000 stack */
typedef struct rs6000_stack {
int first_gp_reg_save; /* first callee saved GP register used */
int first_fp_reg_save; /* first callee saved FP register used */
int lr_save_p; /* true if the link reg needs to be saved */
int cr_save_p; /* true if the CR reg needs to be saved */
int push_p; /* true if we need to allocate stack space */
int calls_p; /* true if the function makes any calls */
int v4_call_p; /* true if V.4 calling sequence used */
int gp_save_offset; /* offset to save GP regs from inital SP */
int fp_save_offset; /* offset to save FP regs from inital SP */
int lr_save_offset; /* offset to save LR from initial SP */
int cr_save_offset; /* offset to save CR from initial SP */
int varargs_save_offset; /* offset to save the varargs registers */
int reg_size; /* register size (4 or 8) */
int varargs_size; /* size to hold V.4 args passed in regs */
int vars_size; /* variable save area size */
int parm_size; /* outgoing parameter size */
int save_size; /* save area size */
int fixed_size; /* fixed size of stack frame */
int gp_size; /* size of saved GP registers */
int fp_size; /* size of saved FP registers */
int cr_size; /* size to hold CR if not in save_size */
int total_size; /* total bytes allocated for stack */
} rs6000_stack_t;
/* Define this if pushing a word on the stack
makes the stack pointer a smaller address. */
#define STACK_GROWS_DOWNWARD
@ -846,6 +892,29 @@ enum reg_class { NO_REGS, BASE_REGS, GENERAL_REGS, FLOAT_REGS,
arguments. */
/* #define FRAME_GROWS_DOWNWARD */
/* Size of the outgoing register save area */
#define RS6000_REG_SAVE (TARGET_64BIT ? 64 : 32)
/* Size of the fixed area on the stack */
#define RS6000_SAVE_AREA (TARGET_64BIT ? 48 : 24)
/* Size of the V.4 varargs area if needed */
#define RS6000_VARARGS_AREA 0
/* Whether a V.4 varargs area is needed */
extern int rs6000_sysv_varargs_p;
/* Align an address */
#define ALIGN(n,a) (((n) + (a) - 1) & ~((a) - 1))
/* Size of V.4 varargs area in bytes */
#define RS6000_VARARGS_SIZE \
((GP_ARG_NUM_REG * (TARGET_64BIT ? 8 : 4)) + (FP_ARG_NUM_REG * 8) + 8)
/* Offset of V.4 varargs area */
#define RS6000_VARARGS_OFFSET \
(ALIGN (current_function_outgoing_args_size, 8) + RS6000_SAVE_AREA)
/* 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
@ -855,8 +924,9 @@ enum reg_class { NO_REGS, BASE_REGS, GENERAL_REGS, FLOAT_REGS,
except for dynamic allocations. So we start after the fixed area and
outgoing parameter area. */
#define STARTING_FRAME_OFFSET (current_function_outgoing_args_size \
+ (TARGET_64BIT ? 48 : 24))
#define STARTING_FRAME_OFFSET (ALIGN (current_function_outgoing_args_size, 8) \
+ RS6000_VARARGS_AREA \
+ RS6000_SAVE_AREA)
/* If we generate an insn to push BYTES bytes,
this says how many the stack pointer really advances by.
@ -866,12 +936,12 @@ enum reg_class { NO_REGS, BASE_REGS, GENERAL_REGS, FLOAT_REGS,
/* Offset of first parameter from the argument pointer register value.
On the RS/6000, we define the argument pointer to the start of the fixed
area. */
#define FIRST_PARM_OFFSET(FNDECL) (TARGET_64BIT ? 48 : 24)
#define FIRST_PARM_OFFSET(FNDECL) RS6000_SAVE_AREA
/* Define this if stack space is still allocated for a parameter passed
in a register. The value is the number of bytes allocated to this
area. */
#define REG_PARM_STACK_SPACE(FNDECL) (TARGET_64BIT ? 64 : 32)
#define REG_PARM_STACK_SPACE(FNDECL) RS6000_REG_SAVE
/* Define this if the above stack space is to be considered part of the
space allocated by the caller. */
@ -880,7 +950,7 @@ enum reg_class { NO_REGS, BASE_REGS, GENERAL_REGS, FLOAT_REGS,
/* This is the difference between the logical top of stack and the actual sp.
For the RS/6000, sp points past the fixed area. */
#define STACK_POINTER_OFFSET (TARGET_64BIT ? 48 : 24)
#define STACK_POINTER_OFFSET RS6000_SAVE_AREA
/* Define this if the maximum size of all the outgoing args is to be
accumulated and pushed during the prologue. The amount can be
@ -922,18 +992,35 @@ enum reg_class { NO_REGS, BASE_REGS, GENERAL_REGS, FLOAT_REGS,
#define RETURN_IN_MEMORY(TYPE) \
(TYPE_MODE (TYPE) == BLKmode)
/* Minimum and maximum general purpose registers used to hold arguments. */
#define GP_ARG_MIN_REG 3
#define GP_ARG_MAX_REG 10
#define GP_ARG_NUM_REG (GP_ARG_MAX_REG - GP_ARG_MIN_REG + 1)
/* Minimum and maximum floating point registers used to hold arguments. */
#define FP_ARG_MIN_REG 33
#define FP_ARG_MAX_REG 45
#define FP_ARG_NUM_REG (FP_ARG_MAX_REG - FP_ARG_MIN_REG + 1)
/* Return registers */
#define GP_ARG_RETURN GP_ARG_MIN_REG
#define FP_ARG_RETURN FP_ARG_MIN_REG
/* Define cutoff for using external functions to save floating point */
#define FP_SAVE_INLINE(FIRST_REG) ((FIRST_REG) == 62 || (FIRST_REG) == 63)
/* 1 if N is a possible register number for a function value
as seen by the caller.
On RS/6000, this is r3 and fp1. */
#define FUNCTION_VALUE_REGNO_P(N) ((N) == 3 || ((N) == 33))
#define FUNCTION_VALUE_REGNO_P(N) ((N) == GP_ARG_RETURN || ((N) == FP_ARG_RETURN))
/* 1 if N is a possible register number for function argument passing.
On RS/6000, these are r3-r10 and fp1-fp13. */
#define FUNCTION_ARG_REGNO_P(N) \
(((unsigned)((N) - GP_ARG_MIN_REG) < (unsigned)(GP_ARG_NUM_REG)) \
|| ((unsigned)((N) - FP_ARG_MIN_REG) < (unsigned)(FP_ARG_NUM_REG)))
#define FUNCTION_ARG_REGNO_P(N) \
(((N) <= 10 && (N) >= 3) || ((N) >= 33 && (N) <= 45))
/* Define a data type for recording info about an argument list
during the scan of that argument list. This data type should
@ -944,10 +1031,21 @@ enum reg_class { NO_REGS, BASE_REGS, GENERAL_REGS, FLOAT_REGS,
On the RS/6000, this is a structure. The first element is the number of
total argument words, the second is used to store the next
floating-point register number, and the third says how many more args we
have prototype types for. */
have prototype types for.
struct rs6000_args {int words, fregno, nargs_prototype; };
#define CUMULATIVE_ARGS struct rs6000_args
The System V.4 varargs/stdarg support requires that this structure's size
be a multiple of sizeof(int), and that WORDS, FREGNO, NARGS_PROTOTYPE,
ORIG_NARGS, and VARARGS_OFFSET be the first five ints. */
typedef struct rs6000_args
{
int words; /* # words uses for passing GP registers */
int fregno; /* next available FP register */
int nargs_prototype; /* # args left in the current prototype */
int orig_nargs; /* Original value of nargs_prototype */
int varargs_offset; /* offset of the varargs save area */
int prototype; /* Whether a prototype was defined */
} CUMULATIVE_ARGS;
/* Define intermediate macro to compute the size (in registers) of an argument
for the RS/6000. */
@ -962,40 +1060,27 @@ struct rs6000_args {int words, fregno, nargs_prototype; };
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) \
(CUM).words = 0, \
(CUM).fregno = 33, \
(CUM).nargs_prototype = (FNTYPE && TYPE_ARG_TYPES (FNTYPE) \
? (list_length (TYPE_ARG_TYPES (FNTYPE)) - 1 \
+ (TYPE_MODE (TREE_TYPE (FNTYPE)) == BLKmode \
|| RETURN_IN_MEMORY (TREE_TYPE (FNTYPE)))) \
: 0)
#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE,LIBNAME) \
init_cumulative_args (&CUM, FNTYPE, LIBNAME, FALSE)
/* Similar, but when scanning the definition of a procedure. We always
set NARGS_PROTOTYPE large so we never return an EXPR_LIST. */
#define INIT_CUMULATIVE_INCOMING_ARGS(CUM,FNTYPE,IGNORE) \
(CUM).words = 0, \
(CUM).fregno = 33, \
(CUM).nargs_prototype = 1000
#define INIT_CUMULATIVE_INCOMING_ARGS(CUM,FNTYPE,LIBNAME) \
init_cumulative_args (&CUM, FNTYPE, LIBNAME, TRUE)
/* 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).nargs_prototype--; \
if (NAMED) \
{ \
(CUM).words += RS6000_ARG_SIZE (MODE, TYPE, NAMED); \
if (GET_MODE_CLASS (MODE) == MODE_FLOAT) \
(CUM).fregno++; \
} \
}
function_arg_advance (&CUM, MODE, TYPE, NAMED)
/* Non-zero if we can use a floating-point register to pass this arg. */
#define USE_FP_FOR_ARG_P(CUM,MODE,TYPE) \
(GET_MODE_CLASS (MODE) == MODE_FLOAT && (CUM).fregno < 46 && TARGET_HARD_FLOAT)
#define USE_FP_FOR_ARG_P(CUM,MODE,TYPE) \
(GET_MODE_CLASS (MODE) == MODE_FLOAT \
&& (CUM).fregno <= FP_ARG_MAX_REG \
&& TARGET_HARD_FLOAT)
/* Determine where to put an argument to a function.
Value is zero to push the argument on the stack,
@ -1019,30 +1104,24 @@ struct rs6000_args {int words, fregno, nargs_prototype; };
so we can pass the FP value just in one register. emit_library_function
doesn't support EXPR_LIST anyway. */
#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \
(! (NAMED) ? 0 \
: ((TYPE) != 0 && TREE_CODE (TYPE_SIZE (TYPE)) != INTEGER_CST) ? 0 \
: USE_FP_FOR_ARG_P (CUM, MODE, TYPE) \
? ((CUM).nargs_prototype > 0 || (TYPE) == 0 \
? gen_rtx (REG, MODE, (CUM).fregno) \
: ((CUM).words < 8 \
? gen_rtx (EXPR_LIST, VOIDmode, \
gen_rtx (REG, (MODE), 3 + (CUM).words), \
gen_rtx (REG, (MODE), (CUM).fregno)) \
: gen_rtx (EXPR_LIST, VOIDmode, 0, \
gen_rtx (REG, (MODE), (CUM).fregno)))) \
: (CUM).words < 8 ? gen_rtx(REG, (MODE), 3 + (CUM).words) : 0)
#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \
function_arg (&CUM, MODE, TYPE, NAMED)
/* 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) \
(! (NAMED) ? 0 \
: USE_FP_FOR_ARG_P (CUM, MODE, TYPE) && (CUM).nargs_prototype >= 0 ? 0 \
: (((CUM).words < 8 \
&& 8 < ((CUM).words + RS6000_ARG_SIZE (MODE, TYPE, NAMED))) \
? 8 - (CUM).words : 0))
#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) \
function_arg_partial_nregs (&CUM, MODE, TYPE, NAMED)
/* A C expression that indicates when an argument must be passed by
reference. If nonzero for an argument, a copy of that argument is
made in memory and a pointer to the argument is passed instead of
the argument itself. The pointer is passed in whatever way is
appropriate for passing a pointer to that type. */
#define FUNCTION_ARG_PASS_BY_REFERENCE(CUM, MODE, TYPE, NAMED) \
function_arg_pass_by_reference(&CUM, MODE, TYPE, NAMED)
/* Perform any needed actions needed for a function that is receiving a
variable number of arguments.
@ -1058,27 +1137,23 @@ struct rs6000_args {int words, fregno, nargs_prototype; };
Normally, this macro will push all remaining incoming registers on the
stack and set PRETEND_SIZE to the length of the registers pushed. */
#define SETUP_INCOMING_VARARGS(CUM,MODE,TYPE,PRETEND_SIZE,NO_RTL) \
{ if ((CUM).words < 8) \
{ \
int first_reg_offset = (CUM).words; \
\
if (MUST_PASS_IN_STACK (MODE, TYPE)) \
first_reg_offset += RS6000_ARG_SIZE (TYPE_MODE (TYPE), TYPE, 1); \
\
if (first_reg_offset > 8) \
first_reg_offset = 8; \
\
if (! (NO_RTL) && first_reg_offset != 8) \
move_block_from_reg \
(3 + first_reg_offset, \
gen_rtx (MEM, BLKmode, \
plus_constant (virtual_incoming_args_rtx, \
first_reg_offset * 4)), \
8 - first_reg_offset, (8 - first_reg_offset) * UNITS_PER_WORD); \
PRETEND_SIZE = (8 - first_reg_offset) * UNITS_PER_WORD; \
} \
}
#define SETUP_INCOMING_VARARGS(CUM,MODE,TYPE,PRETEND_SIZE,NO_RTL) \
setup_incoming_varargs (&CUM, MODE, TYPE, &PRETEND_SIZE, NO_RTL)
/* If defined, is a C expression that produces the machine-specific
code for a call to `__builtin_saveregs'. This code will be moved
to the very beginning of the function, before any parameter access
are made. The return value of this function should be an RTX that
contains the value to use as the return of `__builtin_saveregs'.
The argument ARGS is a `tree_list' containing the arguments that
were passed to `__builtin_saveregs'.
If this macro is not defined, the compiler will output an ordinary
call to the library function `__builtin_saveregs'. */
#define EXPAND_BUILTIN_SAVEREGS(ARGS) \
expand_builtin_saveregs (ARGS)
/* This macro generates the assembly code for function entry.
FILE is a stdio stream to output the code to.
@ -1210,34 +1285,21 @@ struct rs6000_args {int words, fregno, nargs_prototype; };
#define CAN_ELIMINATE(FROM, TO) \
((FROM) == ARG_POINTER_REGNUM && (TO) == STACK_POINTER_REGNUM \
? ! frame_pointer_needed \
: (FROM) == 30 ? ! TARGET_MINIMAL_TOC || get_pool_size () == 0 \
: (FROM) == 30 ? ! TARGET_MINIMAL_TOC || TARGET_NO_TOC || get_pool_size () == 0 \
: 1)
/* Define the offset between two registers, one to be eliminated, and the other
its replacement, at the start of a routine. */
#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \
{ \
int total_stack_size = (rs6000_sa_size () + get_frame_size () \
+ current_function_outgoing_args_size); \
\
total_stack_size = (total_stack_size + 7) & ~7; \
rs6000_stack_t *info = rs6000_stack_info (); \
\
if ((FROM) == FRAME_POINTER_REGNUM && (TO) == STACK_POINTER_REGNUM) \
{ \
if (rs6000_pushes_stack ()) \
(OFFSET) = 0; \
else \
(OFFSET) = - total_stack_size; \
} \
else if ((FROM) == ARG_POINTER_REGNUM && (TO) == FRAME_POINTER_REGNUM) \
(OFFSET) = total_stack_size; \
else if ((FROM) == ARG_POINTER_REGNUM && (TO) == STACK_POINTER_REGNUM) \
{ \
if (rs6000_pushes_stack ()) \
(OFFSET) = total_stack_size; \
else \
(OFFSET) = 0; \
} \
(OFFSET) = (info->push_p) ? 0 : - info->total_size; \
else if ((FROM) == ARG_POINTER_REGNUM && (TO) == FRAME_POINTER_REGNUM) \
(OFFSET) = info->total_size; \
else if ((FROM) == ARG_POINTER_REGNUM && (TO) == STACK_POINTER_REGNUM) \
(OFFSET) = (info->push_p) ? info->total_size : 0; \
else if ((FROM) == 30) \
(OFFSET) = 0; \
else \
@ -1341,12 +1403,14 @@ struct rs6000_args {int words, fregno, nargs_prototype; };
we must ensure that both words are addressable. */
#define LEGITIMATE_CONSTANT_POOL_BASE_P(X) \
(GET_CODE (X) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (X) \
(TARGET_TOC && GET_CODE (X) == SYMBOL_REF \
&& CONSTANT_POOL_ADDRESS_P (X) \
&& ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (get_pool_constant (X)))
#define LEGITIMATE_CONSTANT_POOL_ADDRESS_P(X) \
(LEGITIMATE_CONSTANT_POOL_BASE_P (X) \
|| (GET_CODE (X) == CONST && GET_CODE (XEXP (X, 0)) == PLUS \
|| (TARGET_TOC \
&& GET_CODE (X) == CONST && GET_CODE (XEXP (X, 0)) == PLUS \
&& GET_CODE (XEXP (XEXP (X, 0), 1)) == CONST_INT \
&& LEGITIMATE_CONSTANT_POOL_BASE_P (XEXP (XEXP (X, 0), 0))))
@ -1374,6 +1438,16 @@ struct rs6000_args {int words, fregno, nargs_prototype; };
#define LEGITIMATE_INDIRECT_ADDRESS_P(X) \
(GET_CODE (X) == REG && REG_OK_FOR_BASE_P (X))
#define LEGITIMATE_LO_SUM_ADDRESS_P(MODE, X) \
(TARGET_ELF \
&& (MODE) != DImode \
&& (MODE) != TImode \
&& (TARGET_HARD_FLOAT || (MODE) != DFmode) \
&& GET_CODE (X) == LO_SUM \
&& GET_CODE (XEXP (X, 0)) == REG \
&& REG_OK_FOR_BASE_P (XEXP (X, 0)) \
&& CONSTANT_P (XEXP (X, 1)))
#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \
{ if (LEGITIMATE_INDIRECT_ADDRESS_P (X)) \
goto ADDR; \
@ -1391,6 +1465,8 @@ struct rs6000_args {int words, fregno, nargs_prototype; };
&& (TARGET_HARD_FLOAT || (MODE) != DFmode) \
&& LEGITIMATE_INDEXED_ADDRESS_P (X)) \
goto ADDR; \
if (LEGITIMATE_LO_SUM_ADDRESS_P (MODE, X)) \
goto ADDR; \
}
/* Try machine-dependent ways of modifying an illegitimate address
@ -1416,32 +1492,42 @@ struct rs6000_args {int words, fregno, nargs_prototype; };
Then check for the sum of a register and something not constant, try to
load the other things into a register and return the sum. */
#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN) \
{ if (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 0)) == REG \
&& GET_CODE (XEXP (X, 1)) == CONST_INT \
&& (unsigned) (INTVAL (XEXP (X, 1)) + 0x8000) >= 0x10000) \
{ int high_int, low_int; \
high_int = INTVAL (XEXP (X, 1)) >> 16; \
low_int = INTVAL (XEXP (X, 1)) & 0xffff; \
if (low_int & 0x8000) \
high_int += 1, low_int |= 0xffff0000; \
(X) = gen_rtx (PLUS, SImode, \
force_operand \
(gen_rtx (PLUS, SImode, XEXP (X, 0), \
gen_rtx (CONST_INT, VOIDmode, \
high_int << 16)), 0),\
gen_rtx (CONST_INT, VOIDmode, low_int)); \
goto WIN; \
} \
else if (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 0)) == REG \
&& GET_CODE (XEXP (X, 1)) != CONST_INT \
&& (TARGET_HARD_FLOAT || (MODE) != DFmode) \
&& (MODE) != DImode && (MODE) != TImode) \
{ \
(X) = gen_rtx (PLUS, SImode, XEXP (X, 0), \
#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN) \
{ if (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 0)) == REG \
&& GET_CODE (XEXP (X, 1)) == CONST_INT \
&& (unsigned) (INTVAL (XEXP (X, 1)) + 0x8000) >= 0x10000) \
{ int high_int, low_int; \
high_int = INTVAL (XEXP (X, 1)) >> 16; \
low_int = INTVAL (XEXP (X, 1)) & 0xffff; \
if (low_int & 0x8000) \
high_int += 1, low_int |= 0xffff0000; \
(X) = gen_rtx (PLUS, SImode, \
force_operand \
(gen_rtx (PLUS, SImode, XEXP (X, 0), \
gen_rtx (CONST_INT, VOIDmode, \
high_int << 16)), 0), \
gen_rtx (CONST_INT, VOIDmode, low_int)); \
goto WIN; \
} \
else if (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 0)) == REG \
&& GET_CODE (XEXP (X, 1)) != CONST_INT \
&& (TARGET_HARD_FLOAT || (MODE) != DFmode) \
&& (MODE) != DImode && (MODE) != TImode) \
{ \
(X) = gen_rtx (PLUS, SImode, XEXP (X, 0), \
force_reg (SImode, force_operand (XEXP (X, 1), 0))); \
goto WIN; \
} \
goto WIN; \
} \
else if (TARGET_ELF && !TARGET_64BIT && TARGET_NO_TOC \
&& GET_CODE (X) != CONST_INT \
&& GET_CODE (X) != CONST_DOUBLE && CONSTANT_P (X) \
&& (TARGET_HARD_FLOAT || (MODE) != DFmode) \
&& (MODE) != DImode && (MODE) != TImode) \
{ \
rtx reg = gen_reg_rtx (Pmode); \
emit_insn (gen_elf_high (reg, (X))); \
(X) = gen_rtx (LO_SUM, Pmode, reg, (X)); \
} \
}
/* Go to LABEL if ADDR (a legitimate address expression)
@ -1462,6 +1548,8 @@ struct rs6000_args {int words, fregno, nargs_prototype; };
goto LABEL; \
if (GET_CODE (ADDR) == PRE_DEC) \
goto LABEL; \
if (GET_CODE (ADDR) == LO_SUM) \
goto LABEL; \
}
/* Define this if some processing needs to be done immediately before
@ -1561,7 +1649,7 @@ struct rs6000_args {int words, fregno, nargs_prototype; };
The sle and sre instructions which allow SHIFT_COUNT_TRUNCATED
have been dropped from the PowerPC architecture. */
#define SHIFT_COUNT_TRUNCATED TARGET_POWER ? 1 : 0
#define SHIFT_COUNT_TRUNCATED (TARGET_POWER ? 1 : 0)
/* Use atexit for static constructors/destructors, instead of defining
our own exit function. */
@ -1575,12 +1663,13 @@ struct rs6000_args {int words, fregno, nargs_prototype; };
On the RS/6000, if it is valid in the insn, it is free. So this
always returns 0. */
#define CONST_COSTS(RTX,CODE,OUTER_CODE) \
#define CONST_COSTS(RTX,CODE,OUTER_CODE) \
case CONST_INT: \
case CONST: \
case LABEL_REF: \
case SYMBOL_REF: \
case CONST_DOUBLE: \
case HIGH: \
return 0;
/* Provide the costs of a rtl expression. This is in the body of a
@ -1894,7 +1983,7 @@ toc_section () \
fprintf (FILE, "\t.long ."); \
RS6000_OUTPUT_BASENAME (FILE, NAME); \
fprintf (FILE, ", TOC[tc0], 0\n"); \
fprintf (FILE, ".csect .text[PR]\n."); \
fprintf (FILE, ".csect .text[PR]\n."); \
RS6000_OUTPUT_BASENAME (FILE, NAME); \
fprintf (FILE, ":\n"); \
if (write_symbols == XCOFF_DEBUG) \
@ -1909,15 +1998,16 @@ toc_section () \
we can't check that since not every file that uses
GO_IF_LEGITIMATE_ADDRESS_P includes real.h. */
#define ASM_OUTPUT_SPECIAL_POOL_ENTRY_P(X) \
(GET_CODE (X) == SYMBOL_REF \
|| (GET_CODE (X) == CONST && GET_CODE (XEXP (X, 0)) == PLUS \
&& GET_CODE (XEXP (XEXP (X, 0), 0)) == SYMBOL_REF) \
|| GET_CODE (X) == LABEL_REF \
|| (! (TARGET_NO_FP_IN_TOC && ! TARGET_MINIMAL_TOC) \
&& GET_CODE (X) == CONST_DOUBLE \
&& GET_MODE_CLASS (GET_MODE (X)) == MODE_FLOAT \
&& BITS_PER_WORD == HOST_BITS_PER_INT))
#define ASM_OUTPUT_SPECIAL_POOL_ENTRY_P(X) \
(TARGET_TOC \
&& (GET_CODE (X) == SYMBOL_REF \
|| (GET_CODE (X) == CONST && GET_CODE (XEXP (X, 0)) == PLUS \
&& GET_CODE (XEXP (XEXP (X, 0), 0)) == SYMBOL_REF) \
|| GET_CODE (X) == LABEL_REF \
|| (! (TARGET_NO_FP_IN_TOC && ! TARGET_MINIMAL_TOC) \
&& GET_CODE (X) == CONST_DOUBLE \
&& GET_MODE_CLASS (GET_MODE (X)) == MODE_FLOAT \
&& BITS_PER_WORD == HOST_BITS_PER_INT)))
/* Select section for constant in constant pool.
@ -2230,15 +2320,23 @@ toc_section () \
/* 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) \
asm_fprintf (FILE, "\{tstu|stwu} %s,-4(r1)\n", reg_names[REGNO]);
#define ASM_OUTPUT_REG_PUSH(FILE,REGNO) \
do { \
extern char *reg_names[]; \
asm_fprintf (FILE, "\{tstu|stwu} %s,-4(%s)\n", reg_names[REGNO], \
reg_names[1]); \
} while (0)
/* 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) \
asm_fprintf (FILE, "\t{l|lwz} %s,0(r1)\n\t{ai|addic} r1,r1,4\n", \
reg_names[REGNO])
#define ASM_OUTPUT_REG_POP(FILE,REGNO) \
do { \
extern char *reg_names[]; \
asm_fprintf (FILE, "\t{l|lwz} %s,0(%s)\n\t{ai|addic} %s,%s,4\n", \
reg_names[REGNO], reg_names[1], reg_names[1], \
reg_names[1]); \
} while (0)
/* This is how to output an element of a case-vector that is absolute.
(RS/6000 does not use such vectors, but we must define this macro
@ -2396,6 +2494,13 @@ extern int lwa_operand ();
extern int call_operand ();
extern int current_file_function_operand ();
extern int input_operand ();
extern void init_cumulative_args ();
extern void function_arg_advance ();
extern struct rtx_def *function_arg ();
extern int function_arg_partial_nregs ();
extern int function_arg_pass_by_reference ();
extern void setup_incoming_varargs ();
extern struct rtx_def *expand_builtin_saveregs ();
extern int expand_block_move ();
extern int load_multiple_operation ();
extern int store_multiple_operation ();
@ -2411,10 +2516,8 @@ extern void print_operand ();
extern void print_operand_address ();
extern int first_reg_to_save ();
extern int first_fp_reg_to_save ();
extern int must_save_cr ();
extern int rs6000_sa_size ();
extern int rs6000_makes_calls ();
extern int rs6000_pushes_stack ();
extern rs6000_stack_t *rs6000_stack_info ();
extern void svr4_traceback ();
extern void output_prolog ();
extern void output_epilog ();

View File

@ -3487,6 +3487,7 @@
(use (reg:DF 33))
(parallel [(set (reg:SI 3)
(call (mem:SI (match_operand 2 "" "")) (const_int 0)))
(use (const_int 0))
(clobber (scratch:SI))])
(set (match_operand:SI 0 "gpc_reg_operand" "")
(reg:SI 3))]
@ -3832,7 +3833,24 @@
[(set_attr "type" "delayed_compare")])
;; Now define ways of moving data around.
;;
;; Elf specific ways of loading addresses for non-PIC code.
;; The output of this could be r0, but we limit it to base
;; registers, since almost all uses of this will need it
;; in a base register shortly.
(define_insn "elf_high"
[(set (match_operand:SI 0 "register_operand" "=b")
(high:SI (match_operand 1 "" "")))]
"TARGET_ELF && !TARGET_64BIT"
"{cau|addis} %0,0,%1@ha")
(define_insn "elf_low"
[(set (match_operand:SI 0 "register_operand" "=r")
(lo_sum:SI (match_operand:SI 1 "register_operand" "b")
(match_operand 2 "" "")))]
"TARGET_ELF && !TARGET_64BIT"
"{cal %0,%a2@l(%1)|addi %0,%1,%2@l}")
;; For SI, we special-case integers that can't be loaded in one insn. We
;; do the load 16-bits at a time. We could do this by loading from memory,
;; and this is even supposed to be faster, but it is simpler not to get
@ -3850,7 +3868,22 @@
if (GET_CODE (operands[1]) == CONST_DOUBLE)
operands[1] = GEN_INT (CONST_DOUBLE_LOW (operands[1]));
if (CONSTANT_P (operands[1]) && GET_CODE (operands[1]) != CONST_INT
if (TARGET_ELF && TARGET_NO_TOC && !TARGET_64BIT
&& CONSTANT_P (operands[1])
&& GET_CODE (operands[1]) != HIGH
&& GET_CODE (operands[1]) != CONST_INT)
{
rtx target = (reload_completed || reload_in_progress)
? operands[0] : gen_reg_rtx (SImode);
emit_insn (gen_elf_high (target, operands[1]));
emit_insn (gen_elf_low (operands[0], target, operands[1]));
DONE;
}
if (CONSTANT_P (operands[1])
&& GET_CODE (operands[1]) != CONST_INT
&& GET_CODE (operands[1]) != HIGH
&& ! LEGITIMATE_CONSTANT_POOL_ADDRESS_P (operands[1]))
{
/* If we are to limit the number of things we put in the TOC and
@ -5014,7 +5047,7 @@
"lwaux %3,%0,%2"
[(set_attr "type" "load")])
(define_insn ""
(define_insn "movdi_update"
[(set (mem:DI (plus:DI (match_operand:DI 1 "gpc_reg_operand" "0,0")
(match_operand:DI 2 "reg_or_short_operand" "r,I")))
(match_operand:DI 3 "gpc_reg_operand" "r,r"))
@ -5037,7 +5070,7 @@
{lu|lwzu} %3,%2(%0)"
[(set_attr "type" "load")])
(define_insn ""
(define_insn "movsi_update"
[(set (mem:SI (plus:SI (match_operand:SI 1 "gpc_reg_operand" "0,0")
(match_operand:SI 2 "reg_or_short_operand" "r,I")))
(match_operand:SI 3 "gpc_reg_operand" "r,r"))
@ -5215,12 +5248,48 @@
(minus:SI (reg:SI 1) (match_operand:SI 0 "reg_or_short_operand" "")))]
""
"
{ rtx chain = gen_reg_rtx (SImode);
{ rtx chain = gen_reg_rtx (Pmode);
rtx stack_bot = gen_rtx (MEM, Pmode, stack_pointer_rtx);
rtx neg_op0;
rtx lr_addr = NULL_RTX;
rtx lr = NULL_RTX;
emit_move_insn (chain, stack_bot);
emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx, operands[0]));
emit_move_insn (stack_bot, chain);
#ifdef TARGET_V4_CALLS
if (TARGET_V4_CALLS)
{
lr = gen_reg_rtx (Pmode);
lr_addr = gen_rtx (MEM, Pmode, gen_rtx (PLUS, Pmode,
stack_pointer_rtx,
GEN_INT (4)));
emit_move_insn (lr, lr_addr);
}
#endif
if (GET_CODE (operands[0]) != CONST_INT
|| INTVAL (operands[0]) < -32767
|| INTVAL (operands[0]) > 32768)
{
neg_op0 = gen_reg_rtx (Pmode);
if (TARGET_POWERPC64)
emit_insn (gen_negdi2 (neg_op0, operands[0]));
else
emit_insn (gen_negsi2 (neg_op0, operands[0]));
}
else
neg_op0 = GEN_INT (- INTVAL (operands[0]));
if (TARGET_POWERPC64)
emit_insn (gen_movdi_update (stack_pointer_rtx, stack_pointer_rtx, neg_op0, chain));
else
emit_insn (gen_movsi_update (stack_pointer_rtx, stack_pointer_rtx, neg_op0, chain));
#ifdef TARGET_V4_CALLS
if (TARGET_V4_CALLS)
emit_move_insn (lr_addr, lr);
#endif
DONE;
}")
@ -5310,6 +5379,7 @@
(define_expand "call"
[(parallel [(call (mem:SI (match_operand:SI 0 "address_operand" ""))
(match_operand 1 "" ""))
(use (match_operand 2 "" ""))
(clobber (scratch:SI))])]
""
"
@ -5334,6 +5404,7 @@
[(parallel [(set (match_operand 0 "" "")
(call (mem:SI (match_operand:SI 1 "address_operand" ""))
(match_operand 2 "" "")))
(use (match_operand 3 "" ""))
(clobber (scratch:SI))])]
""
"
@ -5355,24 +5426,50 @@
}")
;; Call to function in current module. No TOC pointer reload needed.
;; Operand2 is non-zero if we are using the V.4 calling sequence and
;; either the function was not prototyped, or it was prototyped as a
;; variable argument function. It is > 0 if FP registers were passed
;; and < 0 if they were not.
(define_insn ""
[(call (mem:SI (match_operand:SI 0 "current_file_function_operand" "s"))
(match_operand 1 "" "g"))
(clobber (match_scratch:SI 2 "=l"))]
""
"bl %z0")
;; Call to function which may be in another module. Restore the TOC
;; pointer (r2) after the call unless this is System V.
(define_insn ""
[(call (mem:SI (match_operand:SI 0 "call_operand" "l,s"))
(match_operand 1 "" "fg,fg"))
(clobber (match_scratch:SI 2 "=l,l"))]
[(call (mem:SI (match_operand:SI 0 "current_file_function_operand" "s,s"))
(match_operand 1 "" "g,g"))
(use (match_operand:SI 2 "immediate_operand" "O,n"))
(clobber (match_scratch:SI 3 "=l,l"))]
""
"*
{
if (INTVAL (operands[2]) > 0)
return \"creqv 6,6,6\;bl %z0\";
else if (INTVAL (operands[2]) < 0)
return \"crxor 6,6,6\;bl %z0\";
return \"bl %z0\";
}"
[(set_attr "length" "4,8")])
;; Call to function which may be in another module. Restore the TOC
;; pointer (r2) after the call unless this is System V.
;; Operand2 is non-zero if we are using the V.4 calling sequence and
;; either the function was not prototyped, or it was prototyped as a
;; variable argument function. It is > 0 if FP registers were passed
;; and < 0 if they were not.
(define_insn ""
[(call (mem:SI (match_operand:SI 0 "call_operand" "l,s,l,s"))
(match_operand 1 "" "fg,fg,fg,fg"))
(use (match_operand:SI 2 "immediate_operand" "O,O,n,n"))
(clobber (match_scratch:SI 3 "=l,l,l,l"))]
""
"*
{
if (INTVAL (operands[2]) > 0)
output_asm_insn (\"creqv 6,6,6\", operands);
else if (INTVAL (operands[2]) < 0)
output_asm_insn (\"crxor 6,6,6\", operands);
#ifndef USING_SVR4_H
if (GET_CODE (operands[0]) == REG)
return \"{brl|blrl}\;{l|lwz} 2,20(1)\";
@ -5386,24 +5483,42 @@
return \"bl %z0\";
#endif
}"
[(set_attr "length" "8")])
(define_insn ""
[(set (match_operand 0 "" "=fg")
(call (mem:SI (match_operand:SI 1 "current_file_function_operand" "s"))
(match_operand 2 "" "g")))
(clobber (match_scratch:SI 3 "=l"))]
""
"bl %z1")
[(set_attr "length" "8,8,12,12")])
(define_insn ""
[(set (match_operand 0 "" "=fg,fg")
(call (mem:SI (match_operand:SI 1 "call_operand" "l,s"))
(match_operand 2 "" "fg,fg")))
(clobber (match_scratch:SI 3 "=l,l"))]
(call (mem:SI (match_operand:SI 1 "current_file_function_operand" "s,s"))
(match_operand 2 "" "g,g")))
(use (match_operand:SI 3 "immediate_operand" "O,n"))
(clobber (match_scratch:SI 4 "=l,l"))]
""
"*
{
if (INTVAL (operands[3]) > 0)
return \"creqv 6,6,6\;bl %z1\";
else if (INTVAL (operands[3]) < 0)
return \"crxor 6,6,6\;bl %z1\";
return \"bl %z1\";
}"
[(set_attr "length" "4,8")])
(define_insn ""
[(set (match_operand 0 "" "=fg,fg,fg,fg")
(call (mem:SI (match_operand:SI 1 "call_operand" "l,s,l,s"))
(match_operand 2 "" "fg,fg,fg,fg")))
(use (match_operand:SI 3 "immediate_operand" "O,O,n,n"))
(clobber (match_scratch:SI 4 "=l,l,l,l"))]
""
"*
{
if (INTVAL (operands[3]) > 0)
output_asm_insn (\"creqv 6,6,6\", operands);
else if (INTVAL (operands[3]) < 0)
output_asm_insn (\"crxor 6,6,6\", operands);
#ifndef USING_SVR4_H
if (GET_CODE (operands[1]) == REG)
return \"{brl|blrl}\;{l|lwz} 2,20(1)\";
@ -5417,7 +5532,7 @@
return \"bl %z1\";
#endif
}"
[(set_attr "length" "8")])
[(set_attr "length" "8,8,12,12")])
;; Call subroutine returning any type.
@ -5431,7 +5546,7 @@
{
int i;
emit_call_insn (gen_call (operands[0], const0_rtx, NULL, const0_rtx));
emit_call_insn (gen_call (operands[0], const0_rtx, const0_rtx, const0_rtx));
for (i = 0; i < XVECLEN (operands[2], 0); i++)
{
@ -5455,6 +5570,13 @@
[(unspec_volatile [(const_int 0)] 0)]
""
"")
;; Sync instruction used for V.4 trampolines
(define_insn "sync"
[(unspec [(match_operand 0 "" "")] 1)]
""
"sync")
;; Compare insns are next. Note that the RS/6000 has two types of compares,
;; signed & unsigned, and one type of branch.

View File

@ -27,20 +27,35 @@ Boston, MA 02111-1307, USA. */
#define MASK_RELOCATABLE 0x10000000 /* GOT pointers are PC relative */
#define MASK_NO_TRACEBACK 0x08000000 /* eliminate traceback words */
#define MASK_LITTLE_ENDIAN 0x04000000 /* target is little endian */
#define MASK_NO_TOC 0x02000000 /* do not use TOC for loading addresses */
#define MASK_AIX_CALLS 0x02000000 /* Use AIX calling sequence */
#define MASK_PROTOTYPE 0x01000000 /* Only prototyped fcns pass variable args */
#define TARGET_NO_BITFIELD_TYPE (target_flags & MASK_NO_BITFIELD_TYPE)
#define TARGET_STRICT_ALIGN (target_flags & MASK_STRICT_ALIGN)
#define TARGET_RELOCATABLE (target_flags & MASK_RELOCATABLE)
#define TARGET_NO_TRACEBACK (target_flags & MASK_NO_TRACEBACK)
#define TARGET_LITTLE_ENDIAN (target_flags & MASK_LITTLE_ENDIAN)
#define TARGET_NO_TOC (target_flags & MASK_NO_TOC)
#define TARGET_AIX_CALLS (target_flags & MASK_AIX_CALLS)
#define TARGET_PROTOTYPE (target_flags & MASK_PROTOTYPE)
#define TARGET_TOC (target_flags & (MASK_64BIT \
| MASK_RELOCATABLE \
| MASK_MINIMAL_TOC))
#define TARGET_BITFIELD_TYPE (! TARGET_NO_BITFIELD_TYPE)
#define TARGET_TRACEBACK (! TARGET_NO_TRACEBACK)
#define TARGET_BIG_ENDIAN (! TARGET_LITTLE_ENDIAN)
#define TARGET_TOC (! TARGET_NO_TOC)
#define TARGET_NO_AIX_CALLS (! TARGET_AIX_CALLS)
#define TARGET_NO_PROTOTYPE (! TARGET_PROTOTYPE)
#define TARGET_NO_TOC (! TARGET_TOC)
#define TARGET_V4_CALLS TARGET_NO_AIX_CALLS
/* Pseudo target to indicate whether the object format is ELF
(to get around not having conditional compilation in the md file) */
#define TARGET_ELF 1
/* Note, V.4 no longer uses a normal TOC, so make -mfull-toc, be just
the same as -mminimal-toc. */
#undef SUBTARGET_SWITCHES
#define SUBTARGET_SWITCHES \
{ "bit-align", -MASK_NO_BITFIELD_TYPE }, \
@ -55,8 +70,13 @@ Boston, MA 02111-1307, USA. */
{ "little", MASK_LITTLE_ENDIAN }, \
{ "big-endian", -MASK_LITTLE_ENDIAN }, \
{ "big", -MASK_LITTLE_ENDIAN }, \
{ "no-toc", MASK_NO_TOC | MASK_MINIMAL_TOC }, \
{ "toc", -MASK_NO_TOC },
{ "no-toc", 0 }, \
{ "toc", MASK_MINIMAL_TOC }, \
{ "full-toc", MASK_MINIMAL_TOC }, \
{ "call-aix", MASK_AIX_CALLS }, \
{ "call-sysv", -MASK_AIX_CALLS }, \
{ "prototype", MASK_PROTOTYPE }, \
{ "no-prototype", -MASK_PROTOTYPE },
/* Sometimes certain combinations of command options do not make sense
on a particular target machine. You can define a macro
@ -69,22 +89,10 @@ Boston, MA 02111-1307, USA. */
#define SUBTARGET_OVERRIDE_OPTIONS \
do { \
if (TARGET_RELOCATABLE && TARGET_NO_TOC) \
{ \
target_flags &= ~ MASK_NO_TOC; \
error ("-mrelocatable and -mno-toc are incompatible."); \
} \
\
if (TARGET_RELOCATABLE && !TARGET_MINIMAL_TOC) \
{ \
target_flags |= MASK_MINIMAL_TOC; \
error ("-mrelocatable and -mno-minimal-toc are incompatible."); \
} \
\
if (TARGET_NO_TOC && !TARGET_MINIMAL_TOC) \
{ \
target_flags |= MASK_MINIMAL_TOC; \
error ("-mno-toc and -mno-minimal-toc are incompatible."); \
} \
} while (0)
@ -96,12 +104,38 @@ do { \
#undef FIXED_R13
#define FIXED_R13 1
/* System V.4 passes the first 8 floating arguments in registers,
instead of the first 13 like AIX does. */
#undef FP_ARG_MAX_REG
#define FP_ARG_AIX_MAX_REG 45
#define FP_ARG_V4_MAX_REG 40
#define FP_ARG_MAX_REG ((TARGET_AIX_CALLS) ? FP_ARG_AIX_MAX_REG : FP_ARG_V4_MAX_REG)
/* Size of the V.4 varargs area if needed */
#undef RS6000_VARARGS_AREA
#define RS6000_VARARGS_AREA ((rs6000_sysv_varargs_p) ? RS6000_VARARGS_SIZE : 0)
/* Override default big endianism */
#undef BYTES_BIG_ENDIAN
#undef WORDS_BIG_ENDIAN
#define BYTES_BIG_ENDIAN (TARGET_BIG_ENDIAN)
#define WORDS_BIG_ENDIAN (TARGET_BIG_ENDIAN)
/* Size of the outgoing register save area */
#undef RS6000_REG_SAVE
#define RS6000_REG_SAVE (TARGET_AIX_CALLS ? (TARGET_64BIT ? 64 : 32) : 0)
/* Size of the fixed area on the stack. For AIX, use the standard 6 word
area, otherwise use 2 words to store back chain & LR. */
#undef RS6000_SAVE_AREA
#define RS6000_SAVE_AREA \
((TARGET_AIX_CALLS ? 24 : 8) << (TARGET_64BIT ? 1 : 0))
/* Define cutoff for using external functions to save floating point.
Currently on V.4, always use inline stores */
#undef FP_SAVE_INLINE
#define FP_SAVE_INLINE(FIRST_REG) ((FIRST_REG) < 64)
/* Don't generate XCOFF debugging information. */
#undef XCOFF_DEBUGGING_INFO
@ -192,37 +226,14 @@ toc_section () \
\
if (in_section != in_toc) \
{ \
in_section = in_toc; \
fprintf (asm_out_file, "%s\n", MINIMAL_TOC_SECTION_ASM_OP); \
if (! toc_initialized) \
{ \
if (!TARGET_RELOCATABLE && !TARGET_NO_TOC) \
fprintf (asm_out_file, "%s\n", TOC_SECTION_ASM_OP); \
\
if (TARGET_MINIMAL_TOC) \
{ \
if (!TARGET_RELOCATABLE && !TARGET_NO_TOC) \
{ \
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LCTOC", 0); \
fprintf (asm_out_file, "\t.tc "); \
ASM_OUTPUT_INTERNAL_LABEL_PREFIX (asm_out_file, "LCTOC1[TC],"); \
ASM_OUTPUT_INTERNAL_LABEL_PREFIX (asm_out_file, "LCTOC1"); \
fprintf (asm_out_file, "\n"); \
} \
\
fprintf (asm_out_file, "%s\n", MINIMAL_TOC_SECTION_ASM_OP); \
ASM_OUTPUT_INTERNAL_LABEL_PREFIX (asm_out_file, "LCTOC1"); \
fprintf (asm_out_file, " = .+32768\n"); \
} \
\
ASM_OUTPUT_INTERNAL_LABEL_PREFIX (asm_out_file, "LCTOC1"); \
fprintf (asm_out_file, " = .+32768\n"); \
toc_initialized = 1; \
} \
\
else \
fprintf (asm_out_file, "%s\n", \
(TARGET_MINIMAL_TOC \
? MINIMAL_TOC_SECTION_ASM_OP \
: TOC_SECTION_ASM_OP)); \
\
in_section = in_toc; \
} \
}
@ -342,7 +353,78 @@ while (0)
#undef TARGET_VERSION
#define TARGET_VERSION fprintf (stderr, " (PowerPC System V.4)");
/* Output assembler code for a block containing the constant parts
of a trampoline, leaving space for the variable parts.
The trampoline should set the static chain pointer to value placed
into the trampoline and should branch to the specified routine.
Unlike AIX, this needs real code. */
#undef TRAMPOLINE_TEMPLATE
#define TRAMPOLINE_TEMPLATE(FILE) \
do { \
char *sc = reg_names[STATIC_CHAIN_REGNUM]; \
char *r0 = reg_names[0]; \
\
if (STATIC_CHAIN_REGNUM == 0 || !TARGET_NEW_MNEMONICS) \
abort (); \
\
if (TARGET_64BIT) \
{ \
fprintf (FILE, "\tmflr %s\n", r0); /* offset 0 */ \
fprintf (FILE, "\tbl .LTRAMP1\n"); /* offset 4 */ \
fprintf (FILE, "\t.long 0,0,0,0\n"); /* offset 8 */ \
fprintf (FILE, ".LTRAMP1:\n"); \
fprintf (FILE, "\tmflr %s\n", sc); /* offset 28 */ \
fprintf (FILE, "\tmtlr %s\n", r0); /* offset 32 */ \
fprintf (FILE, "\tld %s,0(%s)\n", r0, sc); /* offset 36 */ \
fprintf (FILE, "\tld %s,8(%s)\n", sc, sc); /* offset 40 */ \
fprintf (FILE, "\tmtctr %s\n", r0); /* offset 44 */ \
fprintf (FILE, "\tbctr\n"); /* offset 48 */ \
} \
else \
{ \
fprintf (FILE, "\tmflr %s\n", r0); /* offset 0 */ \
fprintf (FILE, "\tbl .LTRAMP1\n"); /* offset 4 */ \
fprintf (FILE, "\t.long 0,0\n"); /* offset 8 */ \
fprintf (FILE, ".LTRAMP1:\n"); \
fprintf (FILE, "\tmflr %s\n", sc); /* offset 20 */ \
fprintf (FILE, "\tmtlr %s\n", r0); /* offset 24 */ \
fprintf (FILE, "\tlwz %s,0(%s)\n", r0, sc); /* offset 28 */ \
fprintf (FILE, "\tlwz %s,4(%s)\n", sc, sc); /* offset 32 */ \
fprintf (FILE, "\tmtctr %s\n", r0); /* offset 36 */ \
fprintf (FILE, "\tbctr\n"); /* offset 40 */ \
} \
} while (0)
/* Length in units of the trampoline for entering a nested function. */
#undef TRAMPOLINE_SIZE
#define TRAMPOLINE_SIZE (TARGET_64BIT ? 52 : 44)
/* 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. */
#undef INITIALIZE_TRAMPOLINE
#define INITIALIZE_TRAMPOLINE(ADDR, FNADDR, CXT) \
{ \
rtx reg = gen_reg_rtx (Pmode); \
\
emit_move_insn (reg, FNADDR); \
emit_move_insn (gen_rtx (MEM, Pmode, \
plus_constant (ADDR, 8)), \
reg); \
emit_move_insn (gen_rtx (MEM, Pmode, \
plus_constant (ADDR, (TARGET_64BIT ? 16 : 12))), \
CXT); \
emit_insn (gen_sync (gen_rtx (MEM, BLKmode, ADDR))); \
}
#undef CPP_PREDEFINES
#define CPP_PREDEFINES \
"-DPPC -Dunix -D__svr4__ -Asystem(unix) -Asystem(svr4) -Acpu(powerpc) -Amachine(powerpc)"
@ -382,6 +464,8 @@ while (0)
#define CPP_SPEC "\
%{posix: -D_POSIX_SOURCE} \
%{mrelocatable: -D_RELOCATABLE} \
%{mcall-sysv: -D_CALL_SYSV} %{mcall-aix: -D_CALL_AIX} %{!mcall-sysv: %{!mcall-aix: -D_CALL_SYSV}} \
%{msoft-float: -D_SOFT_FLOAT} %{mcpu=403: -D_SOFT_FLOAT} \
%{mlittle: -D_LITTLE_ENDIAN -Amachine(littleendian)} \
%{mlittle-endian: -D_LITTLE_ENDIAN -Amachine(littleendian)} \
%{!mlittle: %{!mlittle-endian: -D_BIG_ENDIAN -Amachine(bigendian)}} \

View File

@ -29,6 +29,8 @@ Boston, MA 02111-1307, USA. */
#define CPP_SPEC "\
%{posix: -D_POSIX_SOURCE} \
%{mrelocatable: -D_RELOCATABLE} \
%{mcall-sysv: -D_CALL_SYSV} %{mcall-aix: -D_CALL_AIX} %{!mcall-sysv: %{!mcall-aix: -D_CALL_SYSV}} \
%{msoft-float: -D_SOFT_FLOAT} %{mcpu=403: -D_SOFT_FLOAT} \
%{mbig: -D_BIG_ENDIAN -Amachine(bigendian)} \
%{mbig-endian: -D_BIG_ENDIAN -Amachine(bigendian)} \
%{!mbig: %{!mbig-endian: -D_LITTLE_ENDIAN -Amachine(littleendian)}} \

View File

@ -16,15 +16,12 @@ fp-bit.c: $(srcdir)/config/fp-bit.c
# Build libgcc.a with different options.
MULTILIB_OPTIONS = msoft-float \
mno-toc \
mlittle/mbig
mlittle
MULTILIB_DIRNAMES = soft-float \
no-toc \
little-endian big-endian
little-endian
MULTILIB_MATCHES = mlittle=mlittle-endian \
mbig=mbig-endian \
msoft-float=mcpu?403 \
msoft-float=mcpu?mpc403 \
msoft-float=mcpu?ppc403

View File

@ -15,8 +15,8 @@ fp-bit.c: $(srcdir)/config/fp-bit.c
# Build the libraries for both hard and soft floating point
MULTILIB_OPTIONS = msoft-float
MULTILIB_DIRNAMES = soft-float
MULTILIB_OPTIONS = msoft-float mcpu=common
MULTILIB_DIRNAMES = soft-float common
LIBGCC = stmp-multilib
INSTALL_LIBGCC = install-multilib