/* Subroutines used for code generation on IBM RS/6000.
Copyright (C) 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
- 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+ 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
This file is part of GCC.
char toc_label_name[10];
/* Alias set for saves and restores from the rs6000 stack. */
-static int rs6000_sr_alias_set;
+static GTY(()) int rs6000_sr_alias_set;
/* Call distance, overridden by -mlongcall and #pragma longcall(1).
The only place that looks at this is rs6000_set_default_type_attributes;
int rs6000_default_long_calls;
const char *rs6000_longcall_switch;
-/* Control alignment for fields within structures. */
-/* String from -malign-XXXXX. */
+/* Control alignment for fields within structures. */
+/* String from -malign-XXXXX. */
const char *rs6000_alignment_string;
int rs6000_alignment_flags;
{
size_t i, j;
struct rs6000_cpu_select *ptr;
+ int set_masks;
- /* Simplify the entries below by making a mask for any POWER
- variant and any PowerPC variant. */
+ /* Simplifications for entries below. */
-#define POWER_MASKS (MASK_POWER | MASK_POWER2 | MASK_MULTIPLE | MASK_STRING)
-#define POWERPC_MASKS (MASK_POWERPC | MASK_PPC_GPOPT \
- | MASK_PPC_GFXOPT | MASK_POWERPC64)
-#define POWERPC_OPT_MASKS (MASK_PPC_GPOPT | MASK_PPC_GFXOPT)
+ enum {
+ POWERPC_BASE_MASK = MASK_POWERPC | MASK_NEW_MNEMONICS,
+ POWERPC_7400_MASK = POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_ALTIVEC
+ };
+ /* This table occasionally claims that a processor does not support
+ a particular feature even though it does, but the feature is slower
+ than the alternative. Thus, it shouldn't be relied on as a
+ complete description of the processor's support.
+
+ Please keep this list in order, and don't forget to update the
+ documentation in invoke.texi when adding a new processor or
+ flag. */
static struct ptt
{
const char *const name; /* Canonical processor name. */
const enum processor_type processor; /* Processor type enum value. */
const int target_enable; /* Target flags to enable. */
- const int target_disable; /* Target flags to disable. */
} const processor_target_table[]
- = {{"common", PROCESSOR_COMMON, MASK_NEW_MNEMONICS,
- POWER_MASKS | POWERPC_MASKS},
- {"power", PROCESSOR_POWER,
- MASK_POWER | MASK_MULTIPLE | MASK_STRING,
- MASK_POWER2 | POWERPC_MASKS | MASK_NEW_MNEMONICS},
- {"power2", PROCESSOR_POWER,
- MASK_POWER | MASK_POWER2 | MASK_MULTIPLE | MASK_STRING,
- POWERPC_MASKS | MASK_NEW_MNEMONICS},
- {"power3", PROCESSOR_PPC630,
- MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
- POWER_MASKS},
- {"power4", PROCESSOR_POWER4,
- MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS | MASK_MFCRF,
- POWER_MASKS},
- {"powerpc", PROCESSOR_POWERPC,
- MASK_POWERPC | MASK_NEW_MNEMONICS,
- POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64},
- {"powerpc64", PROCESSOR_POWERPC64,
- MASK_POWERPC | MASK_POWERPC64 | MASK_NEW_MNEMONICS,
- POWER_MASKS | POWERPC_OPT_MASKS},
- {"rios", PROCESSOR_RIOS1,
- MASK_POWER | MASK_MULTIPLE | MASK_STRING,
- MASK_POWER2 | POWERPC_MASKS | MASK_NEW_MNEMONICS},
- {"rios1", PROCESSOR_RIOS1,
- MASK_POWER | MASK_MULTIPLE | MASK_STRING,
- MASK_POWER2 | POWERPC_MASKS | MASK_NEW_MNEMONICS},
- {"rsc", PROCESSOR_PPC601,
- MASK_POWER | MASK_MULTIPLE | MASK_STRING,
- MASK_POWER2 | POWERPC_MASKS | MASK_NEW_MNEMONICS},
- {"rsc1", PROCESSOR_PPC601,
- MASK_POWER | MASK_MULTIPLE | MASK_STRING,
- MASK_POWER2 | POWERPC_MASKS | MASK_NEW_MNEMONICS},
- {"rios2", PROCESSOR_RIOS2,
- MASK_POWER | MASK_MULTIPLE | MASK_STRING | MASK_POWER2,
- POWERPC_MASKS | MASK_NEW_MNEMONICS},
- {"rs64a", PROCESSOR_RS64A,
- MASK_POWERPC | MASK_NEW_MNEMONICS,
- POWER_MASKS | POWERPC_OPT_MASKS},
- {"401", PROCESSOR_PPC403,
- MASK_POWERPC | MASK_SOFT_FLOAT | MASK_NEW_MNEMONICS,
- POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64},
+ = {{"401", PROCESSOR_PPC403, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
{"403", PROCESSOR_PPC403,
- MASK_POWERPC | MASK_SOFT_FLOAT | MASK_NEW_MNEMONICS | MASK_STRICT_ALIGN,
- POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64},
- {"405", PROCESSOR_PPC405,
- MASK_POWERPC | MASK_SOFT_FLOAT | MASK_NEW_MNEMONICS,
- POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64},
- {"405fp", PROCESSOR_PPC405,
- MASK_POWERPC | MASK_NEW_MNEMONICS,
- POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64},
- {"440", PROCESSOR_PPC440,
- MASK_POWERPC | MASK_SOFT_FLOAT | MASK_NEW_MNEMONICS,
- POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64},
- {"440fp", PROCESSOR_PPC440,
- MASK_POWERPC | MASK_NEW_MNEMONICS,
- POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64},
- {"505", PROCESSOR_MPCCORE,
- MASK_POWERPC | MASK_NEW_MNEMONICS,
- POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64},
+ POWERPC_BASE_MASK | MASK_SOFT_FLOAT | MASK_STRICT_ALIGN},
+ {"405", PROCESSOR_PPC405, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
+ {"405fp", PROCESSOR_PPC405, POWERPC_BASE_MASK},
+ {"440", PROCESSOR_PPC440, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
+ {"440fp", PROCESSOR_PPC440, POWERPC_BASE_MASK},
+ {"505", PROCESSOR_MPCCORE, POWERPC_BASE_MASK},
{"601", PROCESSOR_PPC601,
- MASK_POWER | MASK_POWERPC | MASK_NEW_MNEMONICS | MASK_MULTIPLE | MASK_STRING,
- MASK_POWER2 | POWERPC_OPT_MASKS | MASK_POWERPC64},
- {"602", PROCESSOR_PPC603,
- MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
- POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64},
- {"603", PROCESSOR_PPC603,
- MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
- POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64},
- {"603e", PROCESSOR_PPC603,
- MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
- POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64},
- {"ec603e", PROCESSOR_PPC603,
- MASK_POWERPC | MASK_SOFT_FLOAT | MASK_NEW_MNEMONICS,
- POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64},
- {"604", PROCESSOR_PPC604,
- MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
- POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64},
- {"604e", PROCESSOR_PPC604e,
- MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
- POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64},
+ MASK_POWER | POWERPC_BASE_MASK | MASK_MULTIPLE | MASK_STRING},
+ {"602", PROCESSOR_PPC603, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
+ {"603", PROCESSOR_PPC603, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
+ {"603e", PROCESSOR_PPC603, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
+ {"604", PROCESSOR_PPC604, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
+ {"604e", PROCESSOR_PPC604e, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
{"620", PROCESSOR_PPC620,
- MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
- POWER_MASKS},
+ POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_POWERPC64},
{"630", PROCESSOR_PPC630,
- MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
- POWER_MASKS},
- {"740", PROCESSOR_PPC750,
- MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
- POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64},
- {"750", PROCESSOR_PPC750,
- MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
- POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64},
- {"G3", PROCESSOR_PPC750,
- MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
- POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64},
- {"7400", PROCESSOR_PPC7400,
- MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
- POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64},
- {"7450", PROCESSOR_PPC7450,
- MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
- POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64},
- {"G4", PROCESSOR_PPC7450,
- MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
- POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64},
- {"8540", PROCESSOR_PPC8540,
- MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
- POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64},
- {"801", PROCESSOR_MPCCORE,
- MASK_POWERPC | MASK_SOFT_FLOAT | MASK_NEW_MNEMONICS,
- POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64},
- {"821", PROCESSOR_MPCCORE,
- MASK_POWERPC | MASK_SOFT_FLOAT | MASK_NEW_MNEMONICS,
- POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64},
- {"823", PROCESSOR_MPCCORE,
- MASK_POWERPC | MASK_SOFT_FLOAT | MASK_NEW_MNEMONICS,
- POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64},
- {"860", PROCESSOR_MPCCORE,
- MASK_POWERPC | MASK_SOFT_FLOAT | MASK_NEW_MNEMONICS,
- POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64},
+ POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_POWERPC64},
+ {"740", PROCESSOR_PPC750, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
+ {"7400", PROCESSOR_PPC7400, POWERPC_7400_MASK},
+ {"7450", PROCESSOR_PPC7450, POWERPC_7400_MASK},
+ {"750", PROCESSOR_PPC750, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
+ {"801", PROCESSOR_MPCCORE, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
+ {"821", PROCESSOR_MPCCORE, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
+ {"823", PROCESSOR_MPCCORE, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
+ {"8540", PROCESSOR_PPC8540, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
+ {"860", PROCESSOR_MPCCORE, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
{"970", PROCESSOR_POWER4,
- MASK_POWERPC | POWERPC_OPT_MASKS | MASK_NEW_MNEMONICS | MASK_MFCRF,
- POWER_MASKS},
+ POWERPC_7400_MASK | MASK_PPC_GPOPT | MASK_MFCRF | MASK_POWERPC64},
+ {"common", PROCESSOR_COMMON, MASK_NEW_MNEMONICS},
+ {"ec603e", PROCESSOR_PPC603, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
+ {"G3", PROCESSOR_PPC750, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
+ {"G4", PROCESSOR_PPC7450, POWERPC_7400_MASK},
{"G5", PROCESSOR_POWER4,
- MASK_POWERPC | POWERPC_OPT_MASKS | MASK_NEW_MNEMONICS | MASK_MFCRF,
- POWER_MASKS}};
+ POWERPC_7400_MASK | MASK_PPC_GPOPT | MASK_MFCRF | MASK_POWERPC64},
+ {"power", PROCESSOR_POWER, MASK_POWER | MASK_MULTIPLE | MASK_STRING},
+ {"power2", PROCESSOR_POWER,
+ MASK_POWER | MASK_POWER2 | MASK_MULTIPLE | MASK_STRING},
+ {"power3", PROCESSOR_PPC630,
+ POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_POWERPC64},
+ {"power4", PROCESSOR_POWER4,
+ POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_POWERPC64},
+ {"powerpc", PROCESSOR_POWERPC, POWERPC_BASE_MASK},
+ {"powerpc64", PROCESSOR_POWERPC64,
+ POWERPC_BASE_MASK | MASK_POWERPC64},
+ {"rios", PROCESSOR_RIOS1, MASK_POWER | MASK_MULTIPLE | MASK_STRING},
+ {"rios1", PROCESSOR_RIOS1, MASK_POWER | MASK_MULTIPLE | MASK_STRING},
+ {"rios2", PROCESSOR_RIOS2,
+ MASK_POWER | MASK_POWER2 | MASK_MULTIPLE | MASK_STRING},
+ {"rsc", PROCESSOR_PPC601, MASK_POWER | MASK_MULTIPLE | MASK_STRING},
+ {"rsc1", PROCESSOR_PPC601, MASK_POWER | MASK_MULTIPLE | MASK_STRING},
+ {"rs64a", PROCESSOR_RS64A, POWERPC_BASE_MASK | MASK_POWERPC64},
+ };
const size_t ptt_size = ARRAY_SIZE (processor_target_table);
/* Save current -mstring/-mno-string status. */
int string = TARGET_STRING;
+ /* Some OSs don't support saving the high part of 64-bit registers on
+ context switch. Other OSs don't support saving Altivec registers.
+ On those OSs, we don't touch the MASK_POWERPC64 or MASK_ALTIVEC
+ settings; if the user wants either, the user must explicitly specify
+ them and we won't interfere with the user's specification. */
+
+ enum {
+ POWER_MASKS = MASK_POWER | MASK_POWER2 | MASK_MULTIPLE | MASK_STRING,
+ POWERPC_MASKS = (POWERPC_BASE_MASK | MASK_PPC_GPOPT
+ | MASK_PPC_GFXOPT | MASK_POWERPC64 | MASK_ALTIVEC
+ | MASK_MFCRF)
+ };
+ set_masks = POWER_MASKS | POWERPC_MASKS | MASK_SOFT_FLOAT;
+#ifdef OS_MISSING_POWERPC64
+ if (OS_MISSING_POWERPC64)
+ set_masks &= ~MASK_POWERPC64;
+#endif
+#ifdef OS_MISSING_ALTIVEC
+ if (OS_MISSING_ALTIVEC)
+ set_masks &= ~MASK_ALTIVEC;
+#endif
+
/* Identify the processor type. */
rs6000_select[0].string = default_cpu;
rs6000_cpu = TARGET_POWERPC64 ? PROCESSOR_DEFAULT64 : PROCESSOR_DEFAULT;
if (ptr->set_arch_p)
{
- target_flags |= processor_target_table[j].target_enable;
- target_flags &= ~processor_target_table[j].target_disable;
+ target_flags &= ~set_masks;
+ target_flags |= (processor_target_table[j].target_enable
+ & set_masks);
}
break;
}
&& cst2 >= -0x7fff && cst2 <= 0x7fff)
return 1;
- if (TARGET_ALTIVEC && EASY_VECTOR_15 (cst, op, mode))
- return 1;
+ if (TARGET_ALTIVEC)
+ switch (mode)
+ {
+ case V4SImode:
+ if (EASY_VECTOR_15 (cst, op, mode))
+ return 1;
+ if ((cst & 0xffff) != ((cst >> 16) & 0xffff))
+ break;
+ cst = cst >> 16;
+ case V8HImode:
+ if (EASY_VECTOR_15 (cst, op, mode))
+ return 1;
+ if ((cst & 0xff) != ((cst >> 8) & 0xff))
+ break;
+ cst = cst >> 8;
+ case V16QImode:
+ if (EASY_VECTOR_15 (cst, op, mode))
+ return 1;
+ default:
+ break;
+ }
if (TARGET_ALTIVEC && EASY_VECTOR_15_ADD_SELF (cst, op, mode))
return 1;
{
if (zero_constant (vec, mode))
return "vxor %0,%0,%0";
- else if (EASY_VECTOR_15 (cst, vec, mode))
+ else if (EASY_VECTOR_15_ADD_SELF (cst, vec, mode))
+ return "#";
+ else if (easy_vector_constant (vec, mode))
{
operands[1] = GEN_INT (cst);
switch (mode)
{
case V4SImode:
- return "vspltisw %0,%1";
+ if (EASY_VECTOR_15 (cst, vec, mode))
+ {
+ operands[1] = GEN_INT (cst);
+ return "vspltisw %0,%1";
+ }
+ cst = cst >> 16;
case V8HImode:
- return "vspltish %0,%1";
+ if (EASY_VECTOR_15 (cst, vec, mode))
+ {
+ operands[1] = GEN_INT (cst);
+ return "vspltish %0,%1";
+ }
+ cst = cst >> 8;
case V16QImode:
- return "vspltisb %0,%1";
+ if (EASY_VECTOR_15 (cst, vec, mode))
+ {
+ operands[1] = GEN_INT (cst);
+ return "vspltisb %0,%1";
+ }
default:
abort ();
}
}
- else if (EASY_VECTOR_15_ADD_SELF (cst, vec, mode))
- return "#";
else
abort ();
}
int
and64_2_operand (rtx op, enum machine_mode mode)
{
- if (fixed_regs[CR0_REGNO]) /* CR0 not available, don't do andi./andis. */
+ if (fixed_regs[CR0_REGNO]) /* CR0 not available, don't do andi./andis. */
return gpc_reg_operand (op, mode) || mask64_2_operand (op, mode);
return logical_operand (op, mode) || mask64_2_operand (op, mode);
return 0;
}
+
+/* Darwin, AIX increases natural record alignment to doubleword if the first
+ field is an FP double while the FP fields remain word aligned. */
+
+unsigned int
+rs6000_special_round_type_align (tree type, int computed, int specified)
+{
+ tree field = TYPE_FIELDS (type);
+
+ /* Skip all the static variables only if ABI is greater than
+ 1 or equal to 0. */
+ while (field != NULL && TREE_CODE (field) == VAR_DECL)
+ field = TREE_CHAIN (field);
+
+ if (field == NULL || field == type || DECL_MODE (field) != DFmode)
+ return MAX (computed, specified);
+
+ return MAX (MAX (computed, specified), 64);
+}
+
/* Return 1 for an operand in small memory on V.4/eabi. */
int
#endif
}
+/* Return true, if operand is a memory operand and has a
+ displacement divisible by 4. */
+
+int
+word_offset_memref_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
+{
+ rtx addr;
+ int off = 0;
+
+ if (!memory_operand (op, mode))
+ return 0;
+
+ addr = XEXP (op, 0);
+ if (GET_CODE (addr) == PLUS
+ && GET_CODE (XEXP (addr, 0)) == REG
+ && GET_CODE (XEXP (addr, 1)) == CONST_INT)
+ off = INTVAL (XEXP (addr, 1));
+
+ return (off % 4) == 0;
+}
+
/* Return true if either operand is a general purpose register. */
bool
case DFmode:
case DImode:
- if (TARGET_32BIT)
+ if (mode == DFmode || !TARGET_POWERPC64)
extra = 4;
else if (offset & 3)
return false;
case TFmode:
case TImode:
- if (TARGET_32BIT)
+ if (mode == TFmode || !TARGET_POWERPC64)
extra = 12;
else if (offset & 3)
return false;
return false;
x = XEXP (x, 1);
- if (TARGET_ELF)
+ if (TARGET_ELF || TARGET_MACHO)
{
- if (DEFAULT_ABI != ABI_AIX && flag_pic)
+ if (DEFAULT_ABI != ABI_AIX && DEFAULT_ABI != ABI_DARWIN && flag_pic)
return false;
if (TARGET_TOC)
return false;
bool
rs6000_tls_referenced_p (rtx x)
{
+ if (! TARGET_HAVE_TLS)
+ return false;
+
return for_each_rtx (&x, &rs6000_tls_symbol_ref_1, 0);
}
if (GET_CODE (x) == SYMBOL_REF
&& DEFAULT_ABI == ABI_DARWIN
&& !ALTIVEC_VECTOR_MODE (mode)
- && flag_pic)
- {
- /* Darwin load of floating point constant. */
- rtx offset = gen_rtx (CONST, Pmode,
- gen_rtx (MINUS, Pmode, x,
- gen_rtx (SYMBOL_REF, Pmode,
- machopic_function_base_name ())));
- x = gen_rtx (LO_SUM, GET_MODE (x),
- gen_rtx (PLUS, Pmode, pic_offset_table_rtx,
- gen_rtx (HIGH, Pmode, offset)), offset);
+ && (flag_pic || MACHO_DYNAMIC_NO_PIC_P)
+ /* Don't do this for TFmode, since the result isn't offsettable. */
+ && mode != TFmode)
+ {
+ if (flag_pic)
+ {
+ rtx offset = gen_rtx_CONST (Pmode,
+ gen_rtx_MINUS (Pmode, x,
+ gen_rtx_SYMBOL_REF (Pmode,
+ machopic_function_base_name ())));
+ x = gen_rtx_LO_SUM (GET_MODE (x),
+ gen_rtx_PLUS (Pmode, pic_offset_table_rtx,
+ gen_rtx_HIGH (Pmode, offset)), offset);
+ }
+ else
+ x = gen_rtx_LO_SUM (GET_MODE (x),
+ gen_rtx_HIGH (Pmode, x), x);
+
push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
- BASE_REG_CLASS, Pmode, VOIDmode, 0, 0,
- opnum, (enum reload_type)type);
+ BASE_REG_CLASS, Pmode, VOIDmode, 0, 0,
+ opnum, (enum reload_type)type);
*win = 1;
return x;
}
- if (GET_CODE (x) == SYMBOL_REF
- && DEFAULT_ABI == ABI_DARWIN
- && !ALTIVEC_VECTOR_MODE (mode)
- && MACHO_DYNAMIC_NO_PIC_P)
- {
- /* Darwin load of floating point constant. */
- x = gen_rtx (LO_SUM, GET_MODE (x),
- gen_rtx (HIGH, Pmode, x), x);
- push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
- BASE_REG_CLASS, Pmode, VOIDmode, 0, 0,
- opnum, (enum reload_type)type);
- *win = 1;
- return x;
- }
#endif
if (TARGET_TOC
&& constant_pool_expr_p (x)
adjust_address (operands[1], SImode, 4));
return;
}
+#if 0
+ else if (mode == DImode && TARGET_POWERPC64
+ && GET_CODE (operands[0]) == REG
+ && GET_CODE (operands[1]) == MEM && optimize > 0
+ && SLOW_UNALIGNED_ACCESS (DImode,
+ MEM_ALIGN (operands[1]) > 32
+ ? 32
+ : MEM_ALIGN (operands[1]))
+ && !no_new_pseudos)
+ {
+ rtx reg = gen_reg_rtx (SImode);
+ emit_insn (gen_rtx_SET (SImode, reg,
+ adjust_address (operands[1], SImode, 0)));
+ reg = simplify_gen_subreg (DImode, reg, SImode, 0);
+ emit_insn (gen_insvdi (operands[0], GEN_INT (32), const0_rtx, reg));
+ reg = gen_reg_rtx (SImode);
+ emit_insn (gen_rtx_SET (SImode, reg,
+ adjust_address (operands[1], SImode, 4)));
+ reg = simplify_gen_subreg (DImode, reg, SImode, 0);
+ emit_insn (gen_insvdi (operands[0], GEN_INT (32), GEN_INT (32), reg));
+ return;
+ }
+ else if (mode == DImode && TARGET_POWERPC64
+ && GET_CODE (operands[1]) == REG
+ && GET_CODE (operands[0]) == MEM && optimize > 0
+ && SLOW_UNALIGNED_ACCESS (DImode,
+ MEM_ALIGN (operands[0]) > 32
+ ? 32
+ : MEM_ALIGN (operands[0]))
+ && !no_new_pseudos)
+ {
+ rtx reg = gen_reg_rtx (DImode);
+ emit_move_insn (reg,
+ gen_rtx_LSHIFTRT (DImode, operands[1], GEN_INT (32)));
+ emit_move_insn (adjust_address (operands[0], SImode, 0),
+ simplify_gen_subreg (SImode, reg, DImode, 0));
+ emit_move_insn (adjust_address (operands[0], SImode, 4),
+ simplify_gen_subreg (SImode, operands[1], DImode, 0));
+ return;
+ }
+#endif
if (!no_new_pseudos)
{
(ALTIVEC_VECTOR_MODE (MODE) \
&& (CUM)->vregno <= ALTIVEC_ARG_MAX_REG \
&& TARGET_ALTIVEC_ABI \
- && (DEFAULT_ABI == ABI_V4 || (NAMED)))
+ && (NAMED))
/* Return a nonzero value to say to return the function value in
memory, just as large structures are always returned. TYPE will be
if (USE_ALTIVEC_FOR_ARG_P (cum, mode, type, named))
cum->vregno++;
- /* In variable-argument functions, vector arguments get GPRs allocated
- even if they are going to be passed in a vector register. */
- if (cum->stdarg && DEFAULT_ABI != ABI_V4)
- {
+ /* PowerPC64 Linux and AIX allocates GPRs for a vector argument
+ even if it is going to be passed in a vector register.
+ Darwin does the same for variable-argument functions. */
+ if ((DEFAULT_ABI == ABI_AIX && TARGET_64BIT)
+ || (cum->stdarg && DEFAULT_ABI != ABI_V4))
+ {
int align;
/* Vector parameters must be 16-byte aligned. This places
else if (align_words + RS6000_ARG_SIZE (mode, type)
> GP_ARG_NUM_REG)
/* If this is partially on the stack, then we only
- include the portion actually in registers here. */
+ include the portion actually in registers here. */
return gen_rtx_PARALLEL (DFmode,
gen_rtvec (2,
gen_rtx_EXPR_LIST (VOIDmode,
}
if (USE_ALTIVEC_FOR_ARG_P (cum, mode, type, named))
- return gen_rtx_REG (mode, cum->vregno);
+ if (TARGET_64BIT && ! cum->prototype)
+ {
+ /* Vector parameters get passed in vector register
+ and also in GPRs or memory, in absence of prototype. */
+ int align_words;
+ rtx slot;
+ align_words = (cum->words + 1) & ~1;
+
+ if (align_words >= GP_ARG_NUM_REG)
+ {
+ slot = NULL_RTX;
+ }
+ else
+ {
+ slot = gen_rtx_REG (mode, GP_ARG_MIN_REG + align_words);
+ }
+ return gen_rtx_PARALLEL (mode,
+ gen_rtvec (2,
+ gen_rtx_EXPR_LIST (VOIDmode,
+ slot, const0_rtx),
+ gen_rtx_EXPR_LIST (VOIDmode,
+ gen_rtx_REG (mode, cum->vregno),
+ const0_rtx)));
+ }
+ else
+ return gen_rtx_REG (mode, cum->vregno);
else if (TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (mode))
{
if (named || abi == ABI_V4)
value in GPRs is reported here. */
if (align_words + CLASS_MAX_NREGS (mode, GENERAL_REGS)
> GP_ARG_NUM_REG)
- /* Fortunately, there are only two possibilites, the value
+ /* Fortunately, there are only two possibilities, the value
is either wholly in GPRs or half in GPRs and half not. */
part_mode = DImode;
}
static void
-rs6000_move_block_from_reg(int regno, rtx x, int nregs)
+rs6000_move_block_from_reg (int regno, rtx x, int nregs)
{
int i;
enum machine_mode reg_mode = TARGET_32BIT ? SImode : DImode;
return expand_expr (t, NULL_RTX, VOIDmode, EXPAND_NORMAL);
}
else
- {
- /* Altivec arguments must be aligned to a 128-bit boundary. */
- if (TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (TYPE_MODE (type)))
- {
- tree vtype = TREE_TYPE (valist);
- tree new_valist, modify;
-
- /* Round address up to multiple of 16. Computes
- (addr+15)&~0xf. */
- new_valist = fold (build (BIT_AND_EXPR, vtype,
- fold (build (PLUS_EXPR, vtype, valist,
- build_int_2 (15, 0))),
- build_int_2 (~15, -1)));
-
- /* Update valist. */
- modify = build (MODIFY_EXPR, TREE_TYPE (valist), valist,
- new_valist);
- TREE_SIDE_EFFECTS (modify) = 1;
- expand_expr (modify, const0_rtx, VOIDmode, EXPAND_NORMAL);
- }
-
- return std_expand_builtin_va_arg (valist, type);
- }
+ return std_expand_builtin_va_arg (valist, type);
}
f_gpr = TYPE_FIELDS (TREE_TYPE (va_list_type_node));
sav_scale = 4;
}
- /* Pull the value out of the saved registers ... */
+ /* Pull the value out of the saved registers.... */
lab_false = gen_label_rtx ();
lab_over = gen_label_rtx ();
/* AIX library routines for float->int conversion. */
set_conv_libfunc (sfix_optab, SImode, DFmode, "__itrunc");
set_conv_libfunc (ufix_optab, SImode, DFmode, "__uitrunc");
+ set_conv_libfunc (sfix_optab, SImode, TFmode, "_qitrunc");
+ set_conv_libfunc (ufix_optab, SImode, TFmode, "_quitrunc");
}
/* Standard AIX/Darwin/64-bit SVR4 quad floating point routines. */
s += sprintf (s, "{b%s|b%s%s} ", ccode, ccode, pred);
/* We need to escape any '%' characters in the reg_names string.
- Assume they'd only be the first character... */
+ Assume they'd only be the first character.... */
if (reg_names[cc_regno + CR0_REGNO][0] == '%')
*s++ = '%';
s += sprintf (s, "%s", reg_names[cc_regno + CR0_REGNO]);
enum machine_mode result_mode = GET_MODE (dest);
rtx temp;
- /* These modes should always match. */
+ /* These modes should always match. */
if (GET_MODE (op1) != compare_mode
/* In the isel case however, we can use a compare immediate, so
op1 may be a small constant. */
return 0;
/* First, work out if the hardware can do this at all, or
- if it's too slow... */
+ if it's too slow.... */
if (! rs6000_compare_fp_p)
{
if (TARGET_ISEL)
else
info_ptr->spe_gp_size = 0;
- if (TARGET_ALTIVEC_ABI && TARGET_ALTIVEC_VRSAVE)
- {
- info_ptr->vrsave_mask = compute_vrsave_mask ();
- info_ptr->vrsave_size = info_ptr->vrsave_mask ? 4 : 0;
- }
+ if (TARGET_ALTIVEC_ABI)
+ info_ptr->vrsave_mask = compute_vrsave_mask ();
else
- {
- info_ptr->vrsave_mask = 0;
- info_ptr->vrsave_size = 0;
- }
+ info_ptr->vrsave_mask = 0;
+
+ if (TARGET_ALTIVEC_VRSAVE && info_ptr->vrsave_mask)
+ info_ptr->vrsave_size = 4;
+ else
+ info_ptr->vrsave_size = 0;
/* Calculate the offsets. */
switch (DEFAULT_ABI)
/* regs_ever_live has LR marked as used if any sibcalls are present,
but this should not force saving and restoring in the
pro/epilogue. Likewise, reg_set_between_p thinks a sibcall
- clobbers LR, so that is inappropriate. */
+ clobbers LR, so that is inappropriate. */
/* Also, the prologue can generate a store into LR that
doesn't really count, like this:
emit_move_insn (gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM), operands[0]);
}
+static GTY(()) int set = -1;
+
int
get_TOC_alias_set (void)
{
- static int set = -1;
- if (set == -1)
- set = new_alias_set ();
- return set;
+ if (set == -1)
+ set = new_alias_set ();
+ return set;
}
/* This returns nonzero if the current function uses the TOC. This is
- determined by the presence of (unspec ... UNSPEC_TOC) or
- use (unspec ... UNSPEC_TOC), which are generated by the various
- load_toc_* patterns. */
-
-int
+ determined by the presence of (use (unspec ... UNSPEC_TOC)), which
+ is generated by the ABI_V4 load_toc_* patterns. */
+#if TARGET_ELF
+static int
uses_TOC (void)
{
rtx insn;
}
return 0;
}
+#endif
rtx
create_TOC_reference (rtx symbol)
used in this function, and do the corresponding magic in the
epilogue. */
- if (TARGET_ALTIVEC && info->vrsave_mask != 0)
+ if (TARGET_ALTIVEC && TARGET_ALTIVEC_VRSAVE
+ && info->vrsave_mask != 0)
{
rtx reg, mem, vrsave;
int offset;
rs6000_emit_prologue ();
emit_note (NOTE_INSN_DELETED);
- /* Expand INSN_ADDRESSES so final() doesn't crash. */
+ /* Expand INSN_ADDRESSES so final() doesn't crash. */
{
rtx insn;
unsigned addr = 0;
}
/* Restore VRSAVE if needed. */
- if (TARGET_ALTIVEC_ABI && info->vrsave_mask != 0)
+ if (TARGET_ALTIVEC_ABI && TARGET_ALTIVEC_VRSAVE
+ && info->vrsave_mask != 0)
{
rtx addr, mem, reg;
rs6000_emit_epilogue (FALSE);
emit_note (NOTE_INSN_DELETED);
- /* Expand INSN_ADDRESSES so final() doesn't crash. */
+ /* Expand INSN_ADDRESSES so final() doesn't crash. */
{
rtx insn;
unsigned addr = 0;
/* Tbtab format type. Use format type 0. */
fputs ("\t.byte 0,", file);
- /* 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. There is no official value for Java,
- although IBM appears to be using 13. There is no official value
- for Chill, so we've chosen 44 pseudo-randomly. */
- if (! strcmp (language_string, "GNU C")
- || ! strcmp (language_string, "GNU Objective-C"))
+ /* Language type. Unfortunately, there does not seem to be any
+ official way to discover the language being compiled, so we
+ use language_string.
+ C is 0. Fortran is 1. Pascal is 2. Ada is 3. C++ is 9.
+ Java is 13. Objective-C is 14. */
+ if (! strcmp (language_string, "GNU 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 Ada"))
+ i = 3;
else if (! strcmp (language_string, "GNU C++"))
i = 9;
else if (! strcmp (language_string, "GNU Java"))
i = 13;
- else if (! strcmp (language_string, "GNU CHILL"))
- i = 44;
+ else if (! strcmp (language_string, "GNU Objective-C"))
+ i = 14;
else
abort ();
fprintf (file, "%d,", i);
case ABI_DARWIN:
if (!TARGET_PROFILE_KERNEL)
{
- /* Don't do anything, done in output_profile_hook (). */
+ /* Don't do anything, done in output_profile_hook (). */
}
else
{
}
/* The function returns a true if INSN is microcoded.
- Return false ptherwise. */
+ Return false otherwise. */
static bool
is_microcoded_insn (rtx insn)
}
/* The function returns true if INSN can be issued only from
- the branch slot. */
+ the branch slot. */
static bool
is_branch_slot_insn (rtx insn)
return next_insn;
}
-/* Return whether the presence of INSN causes a dispatch group terminatation
+/* Return whether the presence of INSN causes a dispatch group termination
of group WHICH_GROUP.
If WHICH_GROUP == current_group, this function will return true if INSN
return false;
}
-/* Return true if it is recommended to keep NEXT_INSN "far" (in a seperate
+/* Return true if it is recommended to keep NEXT_INSN "far" (in a separate
dispatch group) from the insns in GROUP_INSNS. Return false otherwise. */
static bool
one of the following schemes, depending on the value of the flag
-minsert_sched_nops = X:
(1) X == sched_finish_regroup_exact: insert exactly as many nops as needed
- in order to force NEXT_INSN into a seperate group.
+ in order to force NEXT_INSN into a separate group.
(2) X < sched_finish_regroup_exact: insert exactly X nops.
GROUP_END, CAN_ISSUE_MORE and GROUP_COUNT record the state after nop
insertion (has a group just ended, how many vacant issue slots remain in the
if (GET_CODE (XEXP (orig, 0)) == PLUS)
{
/* Use a different reg for the intermediate value, as
- it will be marked UNCHANGING. */
+ it will be marked UNCHANGING. */
rtx reg_temp = no_new_pseudos ? reg : gen_reg_rtx (Pmode);
base =
if (TARGET_RELOCATABLE
&& (get_pool_size () != 0 || current_function_profile)
- && uses_TOC())
+ && uses_TOC ())
{
char buf[256];
return true;
case MEM:
- /* MEM should be slightly more expensive than (plus (reg) (const)) */
+ /* MEM should be slightly more expensive than (plus (reg) (const)). */
*total = 5;
return true;
return (rs6000_memory_move_cost (mode, from, 0)
+ rs6000_memory_move_cost (mode, GENERAL_REGS, 0));
-/* It's more expensive to move CR_REGS than CR0_REGS because of the shift...*/
+/* It's more expensive to move CR_REGS than CR0_REGS because of the shift.... */
else if (from == CR_REGS)
return 4;
gen_rtx_REG (SImode, regno + 1200)));
}
+/* Map internal gcc register numbers to DWARF2 register numbers. */
+
+unsigned int
+rs6000_dbx_register_number (unsigned int regno)
+{
+ if (regno <= 63 || write_symbols != DWARF2_DEBUG)
+ return regno;
+ if (regno == MQ_REGNO)
+ return 100;
+ if (regno == LINK_REGISTER_REGNUM)
+ return 108;
+ if (regno == COUNT_REGISTER_REGNUM)
+ return 109;
+ if (CR_REGNO_P (regno))
+ return regno - CR0_REGNO + 86;
+ if (regno == XER_REGNO)
+ return 101;
+ if (ALTIVEC_REGNO_P (regno))
+ return regno - FIRST_ALTIVEC_REGNO + 1124;
+ if (regno == VRSAVE_REGNO)
+ return 356;
+ if (regno == VSCR_REGNO)
+ return 67;
+ if (regno == SPE_ACC_REGNO)
+ return 99;
+ if (regno == SPEFSCR_REGNO)
+ return 612;
+ /* SPE high reg number. We get these values of regno from
+ rs6000_dwarf_register_span. */
+ if (regno >= 1200 && regno < 1232)
+ return regno;
+
+ abort ();
+}
+
#include "gt-rs6000.h"