X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fconfig%2Frs6000%2Frs6000.c;h=53b10829cdd535e0581c06f1fadfd5eae80666f9;hb=2c7082e3cd7b37ee58d6e72d334251a9a4c803ec;hp=ab00425f81715c712d5ff7d0537cd61177388875;hpb=c2ecb73ba65d8881e27d92e369e2355696e1354d;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index ab00425f817..53b10829cdd 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -1,6 +1,7 @@ /* Subroutines used for code generation on IBM RS/6000. Copyright (C) 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999, - 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu) This file is part of GCC. @@ -55,6 +56,7 @@ #include "tree-gimple.h" #include "intl.h" #include "params.h" +#include "tm-constrs.h" #if TARGET_XCOFF #include "xcoffout.h" /* get declarations of xcoff_*_section_name */ #endif @@ -77,7 +79,6 @@ typedef struct rs6000_stack { int lr_save_p; /* true if the link reg needs to be saved */ int cr_save_p; /* true if the CR reg needs to be saved */ unsigned int vrsave_mask; /* mask of vec registers to save */ - int toc_save_p; /* true if the TOC needs to be saved */ int push_p; /* true if we need to allocate stack space */ int calls_p; /* true if the function makes any calls */ int world_save_p; /* true if we're saving *everything*: @@ -90,7 +91,6 @@ typedef struct rs6000_stack { int cr_save_offset; /* offset to save CR from initial SP */ int vrsave_save_offset; /* offset to save VRSAVE from initial SP */ int spe_gp_save_offset; /* offset to save spe 64-bit gprs */ - int toc_save_offset; /* offset to save the TOC pointer */ int varargs_save_offset; /* offset to save the varargs registers */ int ehrd_offset; /* offset to EH return data */ int reg_size; /* register size (4 or 8) */ @@ -102,13 +102,11 @@ typedef struct rs6000_stack { int fp_size; /* size of saved FP registers */ int altivec_size; /* size of saved AltiVec 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 vrsave_size; /* size to hold VRSAVE if not in save_size */ int altivec_padding_size; /* size of altivec alignment padding if not in save_size */ int spe_gp_size; /* size of 64-bit GPR save size for SPE */ int spe_padding_size; - int toc_size; /* size to hold TOC if not in save_size */ HOST_WIDE_INT total_size; /* total bytes allocated for stack */ int spe_64bit_regs_used; } rs6000_stack_t; @@ -158,10 +156,13 @@ enum rs6000_nop_insertion rs6000_sched_insert_nops; /* Support targetm.vectorize.builtin_mask_for_load. */ static GTY(()) tree altivec_builtin_mask_for_load; -/* Size of long double */ +/* Size of long double. */ int rs6000_long_double_type_size; -/* Whether -mabi=altivec has appeared */ +/* IEEE quad extended precision long double. */ +int rs6000_ieeequad; + +/* Whether -mabi=altivec has appeared. */ int rs6000_altivec_abi; /* Nonzero if we want SPE ABI extensions. */ @@ -234,8 +235,11 @@ static enum { int toc_initialized; char toc_label_name[10]; -/* Alias set for saves and restores from the rs6000 stack. */ -static GTY(()) int rs6000_sr_alias_set; +static GTY(()) section *read_only_data_section; +static GTY(()) section *private_data_section; +static GTY(()) section *read_only_private_data_section; +static GTY(()) section *sdata2_section; +static GTY(()) section *toc_section; /* Control alignment for fields within structures. */ /* String from -malign-XXXXX. */ @@ -245,11 +249,12 @@ int rs6000_alignment_flags; 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 @@ -585,6 +590,7 @@ static unsigned toc_hash_function (const void *); static int toc_hash_eq (const void *, const void *); static int constant_pool_expr_1 (rtx, int *, int *); static bool constant_pool_expr_p (rtx); +static bool legitimate_small_data_p (enum machine_mode, rtx); static bool legitimate_indexed_address_p (rtx, int); static bool legitimate_lo_sum_address_p (enum machine_mode, rtx, int); static struct machine_function * rs6000_init_machine_status (void); @@ -596,6 +602,8 @@ static void rs6000_assemble_visibility (tree, int); 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[]; @@ -612,21 +620,25 @@ static unsigned int rs6000_elf_section_type_flags (tree, const char *, int); static void rs6000_elf_asm_out_constructor (rtx, int); static void rs6000_elf_asm_out_destructor (rtx, int); static void rs6000_elf_end_indicate_exec_stack (void) ATTRIBUTE_UNUSED; -static void rs6000_elf_select_section (tree, int, unsigned HOST_WIDE_INT); +static void rs6000_elf_asm_init_sections (void); +static section *rs6000_elf_select_section (tree, int, unsigned HOST_WIDE_INT); static void rs6000_elf_unique_section (tree, int); -static void rs6000_elf_select_rtx_section (enum machine_mode, rtx, - unsigned HOST_WIDE_INT); +static section *rs6000_elf_select_rtx_section (enum machine_mode, rtx, + unsigned HOST_WIDE_INT); static void rs6000_elf_encode_section_info (tree, rtx, int) ATTRIBUTE_UNUSED; -static bool rs6000_elf_in_small_data_p (tree); #endif +static bool rs6000_use_blocks_for_constant_p (enum machine_mode, rtx); #if TARGET_XCOFF +static void rs6000_xcoff_asm_output_anchor (rtx); static void rs6000_xcoff_asm_globalize_label (FILE *, const char *); +static void rs6000_xcoff_asm_init_sections (void); static void rs6000_xcoff_asm_named_section (const char *, unsigned int, tree); -static void rs6000_xcoff_select_section (tree, int, unsigned HOST_WIDE_INT); -static void rs6000_xcoff_unique_section (tree, int); -static void rs6000_xcoff_select_rtx_section (enum machine_mode, rtx, +static section *rs6000_xcoff_select_section (tree, int, unsigned HOST_WIDE_INT); +static void rs6000_xcoff_unique_section (tree, int); +static section *rs6000_xcoff_select_rtx_section + (enum machine_mode, rtx, unsigned HOST_WIDE_INT); static const char * rs6000_xcoff_strip_name_encoding (const char *); static unsigned int rs6000_xcoff_section_type_flags (tree, const char *, int); static void rs6000_xcoff_file_start (void); @@ -741,6 +753,7 @@ static void rs6000_darwin_file_start (void); static tree rs6000_build_builtin_va_list (void); static tree rs6000_gimplify_va_arg (tree, tree, tree *, tree *); static bool rs6000_must_pass_in_stack (enum machine_mode, tree); +static bool rs6000_scalar_mode_supported_p (enum machine_mode); static bool rs6000_vector_mode_supported_p (enum machine_mode); static int get_vec_cmp_insn (enum rtx_code, enum machine_mode, enum machine_mode); @@ -921,6 +934,9 @@ static const char alt_reg_names[][8] = #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 @@ -980,6 +996,9 @@ static const char alt_reg_names[][8] = #undef TARGET_EH_RETURN_FILTER_MODE #define TARGET_EH_RETURN_FILTER_MODE rs6000_eh_return_filter_mode +#undef TARGET_SCALAR_MODE_SUPPORTED_P +#define TARGET_SCALAR_MODE_SUPPORTED_P rs6000_scalar_mode_supported_p + #undef TARGET_VECTOR_MODE_SUPPORTED_P #define TARGET_VECTOR_MODE_SUPPORTED_P rs6000_vector_mode_supported_p @@ -991,7 +1010,7 @@ static const char alt_reg_names[][8] = #undef TARGET_DEFAULT_TARGET_FLAGS #define TARGET_DEFAULT_TARGET_FLAGS \ - (TARGET_DEFAULT | MASK_SCHED_PROLOG) + (TARGET_DEFAULT) #undef TARGET_STACK_PROTECT_FAIL #define TARGET_STACK_PROTECT_FAIL rs6000_stack_protect_fail @@ -1012,6 +1031,20 @@ static const char alt_reg_names[][8] = #define TARGET_ASM_OUTPUT_DWARF_DTPREL rs6000_output_dwarf_dtprel #endif +/* Use a 32-bit anchor range. This leads to sequences like: + + addis tmp,anchor,high + add dest,tmp,low + + where tmp itself acts as an anchor, and can be shared between + accesses to the same 64k page. */ +#undef TARGET_MIN_ANCHOR_OFFSET +#define TARGET_MIN_ANCHOR_OFFSET -0x7fffffff - 1 +#undef TARGET_MAX_ANCHOR_OFFSET +#define TARGET_MAX_ANCHOR_OFFSET 0x7fffffff +#undef TARGET_USE_BLOCKS_FOR_CONSTANT_P +#define TARGET_USE_BLOCKS_FOR_CONSTANT_P rs6000_use_blocks_for_constant_p + struct gcc_target targetm = TARGET_INITIALIZER; @@ -1025,10 +1058,12 @@ rs6000_hard_regno_mode_ok (int regno, enum machine_mode mode) if (INT_REGNO_P (regno)) return INT_REGNO_P (regno + HARD_REGNO_NREGS (regno, mode) - 1); - /* The float registers can only hold floating modes and DImode. */ + /* The float registers can only hold floating modes and DImode. + This also excludes decimal float modes. */ if (FP_REGNO_P (regno)) return - (GET_MODE_CLASS (mode) == MODE_FLOAT + (SCALAR_FLOAT_MODE_P (mode) + && !DECIMAL_FLOAT_MODE_P (mode) && FP_REGNO_P (regno + HARD_REGNO_NREGS (regno, mode) - 1)) || (GET_MODE_CLASS (mode) == MODE_INT && GET_MODE_SIZE (mode) == UNITS_PER_FP_WORD); @@ -1107,10 +1142,14 @@ rs6000_override_options (const char *default_cpu) = {{"401", PROCESSOR_PPC403, POWERPC_BASE_MASK | MASK_SOFT_FLOAT}, {"403", PROCESSOR_PPC403, 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}, + {"405", PROCESSOR_PPC405, + POWERPC_BASE_MASK | MASK_SOFT_FLOAT | MASK_MULHW | MASK_DLMZB}, + {"405fp", PROCESSOR_PPC405, + POWERPC_BASE_MASK | MASK_MULHW | MASK_DLMZB}, + {"440", PROCESSOR_PPC440, + POWERPC_BASE_MASK | MASK_SOFT_FLOAT | MASK_MULHW | MASK_DLMZB}, + {"440fp", PROCESSOR_PPC440, + POWERPC_BASE_MASK | MASK_MULHW | MASK_DLMZB}, {"505", PROCESSOR_MPCCORE, POWERPC_BASE_MASK}, {"601", PROCESSOR_PPC601, MASK_POWER | POWERPC_BASE_MASK | MASK_MULTIPLE | MASK_STRING}, @@ -1152,6 +1191,9 @@ rs6000_override_options (const char *default_cpu) {"power5", PROCESSOR_POWER5, POWERPC_BASE_MASK | MASK_POWERPC64 | MASK_PPC_GFXOPT | MASK_MFCRF | MASK_POPCNTB}, + {"power5+", PROCESSOR_POWER5, + POWERPC_BASE_MASK | MASK_POWERPC64 | MASK_PPC_GFXOPT + | MASK_MFCRF | MASK_POPCNTB | MASK_FPRND}, {"powerpc", PROCESSOR_POWERPC, POWERPC_BASE_MASK}, {"powerpc64", PROCESSOR_POWERPC64, POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_POWERPC64}, @@ -1177,7 +1219,8 @@ rs6000_override_options (const char *default_cpu) 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) + | MASK_MFCRF | MASK_POPCNTB | MASK_FPRND | MASK_MULHW + | MASK_DLMZB) }; rs6000_init_hard_regno_mode_ok (); @@ -1284,6 +1327,11 @@ rs6000_override_options (const char *default_cpu) if (!rs6000_explicit_options.long_double) rs6000_long_double_type_size = RS6000_DEFAULT_LONG_DOUBLE_SIZE; +#ifndef POWERPC_LINUX + if (!rs6000_explicit_options.ieee) + rs6000_ieeequad = 1; +#endif + /* Set Altivec ABI as default for powerpc64 linux. */ if (TARGET_ELF && TARGET_64BIT) { @@ -1302,6 +1350,11 @@ rs6000_override_options (const char *default_cpu) 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 (); @@ -1397,13 +1450,9 @@ rs6000_override_options (const char *default_cpu) if (!rs6000_explicit_options.aix_struct_ret) aix_struct_return = (DEFAULT_ABI != ABI_V4 || DRAFT_V4_STRUCT_RET); - if (TARGET_LONG_DOUBLE_128 - && (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_DARWIN)) + if (TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD) REAL_MODE_FORMAT (TFmode) = &ibm_extended_format; - /* Allocate an alias set for register saves & restores from stack. */ - rs6000_sr_alias_set = new_alias_set (); - if (TARGET_TOC) ASM_GENERATE_INTERNAL_LABEL (toc_label_name, "LCTOC", 1); @@ -1577,6 +1626,12 @@ optimization_options (int level ATTRIBUTE_UNUSED, int size ATTRIBUTE_UNUSED) /* 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 (lang_hooks.name[4] != 'O') + flag_section_anchors = 1; } /* Implement TARGET_HANDLE_OPTION. */ @@ -1599,10 +1654,10 @@ rs6000_handle_option (size_t code, const char *arg, int value) | MASK_PPC_GFXOPT | MASK_POWERPC64); break; case OPT_mfull_toc: - target_flags &= ~(MASK_MINIMAL_TOC | MASK_NO_FP_IN_TOC - | MASK_NO_SUM_IN_TOC); - target_flags_explicit |= (MASK_MINIMAL_TOC | MASK_NO_FP_IN_TOC - | MASK_NO_SUM_IN_TOC); + target_flags &= ~MASK_MINIMAL_TOC; + TARGET_NO_FP_IN_TOC = 0; + TARGET_NO_SUM_IN_TOC = 0; + target_flags_explicit |= MASK_MINIMAL_TOC; #ifdef TARGET_USES_SYSV4_OPT /* Note, V.4 no longer uses a normal TOC, so make -mfull-toc, be just the same as -mminimal-toc. */ @@ -1624,9 +1679,9 @@ rs6000_handle_option (size_t code, const char *arg, int value) #else case OPT_m64: #endif - target_flags |= MASK_POWERPC64 | MASK_POWERPC | MASK_PPC_GFXOPT; - target_flags_explicit |= MASK_POWERPC64 | MASK_POWERPC - | MASK_PPC_GFXOPT; + target_flags |= MASK_POWERPC64 | MASK_POWERPC; + target_flags |= ~target_flags_explicit & MASK_PPC_GFXOPT; + target_flags_explicit |= MASK_POWERPC64 | MASK_POWERPC; break; #ifdef TARGET_USES_AIX64_OPT @@ -1645,8 +1700,8 @@ rs6000_handle_option (size_t code, const char *arg, int value) case OPT_mminimal_toc: if (value == 1) { - target_flags &= ~(MASK_NO_FP_IN_TOC | MASK_NO_SUM_IN_TOC); - target_flags_explicit |= (MASK_NO_FP_IN_TOC | MASK_NO_SUM_IN_TOC); + TARGET_NO_FP_IN_TOC = 0; + TARGET_NO_SUM_IN_TOC = 0; } break; @@ -1717,18 +1772,18 @@ rs6000_handle_option (size_t code, const char *arg, int value) case OPT_mrelocatable: if (value == 1) { - target_flags |= MASK_MINIMAL_TOC | MASK_NO_FP_IN_TOC; - target_flags_explicit |= MASK_MINIMAL_TOC | MASK_NO_FP_IN_TOC; + target_flags |= MASK_MINIMAL_TOC; + target_flags_explicit |= MASK_MINIMAL_TOC; + TARGET_NO_FP_IN_TOC = 1; } break; case OPT_mrelocatable_lib: if (value == 1) { - target_flags |= MASK_RELOCATABLE | MASK_MINIMAL_TOC - | MASK_NO_FP_IN_TOC; - target_flags_explicit |= MASK_RELOCATABLE | MASK_MINIMAL_TOC - | MASK_NO_FP_IN_TOC; + target_flags |= MASK_RELOCATABLE | MASK_MINIMAL_TOC; + target_flags_explicit |= MASK_RELOCATABLE | MASK_MINIMAL_TOC; + TARGET_NO_FP_IN_TOC = 1; } else { @@ -1739,23 +1794,31 @@ rs6000_handle_option (size_t code, const char *arg, int value) #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. */ @@ -1770,6 +1833,19 @@ rs6000_handle_option (size_t code, const char *arg, int value) warning (0, "Using old darwin ABI"); } + 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"); + } + else { error ("unknown ABI specified: '%s'", arg); @@ -1909,8 +1985,8 @@ rs6000_file_start (void) if (DEFAULT_ABI == ABI_AIX || (TARGET_ELF && flag_pic == 2)) { - toc_section (); - text_section (); + switch_to_section (toc_section); + switch_to_section (text_section); } } @@ -1944,11 +2020,12 @@ int num_insns_constant_wide (HOST_WIDE_INT value) { /* signed constant loadable with {cal|addi} */ - if (CONST_OK_FOR_LETTER_P (value, 'I')) + if ((unsigned HOST_WIDE_INT) (value + 0x8000) < 0x10000) return 1; /* constant loadable with {cau|addis} */ - else if (CONST_OK_FOR_LETTER_P (value, 'L')) + else if ((value & 0xffff) == 0 + && (value >> 31 == -1 || value >> 31 == 0)) return 1; #if HOST_BITS_PER_WIDE_INT == 64 @@ -2042,73 +2119,150 @@ num_insns_constant (rtx op, enum machine_mode mode) } } -/* Returns the constant for the splat instruction, if exists. */ -int -easy_vector_splat_const (int cst, enum machine_mode mode) +/* 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 + vsplt's operand; if STEP > 1, one in STEP elements is set to the vsplt's + operand and the others are set to the value of the operand's msb. */ + +static bool +vspltis_constant (rtx op, unsigned step, unsigned copies) { - switch (mode) + enum machine_mode mode = GET_MODE (op); + enum machine_mode inner = GET_MODE_INNER (mode); + + unsigned i; + unsigned nunits = GET_MODE_NUNITS (mode); + 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 splat_val = val; + HOST_WIDE_INT msb_val = val > 0 ? 0 : -1; + + /* Construct the value to be splatted, if possible. If not, return 0. */ + for (i = 2; i <= copies; i *= 2) { - case V4SImode: - if (EASY_VECTOR_15 (cst) - || EASY_VECTOR_15_ADD_SELF (cst)) - return cst; - if ((cst & 0xffff) != ((cst >> 16) & 0xffff)) - break; - cst = cst >> 16; - /* Fall thru */ + HOST_WIDE_INT small_val; + bitsize /= 2; + small_val = splat_val >> bitsize; + mask >>= bitsize; + if (splat_val != ((small_val << bitsize) | (small_val & mask))) + return false; + splat_val = small_val; + } - case V8HImode: - if (EASY_VECTOR_15 (cst) - || EASY_VECTOR_15_ADD_SELF (cst)) - return cst; - if ((cst & 0xff) != ((cst >> 8) & 0xff)) - break; - cst = cst >> 8; - /* Fall thru */ + /* Check if SPLAT_VAL can really be the operand of a vspltis[bhw]. */ + if (EASY_VECTOR_15 (splat_val)) + ; - case V16QImode: - if (EASY_VECTOR_15 (cst) - || EASY_VECTOR_15_ADD_SELF (cst)) - return cst; - default: - break; + /* Also check if we can splat, and then add the result to itself. Do so if + the value is positive, of if the splat instruction is using OP's mode; + for splat_val < 0, the splat and the add should use the same mode. */ + else if (EASY_VECTOR_15_ADD_SELF (splat_val) + && (splat_val >= 0 || (step == 1 && copies == 1))) + ; + + else + return false; + + /* Check if VAL is present in every STEP-th element, and the + other elements are filled with its most significant bit. */ + for (i = 0; i < nunits - 1; ++i) + { + HOST_WIDE_INT desired_val; + if (((i + 1) & (step - 1)) == 0) + desired_val = val; + else + desired_val = msb_val; + + if (desired_val != INTVAL (CONST_VECTOR_ELT (op, i))) + return false; } - return 0; + + return true; } -/* Return nonzero if all elements of a vector have the same value. */ -int -easy_vector_same (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) +/* Return true if OP is of the given MODE and can be synthesized + with a vspltisb, vspltish or vspltisw. */ + +bool +easy_altivec_constant (rtx op, enum machine_mode mode) { - int units, i, cst; + unsigned step, copies; + + if (mode == VOIDmode) + mode = GET_MODE (op); + else if (mode != GET_MODE (op)) + return false; - units = CONST_VECTOR_NUNITS (op); + /* Start with a vspltisw. */ + step = GET_MODE_NUNITS (mode) / 4; + copies = 1; - cst = INTVAL (CONST_VECTOR_ELT (op, 0)); - for (i = 1; i < units; ++i) - if (INTVAL (CONST_VECTOR_ELT (op, i)) != cst) - break; - if (i == units && easy_vector_splat_const (cst, mode)) - return 1; - return 0; + if (vspltis_constant (op, step, copies)) + return true; + + /* Then try with a vspltish. */ + if (step == 1) + copies <<= 1; + else + step >>= 1; + + if (vspltis_constant (op, step, copies)) + return true; + + /* And finally a vspltisb. */ + if (step == 1) + copies <<= 1; + else + step >>= 1; + + if (vspltis_constant (op, step, copies)) + return true; + + return false; } -/* Generate easy_vector_constant out of a easy_vector_constant_add_self. */ +/* Generate a VEC_DUPLICATE representing a vspltis[bhw] instruction whose + result is OP. Abort if it is not possible. */ rtx -gen_easy_vector_constant_add_self (rtx op) +gen_easy_altivec_constant (rtx op) { - int i, units; - rtvec v; - units = GET_MODE_NUNITS (GET_MODE (op)); - v = rtvec_alloc (units); + enum machine_mode mode = GET_MODE (op); + int nunits = GET_MODE_NUNITS (mode); + rtx last = CONST_VECTOR_ELT (op, nunits - 1); + unsigned step = nunits / 4; + unsigned copies = 1; + + /* Start with a vspltisw. */ + if (vspltis_constant (op, step, copies)) + return gen_rtx_VEC_DUPLICATE (V4SImode, gen_lowpart (SImode, last)); + + /* Then try with a vspltish. */ + if (step == 1) + copies <<= 1; + else + step >>= 1; + + if (vspltis_constant (op, step, copies)) + return gen_rtx_VEC_DUPLICATE (V8HImode, gen_lowpart (HImode, last)); - for (i = 0; i < units; i++) - RTVEC_ELT (v, i) = - GEN_INT (INTVAL (CONST_VECTOR_ELT (op, i)) >> 1); - return gen_rtx_raw_CONST_VECTOR (GET_MODE (op), v); + /* And finally a vspltisb. */ + if (step == 1) + copies <<= 1; + else + step >>= 1; + + if (vspltis_constant (op, step, copies)) + return gen_rtx_VEC_DUPLICATE (V16QImode, gen_lowpart (QImode, last)); + + gcc_unreachable (); } const char * @@ -2120,51 +2274,30 @@ output_vec_const_move (rtx *operands) dest = operands[0]; vec = operands[1]; - - cst = INTVAL (CONST_VECTOR_ELT (vec, 0)); - cst2 = INTVAL (CONST_VECTOR_ELT (vec, 1)); mode = GET_MODE (dest); if (TARGET_ALTIVEC) { + rtx splat_vec; if (zero_constant (vec, mode)) return "vxor %0,%0,%0"; - gcc_assert (easy_vector_constant (vec, mode)); + splat_vec = gen_easy_altivec_constant (vec); + gcc_assert (GET_CODE (splat_vec) == VEC_DUPLICATE); + operands[1] = XEXP (splat_vec, 0); + if (!EASY_VECTOR_15 (INTVAL (operands[1]))) + return "#"; - operands[1] = GEN_INT (cst); - switch (mode) + switch (GET_MODE (splat_vec)) { case V4SImode: - if (EASY_VECTOR_15 (cst)) - { - operands[1] = GEN_INT (cst); - return "vspltisw %0,%1"; - } - else if (EASY_VECTOR_15_ADD_SELF (cst)) - return "#"; - cst = cst >> 16; - /* Fall thru */ + return "vspltisw %0,%1"; case V8HImode: - if (EASY_VECTOR_15 (cst)) - { - operands[1] = GEN_INT (cst); - return "vspltish %0,%1"; - } - else if (EASY_VECTOR_15_ADD_SELF (cst)) - return "#"; - cst = cst >> 8; - /* Fall thru */ + return "vspltish %0,%1"; case V16QImode: - if (EASY_VECTOR_15 (cst)) - { - operands[1] = GEN_INT (cst); - return "vspltisb %0,%1"; - } - else if (EASY_VECTOR_15_ADD_SELF (cst)) - return "#"; + return "vspltisb %0,%1"; default: gcc_unreachable (); @@ -2178,8 +2311,10 @@ output_vec_const_move (rtx *operands) FIXME: We should probably return # and add post reload splitters for these, but this way is so easy ;-). */ - operands[1] = GEN_INT (cst); - operands[2] = GEN_INT (cst2); + cst = INTVAL (CONST_VECTOR_ELT (vec, 0)); + cst2 = INTVAL (CONST_VECTOR_ELT (vec, 1)); + operands[1] = CONST_VECTOR_ELT (vec, 0); + operands[2] = CONST_VECTOR_ELT (vec, 1); if (cst == cst2) return "li %0,%1\n\tevmergelo %0,%0,%0"; else @@ -2220,11 +2355,10 @@ rs6000_expand_vector_init (rtx target, rtx vals) gen_rtx_XOR (mode, target, target))); return; } - else if (mode != V4SFmode && easy_vector_same (vals, mode)) + else if (mode != V4SFmode && easy_vector_constant (vals, mode)) { /* Splat immediate. */ - x = gen_rtx_VEC_DUPLICATE (mode, CONST_VECTOR_ELT (vals, 0)); - emit_insn (gen_rtx_SET (VOIDmode, target, x)); + emit_insn (gen_rtx_SET (VOIDmode, target, vals)); return; } else if (all_same) @@ -2445,18 +2579,27 @@ invalid_e500_subreg (rtx op, enum machine_mode mode) 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) +rs6000_special_round_type_align (tree type, unsigned int computed, + unsigned int specified) { + unsigned int align = MAX (computed, specified); tree field = TYPE_FIELDS (type); /* Skip all non field decls */ while (field != NULL && TREE_CODE (field) != FIELD_DECL) field = TREE_CHAIN (field); - if (field == NULL || field == type || DECL_MODE (field) != DFmode) - return MAX (computed, specified); + if (field != NULL && field != type) + { + type = TREE_TYPE (field); + while (TREE_CODE (type) == ARRAY_TYPE) + type = TREE_TYPE (type); + + if (type != error_mark_node && TYPE_MODE (type) == DFmode) + align = MAX (align, 64); + } - return MAX (MAX (computed, specified), 64); + return align; } /* Return 1 for an operand in small memory on V.4/eabi. */ @@ -2579,8 +2722,8 @@ legitimate_constant_pool_address_p (rtx x) && constant_pool_expr_p (XEXP (x, 1))); } -bool -rs6000_legitimate_small_data_p (enum machine_mode mode, rtx x) +static bool +legitimate_small_data_p (enum machine_mode mode, rtx x) { return (DEFAULT_ABI == ABI_V4 && !flag_pic && !TARGET_TOC @@ -2675,13 +2818,19 @@ legitimate_indexed_address_p (rtx x, int strict) op0 = XEXP (x, 0); op1 = XEXP (x, 1); - if (!REG_P (op0) || !REG_P (op1)) - return false; + /* Recognize the rtl generated by reload which we know will later be + replaced with proper base and index regs. */ + if (!strict + && reload_in_progress + && (REG_P (op0) || GET_CODE (op0) == PLUS) + && REG_P (op1)) + return true; - return ((INT_REG_OK_FOR_BASE_P (op0, strict) - && INT_REG_OK_FOR_INDEX_P (op1, strict)) - || (INT_REG_OK_FOR_BASE_P (op1, strict) - && INT_REG_OK_FOR_INDEX_P (op0, strict))); + return (REG_P (op0) && REG_P (op1) + && ((INT_REG_OK_FOR_BASE_P (op0, strict) + && INT_REG_OK_FOR_INDEX_P (op1, strict)) + || (INT_REG_OK_FOR_BASE_P (op1, strict) + && INT_REG_OK_FOR_INDEX_P (op0, strict)))); } inline bool @@ -3264,9 +3413,12 @@ rs6000_legitimize_reload_address (rtx x, enum machine_mode mode, && !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) @@ -3311,7 +3463,7 @@ rs6000_legitimize_reload_address (rtx x, enum machine_mode mode, && 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; } @@ -3359,7 +3511,7 @@ rs6000_legitimate_address (enum machine_mode mode, rtx x, int reg_ok_strict) && TARGET_UPDATE && legitimate_indirect_address_p (XEXP (x, 0), reg_ok_strict)) return 1; - if (rs6000_legitimate_small_data_p (mode, x)) + if (legitimate_small_data_p (mode, x)) return 1; if (legitimate_constant_pool_address_p (x)) return 1; @@ -3424,6 +3576,33 @@ rs6000_mode_dependent_address (rtx addr) return false; } +/* More elaborate version of recog's offsettable_memref_p predicate + that works around the ??? note of rs6000_mode_dependent_address. + In particular it accepts + + (mem:DI (plus:SI (reg/f:SI 31 31) (const_int 32760 [0x7ff8]))) + + in 32-bit mode, that the recog predicate rejects. */ + +bool +rs6000_offsettable_memref_p (rtx op) +{ + if (!MEM_P (op)) + return false; + + /* First mimic offsettable_memref_p. */ + if (offsettable_address_p (1, GET_MODE (op), XEXP (op, 0))) + return true; + + /* offsettable_address_p invokes rs6000_mode_dependent_address, but + the latter predicate knows nothing about the mode of the memory + reference and, therefore, assumes that it is the largest supported + mode (TFmode). As a consequence, legitimate offsettable memory + references are rejected. rs6000_legitimate_offset_address_p contains + the correct logic for the PLUS case of rs6000_mode_dependent_address. */ + return rs6000_legitimate_offset_address_p (GET_MODE (op), XEXP (op, 0), 1); +} + /* 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 @@ -3820,7 +3999,7 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode) /* 128-bit constant floating-point values on Darwin should really be loaded as two parts. */ - if ((DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_DARWIN) + if (!TARGET_IEEEQUAD && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_LONG_DOUBLE_128 && mode == TFmode && GET_CODE (operands[1]) == CONST_DOUBLE) { @@ -3920,7 +4099,7 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode) = CONSTANT_POOL_ADDRESS_P (operands[1]); SYMBOL_REF_FLAGS (new_ref) = SYMBOL_REF_FLAGS (operands[1]); SYMBOL_REF_USED (new_ref) = SYMBOL_REF_USED (operands[1]); - SYMBOL_REF_DECL (new_ref) = SYMBOL_REF_DECL (operands[1]); + SYMBOL_REF_DATA (new_ref) = SYMBOL_REF_DATA (operands[1]); operands[1] = new_ref; } @@ -4064,7 +4243,8 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode) /* Nonzero if we can use a floating-point register to pass this arg. */ #define USE_FP_FOR_ARG_P(CUM,MODE,TYPE) \ - (GET_MODE_CLASS (MODE) == MODE_FLOAT \ + (SCALAR_FLOAT_MODE_P (MODE) \ + && !DECIMAL_FLOAT_MODE_P (MODE) \ && (CUM)->fregno <= FP_ARG_MAX_REG \ && TARGET_HARD_FLOAT && TARGET_FPRS) @@ -4144,7 +4324,7 @@ rs6000_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED) return true; } - if (DEFAULT_ABI == ABI_V4 && TYPE_MODE (type) == TFmode) + if (DEFAULT_ABI == ABI_V4 && TARGET_IEEEQUAD && TYPE_MODE (type) == TFmode) return true; return false; @@ -4531,13 +4711,15 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, else if (DEFAULT_ABI == ABI_V4) { if (TARGET_HARD_FLOAT && TARGET_FPRS - && (mode == SFmode || mode == DFmode)) + && (mode == SFmode || mode == DFmode + || (mode == TFmode && !TARGET_IEEEQUAD))) { - if (cum->fregno <= FP_ARG_V4_MAX_REG) - cum->fregno++; + if (cum->fregno + (mode == TFmode ? 1 : 0) <= FP_ARG_V4_MAX_REG) + cum->fregno += (GET_MODE_SIZE (mode) + 7) >> 3; else { - if (mode == DFmode) + cum->fregno = FP_ARG_V4_MAX_REG + 1; + if (mode == DFmode || mode == TFmode) cum->words += cum->words & 1; cum->words += rs6000_arg_size (mode, type); } @@ -4588,7 +4770,8 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, cum->words = align_words + n_words; - if (GET_MODE_CLASS (mode) == MODE_FLOAT + if (SCALAR_FLOAT_MODE_P (mode) + && !DECIMAL_FLOAT_MODE_P (mode) && TARGET_HARD_FLOAT && TARGET_FPRS) cum->fregno += (GET_MODE_SIZE (mode) + 7) >> 3; @@ -4889,17 +5072,13 @@ rs6000_mixed_function_arg (enum machine_mode mode, tree type, int align_words) 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; @@ -5062,9 +5241,10 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, else if (abi == ABI_V4) { if (TARGET_HARD_FLOAT && TARGET_FPRS - && (mode == SFmode || mode == DFmode)) + && (mode == SFmode || mode == DFmode + || (mode == TFmode && !TARGET_IEEEQUAD))) { - if (cum->fregno <= FP_ARG_V4_MAX_REG) + if (cum->fregno + (mode == TFmode ? 1 : 0) <= FP_ARG_V4_MAX_REG) return gen_rtx_REG (mode, cum->fregno); else return NULL_RTX; @@ -5140,9 +5320,8 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, 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 @@ -5221,18 +5400,20 @@ rs6000_arg_partial_bytes (CUMULATIVE_ARGS *cum, enum machine_mode mode, 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; @@ -5267,7 +5448,7 @@ rs6000_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED, enum machine_mode mode, tree type, bool named ATTRIBUTE_UNUSED) { - if (DEFAULT_ABI == ABI_V4 && mode == TFmode) + if (DEFAULT_ABI == ABI_V4 && TARGET_IEEEQUAD && mode == TFmode) { if (TARGET_DEBUG_ARG) fprintf (stderr, "function_arg_pass_by_reference: V4 long double\n"); @@ -5593,10 +5774,10 @@ rs6000_va_start (tree valist, rtx nextarg) f_sav = TREE_CHAIN (f_ovf); valist = build_va_arg_indirect_ref (valist); - gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr, NULL_TREE); - fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr, NULL_TREE); - ovf = build (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf, NULL_TREE); - sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav, NULL_TREE); + gpr = build3 (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr, NULL_TREE); + fpr = build3 (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr, NULL_TREE); + ovf = build3 (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf, NULL_TREE); + sav = build3 (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav, NULL_TREE); /* Count number of gp and fp argument registers used. */ words = current_function_args_info.words; @@ -5612,16 +5793,16 @@ rs6000_va_start (tree valist, rtx nextarg) if (cfun->va_list_gpr_size) { - t = build (MODIFY_EXPR, TREE_TYPE (gpr), gpr, - build_int_cst (NULL_TREE, n_gpr)); + t = build2 (MODIFY_EXPR, TREE_TYPE (gpr), gpr, + build_int_cst (NULL_TREE, n_gpr)); TREE_SIDE_EFFECTS (t) = 1; expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); } if (cfun->va_list_fpr_size) { - t = build (MODIFY_EXPR, TREE_TYPE (fpr), fpr, - build_int_cst (NULL_TREE, n_fpr)); + t = build2 (MODIFY_EXPR, TREE_TYPE (fpr), fpr, + build_int_cst (NULL_TREE, n_fpr)); TREE_SIDE_EFFECTS (t) = 1; expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); } @@ -5629,9 +5810,9 @@ rs6000_va_start (tree valist, rtx nextarg) /* Find the overflow area. */ t = make_tree (TREE_TYPE (ovf), virtual_incoming_args_rtx); if (words != 0) - t = build (PLUS_EXPR, TREE_TYPE (ovf), t, - build_int_cst (NULL_TREE, words * UNITS_PER_WORD)); - t = build (MODIFY_EXPR, TREE_TYPE (ovf), ovf, t); + t = build2 (PLUS_EXPR, TREE_TYPE (ovf), t, + build_int_cst (NULL_TREE, words * UNITS_PER_WORD)); + t = build2 (MODIFY_EXPR, TREE_TYPE (ovf), ovf, t); TREE_SIDE_EFFECTS (t) = 1; expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); @@ -5646,9 +5827,9 @@ rs6000_va_start (tree valist, rtx nextarg) /* Find the register save area. */ t = make_tree (TREE_TYPE (sav), virtual_stack_vars_rtx); if (cfun->machine->varargs_save_offset) - t = build (PLUS_EXPR, TREE_TYPE (sav), t, - build_int_cst (NULL_TREE, cfun->machine->varargs_save_offset)); - t = build (MODIFY_EXPR, TREE_TYPE (sav), sav, t); + t = build2 (PLUS_EXPR, TREE_TYPE (sav), t, + build_int_cst (NULL_TREE, cfun->machine->varargs_save_offset)); + t = build2 (MODIFY_EXPR, TREE_TYPE (sav), sav, t); TREE_SIDE_EFFECTS (t) = 1; expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); } @@ -5694,7 +5875,7 @@ rs6000_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p) imag_part = rs6000_gimplify_va_arg (valist, elem_type, pre_p, post_p); - return build (COMPLEX_EXPR, type, real_part, imag_part); + return build2 (COMPLEX_EXPR, type, real_part, imag_part); } } @@ -5708,24 +5889,26 @@ rs6000_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p) f_sav = TREE_CHAIN (f_ovf); valist = build_va_arg_indirect_ref (valist); - gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr, NULL_TREE); - fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr, NULL_TREE); - ovf = build (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf, NULL_TREE); - sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav, NULL_TREE); + gpr = build3 (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr, NULL_TREE); + fpr = build3 (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr, NULL_TREE); + ovf = build3 (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf, NULL_TREE); + sav = build3 (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav, NULL_TREE); size = int_size_in_bytes (type); rsize = (size + 3) / 4; align = 1; if (TARGET_HARD_FLOAT && TARGET_FPRS - && (TYPE_MODE (type) == SFmode || TYPE_MODE (type) == DFmode)) + && (TYPE_MODE (type) == SFmode + || TYPE_MODE (type) == DFmode + || TYPE_MODE (type) == TFmode)) { /* FP args go in FP registers, if present. */ reg = fpr; - n_reg = 1; + n_reg = (size + 7) / 8; sav_ofs = 8*4; sav_scale = 8; - if (TYPE_MODE (type) == DFmode) + if (TYPE_MODE (type) != SFmode) align = 8; } else @@ -5757,7 +5940,7 @@ rs6000_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p) As are any other 2 gpr item such as complex int due to a historical mistake. */ u = reg; - if (n_reg == 2) + if (n_reg == 2 && reg == gpr) { u = build2 (BIT_AND_EXPR, TREE_TYPE (reg), reg, size_int (n_reg - 1)); @@ -5788,11 +5971,11 @@ rs6000_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p) 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. */ - t = build (MODIFY_EXPR, TREE_TYPE (reg), reg, size_int (8)); + 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); } } @@ -6455,7 +6638,7 @@ rs6000_expand_unop_builtin (enum insn_code icode, tree arglist, rtx target) { rtx pat; tree arg0 = TREE_VALUE (arglist); - rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0); + rtx op0 = expand_normal (arg0); enum machine_mode tmode = insn_data[icode].operand[0].mode; enum machine_mode mode0 = insn_data[icode].operand[1].mode; @@ -6504,7 +6687,7 @@ altivec_expand_abs_builtin (enum insn_code icode, tree arglist, rtx target) { rtx pat, scratch1, scratch2; tree arg0 = TREE_VALUE (arglist); - rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0); + rtx op0 = expand_normal (arg0); enum machine_mode tmode = insn_data[icode].operand[0].mode; enum machine_mode mode0 = insn_data[icode].operand[1].mode; @@ -6537,8 +6720,8 @@ rs6000_expand_binop_builtin (enum insn_code icode, tree arglist, rtx target) rtx pat; tree arg0 = TREE_VALUE (arglist); tree arg1 = TREE_VALUE (TREE_CHAIN (arglist)); - rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0); - rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0); + rtx op0 = expand_normal (arg0); + rtx op1 = expand_normal (arg1); enum machine_mode tmode = insn_data[icode].operand[0].mode; enum machine_mode mode0 = insn_data[icode].operand[1].mode; enum machine_mode mode1 = insn_data[icode].operand[2].mode; @@ -6612,8 +6795,8 @@ altivec_expand_predicate_builtin (enum insn_code icode, const char *opcode, tree cr6_form = TREE_VALUE (arglist); tree arg0 = TREE_VALUE (TREE_CHAIN (arglist)); tree arg1 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))); - rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0); - rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0); + rtx op0 = expand_normal (arg0); + rtx op1 = expand_normal (arg1); enum machine_mode tmode = SImode; enum machine_mode mode0 = insn_data[icode].operand[1].mode; enum machine_mode mode1 = insn_data[icode].operand[2].mode; @@ -6690,8 +6873,8 @@ altivec_expand_lv_builtin (enum insn_code icode, tree arglist, rtx target) enum machine_mode tmode = insn_data[icode].operand[0].mode; enum machine_mode mode0 = Pmode; enum machine_mode mode1 = Pmode; - rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0); - rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0); + rtx op0 = expand_normal (arg0); + rtx op1 = expand_normal (arg1); if (icode == CODE_FOR_nothing) /* Builtin not supported on this processor. */ @@ -6733,9 +6916,9 @@ spe_expand_stv_builtin (enum insn_code icode, tree arglist) tree arg0 = TREE_VALUE (arglist); tree arg1 = TREE_VALUE (TREE_CHAIN (arglist)); tree arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))); - rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0); - rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0); - rtx op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0); + rtx op0 = expand_normal (arg0); + rtx op1 = expand_normal (arg1); + rtx op2 = expand_normal (arg2); rtx pat; enum machine_mode mode0 = insn_data[icode].operand[0].mode; enum machine_mode mode1 = insn_data[icode].operand[1].mode; @@ -6766,9 +6949,9 @@ altivec_expand_stv_builtin (enum insn_code icode, tree arglist) tree arg0 = TREE_VALUE (arglist); tree arg1 = TREE_VALUE (TREE_CHAIN (arglist)); tree arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))); - rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0); - rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0); - rtx op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0); + rtx op0 = expand_normal (arg0); + rtx op1 = expand_normal (arg1); + rtx op2 = expand_normal (arg2); rtx pat, addr; enum machine_mode tmode = insn_data[icode].operand[0].mode; enum machine_mode mode1 = Pmode; @@ -6808,9 +6991,9 @@ rs6000_expand_ternop_builtin (enum insn_code icode, tree arglist, rtx target) tree arg0 = TREE_VALUE (arglist); tree arg1 = TREE_VALUE (TREE_CHAIN (arglist)); tree arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))); - rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0); - rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0); - rtx op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0); + rtx op0 = expand_normal (arg0); + rtx op1 = expand_normal (arg1); + rtx op2 = expand_normal (arg2); enum machine_mode tmode = insn_data[icode].operand[0].mode; enum machine_mode mode0 = insn_data[icode].operand[1].mode; enum machine_mode mode1 = insn_data[icode].operand[2].mode; @@ -6895,7 +7078,7 @@ altivec_expand_ld_builtin (tree exp, rtx target, bool *expandedp) *expandedp = true; arg0 = TREE_VALUE (arglist); - op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0); + op0 = expand_normal (arg0); tmode = insn_data[icode].operand[0].mode; mode0 = insn_data[icode].operand[1].mode; @@ -6948,8 +7131,8 @@ altivec_expand_st_builtin (tree exp, rtx target ATTRIBUTE_UNUSED, arg0 = TREE_VALUE (arglist); arg1 = TREE_VALUE (TREE_CHAIN (arglist)); - op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0); - op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0); + op0 = expand_normal (arg0); + op1 = expand_normal (arg1); mode0 = insn_data[icode].operand[0].mode; mode1 = insn_data[icode].operand[1].mode; @@ -6990,9 +7173,9 @@ altivec_expand_dst_builtin (tree exp, rtx target ATTRIBUTE_UNUSED, arg0 = TREE_VALUE (arglist); arg1 = TREE_VALUE (TREE_CHAIN (arglist)); arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))); - op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0); - op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0); - op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0); + op0 = expand_normal (arg0); + op1 = expand_normal (arg1); + op2 = expand_normal (arg2); mode0 = insn_data[d->icode].operand[0].mode; mode1 = insn_data[d->icode].operand[1].mode; mode2 = insn_data[d->icode].operand[2].mode; @@ -7040,7 +7223,7 @@ altivec_expand_vec_init_builtin (tree type, tree arglist, rtx target) for (i = 0; i < n_elt; ++i, arglist = TREE_CHAIN (arglist)) { - rtx x = expand_expr (TREE_VALUE (arglist), NULL_RTX, VOIDmode, 0); + rtx x = expand_normal (TREE_VALUE (arglist)); RTVEC_ELT (v, i) = gen_lowpart (inner_mode, x); } @@ -7115,7 +7298,7 @@ altivec_expand_vec_ext_builtin (tree arglist, rtx target) arg0 = TREE_VALUE (arglist); arg1 = TREE_VALUE (TREE_CHAIN (arglist)); - op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0); + op0 = expand_normal (arg0); elt = get_element_number (TREE_TYPE (arg0), arg1); tmode = TYPE_MODE (TREE_TYPE (TREE_TYPE (arg0))); @@ -7201,7 +7384,7 @@ altivec_expand_builtin (tree exp, rtx target, bool *expandedp) case ALTIVEC_BUILTIN_MTVSCR: icode = CODE_FOR_altivec_mtvscr; arg0 = TREE_VALUE (arglist); - op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0); + op0 = expand_normal (arg0); mode0 = insn_data[icode].operand[0].mode; /* If we got invalid arguments bail out before generating bad rtl. */ @@ -7224,7 +7407,7 @@ altivec_expand_builtin (tree exp, rtx target, bool *expandedp) icode = CODE_FOR_altivec_dss; arg0 = TREE_VALUE (arglist); STRIP_NOPS (arg0); - op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0); + op0 = expand_normal (arg0); mode0 = insn_data[icode].operand[0].mode; /* If we got invalid arguments bail out before generating bad rtl. */ @@ -7458,7 +7641,7 @@ spe_expand_builtin (tree exp, rtx target, bool *expandedp) case SPE_BUILTIN_MTSPEFSCR: icode = CODE_FOR_spe_mtspefscr; arg0 = TREE_VALUE (arglist); - op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0); + op0 = expand_normal (arg0); mode0 = insn_data[icode].operand[0].mode; if (arg0 == error_mark_node) @@ -7486,8 +7669,8 @@ spe_expand_predicate_builtin (enum insn_code icode, tree arglist, rtx target) tree form = TREE_VALUE (arglist); tree arg0 = TREE_VALUE (TREE_CHAIN (arglist)); tree arg1 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))); - rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0); - rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0); + rtx op0 = expand_normal (arg0); + rtx op1 = expand_normal (arg1); enum machine_mode mode0 = insn_data[icode].operand[1].mode; enum machine_mode mode1 = insn_data[icode].operand[2].mode; int form_int; @@ -7595,10 +7778,10 @@ spe_expand_evsel_builtin (enum insn_code icode, tree arglist, rtx target) tree arg1 = TREE_VALUE (TREE_CHAIN (arglist)); tree arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))); tree arg3 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (arglist)))); - rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0); - rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0); - rtx op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0); - rtx op3 = expand_expr (arg3, NULL_RTX, VOIDmode, 0); + rtx op0 = expand_normal (arg0); + rtx op1 = expand_normal (arg1); + rtx op2 = expand_normal (arg2); + rtx op3 = expand_normal (arg3); enum machine_mode mode0 = insn_data[icode].operand[1].mode; enum machine_mode mode1 = insn_data[icode].operand[2].mode; @@ -7843,6 +8026,12 @@ rs6000_init_builtins (void) altivec_init_builtins (); if (TARGET_ALTIVEC || TARGET_SPE) rs6000_common_init_builtins (); + +#if TARGET_XCOFF + /* AIX libm provides clog as __clog. */ + if (built_in_decls [BUILT_IN_CLOG]) + set_user_assembler_name (built_in_decls [BUILT_IN_CLOG], "__clog"); +#endif } /* Search through a set of builtins and enable the mask bits. @@ -8963,33 +9152,32 @@ rs6000_init_libfuncs (void) if (!TARGET_HARD_FLOAT) return; - if (DEFAULT_ABI != ABI_V4) + if (DEFAULT_ABI != ABI_V4 && TARGET_XCOFF + && !TARGET_POWER2 && !TARGET_POWERPC) { - if (TARGET_XCOFF && ! TARGET_POWER2 && ! TARGET_POWERPC) - { - /* 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"); - } + /* 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"); + } + if (!TARGET_IEEEQUAD) /* AIX/Darwin/64-bit Linux quad floating point routines. */ - if (!TARGET_XL_COMPAT) - { - set_optab_libfunc (add_optab, TFmode, "__gcc_qadd"); - set_optab_libfunc (sub_optab, TFmode, "__gcc_qsub"); - set_optab_libfunc (smul_optab, TFmode, "__gcc_qmul"); - set_optab_libfunc (sdiv_optab, TFmode, "__gcc_qdiv"); - } - else - { - set_optab_libfunc (add_optab, TFmode, "_xlqadd"); - set_optab_libfunc (sub_optab, TFmode, "_xlqsub"); - set_optab_libfunc (smul_optab, TFmode, "_xlqmul"); - set_optab_libfunc (sdiv_optab, TFmode, "_xlqdiv"); - } - } + if (!TARGET_XL_COMPAT) + { + set_optab_libfunc (add_optab, TFmode, "__gcc_qadd"); + set_optab_libfunc (sub_optab, TFmode, "__gcc_qsub"); + set_optab_libfunc (smul_optab, TFmode, "__gcc_qmul"); + set_optab_libfunc (sdiv_optab, TFmode, "__gcc_qdiv"); + } + else + { + set_optab_libfunc (add_optab, TFmode, "_xlqadd"); + set_optab_libfunc (sub_optab, TFmode, "_xlqsub"); + set_optab_libfunc (smul_optab, TFmode, "_xlqmul"); + set_optab_libfunc (sdiv_optab, TFmode, "_xlqdiv"); + } else { /* 32-bit SVR4 quad floating point routines. */ @@ -9016,6 +9204,7 @@ rs6000_init_libfuncs (void) set_conv_libfunc (sfix_optab, SImode, TFmode, "_q_qtoi"); set_conv_libfunc (ufix_optab, SImode, TFmode, "_q_qtou"); set_conv_libfunc (sfloat_optab, TFmode, SImode, "_q_itoq"); + set_conv_libfunc (ufloat_optab, TFmode, SImode, "_q_utoq"); } } @@ -9699,9 +9888,9 @@ mems_ok_for_quad_peep (rtx mem1, rtx mem2) NO_REGS is returned. */ enum reg_class -secondary_reload_class (enum reg_class class, - enum machine_mode mode ATTRIBUTE_UNUSED, - rtx in) +rs6000_secondary_reload_class (enum reg_class class, + enum machine_mode mode ATTRIBUTE_UNUSED, + rtx in) { int regno; @@ -10605,7 +10794,8 @@ print_operand (FILE *file, rtx x, int code) else { gcc_assert (GET_CODE (tmp) == PLUS - && GET_CODE (XEXP (tmp, 1)) == REG); + && REG_P (XEXP (tmp, 0)) + && REG_P (XEXP (tmp, 1))); if (REGNO (XEXP (tmp, 0)) == 0) fprintf (file, "%s,%s", reg_names[ REGNO (XEXP (tmp, 1)) ], @@ -10665,6 +10855,7 @@ print_operand_address (FILE *file, rtx x) } else if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == REG) { + gcc_assert (REG_P (XEXP (x, 0))); if (REGNO (XEXP (x, 0)) == 0) fprintf (file, "%s,%s", reg_names[ REGNO (XEXP (x, 1)) ], reg_names[ REGNO (XEXP (x, 0)) ]); @@ -10744,15 +10935,14 @@ rs6000_assemble_integer (rtx x, unsigned int size, int aligned_p) /* Special handling for SI values. */ if (RELOCATABLE_NEEDS_FIXUP && size == 4 && aligned_p) { - extern int in_toc_section (void); static int recurse = 0; /* For -mrelocatable, we mark all addresses that need to be fixed up in the .fixup section. */ if (TARGET_RELOCATABLE - && !in_toc_section () - && !in_text_section () - && !in_unlikely_text_section () + && in_section != toc_section + && in_section != text_section + && !unlikely_text_section_p (in_section) && !recurse && GET_CODE (x) != CONST_INT && GET_CODE (x) != CONST_DOUBLE @@ -11022,7 +11212,7 @@ rs6000_generate_compare (enum rtx_code code) CLOBBERs to match cmptf_internal2 pattern. */ if (comp_mode == CCFPmode && TARGET_XL_COMPAT && GET_MODE (rs6000_compare_op0) == TFmode - && (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_DARWIN) + && !TARGET_IEEEQUAD && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_LONG_DOUBLE_128) emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (9, @@ -11636,7 +11826,7 @@ rs6000_emit_cmove (rtx dest, rtx op, rtx true_cond, rtx false_cond) return 0; } else if (TARGET_E500 && TARGET_HARD_FLOAT && !TARGET_FPRS - && GET_MODE_CLASS (compare_mode) == MODE_FLOAT) + && SCALAR_FLOAT_MODE_P (compare_mode)) return 0; is_against_zero = op1 == CONST0_RTX (compare_mode); @@ -11646,7 +11836,7 @@ rs6000_emit_cmove (rtx dest, rtx op, rtx true_cond, rtx false_cond) can't be generated if we care about that. It's safe if one side of the construct is zero, since then no subtract will be generated. */ - if (GET_MODE_CLASS (compare_mode) == MODE_FLOAT + if (SCALAR_FLOAT_MODE_P (compare_mode) && flag_trapping_math && ! is_against_zero) return 0; @@ -12198,6 +12388,96 @@ rs6000_split_lock_test_and_set (rtx retval, rtx mem, rtx val, rtx scratch) emit_insn (gen_isync ()); } +void +rs6000_expand_compare_and_swapqhi (rtx dst, rtx mem, rtx oldval, rtx newval) +{ + enum machine_mode mode = GET_MODE (mem); + rtx addrSI, align, wdst, shift, mask; + HOST_WIDE_INT shift_mask = mode == QImode ? 0x18 : 0x10; + HOST_WIDE_INT imask = GET_MODE_MASK (mode); + + /* Shift amount for subword relative to aligned word. */ + addrSI = force_reg (SImode, gen_lowpart_common (SImode, XEXP (mem, 0))); + shift = gen_reg_rtx (SImode); + emit_insn (gen_rlwinm (shift, addrSI, GEN_INT (3), + GEN_INT (shift_mask))); + emit_insn (gen_xorsi3 (shift, shift, GEN_INT (shift_mask))); + + /* Shift and mask old value into position within word. */ + oldval = convert_modes (SImode, mode, oldval, 1); + oldval = expand_binop (SImode, and_optab, + oldval, GEN_INT (imask), NULL_RTX, + 1, OPTAB_LIB_WIDEN); + emit_insn (gen_ashlsi3 (oldval, oldval, shift)); + + /* Shift and mask new value into position within word. */ + newval = convert_modes (SImode, mode, newval, 1); + newval = expand_binop (SImode, and_optab, + newval, GEN_INT (imask), NULL_RTX, + 1, OPTAB_LIB_WIDEN); + emit_insn (gen_ashlsi3 (newval, newval, shift)); + + /* Mask for insertion. */ + mask = gen_reg_rtx (SImode); + emit_move_insn (mask, GEN_INT (imask)); + emit_insn (gen_ashlsi3 (mask, mask, shift)); + + /* Address of aligned word containing subword. */ + align = expand_binop (Pmode, and_optab, XEXP (mem, 0), GEN_INT (-4), + NULL_RTX, 1, OPTAB_LIB_WIDEN); + mem = change_address (mem, SImode, align); + set_mem_align (mem, 32); + MEM_VOLATILE_P (mem) = 1; + + wdst = gen_reg_rtx (SImode); + emit_insn (gen_sync_compare_and_swapqhi_internal (wdst, mask, + oldval, newval, mem)); + + emit_move_insn (dst, gen_lowpart (mode, wdst)); +} + +void +rs6000_split_compare_and_swapqhi (rtx dest, rtx mask, + rtx oldval, rtx newval, rtx mem, + rtx scratch) +{ + rtx label1, label2, x, cond = gen_rtx_REG (CCmode, CR0_REGNO); + + emit_insn (gen_memory_barrier ()); + label1 = gen_rtx_LABEL_REF (VOIDmode, gen_label_rtx ()); + label2 = gen_rtx_LABEL_REF (VOIDmode, gen_label_rtx ()); + emit_label (XEXP (label1, 0)); + + emit_load_locked (SImode, scratch, mem); + + /* Mask subword within loaded value for comparison with oldval. + Use UNSPEC_AND to avoid clobber.*/ + emit_insn (gen_rtx_SET (SImode, dest, + gen_rtx_UNSPEC (SImode, + gen_rtvec (2, scratch, mask), + UNSPEC_AND))); + + x = gen_rtx_COMPARE (CCmode, dest, oldval); + emit_insn (gen_rtx_SET (VOIDmode, cond, x)); + + x = gen_rtx_NE (VOIDmode, cond, const0_rtx); + emit_unlikely_jump (x, label2); + + /* Clear subword within loaded value for insertion of new value. */ + emit_insn (gen_rtx_SET (SImode, scratch, + gen_rtx_AND (SImode, + gen_rtx_NOT (SImode, mask), scratch))); + emit_insn (gen_iorsi3 (scratch, scratch, newval)); + emit_store_conditional (SImode, cond, mem, scratch); + + x = gen_rtx_NE (VOIDmode, cond, const0_rtx); + emit_unlikely_jump (x, label1); + + emit_insn (gen_isync ()); + emit_label (XEXP (label2, 0)); +} + + /* Emit instructions to move SRC to DST. Called by splitters for multi-register moves. It will emit at most one instruction for each register that is accessed; that is, it won't emit li/lis pairs @@ -12265,7 +12545,7 @@ rs6000_split_multireg_move (rtx dst, rtx src) : gen_adddi3 (breg, breg, delta_rtx)); src = replace_equiv_address (src, breg); } - else if (! offsettable_memref_p (src)) + else if (! rs6000_offsettable_memref_p (src)) { rtx basereg; basereg = gen_rtx_REG (Pmode, reg); @@ -12318,7 +12598,7 @@ rs6000_split_multireg_move (rtx dst, rtx src) dst = replace_equiv_address (dst, breg); } else - gcc_assert (offsettable_memref_p (dst)); + gcc_assert (rs6000_offsettable_memref_p (dst)); } for (i = 0; i < nregs; i++) @@ -12606,15 +12886,14 @@ is_altivec_return_reg (rtx reg, void *xyes) static rs6000_stack_t * rs6000_stack_info (void) { - static rs6000_stack_t info, zero_info; + static rs6000_stack_t info; rs6000_stack_t *info_ptr = &info; int reg_size = TARGET_32BIT ? 4 : 8; int ehrd_size; int save_align; HOST_WIDE_INT non_fixed_size; - /* Zero all fields portably. */ - info = zero_info; + memset (&info, 0, sizeof (info)); if (TARGET_SPE) { @@ -12667,10 +12946,9 @@ rs6000_stack_info (void) || cfun->machine->ra_needs_full_frame); /* Determine if we need to save the link register. */ - if (rs6000_ra_ever_killed () - || (DEFAULT_ABI == ABI_AIX - && current_function_profile - && !TARGET_PROFILE_KERNEL) + if ((DEFAULT_ABI == ABI_AIX + && current_function_profile + && !TARGET_PROFILE_KERNEL) #ifdef TARGET_RELOCATABLE || (TARGET_RELOCATABLE && (get_pool_size () != 0)) #endif @@ -12678,7 +12956,8 @@ rs6000_stack_info (void) && !FP_SAVE_INLINE (info_ptr->first_fp_reg_save)) || info_ptr->first_altivec_reg_save <= LAST_ALTIVEC_REGNO || (DEFAULT_ABI == ABI_V4 && current_function_calls_alloca) - || info_ptr->calls_p) + || info_ptr->calls_p + || rs6000_ra_ever_killed ()) { info_ptr->lr_save_p = 1; regs_ever_live[LINK_REGISTER_REGNUM] = 1; @@ -12801,8 +13080,7 @@ rs6000_stack_info (void) - info_ptr->spe_gp_size; /* Adjust for SPE case. */ - info_ptr->toc_save_offset - = info_ptr->spe_gp_save_offset - info_ptr->toc_size; + info_ptr->ehrd_offset = info_ptr->spe_gp_save_offset; } else if (TARGET_ALTIVEC_ABI) { @@ -12822,12 +13100,11 @@ rs6000_stack_info (void) - info_ptr->altivec_size; /* Adjust for AltiVec case. */ - info_ptr->toc_save_offset - = info_ptr->altivec_save_offset - info_ptr->toc_size; + info_ptr->ehrd_offset = info_ptr->altivec_save_offset; } else - info_ptr->toc_save_offset = info_ptr->cr_save_offset - info_ptr->toc_size; - info_ptr->ehrd_offset = info_ptr->toc_save_offset - ehrd_size; + info_ptr->ehrd_offset = info_ptr->cr_save_offset; + info_ptr->ehrd_offset -= ehrd_size; info_ptr->lr_save_offset = reg_size; break; } @@ -12841,9 +13118,7 @@ rs6000_stack_info (void) + info_ptr->spe_padding_size + ehrd_size + info_ptr->cr_size - + info_ptr->lr_size - + info_ptr->vrsave_size - + info_ptr->toc_size, + + info_ptr->vrsave_size, save_align); non_fixed_size = (info_ptr->vars_size @@ -12904,9 +13179,6 @@ rs6000_stack_info (void) if (! info_ptr->cr_save_p) info_ptr->cr_save_offset = 0; - if (! info_ptr->toc_save_p) - info_ptr->toc_save_offset = 0; - return info_ptr; } @@ -13002,9 +13274,6 @@ debug_stack_info (rs6000_stack_t *info) if (info->cr_save_p) fprintf (stderr, "\tcr_save_p = %5d\n", info->cr_save_p); - if (info->toc_save_p) - fprintf (stderr, "\ttoc_save_p = %5d\n", info->toc_save_p); - if (info->vrsave_mask) fprintf (stderr, "\tvrsave_mask = 0x%x\n", info->vrsave_mask); @@ -13038,9 +13307,6 @@ debug_stack_info (rs6000_stack_t *info) if (info->cr_save_offset) fprintf (stderr, "\tcr_save_offset = %5d\n", info->cr_save_offset); - if (info->toc_save_offset) - fprintf (stderr, "\ttoc_save_offset = %5d\n", info->toc_save_offset); - if (info->varargs_save_offset) fprintf (stderr, "\tvarargs_save_offset = %5d\n", info->varargs_save_offset); @@ -13081,15 +13347,9 @@ debug_stack_info (rs6000_stack_t *info) fprintf (stderr, "\tspe_padding_size = %5d\n", info->spe_padding_size); - if (info->lr_size) - fprintf (stderr, "\tlr_size = %5d\n", info->lr_size); - if (info->cr_size) fprintf (stderr, "\tcr_size = %5d\n", info->cr_size); - if (info->toc_size) - fprintf (stderr, "\ttoc_size = %5d\n", info->toc_size); - if (info->save_size) fprintf (stderr, "\tsave_size = %5d\n", info->save_size); @@ -13212,10 +13472,12 @@ rs6000_ra_ever_killed (void) { if (INSN_P (insn)) { - if (FIND_REG_INC_NOTE (insn, reg)) - return 1; - else if (GET_CODE (insn) == CALL_INSN - && !SIBLING_CALL_P (insn)) + if (CALL_P (insn)) + { + if (!SIBLING_CALL_P (insn)) + return 1; + } + else if (find_regno_note (insn, REG_INC, LINK_REGISTER_REGNUM)) return 1; else if (set_of (reg, insn) != NULL_RTX && !prologue_epilogue_contains (insn)) @@ -13380,9 +13642,7 @@ rs6000_emit_eh_reg_restore (rtx source, rtx scratch) || current_function_calls_alloca || info->total_size > 32767) { - tmp = gen_rtx_MEM (Pmode, frame_rtx); - MEM_NOTRAP_P (tmp) = 1; - set_mem_alias_set (tmp, rs6000_sr_alias_set); + tmp = gen_frame_mem (Pmode, frame_rtx); emit_move_insn (operands[1], tmp); frame_rtx = operands[1]; } @@ -13390,9 +13650,7 @@ rs6000_emit_eh_reg_restore (rtx source, rtx scratch) sp_offset = info->total_size; tmp = plus_constant (frame_rtx, info->lr_save_offset + sp_offset); - tmp = gen_rtx_MEM (Pmode, tmp); - MEM_NOTRAP_P (tmp) = 1; - set_mem_alias_set (tmp, rs6000_sr_alias_set); + tmp = gen_frame_mem (Pmode, tmp); emit_move_insn (tmp, operands[0]); } else @@ -13444,6 +13702,8 @@ uses_TOC (void) rtx create_TOC_reference (rtx symbol) { + if (no_new_pseudos) + regs_ever_live[TOC_REGISTER] = 1; return gen_rtx_PLUS (Pmode, gen_rtx_REG (Pmode, TOC_REGISTER), gen_rtx_CONST (Pmode, @@ -13487,15 +13747,15 @@ rs6000_aix_emit_builtin_unwind_init (void) emit_label (no_toc_save_needed); } -/* This ties together stack memory (MEM with an alias set of - rs6000_sr_alias_set) and the change to the stack pointer. */ +/* This ties together stack memory (MEM with an alias set of frame_alias_set) + and the change to the stack pointer. */ static void rs6000_emit_stack_tie (void) { - rtx mem = gen_rtx_MEM (BLKmode, gen_rtx_REG (Pmode, STACK_POINTER_REGNUM)); + rtx mem = gen_frame_mem (BLKmode, + gen_rtx_REG (Pmode, STACK_POINTER_REGNUM)); - set_mem_alias_set (mem, rs6000_sr_alias_set); emit_insn (gen_stack_tie (mem)); } @@ -13835,8 +14095,7 @@ emit_frame_save (rtx frame_reg, rtx frame_ptr, enum machine_mode mode, reg = gen_rtx_REG (mode, regno); addr = gen_rtx_PLUS (Pmode, frame_reg, offset_rtx); - mem = gen_rtx_MEM (mode, addr); - set_mem_alias_set (mem, rs6000_sr_alias_set); + mem = gen_frame_mem (mode, addr); insn = emit_move_insn (mem, reg); @@ -13862,7 +14121,7 @@ gen_frame_mem_offset (enum machine_mode mode, rtx reg, int offset) else offset_rtx = int_rtx; - return gen_rtx_MEM (mode, gen_rtx_PLUS (Pmode, reg, offset_rtx)); + return gen_frame_mem (mode, gen_rtx_PLUS (Pmode, reg, offset_rtx)); } /* Look for user-defined global regs. We should not save and restore these, @@ -14005,8 +14264,7 @@ rs6000_emit_prologue (void) rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, GEN_INT (info->fp_save_offset + sp_offset + 8 * i)); - rtx mem = gen_rtx_MEM (DFmode, addr); - set_mem_alias_set (mem, rs6000_sr_alias_set); + rtx mem = gen_frame_mem (DFmode, addr); RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, mem, reg); } @@ -14016,8 +14274,7 @@ rs6000_emit_prologue (void) rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, GEN_INT (info->altivec_save_offset + sp_offset + 16 * i)); - rtx mem = gen_rtx_MEM (V4SImode, addr); - set_mem_alias_set (mem, rs6000_sr_alias_set); + rtx mem = gen_frame_mem (V4SImode, addr); RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, mem, reg); } @@ -14027,8 +14284,7 @@ rs6000_emit_prologue (void) rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, GEN_INT (info->gp_save_offset + sp_offset + reg_size * i)); - rtx mem = gen_rtx_MEM (reg_mode, addr); - set_mem_alias_set (mem, rs6000_sr_alias_set); + rtx mem = gen_frame_mem (reg_mode, addr); RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, mem, reg); } @@ -14039,8 +14295,7 @@ rs6000_emit_prologue (void) rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, GEN_INT (info->cr_save_offset + sp_offset)); - rtx mem = gen_rtx_MEM (reg_mode, addr); - set_mem_alias_set (mem, rs6000_sr_alias_set); + rtx mem = gen_frame_mem (reg_mode, addr); RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, mem, reg); } @@ -14091,10 +14346,8 @@ rs6000_emit_prologue (void) emit_move_insn (areg, GEN_INT (offset)); /* AltiVec addressing mode is [reg+reg]. */ - mem = gen_rtx_MEM (V4SImode, - gen_rtx_PLUS (Pmode, frame_reg_rtx, areg)); - - set_mem_alias_set (mem, rs6000_sr_alias_set); + mem = gen_frame_mem (V4SImode, + gen_rtx_PLUS (Pmode, frame_reg_rtx, areg)); insn = emit_move_insn (mem, savereg); @@ -14130,10 +14383,9 @@ rs6000_emit_prologue (void) { /* Save VRSAVE. */ offset = info->vrsave_save_offset + sp_offset; - mem - = gen_rtx_MEM (SImode, - gen_rtx_PLUS (Pmode, frame_reg_rtx, GEN_INT (offset))); - set_mem_alias_set (mem, rs6000_sr_alias_set); + mem = gen_frame_mem (SImode, + gen_rtx_PLUS (Pmode, frame_reg_rtx, + GEN_INT (offset))); insn = emit_move_insn (mem, reg); } @@ -14209,8 +14461,7 @@ rs6000_emit_prologue (void) addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, GEN_INT (info->fp_save_offset + sp_offset + 8*i)); - mem = gen_rtx_MEM (DFmode, addr); - set_mem_alias_set (mem, rs6000_sr_alias_set); + mem = gen_frame_mem (DFmode, addr); RTVEC_ELT (p, i + 2) = gen_rtx_SET (VOIDmode, mem, reg); } @@ -14234,8 +14485,7 @@ rs6000_emit_prologue (void) GEN_INT (info->gp_save_offset + sp_offset + reg_size * i)); - mem = gen_rtx_MEM (reg_mode, addr); - set_mem_alias_set (mem, rs6000_sr_alias_set); + mem = gen_frame_mem (reg_mode, addr); RTVEC_ELT (p, i) = gen_rtx_SET (VOIDmode, mem, reg); } @@ -14273,8 +14523,7 @@ rs6000_emit_prologue (void) b = GEN_INT (offset); addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, b); - mem = gen_rtx_MEM (V2SImode, addr); - set_mem_alias_set (mem, rs6000_sr_alias_set); + mem = gen_frame_mem (V2SImode, addr); insn = emit_move_insn (mem, reg); if (GET_CODE (b) == CONST_INT) @@ -14290,8 +14539,7 @@ rs6000_emit_prologue (void) GEN_INT (info->gp_save_offset + sp_offset + reg_size * i)); - mem = gen_rtx_MEM (reg_mode, addr); - set_mem_alias_set (mem, rs6000_sr_alias_set); + mem = gen_frame_mem (reg_mode, addr); insn = emit_move_insn (mem, reg); rs6000_frame_related (insn, frame_ptr_rtx, info->total_size, @@ -14314,8 +14562,7 @@ rs6000_emit_prologue (void) reg = gen_rtx_REG (reg_mode, 2); addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, GEN_INT (sp_offset + 5 * reg_size)); - mem = gen_rtx_MEM (reg_mode, addr); - set_mem_alias_set (mem, rs6000_sr_alias_set); + mem = gen_frame_mem (reg_mode, addr); insn = emit_move_insn (mem, reg); rs6000_frame_related (insn, frame_ptr_rtx, info->total_size, @@ -14343,7 +14590,7 @@ rs6000_emit_prologue (void) GEN_INT (info->lr_save_offset + sp_offset)); rtx reg = gen_rtx_REG (Pmode, 0); rtx mem = gen_rtx_MEM (Pmode, addr); - /* This should not be of rs6000_sr_alias_set, because of + /* This should not be of frame_alias_set, because of __builtin_return_address. */ insn = emit_move_insn (mem, reg); @@ -14356,12 +14603,10 @@ rs6000_emit_prologue (void) { rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, GEN_INT (info->cr_save_offset + sp_offset)); - rtx mem = gen_rtx_MEM (SImode, addr); + rtx mem = gen_frame_mem (SImode, addr); /* See the large comment above about why CR2_REGNO is used. */ rtx magic_eh_cr_reg = gen_rtx_REG (SImode, CR2_REGNO); - set_mem_alias_set (mem, rs6000_sr_alias_set); - /* If r12 was used to hold the original sp, copy cr into r0 now that it's free. */ if (REGNO (frame_reg_rtx) == 12) @@ -14604,8 +14849,7 @@ rs6000_emit_epilogue (int sibcall) rtx reg = gen_rtx_REG (reg_mode, CR2_REGNO); rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, GEN_INT (info->cr_save_offset)); - rtx mem = gen_rtx_MEM (reg_mode, addr); - set_mem_alias_set (mem, rs6000_sr_alias_set); + rtx mem = gen_frame_mem (reg_mode, addr); RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, reg, mem); } @@ -14616,8 +14860,7 @@ rs6000_emit_epilogue (int sibcall) rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, GEN_INT (info->gp_save_offset + reg_size * i)); - rtx mem = gen_rtx_MEM (reg_mode, addr); - set_mem_alias_set (mem, rs6000_sr_alias_set); + rtx mem = gen_frame_mem (reg_mode, addr); RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, reg, mem); } @@ -14627,8 +14870,7 @@ rs6000_emit_epilogue (int sibcall) rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, GEN_INT (info->altivec_save_offset + 16 * i)); - rtx mem = gen_rtx_MEM (V4SImode, addr); - set_mem_alias_set (mem, rs6000_sr_alias_set); + rtx mem = gen_frame_mem (V4SImode, addr); RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, reg, mem); } @@ -14638,8 +14880,7 @@ rs6000_emit_epilogue (int sibcall) rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, GEN_INT (info->fp_save_offset + 8 * i)); - rtx mem = gen_rtx_MEM (DFmode, addr); - set_mem_alias_set (mem, rs6000_sr_alias_set); + rtx mem = gen_frame_mem (DFmode, addr); RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, reg, mem); } @@ -14670,7 +14911,6 @@ rs6000_emit_epilogue (int sibcall) emit_move_insn (frame_reg_rtx, gen_rtx_MEM (Pmode, sp_reg_rtx)); - } else if (info->push_p) { @@ -14705,8 +14945,7 @@ rs6000_emit_epilogue (int sibcall) /* AltiVec addressing mode is [reg+reg]. */ addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, areg); - mem = gen_rtx_MEM (V4SImode, addr); - set_mem_alias_set (mem, rs6000_sr_alias_set); + mem = gen_frame_mem (V4SImode, addr); emit_move_insn (gen_rtx_REG (V4SImode, i), mem); } @@ -14720,8 +14959,7 @@ rs6000_emit_epilogue (int sibcall) addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, GEN_INT (info->vrsave_save_offset + sp_offset)); - mem = gen_rtx_MEM (SImode, addr); - set_mem_alias_set (mem, rs6000_sr_alias_set); + mem = gen_frame_mem (SImode, addr); reg = gen_rtx_REG (SImode, 12); emit_move_insn (reg, mem); @@ -14734,8 +14972,6 @@ rs6000_emit_epilogue (int sibcall) rtx mem = gen_frame_mem_offset (Pmode, frame_reg_rtx, info->lr_save_offset + sp_offset); - set_mem_alias_set (mem, rs6000_sr_alias_set); - emit_move_insn (gen_rtx_REG (Pmode, 0), mem); } @@ -14744,9 +14980,7 @@ rs6000_emit_epilogue (int sibcall) { rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, GEN_INT (info->cr_save_offset + sp_offset)); - rtx mem = gen_rtx_MEM (SImode, addr); - - set_mem_alias_set (mem, rs6000_sr_alias_set); + rtx mem = gen_frame_mem (SImode, addr); emit_move_insn (gen_rtx_REG (SImode, 12), mem); } @@ -14765,9 +14999,7 @@ rs6000_emit_epilogue (int sibcall) { rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, GEN_INT (sp_offset + 5 * reg_size)); - rtx mem = gen_rtx_MEM (reg_mode, addr); - - set_mem_alias_set (mem, rs6000_sr_alias_set); + rtx mem = gen_frame_mem (reg_mode, addr); emit_move_insn (gen_rtx_REG (reg_mode, 2), mem); } @@ -14783,7 +15015,6 @@ rs6000_emit_epilogue (int sibcall) mem = gen_frame_mem_offset (reg_mode, frame_reg_rtx, info->ehrd_offset + sp_offset + reg_size * (int) i); - set_mem_alias_set (mem, rs6000_sr_alias_set); emit_move_insn (gen_rtx_REG (reg_mode, regno), mem); } @@ -14801,9 +15032,7 @@ rs6000_emit_epilogue (int sibcall) GEN_INT (info->gp_save_offset + sp_offset + reg_size * i)); - rtx mem = gen_rtx_MEM (reg_mode, addr); - - set_mem_alias_set (mem, rs6000_sr_alias_set); + rtx mem = gen_frame_mem (reg_mode, addr); RTVEC_ELT (p, i) = gen_rtx_SET (VOIDmode, @@ -14826,7 +15055,7 @@ rs6000_emit_epilogue (int sibcall) GEN_INT (info->gp_save_offset + sp_offset + reg_size * i)); - rtx mem = gen_rtx_MEM (reg_mode, addr); + rtx mem = gen_frame_mem (reg_mode, addr); /* Restore 64-bit quantities for SPE. */ if (TARGET_SPE_ABI && info->spe_64bit_regs_used != 0) @@ -14843,11 +15072,9 @@ rs6000_emit_epilogue (int sibcall) b = GEN_INT (offset); addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, b); - mem = gen_rtx_MEM (V2SImode, addr); + mem = gen_frame_mem (V2SImode, addr); } - set_mem_alias_set (mem, rs6000_sr_alias_set); - emit_move_insn (gen_rtx_REG (reg_mode, info->first_gp_reg_save + i), mem); } @@ -14863,8 +15090,7 @@ rs6000_emit_epilogue (int sibcall) GEN_INT (info->fp_save_offset + sp_offset + 8 * i)); - mem = gen_rtx_MEM (DFmode, addr); - set_mem_alias_set (mem, rs6000_sr_alias_set); + mem = gen_frame_mem (DFmode, addr); emit_move_insn (gen_rtx_REG (DFmode, info->first_fp_reg_save + i), @@ -14918,30 +15144,20 @@ rs6000_emit_epilogue (int sibcall) } /* If this is V.4, unwind the stack pointer after all of the loads - have been done. We need to emit a block here so that sched - doesn't decide to move the sp change before the register restores - (which may not have any obvious dependency on the stack). This - doesn't hurt performance, because there is no scheduling that can - be done after this point. */ - if (DEFAULT_ABI == ABI_V4 - || current_function_calls_eh_return) + have been done. */ + if (frame_reg_rtx != sp_reg_rtx) { - if (frame_reg_rtx != sp_reg_rtx) - rs6000_emit_stack_tie (); - - if (use_backchain_to_restore_sp) - { - emit_move_insn (sp_reg_rtx, frame_reg_rtx); - } - else if (sp_offset != 0) - { - emit_insn (TARGET_32BIT - ? gen_addsi3 (sp_reg_rtx, sp_reg_rtx, - GEN_INT (sp_offset)) - : gen_adddi3 (sp_reg_rtx, sp_reg_rtx, - GEN_INT (sp_offset))); - } + /* This blockage is needed so that sched doesn't decide to move + the sp change before the register restores. */ + rs6000_emit_stack_tie (); + emit_move_insn (sp_reg_rtx, frame_reg_rtx); } + else if (sp_offset != 0) + emit_insn (TARGET_32BIT + ? gen_addsi3 (sp_reg_rtx, sp_reg_rtx, + GEN_INT (sp_offset)) + : gen_adddi3 (sp_reg_rtx, sp_reg_rtx, + GEN_INT (sp_offset))); if (current_function_calls_eh_return) { @@ -14984,8 +15200,7 @@ rs6000_emit_epilogue (int sibcall) rtx addr, mem; addr = gen_rtx_PLUS (Pmode, sp_reg_rtx, GEN_INT (info->fp_save_offset + 8*i)); - mem = gen_rtx_MEM (DFmode, addr); - set_mem_alias_set (mem, rs6000_sr_alias_set); + mem = gen_frame_mem (DFmode, addr); RTVEC_ELT (p, i+3) = gen_rtx_SET (VOIDmode, @@ -15004,8 +15219,6 @@ static void rs6000_output_function_epilogue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED) { - rs6000_stack_t *info = rs6000_stack_info (); - if (! HAVE_epilogue) { rtx insn = get_last_insn (); @@ -15076,13 +15289,14 @@ rs6000_output_function_epilogue (FILE *file, System V.4 Powerpc's (and the embedded ABI derived from it) use a different traceback table. */ if (DEFAULT_ABI == ABI_AIX && ! flag_inhibit_size_directive - && rs6000_traceback != traceback_none) + && rs6000_traceback != traceback_none && !current_function_is_thunk) { const char *fname = NULL; const char *language_string = lang_hooks.name; int fixed_parms = 0, float_parms = 0, parm_info = 0; int i; int optional_tbtab; + rs6000_stack_t *info = rs6000_stack_info (); if (rs6000_traceback == traceback_full) optional_tbtab = 1; @@ -15123,7 +15337,8 @@ rs6000_output_function_epilogue (FILE *file, 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") @@ -15133,7 +15348,8 @@ rs6000_output_function_epilogue (FILE *file, 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; @@ -15187,7 +15403,7 @@ rs6000_output_function_epilogue (FILE *file, if (GET_CODE (parameter) == REG) { - if (GET_MODE_CLASS (mode) == MODE_FLOAT) + if (SCALAR_FLOAT_MODE_P (mode)) { int bits; @@ -15644,13 +15860,17 @@ output_toc (FILE *file, rtx x, int labelno, enum machine_mode mode) /* Handle FP constants specially. Note that if we have a minimal TOC, things we put here aren't actually in the TOC, so we can allow FP constants. */ - if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == TFmode) + if (GET_CODE (x) == CONST_DOUBLE && + (GET_MODE (x) == TFmode || GET_MODE (x) == TDmode)) { REAL_VALUE_TYPE rv; long k[4]; REAL_VALUE_FROM_CONST_DOUBLE (rv, x); - REAL_VALUE_TO_TARGET_LONG_DOUBLE (rv, k); + if (DECIMAL_FLOAT_MODE_P (GET_MODE (x))) + REAL_VALUE_TO_TARGET_DECIMAL128 (rv, k); + else + REAL_VALUE_TO_TARGET_LONG_DOUBLE (rv, k); if (TARGET_64BIT) { @@ -15679,13 +15899,18 @@ output_toc (FILE *file, rtx x, int labelno, enum machine_mode mode) return; } } - else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == DFmode) + else if (GET_CODE (x) == CONST_DOUBLE && + (GET_MODE (x) == DFmode || GET_MODE (x) == DDmode)) { REAL_VALUE_TYPE rv; long k[2]; REAL_VALUE_FROM_CONST_DOUBLE (rv, x); - REAL_VALUE_TO_TARGET_DOUBLE (rv, k); + + if (DECIMAL_FLOAT_MODE_P (GET_MODE (x))) + REAL_VALUE_TO_TARGET_DECIMAL64 (rv, k); + else + REAL_VALUE_TO_TARGET_DOUBLE (rv, k); if (TARGET_64BIT) { @@ -15710,13 +15935,17 @@ output_toc (FILE *file, rtx x, int labelno, enum machine_mode mode) return; } } - else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == SFmode) + else if (GET_CODE (x) == CONST_DOUBLE && + (GET_MODE (x) == SFmode || GET_MODE (x) == SDmode)) { REAL_VALUE_TYPE rv; long l; REAL_VALUE_FROM_CONST_DOUBLE (rv, x); - REAL_VALUE_TO_TARGET_SINGLE (rv, l); + if (DECIMAL_FLOAT_MODE_P (GET_MODE (x))) + REAL_VALUE_TO_TARGET_DECIMAL32 (rv, l); + else + REAL_VALUE_TO_TARGET_SINGLE (rv, l); if (TARGET_64BIT) { @@ -17087,9 +17316,8 @@ rs6000_trampoline_size (void) 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) { @@ -17097,15 +17325,15 @@ rs6000_initialize_trampoline (rtx addr, rtx fnaddr, rtx cxt) 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); @@ -17117,12 +17345,12 @@ rs6000_initialize_trampoline (rtx addr, rtx fnaddr, rtx cxt) /* 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; } @@ -17138,6 +17366,8 @@ const struct attribute_spec rs6000_attribute_table[] = { "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 @@ -17197,6 +17427,8 @@ rs6000_handle_altivec_attribute (tree *node, error ("use of boolean types in AltiVec types is invalid"); else if (TREE_CODE (type) == COMPLEX_TYPE) error ("use of % in AltiVec types is invalid"); + else if (DECIMAL_FLOAT_MODE_P (mode)) + error ("use of decimal floating point types in AltiVec types is invalid"); switch (altivec_type) { @@ -17262,6 +17494,14 @@ rs6000_mangle_fundamental_type (tree type) if (type == pixel_type_node) return "u7__pixel"; if (type == bool_int_type_node) return "U6__booli"; + /* Mangle IBM extended float long double as `g' (__float128) on + powerpc*-linux where long-double-64 previously was the default. */ + if (TYPE_MAIN_VARIANT (type) == long_double_type_node + && TARGET_ELF + && TARGET_LONG_DOUBLE_128 + && !TARGET_IEEEQUAD) + return "g"; + /* For all other types, use normal C++ mangling. */ return NULL; } @@ -17298,6 +17538,10 @@ rs6000_set_default_type_attributes (tree type) 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 @@ -17326,33 +17570,124 @@ rs6000_longcall_ref (rtx call_ref) return force_reg (Pmode, call_ref); } +#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)); +} + #ifdef USING_ELFOS_H -/* A C statement or statements to switch to the appropriate section - for output of RTX in mode MODE. You can assume that RTX is some - kind of constant in RTL. The argument MODE is redundant except in - the case of a `const_int' rtx. Select the section by calling - `text_section' or one of the alternatives for other sections. +/* A get_unnamed_section callback, used for switching to toc_section. */ + +static void +rs6000_elf_output_toc_section_asm_op (const void *data ATTRIBUTE_UNUSED) +{ + if (DEFAULT_ABI == ABI_AIX + && TARGET_MINIMAL_TOC + && !TARGET_RELOCATABLE) + { + if (!toc_initialized) + { + toc_initialized = 1; + fprintf (asm_out_file, "%s\n", TOC_SECTION_ASM_OP); + (*targetm.asm_out.internal_label) (asm_out_file, "LCTOC", 0); + fprintf (asm_out_file, "\t.tc "); + ASM_OUTPUT_INTERNAL_LABEL_PREFIX (asm_out_file, "LCTOC1[TC],"); + ASM_OUTPUT_INTERNAL_LABEL_PREFIX (asm_out_file, "LCTOC1"); + fprintf (asm_out_file, "\n"); + + fprintf (asm_out_file, "%s\n", MINIMAL_TOC_SECTION_ASM_OP); + ASM_OUTPUT_INTERNAL_LABEL_PREFIX (asm_out_file, "LCTOC1"); + fprintf (asm_out_file, " = .+32768\n"); + } + else + fprintf (asm_out_file, "%s\n", MINIMAL_TOC_SECTION_ASM_OP); + } + else if (DEFAULT_ABI == ABI_AIX && !TARGET_RELOCATABLE) + fprintf (asm_out_file, "%s\n", TOC_SECTION_ASM_OP); + else + { + fprintf (asm_out_file, "%s\n", MINIMAL_TOC_SECTION_ASM_OP); + if (!toc_initialized) + { + ASM_OUTPUT_INTERNAL_LABEL_PREFIX (asm_out_file, "LCTOC1"); + fprintf (asm_out_file, " = .+32768\n"); + toc_initialized = 1; + } + } +} - Do not define this macro if you put all constants in the read-only - data section. */ +/* Implement TARGET_ASM_INIT_SECTIONS. */ static void +rs6000_elf_asm_init_sections (void) +{ + toc_section + = get_unnamed_section (0, rs6000_elf_output_toc_section_asm_op, NULL); + + sdata2_section + = get_unnamed_section (SECTION_WRITE, output_section_asm_op, + SDATA2_SECTION_ASM_OP); +} + +/* Implement TARGET_SELECT_RTX_SECTION. */ + +static section * rs6000_elf_select_rtx_section (enum machine_mode mode, rtx x, unsigned HOST_WIDE_INT align) { if (ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (x, mode)) - toc_section (); + return toc_section; else - default_elf_select_rtx_section (mode, x, align); + return default_elf_select_rtx_section (mode, x, align); } -/* A C statement or statements to switch to the appropriate - section for output of DECL. DECL is either a `VAR_DECL' node - or a constant of some sort. RELOC indicates whether forming - the initial value of DECL requires link-time relocations. */ +/* Implement TARGET_ASM_SELECT_SECTION for ELF targets. */ -static void +static section * rs6000_elf_select_section (tree decl, int reloc, unsigned HOST_WIDE_INT align) { @@ -17360,8 +17695,8 @@ rs6000_elf_select_section (tree decl, int reloc, ABI_AIX, because otherwise we end up with dynamic relocations in read-only sections. This happens for function pointers, references to vtables in typeinfo, and probably other cases. */ - default_elf_select_section_1 (decl, reloc, align, - flag_pic || DEFAULT_ABI == ABI_AIX); + return default_elf_select_section_1 (decl, reloc, align, + flag_pic || DEFAULT_ABI == ABI_AIX); } /* A C statement to build up a unique section name, expressed as a @@ -17408,7 +17743,7 @@ rs6000_elf_encode_section_info (tree decl, rtx rtl, int first) } } -static bool +bool rs6000_elf_in_small_data_p (tree decl) { if (rs6000_sdata == SDATA_NONE) @@ -17449,7 +17784,14 @@ rs6000_elf_in_small_data_p (tree decl) } #endif /* USING_ELFOS_H */ + +/* Implement TARGET_USE_BLOCKS_FOR_CONSTANT_P. */ +static bool +rs6000_use_blocks_for_constant_p (enum machine_mode mode, rtx x) +{ + return !ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (x, mode); +} /* Return a REG that occurs in ADDR with coefficient 1. ADDR can be effectively incremented by incrementing REG. @@ -17683,9 +18025,9 @@ machopic_output_stub (FILE *file, const char *symb, const char *stub) GEN_LAZY_PTR_NAME_FOR_SYMBOL (lazy_ptr_name, symb, length); if (flag_pic == 2) - machopic_picsymbol_stub1_section (); + switch_to_section (darwin_sections[machopic_picsymbol_stub1_section]); else - machopic_symbol_stub1_section (); + switch_to_section (darwin_sections[machopic_symbol_stub1_section]); if (flag_pic == 2) { @@ -17725,7 +18067,7 @@ machopic_output_stub (FILE *file, const char *symb, const char *stub) fprintf (file, "\tbctr\n"); } - machopic_lazy_symbol_ptr_section (); + switch_to_section (darwin_sections[machopic_lazy_symbol_ptr_section]); fprintf (file, "%s:\n", lazy_ptr_name); fprintf (file, "\t.indirect_symbol %s\n", symbol_name); fprintf (file, "%sdyld_stub_binding_helper\n", @@ -17786,16 +18128,6 @@ rs6000_machopic_legitimize_pic_address (rtx orig, enum machine_mode mode, return machopic_legitimize_pic_address (orig, mode, reg); } -/* This is just a placeholder to make linking work without having to - add this to the generic Darwin EXTRA_SECTIONS. If -mcall-aix is - ever needed for Darwin (not too likely!) this would have to get a - real definition. */ - -void -toc_section (void) -{ -} - /* Output a .machine directive for the Darwin assembler, and call the generic start_file routine. */ @@ -17828,6 +18160,7 @@ rs6000_darwin_file_start (void) size_t i; rs6000_file_start (); + darwin_file_start (); /* Determine the argument to -mcpu=. Default to G3 if not specified. */ for (i = 0; i < ARRAY_SIZE (rs6000_select); i++) @@ -17881,7 +18214,7 @@ rs6000_elf_asm_out_constructor (rtx symbol, int priority) section = buf; } - named_section_flags (section, SECTION_WRITE); + switch_to_section (get_section (section, SECTION_WRITE, NULL)); assemble_align (POINTER_SIZE); if (TARGET_RELOCATABLE) @@ -17910,7 +18243,7 @@ rs6000_elf_asm_out_destructor (rtx symbol, int priority) section = buf; } - named_section_flags (section, SECTION_WRITE); + switch_to_section (get_section (section, SECTION_WRITE, NULL)); assemble_align (POINTER_SIZE); if (TARGET_RELOCATABLE) @@ -18009,6 +18342,16 @@ rs6000_elf_end_indicate_exec_stack (void) #if TARGET_XCOFF static void +rs6000_xcoff_asm_output_anchor (rtx symbol) +{ + char buffer[100]; + + sprintf (buffer, "$ + " HOST_WIDE_INT_PRINT_DEC, + SYMBOL_REF_BLOCK_OFFSET (symbol)); + ASM_OUTPUT_DEF (asm_out_file, XSTR (symbol, 0), buffer); +} + +static void rs6000_xcoff_asm_globalize_label (FILE *stream, const char *name) { fputs (GLOBAL_ASM_OP, stream); @@ -18016,6 +18359,73 @@ rs6000_xcoff_asm_globalize_label (FILE *stream, const char *name) putc ('\n', stream); } +/* A get_unnamed_decl callback, used for read-only sections. PTR + points to the section string variable. */ + +static void +rs6000_xcoff_output_readonly_section_asm_op (const void *directive) +{ + fprintf (asm_out_file, "\t.csect %s[RO],3\n", + *(const char *const *) directive); +} + +/* Likewise for read-write sections. */ + +static void +rs6000_xcoff_output_readwrite_section_asm_op (const void *directive) +{ + fprintf (asm_out_file, "\t.csect %s[RW],3\n", + *(const char *const *) directive); +} + +/* A get_unnamed_section callback, used for switching to toc_section. */ + +static void +rs6000_xcoff_output_toc_section_asm_op (const void *data ATTRIBUTE_UNUSED) +{ + if (TARGET_MINIMAL_TOC) + { + /* toc_section is always selected at least once from + rs6000_xcoff_file_start, so this is guaranteed to + always be defined once and only once in each file. */ + if (!toc_initialized) + { + fputs ("\t.toc\nLCTOC..1:\n", asm_out_file); + fputs ("\t.tc toc_table[TC],toc_table[RW]\n", asm_out_file); + toc_initialized = 1; + } + fprintf (asm_out_file, "\t.csect toc_table[RW]%s\n", + (TARGET_32BIT ? "" : ",3")); + } + else + fputs ("\t.toc\n", asm_out_file); +} + +/* Implement TARGET_ASM_INIT_SECTIONS. */ + +static void +rs6000_xcoff_asm_init_sections (void) +{ + read_only_data_section + = get_unnamed_section (0, rs6000_xcoff_output_readonly_section_asm_op, + &xcoff_read_only_section_name); + + private_data_section + = get_unnamed_section (SECTION_WRITE, + rs6000_xcoff_output_readwrite_section_asm_op, + &xcoff_private_data_section_name); + + read_only_private_data_section + = get_unnamed_section (0, rs6000_xcoff_output_readonly_section_asm_op, + &xcoff_private_data_section_name); + + toc_section + = get_unnamed_section (0, rs6000_xcoff_output_toc_section_asm_op, NULL); + + readonly_data_section = read_only_data_section; + exception_section = data_section; +} + static void rs6000_xcoff_asm_named_section (const char *name, unsigned int flags, tree decl ATTRIBUTE_UNUSED) @@ -18035,23 +18445,23 @@ rs6000_xcoff_asm_named_section (const char *name, unsigned int flags, name, suffix[smclass], flags & SECTION_ENTSIZE); } -static void +static section * rs6000_xcoff_select_section (tree decl, int reloc, unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED) { if (decl_readonly_section_1 (decl, reloc, 1)) { if (TREE_PUBLIC (decl)) - read_only_data_section (); + return read_only_data_section; else - read_only_private_data_section (); + return read_only_private_data_section; } else { if (TREE_PUBLIC (decl)) - data_section (); + return data_section; else - private_data_section (); + return private_data_section; } } @@ -18080,14 +18490,14 @@ rs6000_xcoff_unique_section (tree decl, int reloc ATTRIBUTE_UNUSED) However, if this is being placed in the TOC it must be output as a toc entry. */ -static void +static section * rs6000_xcoff_select_rtx_section (enum machine_mode mode, rtx x, unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED) { if (ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (x, mode)) - toc_section (); + return toc_section; else - read_only_private_data_section (); + return read_only_private_data_section; } /* Remove any trailing [DS] or the like from the symbol name. */ @@ -18151,8 +18561,8 @@ rs6000_xcoff_file_start (void) output_quoted_string (asm_out_file, main_input_filename); fputc ('\n', asm_out_file); if (write_symbols != NO_DEBUG) - private_data_section (); - text_section (); + switch_to_section (private_data_section); + switch_to_section (text_section); if (profile_flag) fprintf (asm_out_file, "\t.extern %s\n", RS6000_MCOUNT); rs6000_file_start (); @@ -18164,9 +18574,9 @@ rs6000_xcoff_file_start (void) static void rs6000_xcoff_file_end (void) { - text_section (); + switch_to_section (text_section); fputs ("_section_.text:\n", asm_out_file); - data_section (); + switch_to_section (data_section); fputs (TARGET_32BIT ? "\t.long _section_.text\n" : "\t.llong _section_.text\n", asm_out_file); @@ -18189,19 +18599,21 @@ rs6000_rtx_costs (rtx x, int code, int outer_code, int *total) if (((outer_code == SET || outer_code == PLUS || outer_code == MINUS) - && (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I') - || CONST_OK_FOR_LETTER_P (INTVAL (x), 'L'))) + && (satisfies_constraint_I (x) + || satisfies_constraint_L (x))) || (outer_code == AND - && (CONST_OK_FOR_LETTER_P (INTVAL (x), 'K') - || (CONST_OK_FOR_LETTER_P (INTVAL (x), - mode == SImode ? 'L' : 'J')) + && (satisfies_constraint_K (x) + || (mode == SImode + ? satisfies_constraint_L (x) + : satisfies_constraint_J (x)) || mask_operand (x, mode) || (mode == DImode && mask64_operand (x, DImode)))) || ((outer_code == IOR || outer_code == XOR) - && (CONST_OK_FOR_LETTER_P (INTVAL (x), 'K') - || (CONST_OK_FOR_LETTER_P (INTVAL (x), - mode == SImode ? 'L' : 'J')))) + && (satisfies_constraint_K (x) + || (mode == SImode + ? satisfies_constraint_L (x) + : satisfies_constraint_J (x)))) || outer_code == ASHIFT || outer_code == ASHIFTRT || outer_code == LSHIFTRT @@ -18209,22 +18621,23 @@ rs6000_rtx_costs (rtx x, int code, int outer_code, int *total) || outer_code == ROTATERT || outer_code == ZERO_EXTRACT || (outer_code == MULT - && CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')) + && satisfies_constraint_I (x)) || ((outer_code == DIV || outer_code == UDIV || outer_code == MOD || outer_code == UMOD) && exact_log2 (INTVAL (x)) >= 0) || (outer_code == COMPARE - && (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I') - || CONST_OK_FOR_LETTER_P (INTVAL (x), 'K'))) + && (satisfies_constraint_I (x) + || satisfies_constraint_K (x))) || (outer_code == EQ - && (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I') - || CONST_OK_FOR_LETTER_P (INTVAL (x), 'K') - || (CONST_OK_FOR_LETTER_P (INTVAL (x), - mode == SImode ? 'L' : 'J')))) + && (satisfies_constraint_I (x) + || satisfies_constraint_K (x) + || (mode == SImode + ? satisfies_constraint_L (x) + : satisfies_constraint_J (x)))) || (outer_code == GTU - && CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')) + && satisfies_constraint_I (x)) || (outer_code == LTU - && CONST_OK_FOR_LETTER_P (INTVAL (x), 'P'))) + && satisfies_constraint_P (x))) { *total = 0; return true; @@ -18245,28 +18658,25 @@ rs6000_rtx_costs (rtx x, int code, int outer_code, int *total) /* FALLTHRU */ case CONST_DOUBLE: - if (mode == DImode - && ((outer_code == AND - && (CONST_OK_FOR_LETTER_P (INTVAL (x), 'K') - || CONST_OK_FOR_LETTER_P (INTVAL (x), 'L') - || 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 */ @@ -18338,7 +18748,7 @@ rs6000_rtx_costs (rtx x, int code, int outer_code, int *total) case MULT: if (GET_CODE (XEXP (x, 1)) == CONST_INT - && CONST_OK_FOR_LETTER_P (INTVAL (XEXP (x, 1)), 'I')) + && satisfies_constraint_I (XEXP (x, 1))) { if (INTVAL (XEXP (x, 1)) >= -256 && INTVAL (XEXP (x, 1)) <= 255) @@ -18801,6 +19211,7 @@ rs6000_function_value (tree valtype, tree func ATTRIBUTE_UNUSED) GP_ARG_RETURN + 3), GEN_INT (12)))); } + if ((INTEGRAL_TYPE_P (valtype) && TYPE_PRECISION (valtype) < BITS_PER_WORD) || POINTER_TYPE_P (valtype)) @@ -18808,7 +19219,9 @@ rs6000_function_value (tree valtype, tree func ATTRIBUTE_UNUSED) else mode = TYPE_MODE (valtype); - if (SCALAR_FLOAT_TYPE_P (valtype) && TARGET_HARD_FLOAT && TARGET_FPRS) + if (DECIMAL_FLOAT_MODE_P (mode)) + regno = GP_ARG_RETURN; + else if (SCALAR_FLOAT_TYPE_P (valtype) && TARGET_HARD_FLOAT && TARGET_FPRS) regno = FP_ARG_RETURN; else if (TREE_CODE (valtype) == COMPLEX_TYPE && targetm.calls.split_complex_arg) @@ -18847,7 +19260,9 @@ rs6000_libcall_value (enum machine_mode mode) GEN_INT (4)))); } - if (GET_MODE_CLASS (mode) == MODE_FLOAT + if (DECIMAL_FLOAT_MODE_P (mode)) + regno = GP_ARG_RETURN; + else if (SCALAR_FLOAT_MODE_P (mode) && TARGET_HARD_FLOAT && TARGET_FPRS) regno = FP_ARG_RETURN; else if (ALTIVEC_VECTOR_MODE (mode) @@ -18975,6 +19390,16 @@ rs6000_eh_return_filter_mode (void) return TARGET_32BIT ? SImode : word_mode; } +/* Target hook for scalar_mode_supported_p. */ +static bool +rs6000_scalar_mode_supported_p (enum machine_mode mode) +{ + if (DECIMAL_FLOAT_MODE_P (mode)) + return true; + else + return default_scalar_mode_supported_p (mode); +} + /* Target hook for vector_mode_supported_p. */ static bool rs6000_vector_mode_supported_p (enum machine_mode mode)