struct {
bool aix_struct_ret; /* True if -maix-struct-ret was used. */
bool alignment; /* True if -malign- was used. */
- bool abi; /* True if -mabi= was used. */
+ bool abi; /* True if -mabi=spe/nospe was used. */
bool spe; /* True if -mspe= was used. */
bool float_gprs; /* True if -mfloat-gprs= was used. */
bool isel; /* True if -misel was used. */
bool long_double; /* True if -mlong-double- was used. */
+ bool ieee; /* True if -mabi=ieee/ibmlongdouble used. */
} rs6000_explicit_options;
struct builtin_description
static int rs6000_ra_ever_killed (void);
static tree rs6000_handle_longcall_attribute (tree *, tree, tree, int, bool *);
static tree rs6000_handle_altivec_attribute (tree *, tree, tree, int, bool *);
+static bool rs6000_ms_bitfield_layout_p (tree);
+static tree rs6000_handle_struct_attribute (tree *, tree, tree, int, bool *);
static void rs6000_eliminate_indexed_memrefs (rtx operands[2]);
static const char *rs6000_mangle_fundamental_type (tree);
extern const struct attribute_spec rs6000_attribute_table[];
#define TARGET_BINDS_LOCAL_P darwin_binds_local_p
#endif
+#undef TARGET_MS_BITFIELD_LAYOUT_P
+#define TARGET_MS_BITFIELD_LAYOUT_P rs6000_ms_bitfield_layout_p
+
#undef TARGET_ASM_OUTPUT_MI_THUNK
#define TARGET_ASM_OUTPUT_MI_THUNK rs6000_output_mi_thunk
{"power5+", PROCESSOR_POWER5,
POWERPC_BASE_MASK | MASK_POWERPC64 | MASK_PPC_GFXOPT
| MASK_MFCRF | MASK_POPCNTB | MASK_FPRND},
+ {"power6", PROCESSOR_POWER5,
+ POWERPC_7400_MASK | MASK_POWERPC64 | MASK_MFCRF | MASK_POPCNTB
+ | MASK_FPRND},
{"powerpc", PROCESSOR_POWERPC, POWERPC_BASE_MASK},
{"powerpc64", PROCESSOR_POWERPC64,
POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_POWERPC64},
rs6000_long_double_type_size = RS6000_DEFAULT_LONG_DOUBLE_SIZE;
#ifndef POWERPC_LINUX
- if (!rs6000_explicit_options.abi)
+ if (!rs6000_explicit_options.ieee)
rs6000_ieeequad = 1;
#endif
rs6000_alignment_flags = MASK_ALIGN_NATURAL;
}
+ /* Place FP constants in the constant pool instead of TOC
+ if section anchors enabled. */
+ if (flag_section_anchors)
+ TARGET_NO_FP_IN_TOC = 1;
+
/* Handle -mtls-size option. */
rs6000_parse_tls_size_option ();
/* Double growth factor to counter reduced min jump length. */
set_param_value ("max-grow-copy-bb-insns", 16);
+
+ /* Enable section anchors by default.
+ Skip section anchors for Objective C and Objective C++
+ until front-ends fixed. */
+ if (!TARGET_MACHO && lang_hooks.name[4] != 'O')
+ flag_section_anchors = 1;
}
/* Implement TARGET_HANDLE_OPTION. */
#endif
case OPT_mabi_:
- rs6000_explicit_options.abi = true;
if (!strcmp (arg, "altivec"))
{
+ rs6000_explicit_options.abi = true;
rs6000_altivec_abi = 1;
rs6000_spe_abi = 0;
}
else if (! strcmp (arg, "no-altivec"))
- rs6000_altivec_abi = 0;
+ {
+ /* ??? Don't set rs6000_explicit_options.abi here, to allow
+ the default for rs6000_spe_abi to be chosen later. */
+ rs6000_altivec_abi = 0;
+ }
else if (! strcmp (arg, "spe"))
{
+ rs6000_explicit_options.abi = true;
rs6000_spe_abi = 1;
rs6000_altivec_abi = 0;
if (!TARGET_SPE_ABI)
error ("not configured for ABI: '%s'", arg);
}
else if (! strcmp (arg, "no-spe"))
- rs6000_spe_abi = 0;
+ {
+ rs6000_explicit_options.abi = true;
+ rs6000_spe_abi = 0;
+ }
/* These are here for testing during development only, do not
document in the manual please. */
else if (! strcmp (arg, "ibmlongdouble"))
{
+ rs6000_explicit_options.ieee = true;
rs6000_ieeequad = 0;
warning (0, "Using IBM extended precision long double");
}
else if (! strcmp (arg, "ieeelongdouble"))
{
+ rs6000_explicit_options.ieee = true;
rs6000_ieeequad = 1;
warning (0, "Using IEEE extended precision long double");
}
num_insns_constant_wide (HOST_WIDE_INT value)
{
/* signed constant loadable with {cal|addi} */
- if (satisfies_constraint_I (GEN_INT (value)))
+ if ((unsigned HOST_WIDE_INT) (value + 0x8000) < 0x10000)
return 1;
/* constant loadable with {cau|addis} */
- else if (satisfies_constraint_L (GEN_INT (value)))
+ else if ((value & 0xffff) == 0
+ && (value >> 31 == -1 || value >> 31 == 0))
return 1;
#if HOST_BITS_PER_WIDE_INT == 64
}
}
+/* Interpret element ELT of the CONST_VECTOR OP as an integer value.
+ If the mode of OP is MODE_VECTOR_INT, this simply returns the
+ corresponding element of the vector, but for V4SFmode and V2SFmode,
+ the corresponding "float" is interpreted as an SImode integer. */
+
+static HOST_WIDE_INT
+const_vector_elt_as_int (rtx op, unsigned int elt)
+{
+ rtx tmp = CONST_VECTOR_ELT (op, elt);
+ if (GET_MODE (op) == V4SFmode
+ || GET_MODE (op) == V2SFmode)
+ tmp = gen_lowpart (SImode, tmp);
+ return INTVAL (tmp);
+}
-/* Return true if OP can be synthesized with a particular vspltisb, vspltish
+/* Return true if OP can be synthesized with a particular vspltisb, vspltish
or vspltisw instruction. OP is a CONST_VECTOR. Which instruction is used
depends on STEP and COPIES, one of which will be 1. If COPIES > 1,
all items are set to the same value and contain COPIES replicas of the
unsigned bitsize = GET_MODE_BITSIZE (inner);
unsigned mask = GET_MODE_MASK (inner);
- rtx last = CONST_VECTOR_ELT (op, nunits - 1);
- HOST_WIDE_INT val = INTVAL (last);
+ HOST_WIDE_INT val = const_vector_elt_as_int (op, nunits - 1);
HOST_WIDE_INT splat_val = val;
HOST_WIDE_INT msb_val = val > 0 ? 0 : -1;
else
desired_val = msb_val;
- if (desired_val != INTVAL (CONST_VECTOR_ELT (op, i)))
+ if (desired_val != const_vector_elt_as_int (op, i))
return false;
}
}
-/* Return true if OP is of the given MODE and can be synthesized
+/* Return true if OP is of the given MODE and can be synthesized
with a vspltisb, vspltish or vspltisw. */
bool
if (GET_CODE (x) == SYMBOL_REF
&& !ALTIVEC_VECTOR_MODE (mode)
+ && !SPE_VECTOR_MODE (mode)
#if TARGET_MACHO
&& DEFAULT_ABI == ABI_DARWIN
&& (flag_pic || MACHO_DYNAMIC_NO_PIC_P)
&& !flag_pic
#endif
/* Don't do this for TFmode, since the result isn't offsettable.
- The same goes for DImode without 64-bit gprs. */
+ The same goes for DImode without 64-bit gprs and DFmode
+ without fprs. */
&& mode != TFmode
- && (mode != DImode || TARGET_POWERPC64))
+ && (mode != DImode || TARGET_POWERPC64)
+ && (mode != DFmode || TARGET_POWERPC64
+ || (TARGET_FPRS && TARGET_HARD_FLOAT)))
{
#if TARGET_MACHO
if (flag_pic)
&& constant_pool_expr_p (x)
&& ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (get_pool_constant (x), mode))
{
- (x) = create_TOC_reference (x);
+ x = create_TOC_reference (x);
*win = 1;
return x;
}
if ((GET_CODE (x) == PRE_INC || GET_CODE (x) == PRE_DEC)
&& !ALTIVEC_VECTOR_MODE (mode)
&& !SPE_VECTOR_MODE (mode)
+ && mode != TFmode
/* Restrict addressing for DI because of our SUBREG hackery. */
&& !(TARGET_E500_DOUBLE && (mode == DFmode || mode == DImode))
&& TARGET_UPDATE
of an argument with the specified mode and type. If it is not defined,
PARM_BOUNDARY is used for all arguments.
- V.4 wants long longs to be double word aligned.
+ V.4 wants long longs and doubles to be double word aligned. Just
+ testing the mode size is a boneheaded way to do this as it means
+ that other types such as complex int are also double word aligned.
+ However, we're stuck with this because changing the ABI might break
+ existing library interfaces.
+
Doubleword align SPE vectors.
Quadword align Altivec vectors.
Quadword align large synthetic vector types. */
int
function_arg_boundary (enum machine_mode mode, tree type)
{
- if (DEFAULT_ABI == ABI_V4 && GET_MODE_SIZE (mode) == 8)
+ if (DEFAULT_ABI == ABI_V4
+ && (GET_MODE_SIZE (mode) == 8
+ || (TARGET_HARD_FLOAT
+ && TARGET_FPRS
+ && mode == TFmode)))
return 64;
else if (SPE_VECTOR_MODE (mode)
|| (type && TREE_CODE (type) == VECTOR_TYPE
if (align_words + n_units > GP_ARG_NUM_REG)
/* Not all of the arg fits in gprs. Say that it goes in memory too,
using a magic NULL_RTX component.
- FIXME: This is not strictly correct. Only some of the arg
- belongs in memory, not all of it. However, there isn't any way
- to do this currently, apart from building rtx descriptions for
- the pieces of memory we want stored. Due to bugs in the generic
- code we can't use the normal function_arg_partial_nregs scheme
- with the PARALLEL arg description we emit here.
- In any case, the code to store the whole arg to memory is often
- more efficient than code to store pieces, and we know that space
- is available in the right place for the whole arg. */
- /* FIXME: This should be fixed since the conversion to
- TARGET_ARG_PARTIAL_BYTES. */
+ This is not strictly correct. Only some of the arg belongs in
+ memory, not all of it. However, the normal scheme using
+ function_arg_partial_nregs can result in unusual subregs, eg.
+ (subreg:SI (reg:DF) 4), which are not handled well. The code to
+ store the whole arg to memory is often more efficient than code
+ to store pieces, and we know that space is available in the right
+ place for the whole arg. */
rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, NULL_RTX, const0_rtx);
i = 0;
include the portion actually in registers here. */
enum machine_mode rmode = TARGET_32BIT ? SImode : DImode;
rtx off;
- int i=0;
- if (align_words + n_words > GP_ARG_NUM_REG
- && (TARGET_32BIT && TARGET_POWERPC64))
+ int i = 0;
+ if (align_words + n_words > GP_ARG_NUM_REG)
/* Not all of the arg fits in gprs. Say that it
goes in memory too, using a magic NULL_RTX
component. Also see comment in
align_words = rs6000_parm_start (mode, type, cum->words);
- if (USE_FP_FOR_ARG_P (cum, mode, type)
+ if (USE_FP_FOR_ARG_P (cum, mode, type))
+ {
/* If we are passing this arg in the fixed parameter save area
(gprs or memory) as well as fprs, then this function should
- return the number of bytes passed in the parameter save area
- rather than bytes passed in fprs. */
- && !(type
- && (cum->nargs_prototype <= 0
- || (DEFAULT_ABI == ABI_AIX
- && TARGET_XL_COMPAT
- && align_words >= GP_ARG_NUM_REG))))
- {
- if (cum->fregno + ((GET_MODE_SIZE (mode) + 7) >> 3) > FP_ARG_MAX_REG + 1)
+ return the number of partial bytes passed in the parameter
+ save area rather than partial bytes passed in fprs. */
+ if (type
+ && (cum->nargs_prototype <= 0
+ || (DEFAULT_ABI == ABI_AIX
+ && TARGET_XL_COMPAT
+ && align_words >= GP_ARG_NUM_REG)))
+ return 0;
+ else if (cum->fregno + ((GET_MODE_SIZE (mode) + 7) >> 3)
+ > FP_ARG_MAX_REG + 1)
ret = (FP_ARG_MAX_REG + 1 - cum->fregno) * 8;
else if (cum->nargs_prototype >= 0)
return 0;
t = build1 (LABEL_EXPR, void_type_node, lab_false);
append_to_statement_list (t, pre_p);
- if (n_reg > 2)
+ if ((n_reg == 2 && reg != gpr) || n_reg > 2)
{
/* Ensure that we don't find any more args in regs.
- Alignment has taken care of the n_reg == 2 case. */
+ Alignment has taken care of the n_reg == 2 gpr case. */
t = build2 (MODIFY_EXPR, TREE_TYPE (reg), reg, size_int (8));
gimplify_and_add (t, pre_p);
}
int
insvdi_rshift_rlwimi_p (rtx sizeop, rtx startop, rtx shiftop)
{
- if (INTVAL (startop) < 64
- && INTVAL (startop) > 32
- && (INTVAL (sizeop) + INTVAL (startop) < 64)
- && (INTVAL (sizeop) + INTVAL (startop) > 33)
- && (INTVAL (sizeop) + INTVAL (startop) + INTVAL (shiftop) < 96)
- && (INTVAL (sizeop) + INTVAL (startop) + INTVAL (shiftop) >= 64)
+ if (INTVAL (startop) > 32
+ && INTVAL (startop) < 64
+ && INTVAL (sizeop) > 1
+ && INTVAL (sizeop) + INTVAL (startop) < 64
+ && INTVAL (shiftop) > 0
+ && INTVAL (sizeop) + INTVAL (shiftop) < 32
&& (64 - (INTVAL (shiftop) & 63)) >= INTVAL (sizeop))
return 1;
return;
case 'D':
- /* Like 'J' but get to the EQ bit. */
+ /* Like 'J' but get to the GT bit only. */
gcc_assert (GET_CODE (x) == REG);
- /* Bit 1 is EQ bit. */
- i = 4 * (REGNO (x) - CR0_REGNO) + 2;
+ /* Bit 1 is GT bit. */
+ i = 4 * (REGNO (x) - CR0_REGNO) + 1;
- fprintf (file, "%d", i);
+ /* Add one for shift count in rlinm for scc. */
+ fprintf (file, "%d", i + 1);
return;
case 'E':
tmp = XEXP (x, 0);
- if (TARGET_E500)
+ /* Ugly hack because %y is overloaded. */
+ if (TARGET_E500 && GET_MODE_SIZE (GET_MODE (x)) == 8)
{
/* Handle [reg]. */
if (GET_CODE (tmp) == REG)
/* First, the compare. */
compare_result = gen_reg_rtx (comp_mode);
- /* SPE FP compare instructions on the GPRs. Yuck! */
+ /* E500 FP compare instructions on the GPRs. Yuck! */
if ((TARGET_E500 && !TARGET_FPRS && TARGET_HARD_FLOAT)
&& rs6000_compare_fp_p)
{
if (op_mode == VOIDmode)
op_mode = GET_MODE (rs6000_compare_op1);
- /* Note: The E500 comparison instructions set the GT bit (x +
- 1), on success. This explains the mess. */
+ /* The E500 FP compare instructions toggle the GT bit (CR bit 1) only.
+ This explains the following mess. */
switch (code)
{
mispredicted taken branch is more expensive than a
mispredicted not-taken branch. */
if (rs6000_always_hint
- || abs (prob) > REG_BR_PROB_BASE / 100 * 48)
+ || (abs (prob) > REG_BR_PROB_BASE / 100 * 48
+ && br_prob_note_reliable_p (note)))
{
if (abs (prob) > REG_BR_PROB_BASE / 20
&& ((prob > 0) ^ need_longbranch))
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. */
+ Java is 13. Objective-C is 14. Objective-C++ isn't assigned
+ a number, so for now use 9. */
if (! strcmp (language_string, "GNU C"))
i = 0;
else if (! strcmp (language_string, "GNU F77")
i = 2;
else if (! strcmp (language_string, "GNU Ada"))
i = 3;
- else if (! strcmp (language_string, "GNU C++"))
+ else if (! strcmp (language_string, "GNU C++")
+ || ! strcmp (language_string, "GNU Objective-C++"))
i = 9;
else if (! strcmp (language_string, "GNU Java"))
i = 13;
void
rs6000_initialize_trampoline (rtx addr, rtx fnaddr, rtx cxt)
{
- enum machine_mode pmode = Pmode;
int regsize = (TARGET_32BIT) ? 4 : 8;
- rtx ctx_reg = force_reg (pmode, cxt);
+ rtx ctx_reg = force_reg (Pmode, cxt);
switch (DEFAULT_ABI)
{
gcc_unreachable ();
/* Macros to shorten the code expansions below. */
-#define MEM_DEREF(addr) gen_rtx_MEM (pmode, memory_address (pmode, addr))
+#define MEM_DEREF(addr) gen_rtx_MEM (Pmode, memory_address (Pmode, addr))
#define MEM_PLUS(addr,offset) \
- gen_rtx_MEM (pmode, memory_address (pmode, plus_constant (addr, offset)))
+ gen_rtx_MEM (Pmode, memory_address (Pmode, plus_constant (addr, offset)))
/* Under AIX, just build the 3 word function descriptor */
case ABI_AIX:
{
- rtx fn_reg = gen_reg_rtx (pmode);
- rtx toc_reg = gen_reg_rtx (pmode);
+ rtx fn_reg = gen_reg_rtx (Pmode);
+ rtx toc_reg = gen_reg_rtx (Pmode);
emit_move_insn (fn_reg, MEM_DEREF (fnaddr));
emit_move_insn (toc_reg, MEM_PLUS (fnaddr, regsize));
emit_move_insn (MEM_DEREF (addr), fn_reg);
/* Under V.4/eabi/darwin, __trampoline_setup does the real work. */
case ABI_DARWIN:
case ABI_V4:
- emit_library_call (gen_rtx_SYMBOL_REF (SImode, "__trampoline_setup"),
+ emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__trampoline_setup"),
FALSE, VOIDmode, 4,
- addr, pmode,
+ addr, Pmode,
GEN_INT (rs6000_trampoline_size ()), SImode,
- fnaddr, pmode,
- ctx_reg, pmode);
+ fnaddr, Pmode,
+ ctx_reg, Pmode);
break;
}
{ "altivec", 1, 1, false, true, false, rs6000_handle_altivec_attribute },
{ "longcall", 0, 0, false, true, true, rs6000_handle_longcall_attribute },
{ "shortcall", 0, 0, false, true, true, rs6000_handle_longcall_attribute },
+ { "ms_struct", 0, 0, false, false, false, rs6000_handle_struct_attribute },
+ { "gcc_struct", 0, 0, false, false, false, rs6000_handle_struct_attribute },
#ifdef SUBTARGET_ATTRIBUTE_TABLE
SUBTARGET_ATTRIBUTE_TABLE,
#endif
TYPE_ATTRIBUTES (type) = tree_cons (get_identifier ("longcall"),
NULL_TREE,
TYPE_ATTRIBUTES (type));
+
+#if TARGET_MACHO
+ darwin_set_default_type_attributes (type);
+#endif
}
/* Return a reference suitable for calling a function with the
return force_reg (Pmode, call_ref);
}
\f
+#ifndef TARGET_USE_MS_BITFIELD_LAYOUT
+#define TARGET_USE_MS_BITFIELD_LAYOUT 0
+#endif
+
+/* Handle a "ms_struct" or "gcc_struct" attribute; arguments as in
+ struct attribute_spec.handler. */
+static tree
+rs6000_handle_struct_attribute (tree *node, tree name,
+ tree args ATTRIBUTE_UNUSED,
+ int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
+{
+ tree *type = NULL;
+ if (DECL_P (*node))
+ {
+ if (TREE_CODE (*node) == TYPE_DECL)
+ type = &TREE_TYPE (*node);
+ }
+ else
+ type = node;
+
+ if (!(type && (TREE_CODE (*type) == RECORD_TYPE
+ || TREE_CODE (*type) == UNION_TYPE)))
+ {
+ warning (OPT_Wattributes, "%qs attribute ignored", IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+
+ else if ((is_attribute_p ("ms_struct", name)
+ && lookup_attribute ("gcc_struct", TYPE_ATTRIBUTES (*type)))
+ || ((is_attribute_p ("gcc_struct", name)
+ && lookup_attribute ("ms_struct", TYPE_ATTRIBUTES (*type)))))
+ {
+ warning (OPT_Wattributes, "%qs incompatible attribute ignored",
+ IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+static bool
+rs6000_ms_bitfield_layout_p (tree record_type)
+{
+ return (TARGET_USE_MS_BITFIELD_LAYOUT &&
+ !lookup_attribute ("gcc_struct", TYPE_ATTRIBUTES (record_type)))
+ || lookup_attribute ("ms_struct", TYPE_ATTRIBUTES (record_type));
+}
+\f
#ifdef USING_ELFOS_H
/* A get_unnamed_section callback, used for switching to toc_section. */
position-independent addresses go into a reg. This is REG if non
zero, otherwise we allocate register(s) as necessary. */
-#define SMALL_INT(X) ((unsigned) (INTVAL (X) + 0x8000) < 0x10000)
+#define SMALL_INT(X) ((UINTVAL (X) + 0x8000) < 0x10000)
rtx
rs6000_machopic_legitimize_pic_address (rtx orig, enum machine_mode mode,
/* FALLTHRU */
case CONST_DOUBLE:
- if (mode == DImode
- && ((outer_code == AND
- && (satisfies_constraint_K (x)
- || satisfies_constraint_L (x)
- || mask_operand (x, DImode)
- || mask64_operand (x, DImode)))
- || ((outer_code == IOR || outer_code == XOR)
- && CONST_DOUBLE_HIGH (x) == 0
- && (CONST_DOUBLE_LOW (x)
- & ~ (unsigned HOST_WIDE_INT) 0xffff) == 0)))
- {
- *total = 0;
- return true;
- }
- else if (mode == DImode
- && (outer_code == SET
- || outer_code == IOR
- || outer_code == XOR)
- && CONST_DOUBLE_HIGH (x) == 0)
+ if (mode == DImode && code == CONST_DOUBLE)
{
- *total = COSTS_N_INSNS (1);
- return true;
+ if ((outer_code == IOR || outer_code == XOR)
+ && CONST_DOUBLE_HIGH (x) == 0
+ && (CONST_DOUBLE_LOW (x)
+ & ~ (unsigned HOST_WIDE_INT) 0xffff) == 0)
+ {
+ *total = 0;
+ return true;
+ }
+ else if ((outer_code == AND && and64_2_operand (x, DImode))
+ || ((outer_code == SET
+ || outer_code == IOR
+ || outer_code == XOR)
+ && CONST_DOUBLE_HIGH (x) == 0))
+ {
+ *total = COSTS_N_INSNS (1);
+ return true;
+ }
}
/* FALLTHRU */