/* ABI enumeration available for subtarget to use. */
enum rs6000_abi rs6000_current_abi;
+/* Offset & size for fpmem stack locations used for converting between
+ float and integral types. */
+int rs6000_fpmem_offset;
+int rs6000_fpmem_size;
+
\f
/* Default register names. */
char rs6000_reg_names[][8] =
{
- "0", "1", "2", "3", "4", "5", "6", "7",
- "8", "9", "10", "11", "12", "13", "14", "15",
- "16", "17", "18", "19", "20", "21", "22", "23",
- "24", "25", "26", "27", "28", "29", "30", "31",
- "0", "1", "2", "3", "4", "5", "6", "7",
- "8", "9", "10", "11", "12", "13", "14", "15",
- "16", "17", "18", "19", "20", "21", "22", "23",
- "24", "25", "26", "27", "28", "29", "30", "31",
- "mq", "lr", "ctr","ap",
- "0", "1", "2", "3", "4", "5", "6", "7"
+ "0", "1", "2", "3", "4", "5", "6", "7",
+ "8", "9", "10", "11", "12", "13", "14", "15",
+ "16", "17", "18", "19", "20", "21", "22", "23",
+ "24", "25", "26", "27", "28", "29", "30", "31",
+ "0", "1", "2", "3", "4", "5", "6", "7",
+ "8", "9", "10", "11", "12", "13", "14", "15",
+ "16", "17", "18", "19", "20", "21", "22", "23",
+ "24", "25", "26", "27", "28", "29", "30", "31",
+ "mq", "lr", "ctr","ap",
+ "0", "1", "2", "3", "4", "5", "6", "7",
+ "fpmem"
};
#ifdef TARGET_REGNAMES
static char alt_reg_names[][8] =
{
- "%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", "%f15",
- "%f16", "%f17", "%f18", "%f19", "%f20", "%f21", "%f22", "%f23",
- "%f24", "%f25", "%f26", "%f27", "%f28", "%f29", "%f30", "%f31",
- "mq", "lr", "ctr", "ap",
- "%cr0", "%cr1", "%cr2", "%cr3", "%cr4", "%cr5", "%cr6", "%cr7"
+ "%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", "%f15",
+ "%f16", "%f17", "%f18", "%f19", "%f20", "%f21", "%f22", "%f23",
+ "%f24", "%f25", "%f26", "%f27", "%f28", "%f29", "%f30", "%f31",
+ "mq", "lr", "ctr", "ap",
+ "%cr0", "%cr1", "%cr2", "%cr3", "%cr4", "%cr5", "%cr6", "%cr7",
+ "fpmem"
};
#endif
\f
return 0;
}
+/* Returns 1 if op is memory location for float/int conversions that masquerades
+ as a register. */
+int fpmem_operand(op, mode)
+ register rtx op;
+ enum machine_mode mode;
+{
+ if (GET_CODE (op) != REG)
+ return 0;
+
+ if (FPMEM_REGNO_P (REGNO (op)))
+ return 1;
+
+#if 0
+ if (REGNO (op) > FIRST_PSEUDO_REGISTER)
+ return 1;
+#endif
+
+ return 0;
+}
+
/* Return 1 if OP is a constant that can fit in a D field. */
int
enum machine_mode mode;
{
return (register_operand (op, mode)
- && (GET_CODE (op) != REG || REGNO (op) >= 67 || REGNO (op) < 64));
+ && (GET_CODE (op) != REG
+ || (REGNO (op) >= 67 && !FPMEM_REGNO_P (REGNO (op)))
+ || REGNO (op) < 64));
}
/* Returns 1 if OP is either a pseudo-register or a register denoting a
register rtx shiftop;
register rtx andop;
{
- unsigned shift_mask = ~0;
+ unsigned shift_mask = ~(unsigned)0;
shift_mask >>= INTVAL (shiftop);
return;
case 'u':
- /* High-order 16 bits of constant. */
+ /* High-order 16 bits of constant for use in unsigned operand. */
if (! INT_P (x))
output_operand_lossage ("invalid %%u value");
fprintf (file, "0x%x", (INT_LOWPART (x) >> 16) & 0xffff);
return;
+ case 'v':
+ /* High-order 16 bits of constant for use in signed operand. */
+ if (! INT_P (x))
+ output_operand_lossage ("invalid %%v value");
+
+ {
+ int value = (INT_LOWPART (x) >> 16) & 0xffff;
+
+ /* Solaris assembler doesn't like lis 0,0x80000 */
+ if (DEFAULT_ABI == ABI_SOLARIS && (value & 0x8000) != 0)
+ fprintf (file, "%d", value | (~0 << 16));
+ else
+ fprintf (file, "0x%x", value);
+ return;
+ }
+
case 'U':
/* Print `u' if this has an auto-increment or auto-decrement. */
if (GET_CODE (x) == MEM
+---------------------------------------+
| Parameter save area (P) | 24
+---------------------------------------+
- | Alloca space (A) | 24+P
+ | Float/int conversion temporary (X) | 24+P
+ +---------------------------------------+
+ | Alloca space (A) | 24+P+X
+---------------------------------------+
- | Local variable space (L) | 24+P+A
+ | Local variable space (L) | 24+P+X+A
+---------------------------------------+
- | Save area for GP registers (G) | 24+P+A+L
+ | Save area for GP registers (G) | 24+P+X+A+L
+---------------------------------------+
- | Save area for FP registers (F) | 24+P+A+L+G
+ | Save area for FP registers (F) | 24+P+X+A+L+G
+---------------------------------------+
old SP->| back chain to caller's caller |
+---------------------------------------+
+---------------------------------------+
| Parameter save area (P) | 8
+---------------------------------------+
- | Alloca space (A) | 8+P
+ | Float/int conversion temporary (X) | 8+P
+---------------------------------------+
- | Varargs save area (V) | 8+P+A
+ | Alloca space (A) | 8+P+X
+---------------------------------------+
- | Local variable space (L) | 8+P+A+V
+ | Varargs save area (V) | 8+P+X+A
+---------------------------------------+
- | saved CR (C) | 8+P+A+V+L
+ | Local variable space (L) | 8+P+X+A+V
+---------------------------------------+
- | Save area for GP registers (G) | 8+P+A+V+L+C
+ | saved CR (C) | 8+P+X+A+V+L
+---------------------------------------+
- | Save area for FP registers (F) | 8+P+A+V+L+C+G
+ | Save area for GP registers (G) | 8+P+X+A+V+L+C
+ +---------------------------------------+
+ | Save area for FP registers (F) | 8+P+X+A+V+L+C+G
+---------------------------------------+
old SP->| back chain to caller's caller |
+---------------------------------------+
+---------------------------------------+
| Parameter save area (P) | 24
+---------------------------------------+
- | Alloca space (A) | 24+P
+ | Float/int conversion temporary (X) | 24+P
+ +---------------------------------------+
+ | Alloca space (A) | 24+P+X
+---------------------------------------+
- | Local variable space (L) | 24+P+A
+ | Local variable space (L) | 24+P+X+A
+---------------------------------------+
- | Save area for FP registers (F) | 24+P+A+L
+ | Save area for FP registers (F) | 24+P+X+A+L
+---------------------------------------+
- | Possible alignment area (X) | 24+P+A+L+F
+ | Possible alignment area (X) | 24+P+X+A+L+F
+---------------------------------------+
- | Save area for GP registers (G) | 24+P+A+L+F+X
+ | Save area for GP registers (G) | 24+P+X+A+L+F+X
+---------------------------------------+
- | Save area for CR (C) | 24+P+A+L+F+X+G
+ | Save area for CR (C) | 24+P+X+A+L+F+X+G
+---------------------------------------+
- | Save area for TOC (T) | 24+P+A+L+F+X+G+C
+ | Save area for TOC (T) | 24+P+X+A+L+F+X+G+C
+---------------------------------------+
- | Save area for LR (R) | 24+P+A+L+F+X+G+C+T
+ | Save area for LR (R) | 24+P+X+A+L+F+X+G+C+T
+---------------------------------------+
old SP->| back chain to caller's caller |
+---------------------------------------+
info_ptr->toc_size = reg_size;
}
+ /* Does this machine need the float/int conversion area? */
+ info_ptr->fpmem_p = regs_ever_live[FPMEM_REGNUM];
+
/* If this is main and we need to call a function to set things up,
save main's arguments around the call. */
#ifdef TARGET_EABI
info_ptr->varargs_size = RS6000_VARARGS_AREA;
info_ptr->vars_size = ALIGN (get_frame_size (), 8);
info_ptr->parm_size = ALIGN (current_function_outgoing_args_size, 8);
+ info_ptr->fpmem_size = (info_ptr->fpmem_p) ? 8 : 0;
info_ptr->save_size = ALIGN (info_ptr->fp_size
+ info_ptr->gp_size
+ info_ptr->cr_size
total_raw_size = (info_ptr->vars_size
+ info_ptr->parm_size
+ + info_ptr->fpmem_size
+ info_ptr->save_size
+ info_ptr->varargs_size
+ info_ptr->fixed_size);
|| info_ptr->total_size > 220);
/* Calculate the offsets */
+ info_ptr->fpmem_offset = info_ptr->total_size - info_ptr->parm_size;
switch (abi)
{
case ABI_NONE:
if (!info_ptr->main_save_p)
info_ptr->main_save_offset = 0;
+ if (!info_ptr->fpmem_p)
+ info_ptr->fpmem_offset = 0;
+ else
+ {
+ rs6000_fpmem_size = info_ptr->fpmem_size;
+ rs6000_fpmem_offset = STACK_DYNAMIC_OFFSET (current_function_decl) - info_ptr->fpmem_size;
+ if (rs6000_fpmem_offset > 32767)
+ abort ();
+ }
+
return info_ptr;
}
if (info->main_save_p)
fprintf (stderr, "\tmain_save_p = %5d\n", info->main_save_p);
+ if (info->fpmem_p)
+ fprintf (stderr, "\tfpmem_p = %5d\n", info->fpmem_p);
+
if (info->gp_save_offset)
fprintf (stderr, "\tgp_save_offset = %5d\n", info->gp_save_offset);
if (info->main_save_offset)
fprintf (stderr, "\tmain_save_offset = %5d\n", info->main_save_offset);
+ if (info->fpmem_offset)
+ fprintf (stderr, "\tfpmem_offset = %5d\n", info->fpmem_offset);
+
if (info->total_size)
fprintf (stderr, "\ttotal_size = %5d\n", info->total_size);
if (info->parm_size)
fprintf (stderr, "\tparm_size = %5d\n", info->parm_size);
+ if (info->fpmem_size)
+ fprintf (stderr, "\tfpmem_size = %5d\n", info->fpmem_size);
+
if (info->fixed_size)
fprintf (stderr, "\tfixed_size = %5d\n", info->fixed_size);
/* Reset varargs and save TOC indicator */
rs6000_sysv_varargs_p = 0;
rs6000_save_toc_p = 0;
+ rs6000_fpmem_size = 0;
+ rs6000_fpmem_offset = 0;
pic_offset_table_rtx = (rtx)0;
if (DEFAULT_ABI == ABI_NT)
pname = IDENTIFIER_POINTER (t);
if (strcmp (pname, "segment") == 0)
{
- retval = 1;
/* (should collect pbuf + 8 into a segment name) */
}
else if (strcmp (pname, "options") == 0)
/* Return without doing anything if no content. */
if (c == '\n' || c == EOF)
- return 0;
+ {
+ ungetc (c, finput);
+ return 0;
+ }
/* Collect the rest of the line. */
while (psize < sizeof (pbuf) - 1 && c != '\n')
if (strncmp (pbuf, "align=mac68k", 12) == 0)
{
- mac68k_aligned = retval = 1;
+ mac68k_aligned = 1;
+ retval = 1;
+ }
+ else if (strncmp (pbuf, "align=power", 11) == 0)
+ {
+ mac68k_aligned = 0;
+ retval = 1;
}
else if (strncmp (pbuf, "align=reset", 11) == 0)
{
- mac68k_aligned = 0, retval = 1;
+ mac68k_aligned = 0;
+ retval = 1;
}
}
- return c;
+ return retval;
}
/* END CYGNUS LOCAL mac */
In addition, the difference between the frame and argument pointers is
a function of the number of registers saved, so we need to have a
register for AP that will later be eliminated in favor of SP or FP.
- This is a normal register, but it is fixed. */
+ This is a normal register, but it is fixed.
-#define FIRST_PSEUDO_REGISTER 76
+ We also create a pseudo register for float/int conversions, that will
+ really represent the memory location used. It is represented here as
+ a register, in order to work around problems in allocating stack storage
+ in inline functions. */
+
+#define FIRST_PSEUDO_REGISTER 77
/* 1 for registers that have pervasive standard uses
and are not available for the register allocator.
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, 0, 0, 0, 0, \
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
- 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0}
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1}
/* 1 for registers not available across function calls.
These must include the FIXED_REGISTERS and also any
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, 0, 0, \
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
- 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1}
+ 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1}
/* List the order in which to allocate registers. Each register must be
listed once, even those in FIXED_REGISTERS.
31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, \
18, 17, 16, 15, 14, 13, 12, \
64, 66, 65, \
- 73, 1, 2, 67}
+ 73, 1, 2, 67, 76}
/* True if register is floating-point. */
#define FP_REGNO_P(N) ((N) >= 32 && (N) <= 63)
/* True if register is an integer register. */
#define INT_REGNO_P(N) ((N) <= 31 || (N) == 67)
+/* True if register is the temporary memory location used for int/float
+ conversion. */
+#define FPMEM_REGNO_P(N) ((N) == FPMEM_REGNUM)
+
/* 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
On RS/6000, ordinary registers hold 32 bits worth;
a single floating point register holds 64 bits worth. */
-#define HARD_REGNO_NREGS(REGNO, MODE) \
- (FP_REGNO_P (REGNO) \
+#define HARD_REGNO_NREGS(REGNO, MODE) \
+ (FP_REGNO_P (REGNO) || FPMEM_REGNO_P (REGNO) \
? ((GET_MODE_SIZE (MODE) + UNITS_PER_FP_WORD - 1) / UNITS_PER_FP_WORD) \
: ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD))
can hold CC modes. We cannot put TImode anywhere except general
register and it must be able to fit within the register set. */
-#define HARD_REGNO_MODE_OK(REGNO, MODE) \
- (FP_REGNO_P (REGNO) ? \
- (GET_MODE_CLASS (MODE) == MODE_FLOAT \
- || (GET_MODE_CLASS (MODE) == MODE_INT \
- && GET_MODE_SIZE (MODE) == UNITS_PER_FP_WORD)) \
- : CR_REGNO_P (REGNO) ? GET_MODE_CLASS (MODE) == MODE_CC \
- : ! INT_REGNO_P (REGNO) ? (GET_MODE_CLASS (MODE) == MODE_INT \
+#define HARD_REGNO_MODE_OK(REGNO, MODE) \
+ (FP_REGNO_P (REGNO) ? \
+ (GET_MODE_CLASS (MODE) == MODE_FLOAT \
+ || (GET_MODE_CLASS (MODE) == MODE_INT \
+ && GET_MODE_SIZE (MODE) == UNITS_PER_FP_WORD)) \
+ : CR_REGNO_P (REGNO) ? GET_MODE_CLASS (MODE) == MODE_CC \
+ : FPMEM_REGNO_P (REGNO) ? ((MODE) == DImode || (MODE) == DFmode) \
+ : ! INT_REGNO_P (REGNO) ? (GET_MODE_CLASS (MODE) == MODE_INT \
&& GET_MODE_SIZE (MODE) <= UNITS_PER_WORD) \
: 1)
|| (CLASS1) == LINK_OR_CTR_REGS) \
&& ((CLASS2) == SPECIAL_REGS || (CLASS2) == MQ_REGS \
|| (CLASS2) == LINK_REGS || (CLASS2) == CTR_REGS \
- || (CLASS2) == LINK_OR_CTR_REGS)) ? 10 \
+ || (CLASS2) == LINK_OR_CTR_REGS)) ? 10 \
: 2)
/* A C expressions returning the cost of moving data of MODE from a register to
/* count register number for special purposes */
#define COUNT_REGISTER_REGNUM 66
+/* Special register that represents memory, used for float/int conversions. */
+#define FPMEM_REGNUM 76
+
/* Place that structure value return address is placed.
On the RS/6000, it is passed as an extra parameter. */
So make a class for registers valid as base registers.
Also, cr0 is the only condition code register that can be used in
- arithmetic insns, so make a separate class for it. */
+ arithmetic insns, so make a separate class for it.
+
+ There is a special 'registrer' (76), which is not a register, but a
+ placeholder for memory allocated to convert between floating point and
+ integral types. This works around a problem where if we allocate memory
+ with allocate_stack_{local,temp} and the function is an inline function, the
+ memory allocated will clobber memory in the caller. So we use a special
+ register, and if that is used, we allocate stack space for it. */
enum reg_class
{
CR0_REGS,
CR_REGS,
NON_FLOAT_REGS,
+ FPMEM_REGS,
+ FLOAT_OR_FPMEM_REGS,
ALL_REGS,
LIM_REG_CLASSES
};
"CR0_REGS", \
"CR_REGS", \
"NON_FLOAT_REGS", \
+ "FPMEM_REGS", \
+ "FLOAT_OR_FPMEM_REGS", \
"ALL_REGS" \
}
{ 0x00000000, 0x00000000, 0x00000010 }, /* CR0_REGS */ \
{ 0x00000000, 0x00000000, 0x00000ff0 }, /* CR_REGS */ \
{ 0xffffffff, 0x00000000, 0x0000ffff }, /* NON_FLOAT_REGS */ \
- { 0xffffffff, 0xffffffff, 0x0000ffff } /* ALL_REGS */ \
+ { 0x00000000, 0x00000000, 0x00010000 }, /* FPMEM_REGS */ \
+ { 0x00000000, 0xffffffff, 0x00010000 }, /* FLOAT_OR_FPMEM_REGS */ \
+ { 0xffffffff, 0xffffffff, 0x0001ffff } /* ALL_REGS */ \
}
/* The same information, inverted:
reg number REGNO. This could be a conditional expression
or could index an array. */
-#define REGNO_REG_CLASS(REGNO) \
- ((REGNO) == 0 ? GENERAL_REGS \
- : (REGNO) < 32 ? BASE_REGS \
- : FP_REGNO_P (REGNO) ? FLOAT_REGS \
- : (REGNO) == 68 ? CR0_REGS \
- : CR_REGNO_P (REGNO) ? CR_REGS \
- : (REGNO) == 64 ? MQ_REGS \
- : (REGNO) == 65 ? LINK_REGS \
- : (REGNO) == 66 ? CTR_REGS \
- : (REGNO) == 67 ? BASE_REGS \
+#define REGNO_REG_CLASS(REGNO) \
+ ((REGNO) == 0 ? GENERAL_REGS \
+ : (REGNO) < 32 ? BASE_REGS \
+ : FP_REGNO_P (REGNO) ? FLOAT_REGS \
+ : (REGNO) == 68 ? CR0_REGS \
+ : CR_REGNO_P (REGNO) ? CR_REGS \
+ : (REGNO) == 64 ? MQ_REGS \
+ : (REGNO) == 65 ? LINK_REGS \
+ : (REGNO) == 66 ? CTR_REGS \
+ : (REGNO) == 67 ? BASE_REGS \
+ : (REGNO) == 76 ? FPMEM_REGS \
: NO_REGS)
/* The class value for index registers, and the one for base regs. */
: (C) == 'l' ? LINK_REGS \
: (C) == 'x' ? CR0_REGS \
: (C) == 'y' ? CR_REGS \
+ : (C) == 'z' ? FPMEM_REGS \
: NO_REGS)
/* The letters I, J, K, L, M, N, and P in a register constraint string
On the RS/6000, we have to return NO_REGS when we want to reload a
floating-point CONST_DOUBLE to force it to be copied to memory. */
-#define PREFERRED_RELOAD_CLASS(X,CLASS) \
+#define PREFERRED_RELOAD_CLASS(X,CLASS) \
((GET_CODE (X) == CONST_DOUBLE \
&& GET_MODE_CLASS (GET_MODE (X)) == MODE_FLOAT) \
? NO_REGS : (CLASS))
On RS/6000, this is the size of MODE in words,
except in the FP regs, where a single reg is enough for two words. */
-#define CLASS_MAX_NREGS(CLASS, MODE) \
- ((CLASS) == FLOAT_REGS \
+#define CLASS_MAX_NREGS(CLASS, MODE) \
+ (((CLASS) == FLOAT_REGS || (CLASS) == FPMEM_REGS \
+ || (CLASS) == FLOAT_OR_FPMEM_REGS) \
? ((GET_MODE_SIZE (MODE) + UNITS_PER_FP_WORD - 1) / UNITS_PER_FP_WORD) \
: ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD))
/* If defined, gives a class of registers that cannot be used as the
operand of a SUBREG that changes the size of the object. */
-#define CLASS_CANNOT_CHANGE_SIZE FLOAT_REGS
+#define CLASS_CANNOT_CHANGE_SIZE FLOAT_OR_FPMEM_REGS
\f
/* Stack layout; function entry, exit and calling. */
int calls_p; /* true if the function makes any calls */
int main_p; /* true if this is main */
int main_save_p; /* true if this is main and we need to save args */
+ int fpmem_p; /* true if float/int conversion temp needed */
enum rs6000_abi abi; /* which ABI to use */
int gp_save_offset; /* offset to save GP regs from initial SP */
int fp_save_offset; /* offset to save FP regs from initial SP */
int toc_save_offset; /* offset to save the TOC pointer */
int varargs_save_offset; /* offset to save the varargs registers */
int main_save_offset; /* offset to save main's args */
+ int fpmem_offset; /* offset for float/int conversion temp */
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 fp_size; /* size of saved FP registers */
int cr_size; /* size to hold CR if not in save_size */
int lr_size; /* size to hold LR if not in save_size */
+ int fpmem_size; /* size to hold float/int conversion */
int toc_size; /* size to hold TOC if not in save_size */
int total_size; /* total bytes allocated for stack */
} rs6000_stack_t;
/* Whether a separate TOC save area is needed */
extern int rs6000_save_toc_p;
+/* Offset & size for fpmem stack locations used for converting between
+ float and integral types. */
+extern int rs6000_fpmem_offset;
+extern int rs6000_fpmem_size;
+
/* Size of the V.4 varargs area if needed */
#define RS6000_VARARGS_AREA 0
((GP_ARG_NUM_REG * (TARGET_32BIT ? 4 : 8)) + (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)
+#define RS6000_VARARGS_OFFSET \
+ (ALIGN (current_function_outgoing_args_size, 8) \
+ + ALIGN (rs6000_fpmem_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
except for dynamic allocations. So we start after the fixed area and
outgoing parameter area. */
-#define STARTING_FRAME_OFFSET (ALIGN (current_function_outgoing_args_size, 8) \
- + RS6000_VARARGS_AREA \
- + RS6000_SAVE_AREA)
+#define STARTING_FRAME_OFFSET \
+ (ALIGN (current_function_outgoing_args_size, 8) \
+ + ALIGN (rs6000_fpmem_size, 8) \
+ + RS6000_VARARGS_AREA \
+ + RS6000_SAVE_AREA)
+
+/* Offset from the stack pointer register to an item dynamically
+ allocated on the stack, e.g., by `alloca'.
+
+ The default value for this macro is `STACK_POINTER_OFFSET' plus the
+ length of the outgoing arguments. The default is correct for most
+ machines. See `function.c' for details. */
+#define STACK_DYNAMIC_OFFSET(FUNDECL) \
+ (ALIGN (current_function_outgoing_args_size, 8) \
+ + ALIGN (rs6000_fpmem_size, 8) \
+ + (STACK_POINTER_OFFSET))
/* If we generate an insn to push BYTES bytes,
this says how many the stack pointer really advances by.
/* How to refer to registers in assembler output.
This sequence is indexed by compiler's hard-register-number (see above). */
-extern char rs6000_reg_names[][8]; /* register names (a0 vs. $4). */
+extern char rs6000_reg_names[][8]; /* register names (0 vs. %r0). */
#define REGISTER_NAMES \
{ \
&rs6000_reg_names[73][0], /* cr5 */ \
&rs6000_reg_names[74][0], /* cr6 */ \
&rs6000_reg_names[75][0], /* cr7 */ \
+ \
+ &rs6000_reg_names[76][0], /* fpmem */ \
}
/* print-rtl can't handle the above REGISTER_NAMES, so define the
#define DEBUG_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", "f15", \
- "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", \
- "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", \
- "mq", "lr", "ctr", "ap", \
- "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7" \
+ "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", "f15", \
+ "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", \
+ "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", \
+ "mq", "lr", "ctr", "ap", \
+ "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", \
+ "fpmem" \
}
/* Table of additional register names to use in user input. */
/* Define the codes that are matched by predicates in rs6000.c. */
-#define PREDICATE_CODES \
+#define PREDICATE_CODES \
{"short_cint_operand", {CONST_INT}}, \
{"u_short_cint_operand", {CONST_INT}}, \
{"non_short_cint_operand", {CONST_INT}}, \
{"non_logical_cint_operand", {CONST_INT}}, \
{"mask_operand", {CONST_INT}}, \
{"count_register_operand", {REG}}, \
+ {"fpmem_operand", {REG}}, \
{"call_operand", {SYMBOL_REF, REG}}, \
{"current_file_function_operand", {SYMBOL_REF}}, \
{"input_operand", {SUBREG, MEM, REG, CONST_INT, SYMBOL_REF}}, \
extern int mask_constant ();
extern int mask_operand ();
extern int and_operand ();
+extern int count_register_operand ();
+extern int fpmem_operand ();
extern int non_and_cint_operand ();
extern int reg_or_mem_operand ();
extern int lwa_operand ();
{cax|add} %0,%1,%2
{cal %0,%2(%1)|addi %0,%1,%2}
{ai|addic} %0,%1,%2
- {cau|addis} %0,%1,%u2")
+ {cau|addis} %0,%1,%v2")
(define_insn ""
[(set (match_operand:CC 0 "cc_reg_operand" "=x,x")
[(set_attr "type" "fp")])
\f
;; Conversions to and from floating-point.
+
(define_expand "floatsidf2"
- [(set (match_operand:DF 0 "gpc_reg_operand" "")
- (float:DF (match_operand:SI 1 "gpc_reg_operand" "")))]
+ [(parallel [(set (match_operand:DF 0 "gpc_reg_operand" "")
+ (float:DF (match_operand:SI 1 "gpc_reg_operand" "")))
+ (use (match_dup 2))
+ (use (match_dup 3))
+ (clobber (reg:DF 76))])]
"! TARGET_POWERPC64 && TARGET_HARD_FLOAT"
"
{
- if (operands[0])
- { /* prevent unused warning messages */
- rtx high = force_reg (SImode, GEN_INT (0x43300000));
- rtx low = gen_reg_rtx (SImode);
- rtx df = gen_reg_rtx (DFmode);
- rtx adjust = force_reg (DFmode, rs6000_float_const (\"4503601774854144\", DFmode));
-
- emit_insn (gen_xorsi3 (low, operands[1], GEN_INT (0x80000000)));
- emit_insn (gen_move_to_float (df, low, high));
- emit_insn (gen_subdf3 (operands[0], df, adjust));
- DONE;
- }
+ rtx low = gen_reg_rtx (SImode);
+ operands[2] = force_reg (SImode, GEN_INT (0x43300000));
+ operands[3] = force_reg (DFmode, rs6000_float_const (\"4503601774854144\", DFmode));
+
+ emit_insn (gen_xorsi3 (low, operands[1], GEN_INT (0x80000000)));
+ operands[1] = low;
}")
-(define_expand "floatunssidf2"
+(define_insn "*floatsidf2_internal"
+ [(set (match_operand:DF 0 "gpc_reg_operand" "=&f")
+ (float:DF (match_operand:SI 1 "gpc_reg_operand" "r")))
+ (use (match_operand:SI 2 "gpc_reg_operand" "r"))
+ (use (match_operand:DF 3 "gpc_reg_operand" "f"))
+ (clobber (reg:DF 76))]
+ "! TARGET_POWERPC64 && TARGET_HARD_FLOAT"
+ "#"
+ [(set_attr "length" "16")])
+
+(define_split
[(set (match_operand:DF 0 "gpc_reg_operand" "")
- (unsigned_float:DF (match_operand:SI 1 "gpc_reg_operand" "")))]
+ (float:DF (match_operand:SI 1 "gpc_reg_operand" "")))
+ (use (match_operand:SI 2 "gpc_reg_operand" ""))
+ (use (match_operand:DF 3 "gpc_reg_operand" ""))
+ (clobber (reg:DF 76))]
+ "! TARGET_POWERPC64 && TARGET_HARD_FLOAT"
+ [(set (match_dup 4)
+ (unspec [(match_dup 1) ;; low word
+ (reg:SI 1)] 11))
+ (set (match_dup 4)
+ (unspec [(match_dup 2) ;; high word
+ (reg:SI 1)
+ (match_dup 4)] 12))
+ (set (match_dup 0)
+ (unspec [(match_dup 4)
+ (reg:SI 1)] 13))
+ (set (match_dup 0)
+ (minus:DF (match_dup 0)
+ (match_dup 3)))]
+ "operands[4] = gen_rtx (REG, DFmode, FPMEM_REGNUM);")
+
+(define_expand "floatunssidf2"
+ [(parallel [(set (match_operand:DF 0 "gpc_reg_operand" "")
+ (unsigned_float:DF (match_operand:SI 1 "gpc_reg_operand" "")))
+ (use (match_dup 2))
+ (use (match_dup 3))
+ (clobber (reg:DF 76))])]
"! TARGET_POWERPC64 && TARGET_HARD_FLOAT"
"
{
- if (operands[0])
- { /* prevent unused warning messages */
- rtx high = force_reg (SImode, GEN_INT (0x43300000));
- rtx df = gen_reg_rtx (DFmode);
- rtx adjust = force_reg (DFmode, rs6000_float_const (\"4503599627370496\", DFmode));
-
- emit_insn (gen_move_to_float (df, operands[1], high));
- emit_insn (gen_subdf3 (operands[0], df, adjust));
- DONE;
- }
+ operands[2] = force_reg (SImode, GEN_INT (0x43300000));
+ operands[3] = force_reg (DFmode, rs6000_float_const (\"4503599627370496\", DFmode));
}")
-(define_expand "move_to_float"
- [(set (match_dup 4) ;; low word
- (match_operand:SI 1 "register_operand" ""))
- (set (match_dup 5) ;; high word
- (match_operand:SI 2 "register_operand" ""))
- (set (match_operand:SI 0 "register_operand" "") ;; float value
- (match_dup 3))]
+(define_insn "*floatunssidf2_internal"
+ [(set (match_operand:DF 0 "gpc_reg_operand" "=&f")
+ (unsigned_float:DF (match_operand:SI 1 "gpc_reg_operand" "r")))
+ (use (match_operand:SI 2 "gpc_reg_operand" "r"))
+ (use (match_operand:DF 3 "gpc_reg_operand" "f"))
+ (clobber (reg:DF 76))]
"! TARGET_POWERPC64 && TARGET_HARD_FLOAT"
- "
+ "#"
+ [(set_attr "length" "16")])
+
+(define_split
+ [(set (match_operand:DF 0 "gpc_reg_operand" "")
+ (unsigned_float:DF (match_operand:SI 1 "gpc_reg_operand" "")))
+ (use (match_operand:SI 2 "gpc_reg_operand" ""))
+ (use (match_operand:DF 3 "gpc_reg_operand" ""))
+ (clobber (reg:DF 76))]
+ "! TARGET_POWERPC64 && TARGET_HARD_FLOAT"
+ [(set (match_dup 4)
+ (unspec [(match_dup 1) ;; low word
+ (reg:SI 1)] 11))
+ (set (match_dup 4)
+ (unspec [(match_dup 2) ;; high word
+ (reg:SI 1)
+ (reg:DF 76)] 12))
+ (set (match_dup 0)
+ (unspec [(match_dup 4)
+ (reg:SI 1)] 13))
+ (set (match_dup 0)
+ (minus:DF (match_dup 0)
+ (match_dup 3)))]
+ "operands[4] = gen_rtx (REG, DFmode, FPMEM_REGNUM);")
+
+;; Note, we list r1 in the unspec, so that the optimizer is not tempted to optimize
+;; around an alloca call (the memory address is constructed directly from r1).
+
+(define_insn "*floatsidf2_store1"
+ [(set (reg:DF 76)
+ (unspec [(match_operand:SI 0 "gpc_reg_operand" "r")
+ (reg:SI 1)] 11))]
+ "! TARGET_POWERPC64 && TARGET_HARD_FLOAT"
+ "*
{
- operands[3] = gen_reg_rtx (DFmode);
+ operands[1] = gen_rtx (MEM, SImode,
+ gen_rtx (PLUS, Pmode,
+ stack_pointer_rtx,
+ GEN_INT (rs6000_fpmem_offset
+ + ((WORDS_BIG_ENDIAN != 0) * 4))));
- if (WORDS_BIG_ENDIAN)
- {
- operands[4] = gen_rtx (SUBREG, SImode, operands[3], 1);
- operands[5] = gen_rtx (SUBREG, SImode, operands[3], 0);
- }
- else
- {
- operands[4] = gen_rtx (SUBREG, SImode, operands[3], 0);
- operands[5] = gen_rtx (SUBREG, SImode, operands[3], 1);
- }
-}")
+ return \"{st|stw} %0,%1\";
+}"
+ [(set_attr "type" "store")])
+
+(define_insn "*floatsidf2_store2"
+ [(set (reg:DF 76)
+ (unspec [(match_operand:SI 0 "gpc_reg_operand" "r")
+ (reg:SI 1)
+ (reg:DF 76)] 12))]
+ "! TARGET_POWERPC64 && TARGET_HARD_FLOAT"
+ "*
+{
+ operands[1] = gen_rtx (MEM, SImode,
+ gen_rtx (PLUS, Pmode,
+ stack_pointer_rtx,
+ GEN_INT (rs6000_fpmem_offset
+ + ((WORDS_BIG_ENDIAN == 0) * 4))));
+
+ return \"{st|stw} %0,%1\";
+}"
+ [(set_attr "type" "store")])
+
+(define_insn "*floatsidf2_load"
+ [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
+ (unspec [(reg:DF 76)
+ (reg:SI 1)] 13))]
+ "! TARGET_POWERPC64 && TARGET_HARD_FLOAT"
+ "*
+{
+ operands[1] = gen_rtx (MEM, SImode,
+ gen_rtx (PLUS, Pmode,
+ stack_pointer_rtx,
+ GEN_INT (rs6000_fpmem_offset)));
+
+ return \"lfd %0,%1\";
+}"
+ [(set_attr "type" "fpload")])
(define_expand "fix_truncdfsi2"
- [(set (match_operand:SI 0 "gpc_reg_operand" "")
- (fix:SI (match_operand:DF 1 "gpc_reg_operand" "")))]
+ [(parallel [(set (match_operand:SI 0 "gpc_reg_operand" "")
+ (fix:SI (match_operand:DF 1 "gpc_reg_operand" "")))
+ (clobber (match_dup 2))
+ (clobber (match_dup 3))])]
"TARGET_HARD_FLOAT"
"
{
- if (TARGET_POWER2 || TARGET_POWERPC)
- {
- rtx temp1 = gen_reg_rtx (DImode);
- rtx temp2 = gen_reg_rtx (SImode);
-
- emit_insn (gen_fpcvtsi (temp1, operands[1]));
- emit_move_insn (temp2, gen_rtx (SUBREG, SImode, temp1, WORDS_BIG_ENDIAN));
- emit_move_insn (operands[0], temp2);
- DONE;
- }
- else
+ if (!TARGET_POWER2 && !TARGET_POWERPC)
{
emit_insn (gen_trunc_call (operands[0], operands[1],
gen_rtx (SYMBOL_REF, Pmode, RS6000_ITRUNC)));
DONE;
}
+
+ operands[2] = gen_reg_rtx (DImode);
+ operands[3] = gen_rtx (REG, DImode, FPMEM_REGNUM);
}")
-(define_insn "fpcvtsi"
+(define_insn "*fix_truncdfsi2_internal"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (fix:SI (match_operand:DF 1 "gpc_reg_operand" "f")))
+ (clobber (match_operand:DI 2 "gpc_reg_operand" "=f"))
+ (clobber (reg:DI 76))]
+ "TARGET_HARD_FLOAT"
+ "#"
+ [(set_attr "length" "12")])
+
+(define_split
+ [(set (match_operand:SI 0 "gpc_reg_operand" "")
+ (fix:SI (match_operand:DF 1 "gpc_reg_operand" "f")))
+ (clobber (match_operand:DI 2 "gpc_reg_operand" ""))
+ (clobber (reg:DI 76))]
+ "TARGET_HARD_FLOAT"
+ [(set (match_dup 2)
+ (sign_extend:DI (fix:SI (match_operand:DF 1 "gpc_reg_operand" ""))))
+ (set (match_dup 3)
+ (unspec [(match_dup 2)
+ (reg:SI 1)] 14))
+ (set (match_operand:SI 0 "gpc_reg_operand" "")
+ (unspec [(match_dup 3)
+ (reg:SI 1)] 15))]
+ "operands[3] = gen_rtx (REG, DImode, FPMEM_REGNUM);")
+
+(define_insn "*fctiwz"
[(set (match_operand:DI 0 "gpc_reg_operand" "=f")
- (sign_extend:DI
- (fix:SI (match_operand:DF 1 "gpc_reg_operand" "f"))))]
+ (sign_extend:DI (fix:SI (match_operand:DF 1 "gpc_reg_operand" "f"))))]
"(TARGET_POWER2 || TARGET_POWERPC) && TARGET_HARD_FLOAT"
"{fcirz|fctiwz} %0,%1"
[(set_attr "type" "fp")])
+(define_insn "*fix_truncdfsi2_store"
+ [(set (reg:DI 76)
+ (unspec [(match_operand:DI 0 "gpc_reg_operand" "f")
+ (reg:SI 1)] 14))]
+ "(TARGET_POWER2 || TARGET_POWERPC) && TARGET_HARD_FLOAT"
+ "*
+{
+ operands[1] = gen_rtx (MEM, DFmode,
+ gen_rtx (PLUS, Pmode,
+ stack_pointer_rtx,
+ GEN_INT (rs6000_fpmem_offset)));
+
+ return \"stfd %0,%1\";
+}"
+ [(set_attr "type" "fpstore")])
+
+(define_insn "*fix_truncdfsi2_load"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (unspec [(reg:DI 76)
+ (reg:SI 1)] 15))]
+ "(TARGET_POWER2 || TARGET_POWERPC) && TARGET_HARD_FLOAT"
+ "*
+{
+ operands[1] = gen_rtx (MEM, DFmode,
+ gen_rtx (PLUS, Pmode,
+ stack_pointer_rtx,
+ GEN_INT (rs6000_fpmem_offset + ((WORDS_BIG_ENDIAN) ? 4 : 0))));
+
+ return \"{l|lwz} %0,%1\";
+}"
+ [(set_attr "type" "load")])
+
(define_expand "fixuns_truncdfsi2"
[(set (match_operand:SI 0 "gpc_reg_operand" "")
(unsigned_fix:SI (match_operand:DF 1 "gpc_reg_operand" "")))]
add %0,%1,%2
addi %0,%1,%2
addic %0,%1,%2
- addis %0,%1,%u2")
+ addis %0,%1,%v2")
(define_insn ""
[(set (match_operand:CC 0 "cc_reg_operand" "=x,x")
{l%U1%X1|lwz%U1%X1} %0,%1
{st%U0%X0|stw%U0%X0} %1,%0
{lil|li} %0,%1
- {liu|lis} %0,%u1
+ {liu|lis} %0,%v1
#
{cal|la} %0,%1(%*)
mf%1 %0
{l%U1%X1|lwz%U1%X1} %0,%1
{st%U0%X0|stw%U0%X0} %1,%0
{lil|li} %0,%1
- {liu|lis} %0,%u1
+ {liu|lis} %0,%v1
{cal|la} %0,%1(%*)"
[(set_attr "type" "*,load,store,*,*,*")])
ld%U1%X1 %0,%1
std%U0%X0 %1,%0
li %0,%1
- lis %0,%u1
+ lis %0,%v1
#
{cal|la} %0,%1(%*)
fmr %0,%1
#include "rs6000/sysv4le.h"
+/* Default ABI to use */
+#undef RS6000_ABI_NAME
+#define RS6000_ABI_NAME "solaris"
+
#undef CPP_PREDEFINES
#define CPP_PREDEFINES \
"-Dsun=1 -Dunix -D__svr4__ -DSVR4 -DPPC \
#define PREFERRED_DEBUGGING_TYPE DBX_DEBUG
+#if 0
#undef ASM_OUTPUT_ALIGNED_LOCAL
#define ASM_OUTPUT_ALIGNED_LOCAL(FILE, NAME, SIZE, ALIGN) \
do { \
assemble_name ((FILE), (NAME)); \
fprintf ((FILE), ",%u,%u\n", (SIZE), (ALIGN) / BITS_PER_UNIT); \
} while (0)
-
+#endif
/* Like block addresses, stabs line numbers are relative to the
current function. */
fputs (_name, FILE); \
} while (0)
-#if 0
-/* The Solaris 2.51 linker has a bug in that it doesn't properly
- resolve references from the .init and .fini sections. So fall
- back to the old way of handling constructors and destructors. */
#undef ASM_OUTPUT_CONSTRUCTOR
#define ASM_OUTPUT_CONSTRUCTOR(FILE,NAME) \
do { \
- init_section (); \
- fputs ("\tbl ", FILE); \
- assemble_name (FILE, NAME); \
- fputs ((flag_pic) ? "@plt\n" : "\n", FILE); \
+ if (DEFAULT_ABI != ABI_SOLARIS) \
+ { \
+ ctors_section (); \
+ fprintf (FILE, "\t%s\t ", INT_ASM_OP); \
+ assemble_name (FILE, NAME); \
+ } \
+ else \
+ { \
+ init_section (); \
+ fputs ("\tbl ", FILE); \
+ assemble_name (FILE, NAME); \
+ } \
+ fputs ("\n", FILE); \
} while (0)
/* A C statement (sans semicolon) to output an element in the table of
#undef ASM_OUTPUT_DESTRUCTOR
#define ASM_OUTPUT_DESTRUCTOR(FILE,NAME) \
do { \
- fini_section (); \
- fputs ("\tbl ", FILE); \
- assemble_name (FILE, NAME); \
- fputs ((flag_pic) ? "@plt\n" : "\n", FILE); \
+ if (DEFAULT_ABI != ABI_SOLARIS) \
+ { \
+ dtors_section (); \
+ fprintf (FILE, "\t%s\t ", INT_ASM_OP); \
+ assemble_name (FILE, NAME); \
+ } \
+ else \
+ { \
+ fini_section (); \
+ fputs ("\tbl ", FILE); \
+ assemble_name (FILE, NAME); \
+ } \
+ fputs ("\n", FILE); \
} while (0)
-#endif
/* But, to make this work, we have to output the stabs for the function
name *first*... */
/* Pass various options to the assembler */
#undef ASM_SPEC
-#define ASM_SPEC "-u %(asm_cpu) %{mregnames} \
+#define ASM_SPEC "%(asm_cpu) %{mregnames} \
%{v:-V} %{Qy:} %{!Qn:-Qy} %{n} %{T} %{Ym,*} %{Yd,*} %{Wa,*:%*} \
%{mrelocatable} %{mrelocatable-lib} \
%{memb} %{!memb: %{msdata: -memb} %{msdata=eabi: -memb}} \
%{mno-sdata: -msdata=none } \
%{meabi: %{!mcall-*: -mcall-sysv }} \
%{!meabi: %{!mno-eabi: \
+ %{mrelocatable: -meabi } \
%{mcall-solaris: -mno-eabi } \
%{mcall-linux: -mno-eabi }}}"