/* Subroutines used for code generation on IBM RS/6000.
- Copyright (C) 1991, 1993 Free Software Foundation, Inc.
- Contributed by Richard Kenner (kenner@nyu.edu)
+ Copyright (C) 1991, 1993, 1994 Free Software Foundation, Inc.
+ Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
This file is part of GNU CC.
static int trunc_defined;
+/* Set to non-zero once AIX common-mode calls have been defined. */
+static int common_mode_defined;
/* Save information from a "cmpxx" operation until the branch or scc is
emitted. */
{
int i;
+ /* Simplify the entries below by making a mask for any POWER
+ variant and any PowerPC variant. */
+
+#define POWER_MASKS (MASK_POWER | MASK_POWER2)
+#define POWERPC_MASKS (MASK_POWERPC | MASK_PPC_GPOPT \
+ | MASK_PPC_GFXOPT | MASK_POWERPC64)
+#define POWERPC_OPT_MASKS (MASK_PPC_GPOPT | MASK_PPC_GFXOPT)
+
static struct ptt
{
char *name; /* Canonical processor name. */
int target_enable; /* Target flags to enable. */
int target_disable; /* Target flags to disable. */
} processor_target_table[]
- = {{"all", PROCESSOR_DEFAULT,
- 0, MASK_POWER | MASK_POWERPC | MASK_POWERPC64},
+ = {{"common", PROCESSOR_COMMON, 0, POWER_MASKS | POWERPC_MASKS},
+ {"power", PROCESSOR_POWER,
+ MASK_POWER,
+ MASK_POWER2 | POWERPC_MASKS | MASK_NEW_MNEMONICS},
+ {"powerpc", PROCESSOR_POWERPC,
+ MASK_POWERPC | MASK_NEW_MNEMONICS,
+ POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64},
{"rios", PROCESSOR_RIOS1,
- MASK_POWER, MASK_POWERPC | MASK_POWERPC64},
+ MASK_POWER,
+ MASK_POWER2 | POWERPC_MASKS | MASK_NEW_MNEMONICS},
{"rios1", PROCESSOR_RIOS1,
- MASK_POWER, MASK_POWERPC | MASK_POWERPC64},
+ MASK_POWER,
+ MASK_POWER2 | POWERPC_MASKS | MASK_NEW_MNEMONICS},
+ {"rsc", PROCESSOR_PPC601,
+ MASK_POWER,
+ MASK_POWER2 | POWERPC_MASKS | MASK_NEW_MNEMONICS},
+ {"rsc1", PROCESSOR_PPC601,
+ MASK_POWER,
+ MASK_POWER2 | POWERPC_MASKS | MASK_NEW_MNEMONICS},
{"rios2", PROCESSOR_RIOS2,
- MASK_POWER, MASK_POWERPC | MASK_POWERPC64},
+ MASK_POWER | MASK_POWER2,
+ POWERPC_MASKS | MASK_NEW_MNEMONICS},
{"601", PROCESSOR_PPC601,
- MASK_POWER | MASK_POWERPC | MASK_NEW_MNEMONICS, MASK_POWERPC64},
+ MASK_POWER | MASK_POWERPC | MASK_NEW_MNEMONICS,
+ MASK_POWER2 | POWERPC_OPT_MASKS | MASK_POWERPC64},
{"mpc601", PROCESSOR_PPC601,
- MASK_POWER | MASK_POWERPC | MASK_NEW_MNEMONICS, MASK_POWERPC64},
+ MASK_POWER | MASK_POWERPC | MASK_NEW_MNEMONICS,
+ MASK_POWER2 | POWERPC_OPT_MASKS | MASK_POWERPC64},
+ {"ppc601", PROCESSOR_PPC601,
+ MASK_POWER | MASK_POWERPC | MASK_NEW_MNEMONICS,
+ MASK_POWER2 | POWERPC_OPT_MASKS | MASK_POWERPC64},
{"603", PROCESSOR_PPC603,
- MASK_POWERPC | MASK_NEW_MNEMONICS, MASK_POWER | MASK_POWERPC64},
+ MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
+ POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64},
{"mpc603", PROCESSOR_PPC603,
- MASK_POWERPC | MASK_NEW_MNEMONICS, MASK_POWER | MASK_POWERPC64},
+ MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
+ POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64},
+ {"ppc603", PROCESSOR_PPC603,
+ MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
+ POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64},
{"604", PROCESSOR_PPC604,
- MASK_POWERPC | MASK_NEW_MNEMONICS, MASK_POWER | MASK_POWERPC64},
+ MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
+ POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64},
{"mpc604", PROCESSOR_PPC604,
- MASK_POWERPC | MASK_NEW_MNEMONICS, MASK_POWER | MASK_POWERPC64},
+ MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
+ POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64},
+ {"ppc604", PROCESSOR_PPC604,
+ MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
+ POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64},
{"620", PROCESSOR_PPC620,
- MASK_POWERPC | MASK_POWERPC64 | MASK_NEW_MNEMONICS, MASK_POWER},
+ (MASK_POWERPC | POWERPC_OPT_MASKS | MASK_POWERPC64
+ | MASK_NEW_MNEMONICS),
+ POWER_MASKS},
{"mpc620", PROCESSOR_PPC620,
- MASK_POWERPC | MASK_POWERPC64 | MASK_NEW_MNEMONICS, MASK_POWER}};
+ (MASK_POWERPC | POWERPC_OPT_MASKS | MASK_POWERPC64
+ | MASK_NEW_MNEMONICS),
+ POWER_MASKS},
+ {"ppc620", PROCESSOR_PPC620,
+ (MASK_POWERPC | POWERPC_OPT_MASKS | MASK_POWERPC64
+ | MASK_NEW_MNEMONICS),
+ POWER_MASKS}};
int ptt_size = sizeof (processor_target_table) / sizeof (struct ptt);
return GET_CODE (op) == CONST_INT || gpc_reg_operand (op, mode);
}
-/* Return 1 if the operand is a CONST_DOUBLE and it can be put into a
- register with one instruction per word. For SFmode, this means that
- the low 16-bits are zero. For DFmode, it means the low 16-bits of
- the first word are zero and the high 16 bits of the second word
- are zero (usually all bits in the low-order word will be zero).
-
- We only do this if we can safely read CONST_DOUBLE_{LOW,HIGH}. */
+/* Return 1 if the operand is a CONST_DOUBLE and it can be put into a register
+ with one instruction per word. We only do this if we can safely read
+ CONST_DOUBLE_{LOW,HIGH}. */
int
easy_fp_constant (op, mode)
high = operand_subword (op, 0, 0, mode);
low = operand_subword (op, 1, 0, mode);
- if (high == 0 || GET_CODE (high) != CONST_INT || (INTVAL (high) & 0xffff))
+ if (high == 0 || ! input_operand (high, word_mode))
return 0;
return (mode == SFmode
- || (low != 0 && GET_CODE (low) == CONST_INT
- && (INTVAL (low) & 0xffff0000) == 0));
+ || (low != 0 && input_operand (low, word_mode)));
}
/* Return 1 if the operand is either a floating-point register, a pseudo
switch (code)
{
case '.':
- /* Write out the bit number for "cror" after a call. This differs
- between AIX 3.2 and earlier versions. */
- fprintf (file, "%d", RS6000_CROR_BIT_NUMBER);
+ /* Write out an instruction after the call which may be replaced
+ with glue code by the loader. This depends on the AIX version. */
+ asm_fprintf (file, RS6000_CALL_GLUE);
return;
case 'A':
output_operand_lossage ("invalid %%E value");
fprintf(file, "%d", 4 * (REGNO (x) - 68) + 3);
- break;
+ return;
case 'f':
/* X is a CR register. Print the shift count needed to move it
}
else
output_addr_const (file, x);
- break;
+ return;
default:
output_operand_lossage ("invalid %%xn code");
/* Write .extern for truncation routines, if needed. */
if (rs6000_trunc_used && ! trunc_defined)
{
- fprintf (file, "\t.extern .itrunc\n\t.extern .uitrunc\n");
+ fprintf (file, "\t.extern .%s\n\t.extern .%s\n",
+ RS6000_ITRUNC, RS6000_UITRUNC);
trunc_defined = 1;
}
+ /* Write .extern for AIX common mode routines, if needed. */
+ if (! TARGET_POWER && ! TARGET_POWERPC && ! common_mode_defined)
+ {
+ fputs ("\t.extern __mulh\n", file);
+ fputs ("\t.extern __mull\n", file);
+ fputs ("\t.extern __divss\n", file);
+ fputs ("\t.extern __divus\n", file);
+ fputs ("\t.extern __quoss\n", file);
+ fputs ("\t.extern __quous\n", file);
+ common_mode_defined = 1;
+ }
/* If we have to call a function to save fpr's, or if we are doing profiling,
then we will be using LR. */
/* If we use the link register, get it into r0. */
if (regs_ever_live[65])
- fprintf (file, "\tmflr 0\n");
+ asm_fprintf (file, "\tmflr 0\n");
/* If we need to save CR, put it into r12. */
if (must_save_cr ())
- fprintf (file, "\tmfcr 12\n");
+ asm_fprintf (file, "\tmfcr 12\n");
/* Do any required saving of fpr's. If only one or two to save, do it
ourself. Otherwise, call function. Note that since they are statically
linked, we do not need a nop following them. */
if (first_fp_reg == 62)
- fprintf (file, "\tstfd 30,-16(1)\n\tstfd 31,-8(1)\n");
+ asm_fprintf (file, "\tstfd 30,-16(1)\n\tstfd 31,-8(1)\n");
else if (first_fp_reg == 63)
- fprintf (file, "\tstfd 31,-8(1)\n");
+ asm_fprintf (file, "\tstfd 31,-8(1)\n");
else if (first_fp_reg != 64)
- fprintf (file, "\tbl ._savef%d\n", first_fp_reg - 32);
+ asm_fprintf (file, "\tbl ._savef%d\n", first_fp_reg - 32);
/* Now save gpr's. */
- if (first_reg == 31)
- fprintf (file, "\tst 31,%d(1)\n", -4 - (64 - first_fp_reg) * 8);
+ if (! TARGET_POWER || first_reg == 31)
+ {
+ int regno, loc;
+
+ for (regno = first_reg,
+ loc = - (32 - first_reg) * 4 - (64 - first_fp_reg) * 8;
+ regno < 32;
+ regno++, loc += 4)
+ asm_fprintf (file, "\t{st|stw} %d,%d(1)\n", regno, loc);
+ }
+
else if (first_reg != 32)
- fprintf (file, "\tstm %d,%d(1)\n", first_reg,
+ asm_fprintf (file, "\t{stm|stmw} %d,%d(1)\n", first_reg,
- (32 - first_reg) * 4 - (64 - first_fp_reg) * 8);
/* Save lr if we used it. */
if (regs_ever_live[65])
- fprintf (file, "\tst 0,8(1)\n");
+ asm_fprintf (file, "\t{st|stw} 0,8(1)\n");
/* Save CR if we use any that must be preserved. */
if (must_save_cr ())
- fprintf (file, "\tst 12,4(1)\n");
+ asm_fprintf (file, "\t{st|stw} 12,4(1)\n");
/* Update stack and set back pointer. */
if (must_push)
{
if (total_size < 32767)
- fprintf (file, "\tstu 1,%d(1)\n", - total_size);
+ asm_fprintf (file, "\t{stu|stwu} 1,%d(1)\n", - total_size);
else
{
- fprintf (file, "\tcau 0,0,%d\n\toril 0,0,%d\n",
+ asm_fprintf (file, "\t{cau 0,0,%d|lis 0,%d}\n\t{oril|ori} 0,0,%d\n",
(total_size >> 16) & 0xffff, total_size & 0xffff);
- fprintf (file, "\tsf 12,0,1\n\tst 1,0(12)\n\toril 1,12,0\n");
+ if (TARGET_POWERPC)
+ asm_fprintf (file, "\tsubf 12,0,1\n");
+ else
+ asm_fprintf (file, "\t{sf|subfc} 12,0,1\n");
+ asm_fprintf (file, "\t{st|stw} 1,0(12)\n\tmr 1,12\n");
}
}
/* Set frame pointer, if needed. */
if (frame_pointer_needed)
- fprintf (file, "\toril 31,1,0\n");
+ asm_fprintf (file, "\tmr 31,1\n");
/* If TARGET_MINIMAL_TOC, and the constant pool is needed, then load the
TOC_TABLE address into register 30. */
if (TARGET_MINIMAL_TOC && get_pool_size () != 0)
- fprintf (file, "\tl 30,LCTOC..0(2)\n");
+ {
+ char buf[100];
+
+ ASM_GENERATE_INTERNAL_LABEL (buf, "LCTOC", 0);
+ asm_fprintf (file, "\t{l|lwz} 30,");
+ assemble_name (file, buf);
+ asm_fprintf (file, "(2)\n");
+ }
}
/* Write function epilogue. */
we know what size to update it with. */
if (frame_pointer_needed || current_function_calls_alloca
|| total_size > 32767)
- fprintf (file, "\tl 1,0(1)\n");
+ asm_fprintf (file, "\t{l|lwz} 1,0(1)\n");
else if (must_push)
- fprintf (file, "\tai 1,1,%d\n", total_size);
+ asm_fprintf (file, "\t{cal 1,%d(1)|addi 1,1,%d}\n", total_size);
/* Get the old lr if we saved it. */
if (regs_ever_live[65])
- fprintf (file, "\tl 0,8(1)\n");
+ asm_fprintf (file, "\t{l|lwz} 0,8(1)\n");
/* Get the old cr if we saved it. */
if (must_save_cr ())
- fprintf (file, "\tl 12,4(1)\n");
+ asm_fprintf (file, "\t{l|lwz} 12,4(1)\n");
/* Set LR here to try to overlap restores below. */
if (regs_ever_live[65])
- fprintf (file, "\tmtlr 0\n");
+ asm_fprintf (file, "\tmtlr 0\n");
/* Restore gpr's. */
- if (first_reg == 31)
- fprintf (file, "\tl 31,%d(1)\n", -4 - (64 - first_fp_reg) * 8);
+ if (! TARGET_POWER || first_reg == 31)
+ {
+ int regno, loc;
+
+ for (regno = first_reg,
+ loc = - (32 - first_reg) * 4 - (64 - first_fp_reg) * 8;
+ regno < 32;
+ regno++, loc += 4)
+ asm_fprintf (file, "\t{l|lwz} %d,%d(1)\n", regno, loc);
+ }
+
else if (first_reg != 32)
- fprintf (file, "\tlm %d,%d(1)\n", first_reg,
- - (32 - first_reg) * 4 - (64 - first_fp_reg) * 8);
+ asm_fprintf (file, "\t{lm|lmw} %d,%d(1)\n", first_reg,
+ - (32 - first_reg) * 4 - (64 - first_fp_reg) * 8);
/* Restore fpr's if we can do it without calling a function. */
if (first_fp_reg == 62)
- fprintf (file, "\tlfd 30,-16(1)\n\tlfd 31,-8(1)\n");
+ asm_fprintf (file, "\tlfd 30,-16(1)\n\tlfd 31,-8(1)\n");
else if (first_fp_reg == 63)
- fprintf (file, "\tlfd 31,-8(1)\n");
+ asm_fprintf (file, "\tlfd 31,-8(1)\n");
/* If we saved cr, restore it here. Just those of cr2, cr3, and cr4
that were used. */
if (must_save_cr ())
- fprintf (file, "\tmtcrf %d,12\n",
- (regs_ever_live[70] != 0) * 0x20
- + (regs_ever_live[71] != 0) * 0x10
- + (regs_ever_live[72] != 0) * 0x8);
+ asm_fprintf (file, "\tmtcrf %d,12\n",
+ (regs_ever_live[70] != 0) * 0x20
+ + (regs_ever_live[71] != 0) * 0x10
+ + (regs_ever_live[72] != 0) * 0x8);
/* If we have to restore more than two FP registers, branch to the
restore function. It will return to our caller. */
if (first_fp_reg < 62)
- fprintf (file, "\tb ._restf%d\n", first_fp_reg - 32);
+ asm_fprintf (file, "\tb ._restf%d\n", first_fp_reg - 32);
else
- fprintf (file, "\tbr\n");
+ asm_fprintf (file, "\t{br|blr}\n");
}
/* Output a traceback table here. See /usr/include/sys/debug.h for info
- on its format. */
- {
- char *fname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
- int fixed_parms, float_parms, parm_info;
- int i;
-
- /* Need label immediately before tbtab, so we can compute its offset
- from the function start. */
- if (*fname == '*')
- ++fname;
- fprintf (file, "LT..");
- ASM_OUTPUT_LABEL (file, fname);
-
- /* The .tbtab pseudo-op can only be used for the first eight
- expressions, since it can't handle the possibly variable length
- fields that follow. However, if you omit the optional fields,
- the assembler outputs zeros for all optional fields anyways, giving each
- variable length field is minimum length (as defined in sys/debug.h).
- Thus we can not use the .tbtab pseudo-op at all. */
-
- /* An all-zero word flags the start of the tbtab, for debuggers that have
- to find it by searching forward from the entry point or from the
- current pc. */
- fprintf (file, "\t.long 0\n");
-
- /* Tbtab format type. Use format type 0. */
- fprintf (file, "\t.byte 0,");
-
- /* Language type. Unfortunately, there doesn't seem to be any official way
- to get this info, so we use language_string. C is 0. C++ is 9.
- No number defined for Obj-C, so use the value for C for now. */
- if (! strcmp (language_string, "GNU C")
- || ! strcmp (language_string, "GNU Obj-C"))
- i = 0;
- else if (! strcmp (language_string, "GNU F77"))
- i = 1;
- else if (! strcmp (language_string, "GNU Ada"))
- i = 3;
- else if (! strcmp (language_string, "GNU PASCAL"))
- i = 2;
- else if (! strcmp (language_string, "GNU C++"))
- i = 9;
- else
- abort ();
- fprintf (file, "%d,", i);
-
- /* 8 single bit fields: global linkage (not set for C extern linkage,
- apparently a PL/I convention?), out-of-line epilogue/prologue, offset
- from start of procedure stored in tbtab, internal function, function
- has controlled storage, function has no toc, function uses fp,
- function logs/aborts fp operations. */
- /* Assume that fp operations are used if any fp reg must be saved. */
- fprintf (file, "%d,", (1 << 5) | ((first_fp_reg != 64) << 1));
-
- /* 6 bitfields: function is interrupt handler, name present in proc table,
- function calls alloca, on condition directives (controls stack walks,
- 3 bits), saves condition reg, saves link reg. */
- /* The `function calls alloca' bit seems to be set whenever reg 31 is
- set up as a frame pointer, even when there is no alloca call. */
- fprintf (file, "%d,",
- ((1 << 6) | (frame_pointer_needed << 5)
- | (must_save_cr () << 1) | (regs_ever_live[65])));
-
- /* 3 bitfields: saves backchain, spare bit, number of fpr saved
- (6 bits). */
- fprintf (file, "%d,",
- (must_push << 7) | (64 - first_fp_reg_to_save ()));
-
- /* 2 bitfields: spare bits (2 bits), number of gpr saved (6 bits). */
- fprintf (file, "%d,", (32 - first_reg_to_save ()));
-
+ on its format.
+
+ We don't output a traceback table if -finhibit-size-directive was
+ used. The documentation for -finhibit-size-directive reads
+ ``don't output a @code{.size} assembler directive, or anything
+ else that would cause trouble if the function is split in the
+ middle, and the two halves are placed at locations far apart in
+ memory.'' The traceback table has this property, since it
+ includes the offset from the start of the function to the
+ traceback table itself. */
+ if (! flag_inhibit_size_directive)
{
- /* Compute the parameter info from the function decl argument list. */
- tree decl;
- int next_parm_info_bit;
-
- next_parm_info_bit = 31;
- parm_info = 0;
- fixed_parms = 0;
- float_parms = 0;
-
- for (decl = DECL_ARGUMENTS (current_function_decl);
- decl; decl = TREE_CHAIN (decl))
- {
- rtx parameter = DECL_INCOMING_RTL (decl);
- enum machine_mode mode = GET_MODE (parameter);
-
- if (GET_CODE (parameter) == REG)
- {
- if (GET_MODE_CLASS (mode) == MODE_FLOAT)
- {
- int bits;
-
- float_parms++;
-
- if (mode == SFmode)
- bits = 0x2;
- else if (mode == DFmode)
- bits = 0x3;
- else
- abort ();
-
- /* If only one bit will fit, don't or in this entry. */
- if (next_parm_info_bit > 0)
- parm_info |= (bits << (next_parm_info_bit - 1));
- next_parm_info_bit -= 2;
- }
- else
- {
- fixed_parms += ((GET_MODE_SIZE (mode) + (UNITS_PER_WORD - 1))
- / UNITS_PER_WORD);
- next_parm_info_bit -= 1;
- }
- }
- }
+ char *fname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
+ int fixed_parms, float_parms, parm_info;
+ int i;
+
+ /* Need label immediately before tbtab, so we can compute its offset
+ from the function start. */
+ if (*fname == '*')
+ ++fname;
+ ASM_OUTPUT_INTERNAL_LABEL_PREFIX (file, "LT");
+ ASM_OUTPUT_LABEL (file, fname);
+
+ /* The .tbtab pseudo-op can only be used for the first eight
+ expressions, since it can't handle the possibly variable
+ length fields that follow. However, if you omit the optional
+ fields, the assembler outputs zeros for all optional fields
+ anyways, giving each variable length field is minimum length
+ (as defined in sys/debug.h). Thus we can not use the .tbtab
+ pseudo-op at all. */
+
+ /* An all-zero word flags the start of the tbtab, for debuggers
+ that have to find it by searching forward from the entry
+ point or from the current pc. */
+ fprintf (file, "\t.long 0\n");
+
+ /* Tbtab format type. Use format type 0. */
+ fprintf (file, "\t.byte 0,");
+
+ /* Language type. Unfortunately, there doesn't seem to be any
+ official way to get this info, so we use language_string. C
+ is 0. C++ is 9. No number defined for Obj-C, so use the
+ value for C for now. */
+ if (! strcmp (language_string, "GNU C")
+ || ! strcmp (language_string, "GNU Obj-C"))
+ i = 0;
+ else if (! strcmp (language_string, "GNU F77"))
+ i = 1;
+ else if (! strcmp (language_string, "GNU Ada"))
+ i = 3;
+ else if (! strcmp (language_string, "GNU PASCAL"))
+ i = 2;
+ else if (! strcmp (language_string, "GNU C++"))
+ i = 9;
+ else
+ abort ();
+ fprintf (file, "%d,", i);
+
+ /* 8 single bit fields: global linkage (not set for C extern linkage,
+ apparently a PL/I convention?), out-of-line epilogue/prologue, offset
+ from start of procedure stored in tbtab, internal function, function
+ has controlled storage, function has no toc, function uses fp,
+ function logs/aborts fp operations. */
+ /* Assume that fp operations are used if any fp reg must be saved. */
+ fprintf (file, "%d,", (1 << 5) | ((first_fp_reg != 64) << 1));
+
+ /* 6 bitfields: function is interrupt handler, name present in
+ proc table, function calls alloca, on condition directives
+ (controls stack walks, 3 bits), saves condition reg, saves
+ link reg. */
+ /* The `function calls alloca' bit seems to be set whenever reg 31 is
+ set up as a frame pointer, even when there is no alloca call. */
+ fprintf (file, "%d,",
+ ((1 << 6) | (frame_pointer_needed << 5)
+ | (must_save_cr () << 1) | (regs_ever_live[65])));
+
+ /* 3 bitfields: saves backchain, spare bit, number of fpr saved
+ (6 bits). */
+ fprintf (file, "%d,",
+ (must_push << 7) | (64 - first_fp_reg_to_save ()));
+
+ /* 2 bitfields: spare bits (2 bits), number of gpr saved (6 bits). */
+ fprintf (file, "%d,", (32 - first_reg_to_save ()));
+
+ {
+ /* Compute the parameter info from the function decl argument
+ list. */
+ tree decl;
+ int next_parm_info_bit;
+
+ next_parm_info_bit = 31;
+ parm_info = 0;
+ fixed_parms = 0;
+ float_parms = 0;
+
+ for (decl = DECL_ARGUMENTS (current_function_decl);
+ decl; decl = TREE_CHAIN (decl))
+ {
+ rtx parameter = DECL_INCOMING_RTL (decl);
+ enum machine_mode mode = GET_MODE (parameter);
+
+ if (GET_CODE (parameter) == REG)
+ {
+ if (GET_MODE_CLASS (mode) == MODE_FLOAT)
+ {
+ int bits;
+
+ float_parms++;
+
+ if (mode == SFmode)
+ bits = 0x2;
+ else if (mode == DFmode)
+ bits = 0x3;
+ else
+ abort ();
+
+ /* If only one bit will fit, don't or in this entry. */
+ if (next_parm_info_bit > 0)
+ parm_info |= (bits << (next_parm_info_bit - 1));
+ next_parm_info_bit -= 2;
+ }
+ else
+ {
+ fixed_parms += ((GET_MODE_SIZE (mode)
+ + (UNITS_PER_WORD - 1))
+ / UNITS_PER_WORD);
+ next_parm_info_bit -= 1;
+ }
+ }
+ }
+ }
+
+ /* Number of fixed point parameters. */
+ /* This is actually the number of words of fixed point parameters; thus
+ an 8 byte struct counts as 2; and thus the maximum value is 8. */
+ fprintf (file, "%d,", fixed_parms);
+
+ /* 2 bitfields: number of floating point parameters (7 bits), parameters
+ all on stack. */
+ /* This is actually the number of fp registers that hold parameters;
+ and thus the maximum value is 13. */
+ /* Set parameters on stack bit if parameters are not in their original
+ registers, regardless of whether they are on the stack? Xlc
+ seems to set the bit when not optimizing. */
+ fprintf (file, "%d\n", ((float_parms << 1) | (! optimize)));
+
+ /* Optional fields follow. Some are variable length. */
+
+ /* Parameter types, left adjusted bit fields: 0 fixed, 10 single float,
+ 11 double float. */
+ /* There is an entry for each parameter in a register, in the order that
+ they occur in the parameter list. Any intervening arguments on the
+ stack are ignored. If the list overflows a long (max possible length
+ 34 bits) then completely leave off all elements that don't fit. */
+ /* Only emit this long if there was at least one parameter. */
+ if (fixed_parms || float_parms)
+ fprintf (file, "\t.long %d\n", parm_info);
+
+ /* Offset from start of code to tb table. */
+ fprintf (file, "\t.long ");
+ ASM_OUTPUT_INTERNAL_LABEL_PREFIX (file, "LT");
+ RS6000_OUTPUT_BASENAME (file, fname);
+ fprintf (file, "-.");
+ RS6000_OUTPUT_BASENAME (file, fname);
+ fprintf (file, "\n");
+
+ /* Interrupt handler mask. */
+ /* Omit this long, since we never set the interrupt handler bit
+ above. */
+
+ /* Number of CTL (controlled storage) anchors. */
+ /* Omit this long, since the has_ctl bit is never set above. */
+
+ /* Displacement into stack of each CTL anchor. */
+ /* Omit this list of longs, because there are no CTL anchors. */
+
+ /* Length of function name. */
+ fprintf (file, "\t.short %d\n", strlen (fname));
+
+ /* Function name. */
+ assemble_string (fname, strlen (fname));
+
+ /* Register for alloca automatic storage; this is always reg 31.
+ Only emit this if the alloca bit was set above. */
+ if (frame_pointer_needed)
+ fprintf (file, "\t.byte 31\n");
}
-
- /* Number of fixed point parameters. */
- /* This is actually the number of words of fixed point parameters; thus
- an 8 byte struct counts as 2; and thus the maximum value is 8. */
- fprintf (file, "%d,", fixed_parms);
-
- /* 2 bitfields: number of floating point parameters (7 bits), parameters
- all on stack. */
- /* This is actually the number of fp registers that hold parameters;
- and thus the maximum value is 13. */
- /* Set parameters on stack bit if parameters are not in their original
- registers, regardless of whether they are on the stack? Xlc
- seems to set the bit when not optimizing. */
- fprintf (file, "%d\n", ((float_parms << 1) | (! optimize)));
-
- /* Optional fields follow. Some are variable length. */
-
- /* Parameter types, left adjusted bit fields: 0 fixed, 10 single float,
- 11 double float. */
- /* There is an entry for each parameter in a register, in the order that
- they occur in the parameter list. Any intervening arguments on the
- stack are ignored. If the list overflows a long (max possible length
- 34 bits) then completely leave off all elements that don't fit. */
- /* Only emit this long if there was at least one parameter. */
- if (fixed_parms || float_parms)
- fprintf (file, "\t.long %d\n", parm_info);
-
- /* Offset from start of code to tb table. */
- fprintf (file, "\t.long LT..");
- RS6000_OUTPUT_BASENAME (file, fname);
- fprintf (file, "-.");
- RS6000_OUTPUT_BASENAME (file, fname);
- fprintf (file, "\n");
-
- /* Interrupt handler mask. */
- /* Omit this long, since we never set the interrupt handler bit above. */
-
- /* Number of CTL (controlled storage) anchors. */
- /* Omit this long, since the has_ctl bit is never set above. */
-
- /* Displacement into stack of each CTL anchor. */
- /* Omit this list of longs, because there are no CTL anchors. */
-
- /* Length of function name. */
- fprintf (file, "\t.short %d\n", strlen (fname));
-
- /* Function name. */
- assemble_string (fname, strlen (fname));
-
- /* Register for alloca automatic storage; this is always reg 31.
- Only emit this if the alloca bit was set above. */
- if (frame_pointer_needed)
- fprintf (file, "\t.byte 31\n");
- }
}
\f
/* Output a TOC entry. We derive the entry name from what is
/* The last used parameter register. */
int last_parm_reg;
int i, j;
+ char buf[100];
/* Set up a TOC entry for the profiler label. */
toc_section ();
- fprintf (file, "LPC..%d:\n\t.tc\tLP..%d[TC],LP..%d\n",
- labelno, labelno, labelno);
+ ASM_OUTPUT_INTERNAL_LABEL (file, "LPC", labelno);
+ ASM_GENERATE_INTERNAL_LABEL (buf, "LP", labelno);
+ if (TARGET_MINIMAL_TOC)
+ {
+ fprintf (file, "\t.long ");
+ assemble_name (file, buf);
+ fprintf (file, "\n");
+ }
+ else
+ {
+ fprintf (file, "\t.tc\t");
+ assemble_name (file, buf);
+ fprintf (file, "[TC],");
+ assemble_name (file, buf);
+ fprintf (file, "\n");
+ }
text_section ();
/* Figure out last used parameter register. The proper thing to do is
/* Load location address into r3, and call mcount. */
- fprintf (file, "\tl 3,LPC..%d(2)\n\tbl .mcount\n", labelno);
+ ASM_GENERATE_INTERNAL_LABEL (buf, "LPC", labelno);
+ fprintf (file, "\tl 3,");
+ assemble_name (file, buf);
+ fprintf (file, "(2)\n\tbl .mcount\n");
/* Restore parameter registers. */
for (i = 3, j = 30; i <= last_parm_reg; i++, j--)
fprintf (file, "\tai %d,%d,0\n", i, j);
}
+
+/* Adjust the cost of a scheduling dependency. Return the new cost of
+ a dependency LINK or INSN on DEP_INSN. COST is the current cost. */
+
+int
+rs6000_adjust_cost (insn, link, dep_insn, cost)
+ rtx insn;
+ rtx link;
+ rtx dep_insn;
+ int cost;
+{
+ if (! recog_memoized (insn))
+ return 0;
+
+ if (REG_NOTE_KIND (link) != 0)
+ return 0;
+
+ if (REG_NOTE_KIND (link) == 0)
+ {
+ /* Data dependency; DEP_INSN writes a register that INSN reads some
+ cycles later. */
+
+ /* Tell the first scheduling pass about the latency between a mtctr
+ and bctr (and mtlr and br/blr). The first scheduling pass will not
+ know about this latency since the mtctr instruction, which has the
+ latency associated to it, will be generated by reload. */
+ if (get_attr_type (insn) == TYPE_JMPREG)
+ return TARGET_POWER ? 5 : 4;
+
+ /* Fall out to return default cost. */
+ }
+
+ return cost;
+}