| /* Subroutines used for code generation on IBM RS/6000. |
| Copyright (C) 1991-2018 Free Software Foundation, Inc. |
| Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu) |
| |
| This file is part of GCC. |
| |
| GCC is free software; you can redistribute it and/or modify it |
| under the terms of the GNU General Public License as published |
| by the Free Software Foundation; either version 3, or (at your |
| option) any later version. |
| |
| GCC is distributed in the hope that it will be useful, but WITHOUT |
| ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
| or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public |
| License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GCC; see the file COPYING3. If not see |
| <http://www.gnu.org/licenses/>. */ |
| |
| #define IN_TARGET_CODE 1 |
| |
| #include "config.h" |
| #include "system.h" |
| #include "coretypes.h" |
| #include "backend.h" |
| #include "rtl.h" |
| #include "tree.h" |
| #include "memmodel.h" |
| #include "gimple.h" |
| #include "cfghooks.h" |
| #include "cfgloop.h" |
| #include "df.h" |
| #include "tm_p.h" |
| #include "stringpool.h" |
| #include "expmed.h" |
| #include "optabs.h" |
| #include "regs.h" |
| #include "ira.h" |
| #include "recog.h" |
| #include "cgraph.h" |
| #include "diagnostic-core.h" |
| #include "insn-attr.h" |
| #include "flags.h" |
| #include "alias.h" |
| #include "fold-const.h" |
| #include "attribs.h" |
| #include "stor-layout.h" |
| #include "calls.h" |
| #include "print-tree.h" |
| #include "varasm.h" |
| #include "explow.h" |
| #include "expr.h" |
| #include "output.h" |
| #include "dbxout.h" |
| #include "common/common-target.h" |
| #include "langhooks.h" |
| #include "reload.h" |
| #include "sched-int.h" |
| #include "gimplify.h" |
| #include "gimple-fold.h" |
| #include "gimple-iterator.h" |
| #include "gimple-ssa.h" |
| #include "gimple-walk.h" |
| #include "intl.h" |
| #include "params.h" |
| #include "tm-constrs.h" |
| #include "tree-vectorizer.h" |
| #include "target-globals.h" |
| #include "builtins.h" |
| #include "tree-vector-builder.h" |
| #include "context.h" |
| #include "tree-pass.h" |
| #include "except.h" |
| #if TARGET_XCOFF |
| #include "xcoffout.h" /* get declarations of xcoff_*_section_name */ |
| #endif |
| #if TARGET_MACHO |
| #include "gstab.h" /* for N_SLINE */ |
| #endif |
| #include "case-cfn-macros.h" |
| #include "ppc-auxv.h" |
| #include "tree-ssa-propagate.h" |
| |
| /* This file should be included last. */ |
| #include "target-def.h" |
| |
| #ifndef TARGET_NO_PROTOTYPE |
| #define TARGET_NO_PROTOTYPE 0 |
| #endif |
| |
| /* Set -mabi=ieeelongdouble on some old targets. In the future, power server |
| systems will also set long double to be IEEE 128-bit. AIX and Darwin |
| explicitly redefine TARGET_IEEEQUAD and TARGET_IEEEQUAD_DEFAULT to 0, so |
| those systems will not pick up this default. This needs to be after all |
| of the include files, so that POWERPC_LINUX and POWERPC_FREEBSD are |
| properly defined. */ |
| #ifndef TARGET_IEEEQUAD_DEFAULT |
| #if !defined (POWERPC_LINUX) && !defined (POWERPC_FREEBSD) |
| #define TARGET_IEEEQUAD_DEFAULT 1 |
| #else |
| #define TARGET_IEEEQUAD_DEFAULT 0 |
| #endif |
| #endif |
| |
| #define min(A,B) ((A) < (B) ? (A) : (B)) |
| #define max(A,B) ((A) > (B) ? (A) : (B)) |
| |
| static pad_direction rs6000_function_arg_padding (machine_mode, const_tree); |
| |
| /* Structure used to define the rs6000 stack */ |
| typedef struct rs6000_stack { |
| int reload_completed; /* stack info won't change from here on */ |
| int first_gp_reg_save; /* first callee saved GP register used */ |
| int first_fp_reg_save; /* first callee saved FP register used */ |
| int first_altivec_reg_save; /* first callee saved AltiVec register used */ |
| 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 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*: |
| r13-r31, cr, f14-f31, vrsave, v20-v31 */ |
| enum rs6000_abi abi; /* which ABI to use */ |
| int gp_save_offset; /* offset to save GP regs from initial SP */ |
| int fp_save_offset; /* offset to save FP regs from initial SP */ |
| int altivec_save_offset; /* offset to save AltiVec regs from initial SP */ |
| int lr_save_offset; /* offset to save LR from initial SP */ |
| int cr_save_offset; /* offset to save CR from initial SP */ |
| int vrsave_save_offset; /* offset to save VRSAVE from initial SP */ |
| int varargs_save_offset; /* offset to save the varargs registers */ |
| int ehrd_offset; /* offset to EH return data */ |
| int ehcr_offset; /* offset to EH CR field data */ |
| int reg_size; /* register size (4 or 8) */ |
| HOST_WIDE_INT vars_size; /* variable save area size */ |
| int parm_size; /* outgoing parameter size */ |
| int save_size; /* save area size */ |
| int fixed_size; /* fixed size of stack frame */ |
| int gp_size; /* size of saved GP registers */ |
| 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 fixed area */ |
| int vrsave_size; /* size to hold VRSAVE */ |
| int altivec_padding_size; /* size of altivec alignment padding */ |
| HOST_WIDE_INT total_size; /* total bytes allocated for stack */ |
| int savres_strategy; |
| } rs6000_stack_t; |
| |
| /* A C structure for machine-specific, per-function data. |
| This is added to the cfun structure. */ |
| typedef struct GTY(()) machine_function |
| { |
| /* Flags if __builtin_return_address (n) with n >= 1 was used. */ |
| int ra_needs_full_frame; |
| /* Flags if __builtin_return_address (0) was used. */ |
| int ra_need_lr; |
| /* Cache lr_save_p after expansion of builtin_eh_return. */ |
| int lr_save_state; |
| /* Whether we need to save the TOC to the reserved stack location in the |
| function prologue. */ |
| bool save_toc_in_prologue; |
| /* Offset from virtual_stack_vars_rtx to the start of the ABI_V4 |
| varargs save area. */ |
| HOST_WIDE_INT varargs_save_offset; |
| /* Alternative internal arg pointer for -fsplit-stack. */ |
| rtx split_stack_arg_pointer; |
| bool split_stack_argp_used; |
| /* Flag if r2 setup is needed with ELFv2 ABI. */ |
| bool r2_setup_needed; |
| /* The number of components we use for separate shrink-wrapping. */ |
| int n_components; |
| /* The components already handled by separate shrink-wrapping, which should |
| not be considered by the prologue and epilogue. */ |
| bool gpr_is_wrapped_separately[32]; |
| bool fpr_is_wrapped_separately[32]; |
| bool lr_is_wrapped_separately; |
| bool toc_is_wrapped_separately; |
| } machine_function; |
| |
| /* Support targetm.vectorize.builtin_mask_for_load. */ |
| static GTY(()) tree altivec_builtin_mask_for_load; |
| |
| /* Set to nonzero once AIX common-mode calls have been defined. */ |
| static GTY(()) int common_mode_defined; |
| |
| /* Label number of label created for -mrelocatable, to call to so we can |
| get the address of the GOT section */ |
| static int rs6000_pic_labelno; |
| |
| #ifdef USING_ELFOS_H |
| /* Counter for labels which are to be placed in .fixup. */ |
| int fixuplabelno = 0; |
| #endif |
| |
| /* Whether to use variant of AIX ABI for PowerPC64 Linux. */ |
| int dot_symbols; |
| |
| /* Specify the machine mode that pointers have. After generation of rtl, the |
| compiler makes no further distinction between pointers and any other objects |
| of this machine mode. */ |
| scalar_int_mode rs6000_pmode; |
| |
| #if TARGET_ELF |
| /* Note whether IEEE 128-bit floating point was passed or returned, either as |
| the __float128/_Float128 explicit type, or when long double is IEEE 128-bit |
| floating point. We changed the default C++ mangling for these types and we |
| may want to generate a weak alias of the old mangling (U10__float128) to the |
| new mangling (u9__ieee128). */ |
| static bool rs6000_passes_ieee128; |
| #endif |
| |
| /* Generate the manged name (i.e. U10__float128) used in GCC 8.1, and not the |
| name used in current releases (i.e. u9__ieee128). */ |
| static bool ieee128_mangling_gcc_8_1; |
| |
| /* Width in bits of a pointer. */ |
| unsigned rs6000_pointer_size; |
| |
| #ifdef HAVE_AS_GNU_ATTRIBUTE |
| # ifndef HAVE_LD_PPC_GNU_ATTR_LONG_DOUBLE |
| # define HAVE_LD_PPC_GNU_ATTR_LONG_DOUBLE 0 |
| # endif |
| /* Flag whether floating point values have been passed/returned. |
| Note that this doesn't say whether fprs are used, since the |
| Tag_GNU_Power_ABI_FP .gnu.attributes value this flag controls |
| should be set for soft-float values passed in gprs and ieee128 |
| values passed in vsx registers. */ |
| static bool rs6000_passes_float; |
| static bool rs6000_passes_long_double; |
| /* Flag whether vector values have been passed/returned. */ |
| static bool rs6000_passes_vector; |
| /* Flag whether small (<= 8 byte) structures have been returned. */ |
| static bool rs6000_returns_struct; |
| #endif |
| |
| /* Value is TRUE if register/mode pair is acceptable. */ |
| static bool rs6000_hard_regno_mode_ok_p |
| [NUM_MACHINE_MODES][FIRST_PSEUDO_REGISTER]; |
| |
| /* Maximum number of registers needed for a given register class and mode. */ |
| unsigned char rs6000_class_max_nregs[NUM_MACHINE_MODES][LIM_REG_CLASSES]; |
| |
| /* How many registers are needed for a given register and mode. */ |
| unsigned char rs6000_hard_regno_nregs[NUM_MACHINE_MODES][FIRST_PSEUDO_REGISTER]; |
| |
| /* Map register number to register class. */ |
| enum reg_class rs6000_regno_regclass[FIRST_PSEUDO_REGISTER]; |
| |
| static int dbg_cost_ctrl; |
| |
| /* Built in types. */ |
| tree rs6000_builtin_types[RS6000_BTI_MAX]; |
| tree rs6000_builtin_decls[RS6000_BUILTIN_COUNT]; |
| |
| /* Flag to say the TOC is initialized */ |
| int toc_initialized, need_toc_init; |
| char toc_label_name[10]; |
| |
| /* Cached value of rs6000_variable_issue. This is cached in |
| rs6000_variable_issue hook and returned from rs6000_sched_reorder2. */ |
| static short cached_can_issue_more; |
| |
| static GTY(()) section *read_only_data_section; |
| static GTY(()) section *private_data_section; |
| static GTY(()) section *tls_data_section; |
| static GTY(()) section *tls_private_data_section; |
| static GTY(()) section *read_only_private_data_section; |
| static GTY(()) section *sdata2_section; |
| static GTY(()) section *toc_section; |
| |
| struct builtin_description |
| { |
| const HOST_WIDE_INT mask; |
| const enum insn_code icode; |
| const char *const name; |
| const enum rs6000_builtins code; |
| }; |
| |
| /* Describe the vector unit used for modes. */ |
| enum rs6000_vector rs6000_vector_unit[NUM_MACHINE_MODES]; |
| enum rs6000_vector rs6000_vector_mem[NUM_MACHINE_MODES]; |
| |
| /* Register classes for various constraints that are based on the target |
| switches. */ |
| enum reg_class rs6000_constraints[RS6000_CONSTRAINT_MAX]; |
| |
| /* Describe the alignment of a vector. */ |
| int rs6000_vector_align[NUM_MACHINE_MODES]; |
| |
| /* Map selected modes to types for builtins. */ |
| static GTY(()) tree builtin_mode_to_type[MAX_MACHINE_MODE][2]; |
| |
| /* What modes to automatically generate reciprocal divide estimate (fre) and |
| reciprocal sqrt (frsqrte) for. */ |
| unsigned char rs6000_recip_bits[MAX_MACHINE_MODE]; |
| |
| /* Masks to determine which reciprocal esitmate instructions to generate |
| automatically. */ |
| enum rs6000_recip_mask { |
| RECIP_SF_DIV = 0x001, /* Use divide estimate */ |
| RECIP_DF_DIV = 0x002, |
| RECIP_V4SF_DIV = 0x004, |
| RECIP_V2DF_DIV = 0x008, |
| |
| RECIP_SF_RSQRT = 0x010, /* Use reciprocal sqrt estimate. */ |
| RECIP_DF_RSQRT = 0x020, |
| RECIP_V4SF_RSQRT = 0x040, |
| RECIP_V2DF_RSQRT = 0x080, |
| |
| /* Various combination of flags for -mrecip=xxx. */ |
| RECIP_NONE = 0, |
| RECIP_ALL = (RECIP_SF_DIV | RECIP_DF_DIV | RECIP_V4SF_DIV |
| | RECIP_V2DF_DIV | RECIP_SF_RSQRT | RECIP_DF_RSQRT |
| | RECIP_V4SF_RSQRT | RECIP_V2DF_RSQRT), |
| |
| RECIP_HIGH_PRECISION = RECIP_ALL, |
| |
| /* On low precision machines like the power5, don't enable double precision |
| reciprocal square root estimate, since it isn't accurate enough. */ |
| RECIP_LOW_PRECISION = (RECIP_ALL & ~(RECIP_DF_RSQRT | RECIP_V2DF_RSQRT)) |
| }; |
| |
| /* -mrecip options. */ |
| static struct |
| { |
| const char *string; /* option name */ |
| unsigned int mask; /* mask bits to set */ |
| } recip_options[] = { |
| { "all", RECIP_ALL }, |
| { "none", RECIP_NONE }, |
| { "div", (RECIP_SF_DIV | RECIP_DF_DIV | RECIP_V4SF_DIV |
| | RECIP_V2DF_DIV) }, |
| { "divf", (RECIP_SF_DIV | RECIP_V4SF_DIV) }, |
| { "divd", (RECIP_DF_DIV | RECIP_V2DF_DIV) }, |
| { "rsqrt", (RECIP_SF_RSQRT | RECIP_DF_RSQRT | RECIP_V4SF_RSQRT |
| | RECIP_V2DF_RSQRT) }, |
| { "rsqrtf", (RECIP_SF_RSQRT | RECIP_V4SF_RSQRT) }, |
| { "rsqrtd", (RECIP_DF_RSQRT | RECIP_V2DF_RSQRT) }, |
| }; |
| |
| /* Used by __builtin_cpu_is(), mapping from PLATFORM names to values. */ |
| static const struct |
| { |
| const char *cpu; |
| unsigned int cpuid; |
| } cpu_is_info[] = { |
| { "power9", PPC_PLATFORM_POWER9 }, |
| { "power8", PPC_PLATFORM_POWER8 }, |
| { "power7", PPC_PLATFORM_POWER7 }, |
| { "power6x", PPC_PLATFORM_POWER6X }, |
| { "power6", PPC_PLATFORM_POWER6 }, |
| { "power5+", PPC_PLATFORM_POWER5_PLUS }, |
| { "power5", PPC_PLATFORM_POWER5 }, |
| { "ppc970", PPC_PLATFORM_PPC970 }, |
| { "power4", PPC_PLATFORM_POWER4 }, |
| { "ppca2", PPC_PLATFORM_PPCA2 }, |
| { "ppc476", PPC_PLATFORM_PPC476 }, |
| { "ppc464", PPC_PLATFORM_PPC464 }, |
| { "ppc440", PPC_PLATFORM_PPC440 }, |
| { "ppc405", PPC_PLATFORM_PPC405 }, |
| { "ppc-cell-be", PPC_PLATFORM_CELL_BE } |
| }; |
| |
| /* Used by __builtin_cpu_supports(), mapping from HWCAP names to masks. */ |
| static const struct |
| { |
| const char *hwcap; |
| int mask; |
| unsigned int id; |
| } cpu_supports_info[] = { |
| /* AT_HWCAP masks. */ |
| { "4xxmac", PPC_FEATURE_HAS_4xxMAC, 0 }, |
| { "altivec", PPC_FEATURE_HAS_ALTIVEC, 0 }, |
| { "arch_2_05", PPC_FEATURE_ARCH_2_05, 0 }, |
| { "arch_2_06", PPC_FEATURE_ARCH_2_06, 0 }, |
| { "archpmu", PPC_FEATURE_PERFMON_COMPAT, 0 }, |
| { "booke", PPC_FEATURE_BOOKE, 0 }, |
| { "cellbe", PPC_FEATURE_CELL_BE, 0 }, |
| { "dfp", PPC_FEATURE_HAS_DFP, 0 }, |
| { "efpdouble", PPC_FEATURE_HAS_EFP_DOUBLE, 0 }, |
| { "efpsingle", PPC_FEATURE_HAS_EFP_SINGLE, 0 }, |
| { "fpu", PPC_FEATURE_HAS_FPU, 0 }, |
| { "ic_snoop", PPC_FEATURE_ICACHE_SNOOP, 0 }, |
| { "mmu", PPC_FEATURE_HAS_MMU, 0 }, |
| { "notb", PPC_FEATURE_NO_TB, 0 }, |
| { "pa6t", PPC_FEATURE_PA6T, 0 }, |
| { "power4", PPC_FEATURE_POWER4, 0 }, |
| { "power5", PPC_FEATURE_POWER5, 0 }, |
| { "power5+", PPC_FEATURE_POWER5_PLUS, 0 }, |
| { "power6x", PPC_FEATURE_POWER6_EXT, 0 }, |
| { "ppc32", PPC_FEATURE_32, 0 }, |
| { "ppc601", PPC_FEATURE_601_INSTR, 0 }, |
| { "ppc64", PPC_FEATURE_64, 0 }, |
| { "ppcle", PPC_FEATURE_PPC_LE, 0 }, |
| { "smt", PPC_FEATURE_SMT, 0 }, |
| { "spe", PPC_FEATURE_HAS_SPE, 0 }, |
| { "true_le", PPC_FEATURE_TRUE_LE, 0 }, |
| { "ucache", PPC_FEATURE_UNIFIED_CACHE, 0 }, |
| { "vsx", PPC_FEATURE_HAS_VSX, 0 }, |
| |
| /* AT_HWCAP2 masks. */ |
| { "arch_2_07", PPC_FEATURE2_ARCH_2_07, 1 }, |
| { "dscr", PPC_FEATURE2_HAS_DSCR, 1 }, |
| { "ebb", PPC_FEATURE2_HAS_EBB, 1 }, |
| { "htm", PPC_FEATURE2_HAS_HTM, 1 }, |
| { "htm-nosc", PPC_FEATURE2_HTM_NOSC, 1 }, |
| { "htm-no-suspend", PPC_FEATURE2_HTM_NO_SUSPEND, 1 }, |
| { "isel", PPC_FEATURE2_HAS_ISEL, 1 }, |
| { "tar", PPC_FEATURE2_HAS_TAR, 1 }, |
| { "vcrypto", PPC_FEATURE2_HAS_VEC_CRYPTO, 1 }, |
| { "arch_3_00", PPC_FEATURE2_ARCH_3_00, 1 }, |
| { "ieee128", PPC_FEATURE2_HAS_IEEE128, 1 }, |
| { "darn", PPC_FEATURE2_DARN, 1 }, |
| { "scv", PPC_FEATURE2_SCV, 1 } |
| }; |
| |
| /* On PowerPC, we have a limited number of target clones that we care about |
| which means we can use an array to hold the options, rather than having more |
| elaborate data structures to identify each possible variation. Order the |
| clones from the default to the highest ISA. */ |
| enum { |
| CLONE_DEFAULT = 0, /* default clone. */ |
| CLONE_ISA_2_05, /* ISA 2.05 (power6). */ |
| CLONE_ISA_2_06, /* ISA 2.06 (power7). */ |
| CLONE_ISA_2_07, /* ISA 2.07 (power8). */ |
| CLONE_ISA_3_00, /* ISA 3.00 (power9). */ |
| CLONE_MAX |
| }; |
| |
| /* Map compiler ISA bits into HWCAP names. */ |
| struct clone_map { |
| HOST_WIDE_INT isa_mask; /* rs6000_isa mask */ |
| const char *name; /* name to use in __builtin_cpu_supports. */ |
| }; |
| |
| static const struct clone_map rs6000_clone_map[CLONE_MAX] = { |
| { 0, "" }, /* Default options. */ |
| { OPTION_MASK_CMPB, "arch_2_05" }, /* ISA 2.05 (power6). */ |
| { OPTION_MASK_POPCNTD, "arch_2_06" }, /* ISA 2.06 (power7). */ |
| { OPTION_MASK_P8_VECTOR, "arch_2_07" }, /* ISA 2.07 (power8). */ |
| { OPTION_MASK_P9_VECTOR, "arch_3_00" }, /* ISA 3.00 (power9). */ |
| }; |
| |
| |
| /* Newer LIBCs explicitly export this symbol to declare that they provide |
| the AT_PLATFORM and AT_HWCAP/AT_HWCAP2 values in the TCB. We emit a |
| reference to this symbol whenever we expand a CPU builtin, so that |
| we never link against an old LIBC. */ |
| const char *tcb_verification_symbol = "__parse_hwcap_and_convert_at_platform"; |
| |
| /* True if we have expanded a CPU builtin. */ |
| bool cpu_builtin_p; |
| |
| /* Pointer to function (in rs6000-c.c) that can define or undefine target |
| macros that have changed. Languages that don't support the preprocessor |
| don't link in rs6000-c.c, so we can't call it directly. */ |
| void (*rs6000_target_modify_macros_ptr) (bool, HOST_WIDE_INT, HOST_WIDE_INT); |
| |
| /* Simplfy register classes into simpler classifications. We assume |
| GPR_REG_TYPE - FPR_REG_TYPE are ordered so that we can use a simple range |
| check for standard register classes (gpr/floating/altivec/vsx) and |
| floating/vector classes (float/altivec/vsx). */ |
| |
| enum rs6000_reg_type { |
| NO_REG_TYPE, |
| PSEUDO_REG_TYPE, |
| GPR_REG_TYPE, |
| VSX_REG_TYPE, |
| ALTIVEC_REG_TYPE, |
| FPR_REG_TYPE, |
| SPR_REG_TYPE, |
| CR_REG_TYPE |
| }; |
| |
| /* Map register class to register type. */ |
| static enum rs6000_reg_type reg_class_to_reg_type[N_REG_CLASSES]; |
| |
| /* First/last register type for the 'normal' register types (i.e. general |
| purpose, floating point, altivec, and VSX registers). */ |
| #define IS_STD_REG_TYPE(RTYPE) IN_RANGE(RTYPE, GPR_REG_TYPE, FPR_REG_TYPE) |
| |
| #define IS_FP_VECT_REG_TYPE(RTYPE) IN_RANGE(RTYPE, VSX_REG_TYPE, FPR_REG_TYPE) |
| |
| |
| /* Register classes we care about in secondary reload or go if legitimate |
| address. We only need to worry about GPR, FPR, and Altivec registers here, |
| along an ANY field that is the OR of the 3 register classes. */ |
| |
| enum rs6000_reload_reg_type { |
| RELOAD_REG_GPR, /* General purpose registers. */ |
| RELOAD_REG_FPR, /* Traditional floating point regs. */ |
| RELOAD_REG_VMX, /* Altivec (VMX) registers. */ |
| RELOAD_REG_ANY, /* OR of GPR, FPR, Altivec masks. */ |
| N_RELOAD_REG |
| }; |
| |
| /* For setting up register classes, loop through the 3 register classes mapping |
| into real registers, and skip the ANY class, which is just an OR of the |
| bits. */ |
| #define FIRST_RELOAD_REG_CLASS RELOAD_REG_GPR |
| #define LAST_RELOAD_REG_CLASS RELOAD_REG_VMX |
| |
| /* Map reload register type to a register in the register class. */ |
| struct reload_reg_map_type { |
| const char *name; /* Register class name. */ |
| int reg; /* Register in the register class. */ |
| }; |
| |
| static const struct reload_reg_map_type reload_reg_map[N_RELOAD_REG] = { |
| { "Gpr", FIRST_GPR_REGNO }, /* RELOAD_REG_GPR. */ |
| { "Fpr", FIRST_FPR_REGNO }, /* RELOAD_REG_FPR. */ |
| { "VMX", FIRST_ALTIVEC_REGNO }, /* RELOAD_REG_VMX. */ |
| { "Any", -1 }, /* RELOAD_REG_ANY. */ |
| }; |
| |
| /* Mask bits for each register class, indexed per mode. Historically the |
| compiler has been more restrictive which types can do PRE_MODIFY instead of |
| PRE_INC and PRE_DEC, so keep track of sepaate bits for these two. */ |
| typedef unsigned char addr_mask_type; |
| |
| #define RELOAD_REG_VALID 0x01 /* Mode valid in register.. */ |
| #define RELOAD_REG_MULTIPLE 0x02 /* Mode takes multiple registers. */ |
| #define RELOAD_REG_INDEXED 0x04 /* Reg+reg addressing. */ |
| #define RELOAD_REG_OFFSET 0x08 /* Reg+offset addressing. */ |
| #define RELOAD_REG_PRE_INCDEC 0x10 /* PRE_INC/PRE_DEC valid. */ |
| #define RELOAD_REG_PRE_MODIFY 0x20 /* PRE_MODIFY valid. */ |
| #define RELOAD_REG_AND_M16 0x40 /* AND -16 addressing. */ |
| #define RELOAD_REG_QUAD_OFFSET 0x80 /* quad offset is limited. */ |
| |
| /* Register type masks based on the type, of valid addressing modes. */ |
| struct rs6000_reg_addr { |
| enum insn_code reload_load; /* INSN to reload for loading. */ |
| enum insn_code reload_store; /* INSN to reload for storing. */ |
| enum insn_code reload_fpr_gpr; /* INSN to move from FPR to GPR. */ |
| enum insn_code reload_gpr_vsx; /* INSN to move from GPR to VSX. */ |
| enum insn_code reload_vsx_gpr; /* INSN to move from VSX to GPR. */ |
| enum insn_code fusion_gpr_ld; /* INSN for fusing gpr ADDIS/loads. */ |
| /* INSNs for fusing addi with loads |
| or stores for each reg. class. */ |
| enum insn_code fusion_addi_ld[(int)N_RELOAD_REG]; |
| enum insn_code fusion_addi_st[(int)N_RELOAD_REG]; |
| /* INSNs for fusing addis with loads |
| or stores for each reg. class. */ |
| enum insn_code fusion_addis_ld[(int)N_RELOAD_REG]; |
| enum insn_code fusion_addis_st[(int)N_RELOAD_REG]; |
| addr_mask_type addr_mask[(int)N_RELOAD_REG]; /* Valid address masks. */ |
| bool scalar_in_vmx_p; /* Scalar value can go in VMX. */ |
| bool fused_toc; /* Mode supports TOC fusion. */ |
| }; |
| |
| static struct rs6000_reg_addr reg_addr[NUM_MACHINE_MODES]; |
| |
| /* Helper function to say whether a mode supports PRE_INC or PRE_DEC. */ |
| static inline bool |
| mode_supports_pre_incdec_p (machine_mode mode) |
| { |
| return ((reg_addr[mode].addr_mask[RELOAD_REG_ANY] & RELOAD_REG_PRE_INCDEC) |
| != 0); |
| } |
| |
| /* Helper function to say whether a mode supports PRE_MODIFY. */ |
| static inline bool |
| mode_supports_pre_modify_p (machine_mode mode) |
| { |
| return ((reg_addr[mode].addr_mask[RELOAD_REG_ANY] & RELOAD_REG_PRE_MODIFY) |
| != 0); |
| } |
| |
| /* Given that there exists at least one variable that is set (produced) |
| by OUT_INSN and read (consumed) by IN_INSN, return true iff |
| IN_INSN represents one or more memory store operations and none of |
| the variables set by OUT_INSN is used by IN_INSN as the address of a |
| store operation. If either IN_INSN or OUT_INSN does not represent |
| a "single" RTL SET expression (as loosely defined by the |
| implementation of the single_set function) or a PARALLEL with only |
| SETs, CLOBBERs, and USEs inside, this function returns false. |
| |
| This rs6000-specific version of store_data_bypass_p checks for |
| certain conditions that result in assertion failures (and internal |
| compiler errors) in the generic store_data_bypass_p function and |
| returns false rather than calling store_data_bypass_p if one of the |
| problematic conditions is detected. */ |
| |
| int |
| rs6000_store_data_bypass_p (rtx_insn *out_insn, rtx_insn *in_insn) |
| { |
| rtx out_set, in_set; |
| rtx out_pat, in_pat; |
| rtx out_exp, in_exp; |
| int i, j; |
| |
| in_set = single_set (in_insn); |
| if (in_set) |
| { |
| if (MEM_P (SET_DEST (in_set))) |
| { |
| out_set = single_set (out_insn); |
| if (!out_set) |
| { |
| out_pat = PATTERN (out_insn); |
| if (GET_CODE (out_pat) == PARALLEL) |
| { |
| for (i = 0; i < XVECLEN (out_pat, 0); i++) |
| { |
| out_exp = XVECEXP (out_pat, 0, i); |
| if ((GET_CODE (out_exp) == CLOBBER) |
| || (GET_CODE (out_exp) == USE)) |
| continue; |
| else if (GET_CODE (out_exp) != SET) |
| return false; |
| } |
| } |
| } |
| } |
| } |
| else |
| { |
| in_pat = PATTERN (in_insn); |
| if (GET_CODE (in_pat) != PARALLEL) |
| return false; |
| |
| for (i = 0; i < XVECLEN (in_pat, 0); i++) |
| { |
| in_exp = XVECEXP (in_pat, 0, i); |
| if ((GET_CODE (in_exp) == CLOBBER) || (GET_CODE (in_exp) == USE)) |
| continue; |
| else if (GET_CODE (in_exp) != SET) |
| return false; |
| |
| if (MEM_P (SET_DEST (in_exp))) |
| { |
| out_set = single_set (out_insn); |
| if (!out_set) |
| { |
| out_pat = PATTERN (out_insn); |
| if (GET_CODE (out_pat) != PARALLEL) |
| return false; |
| for (j = 0; j < XVECLEN (out_pat, 0); j++) |
| { |
| out_exp = XVECEXP (out_pat, 0, j); |
| if ((GET_CODE (out_exp) == CLOBBER) |
| || (GET_CODE (out_exp) == USE)) |
| continue; |
| else if (GET_CODE (out_exp) != SET) |
| return false; |
| } |
| } |
| } |
| } |
| } |
| return store_data_bypass_p (out_insn, in_insn); |
| } |
| |
| /* Return true if we have D-form addressing in altivec registers. */ |
| static inline bool |
| mode_supports_vmx_dform (machine_mode mode) |
| { |
| return ((reg_addr[mode].addr_mask[RELOAD_REG_VMX] & RELOAD_REG_OFFSET) != 0); |
| } |
| |
| /* Return true if we have D-form addressing in VSX registers. This addressing |
| is more limited than normal d-form addressing in that the offset must be |
| aligned on a 16-byte boundary. */ |
| static inline bool |
| mode_supports_vsx_dform_quad (machine_mode mode) |
| { |
| return ((reg_addr[mode].addr_mask[RELOAD_REG_ANY] & RELOAD_REG_QUAD_OFFSET) |
| != 0); |
| } |
| |
| |
| /* Processor costs (relative to an add) */ |
| |
| const struct processor_costs *rs6000_cost; |
| |
| /* Instruction size costs on 32bit processors. */ |
| static const |
| struct processor_costs size32_cost = { |
| COSTS_N_INSNS (1), /* mulsi */ |
| COSTS_N_INSNS (1), /* mulsi_const */ |
| COSTS_N_INSNS (1), /* mulsi_const9 */ |
| COSTS_N_INSNS (1), /* muldi */ |
| COSTS_N_INSNS (1), /* divsi */ |
| COSTS_N_INSNS (1), /* divdi */ |
| COSTS_N_INSNS (1), /* fp */ |
| COSTS_N_INSNS (1), /* dmul */ |
| COSTS_N_INSNS (1), /* sdiv */ |
| COSTS_N_INSNS (1), /* ddiv */ |
| 32, /* cache line size */ |
| 0, /* l1 cache */ |
| 0, /* l2 cache */ |
| 0, /* streams */ |
| 0, /* SF->DF convert */ |
| }; |
| |
| /* Instruction size costs on 64bit processors. */ |
| static const |
| struct processor_costs size64_cost = { |
| COSTS_N_INSNS (1), /* mulsi */ |
| COSTS_N_INSNS (1), /* mulsi_const */ |
| COSTS_N_INSNS (1), /* mulsi_const9 */ |
| COSTS_N_INSNS (1), /* muldi */ |
| COSTS_N_INSNS (1), /* divsi */ |
| COSTS_N_INSNS (1), /* divdi */ |
| COSTS_N_INSNS (1), /* fp */ |
| COSTS_N_INSNS (1), /* dmul */ |
| COSTS_N_INSNS (1), /* sdiv */ |
| COSTS_N_INSNS (1), /* ddiv */ |
| 128, /* cache line size */ |
| 0, /* l1 cache */ |
| 0, /* l2 cache */ |
| 0, /* streams */ |
| 0, /* SF->DF convert */ |
| }; |
| |
| /* Instruction costs on RS64A processors. */ |
| static const |
| struct processor_costs rs64a_cost = { |
| COSTS_N_INSNS (20), /* mulsi */ |
| COSTS_N_INSNS (12), /* mulsi_const */ |
| COSTS_N_INSNS (8), /* mulsi_const9 */ |
| COSTS_N_INSNS (34), /* muldi */ |
| COSTS_N_INSNS (65), /* divsi */ |
| COSTS_N_INSNS (67), /* divdi */ |
| COSTS_N_INSNS (4), /* fp */ |
| COSTS_N_INSNS (4), /* dmul */ |
| COSTS_N_INSNS (31), /* sdiv */ |
| COSTS_N_INSNS (31), /* ddiv */ |
| 128, /* cache line size */ |
| 128, /* l1 cache */ |
| 2048, /* l2 cache */ |
| 1, /* streams */ |
| 0, /* SF->DF convert */ |
| }; |
| |
| /* Instruction costs on MPCCORE processors. */ |
| static const |
| struct processor_costs mpccore_cost = { |
| COSTS_N_INSNS (2), /* mulsi */ |
| COSTS_N_INSNS (2), /* mulsi_const */ |
| COSTS_N_INSNS (2), /* mulsi_const9 */ |
| COSTS_N_INSNS (2), /* muldi */ |
| COSTS_N_INSNS (6), /* divsi */ |
| COSTS_N_INSNS (6), /* divdi */ |
| COSTS_N_INSNS (4), /* fp */ |
| COSTS_N_INSNS (5), /* dmul */ |
| COSTS_N_INSNS (10), /* sdiv */ |
| COSTS_N_INSNS (17), /* ddiv */ |
| 32, /* cache line size */ |
| 4, /* l1 cache */ |
| 16, /* l2 cache */ |
| 1, /* streams */ |
| 0, /* SF->DF convert */ |
| }; |
| |
| /* Instruction costs on PPC403 processors. */ |
| static const |
| struct processor_costs ppc403_cost = { |
| COSTS_N_INSNS (4), /* mulsi */ |
| COSTS_N_INSNS (4), /* mulsi_const */ |
| COSTS_N_INSNS (4), /* mulsi_const9 */ |
| COSTS_N_INSNS (4), /* muldi */ |
| COSTS_N_INSNS (33), /* divsi */ |
| COSTS_N_INSNS (33), /* divdi */ |
| COSTS_N_INSNS (11), /* fp */ |
| COSTS_N_INSNS (11), /* dmul */ |
| COSTS_N_INSNS (11), /* sdiv */ |
| COSTS_N_INSNS (11), /* ddiv */ |
| 32, /* cache line size */ |
| 4, /* l1 cache */ |
| 16, /* l2 cache */ |
| 1, /* streams */ |
| 0, /* SF->DF convert */ |
| }; |
| |
| /* Instruction costs on PPC405 processors. */ |
| static const |
| struct processor_costs ppc405_cost = { |
| COSTS_N_INSNS (5), /* mulsi */ |
| COSTS_N_INSNS (4), /* mulsi_const */ |
| COSTS_N_INSNS (3), /* mulsi_const9 */ |
| COSTS_N_INSNS (5), /* muldi */ |
| COSTS_N_INSNS (35), /* divsi */ |
| COSTS_N_INSNS (35), /* divdi */ |
| COSTS_N_INSNS (11), /* fp */ |
| COSTS_N_INSNS (11), /* dmul */ |
| COSTS_N_INSNS (11), /* sdiv */ |
| COSTS_N_INSNS (11), /* ddiv */ |
| 32, /* cache line size */ |
| 16, /* l1 cache */ |
| 128, /* l2 cache */ |
| 1, /* streams */ |
| 0, /* SF->DF convert */ |
| }; |
| |
| /* Instruction costs on PPC440 processors. */ |
| static const |
| struct processor_costs ppc440_cost = { |
| COSTS_N_INSNS (3), /* mulsi */ |
| COSTS_N_INSNS (2), /* mulsi_const */ |
| COSTS_N_INSNS (2), /* mulsi_const9 */ |
| COSTS_N_INSNS (3), /* muldi */ |
| COSTS_N_INSNS (34), /* divsi */ |
| COSTS_N_INSNS (34), /* divdi */ |
| COSTS_N_INSNS (5), /* fp */ |
| COSTS_N_INSNS (5), /* dmul */ |
| COSTS_N_INSNS (19), /* sdiv */ |
| COSTS_N_INSNS (33), /* ddiv */ |
| 32, /* cache line size */ |
| 32, /* l1 cache */ |
| 256, /* l2 cache */ |
| 1, /* streams */ |
| 0, /* SF->DF convert */ |
| }; |
| |
| /* Instruction costs on PPC476 processors. */ |
| static const |
| struct processor_costs ppc476_cost = { |
| COSTS_N_INSNS (4), /* mulsi */ |
| COSTS_N_INSNS (4), /* mulsi_const */ |
| COSTS_N_INSNS (4), /* mulsi_const9 */ |
| COSTS_N_INSNS (4), /* muldi */ |
| COSTS_N_INSNS (11), /* divsi */ |
| COSTS_N_INSNS (11), /* divdi */ |
| COSTS_N_INSNS (6), /* fp */ |
| COSTS_N_INSNS (6), /* dmul */ |
| COSTS_N_INSNS (19), /* sdiv */ |
| COSTS_N_INSNS (33), /* ddiv */ |
| 32, /* l1 cache line size */ |
| 32, /* l1 cache */ |
| 512, /* l2 cache */ |
| 1, /* streams */ |
| 0, /* SF->DF convert */ |
| }; |
| |
| /* Instruction costs on PPC601 processors. */ |
| static const |
| struct processor_costs ppc601_cost = { |
| COSTS_N_INSNS (5), /* mulsi */ |
| COSTS_N_INSNS (5), /* mulsi_const */ |
| COSTS_N_INSNS (5), /* mulsi_const9 */ |
| COSTS_N_INSNS (5), /* muldi */ |
| COSTS_N_INSNS (36), /* divsi */ |
| COSTS_N_INSNS (36), /* divdi */ |
| COSTS_N_INSNS (4), /* fp */ |
| COSTS_N_INSNS (5), /* dmul */ |
| COSTS_N_INSNS (17), /* sdiv */ |
| COSTS_N_INSNS (31), /* ddiv */ |
| 32, /* cache line size */ |
| 32, /* l1 cache */ |
| 256, /* l2 cache */ |
| 1, /* streams */ |
| 0, /* SF->DF convert */ |
| }; |
| |
| /* Instruction costs on PPC603 processors. */ |
| static const |
| struct processor_costs ppc603_cost = { |
| COSTS_N_INSNS (5), /* mulsi */ |
| COSTS_N_INSNS (3), /* mulsi_const */ |
| COSTS_N_INSNS (2), /* mulsi_const9 */ |
| COSTS_N_INSNS (5), /* muldi */ |
| COSTS_N_INSNS (37), /* divsi */ |
| COSTS_N_INSNS (37), /* divdi */ |
| COSTS_N_INSNS (3), /* fp */ |
| COSTS_N_INSNS (4), /* dmul */ |
| COSTS_N_INSNS (18), /* sdiv */ |
| COSTS_N_INSNS (33), /* ddiv */ |
| 32, /* cache line size */ |
| 8, /* l1 cache */ |
| 64, /* l2 cache */ |
| 1, /* streams */ |
| 0, /* SF->DF convert */ |
| }; |
| |
| /* Instruction costs on PPC604 processors. */ |
| static const |
| struct processor_costs ppc604_cost = { |
| COSTS_N_INSNS (4), /* mulsi */ |
| COSTS_N_INSNS (4), /* mulsi_const */ |
| COSTS_N_INSNS (4), /* mulsi_const9 */ |
| COSTS_N_INSNS (4), /* muldi */ |
| COSTS_N_INSNS (20), /* divsi */ |
| COSTS_N_INSNS (20), /* divdi */ |
| COSTS_N_INSNS (3), /* fp */ |
| COSTS_N_INSNS (3), /* dmul */ |
| COSTS_N_INSNS (18), /* sdiv */ |
| COSTS_N_INSNS (32), /* ddiv */ |
| 32, /* cache line size */ |
| 16, /* l1 cache */ |
| 512, /* l2 cache */ |
| 1, /* streams */ |
| 0, /* SF->DF convert */ |
| }; |
| |
| /* Instruction costs on PPC604e processors. */ |
| static const |
| struct processor_costs ppc604e_cost = { |
| COSTS_N_INSNS (2), /* mulsi */ |
| COSTS_N_INSNS (2), /* mulsi_const */ |
| COSTS_N_INSNS (2), /* mulsi_const9 */ |
| COSTS_N_INSNS (2), /* muldi */ |
| COSTS_N_INSNS (20), /* divsi */ |
| COSTS_N_INSNS (20), /* divdi */ |
| COSTS_N_INSNS (3), /* fp */ |
| COSTS_N_INSNS (3), /* dmul */ |
| COSTS_N_INSNS (18), /* sdiv */ |
| COSTS_N_INSNS (32), /* ddiv */ |
| 32, /* cache line size */ |
| 32, /* l1 cache */ |
| 1024, /* l2 cache */ |
| 1, /* streams */ |
| 0, /* SF->DF convert */ |
| }; |
| |
| /* Instruction costs on PPC620 processors. */ |
| static const |
| struct processor_costs ppc620_cost = { |
| COSTS_N_INSNS (5), /* mulsi */ |
| COSTS_N_INSNS (4), /* mulsi_const */ |
| COSTS_N_INSNS (3), /* mulsi_const9 */ |
| COSTS_N_INSNS (7), /* muldi */ |
| COSTS_N_INSNS (21), /* divsi */ |
| COSTS_N_INSNS (37), /* divdi */ |
| COSTS_N_INSNS (3), /* fp */ |
| COSTS_N_INSNS (3), /* dmul */ |
| COSTS_N_INSNS (18), /* sdiv */ |
| COSTS_N_INSNS (32), /* ddiv */ |
| 128, /* cache line size */ |
| 32, /* l1 cache */ |
| 1024, /* l2 cache */ |
| 1, /* streams */ |
| 0, /* SF->DF convert */ |
| }; |
| |
| /* Instruction costs on PPC630 processors. */ |
| static const |
| struct processor_costs ppc630_cost = { |
| COSTS_N_INSNS (5), /* mulsi */ |
| COSTS_N_INSNS (4), /* mulsi_const */ |
| COSTS_N_INSNS (3), /* mulsi_const9 */ |
| COSTS_N_INSNS (7), /* muldi */ |
| COSTS_N_INSNS (21), /* divsi */ |
| COSTS_N_INSNS (37), /* divdi */ |
| COSTS_N_INSNS (3), /* fp */ |
| COSTS_N_INSNS (3), /* dmul */ |
| COSTS_N_INSNS (17), /* sdiv */ |
| COSTS_N_INSNS (21), /* ddiv */ |
| 128, /* cache line size */ |
| 64, /* l1 cache */ |
| 1024, /* l2 cache */ |
| 1, /* streams */ |
| 0, /* SF->DF convert */ |
| }; |
| |
| /* Instruction costs on Cell processor. */ |
| /* COSTS_N_INSNS (1) ~ one add. */ |
| static const |
| struct processor_costs ppccell_cost = { |
| COSTS_N_INSNS (9/2)+2, /* mulsi */ |
| COSTS_N_INSNS (6/2), /* mulsi_const */ |
| COSTS_N_INSNS (6/2), /* mulsi_const9 */ |
| COSTS_N_INSNS (15/2)+2, /* muldi */ |
| COSTS_N_INSNS (38/2), /* divsi */ |
| COSTS_N_INSNS (70/2), /* divdi */ |
| COSTS_N_INSNS (10/2), /* fp */ |
| COSTS_N_INSNS (10/2), /* dmul */ |
| COSTS_N_INSNS (74/2), /* sdiv */ |
| COSTS_N_INSNS (74/2), /* ddiv */ |
| 128, /* cache line size */ |
| 32, /* l1 cache */ |
| 512, /* l2 cache */ |
| 6, /* streams */ |
| 0, /* SF->DF convert */ |
| }; |
| |
| /* Instruction costs on PPC750 and PPC7400 processors. */ |
| static const |
| struct processor_costs ppc750_cost = { |
| COSTS_N_INSNS (5), /* mulsi */ |
| COSTS_N_INSNS (3), /* mulsi_const */ |
| COSTS_N_INSNS (2), /* mulsi_const9 */ |
| COSTS_N_INSNS (5), /* muldi */ |
| COSTS_N_INSNS (17), /* divsi */ |
| COSTS_N_INSNS (17), /* divdi */ |
| COSTS_N_INSNS (3), /* fp */ |
| COSTS_N_INSNS (3), /* dmul */ |
| COSTS_N_INSNS (17), /* sdiv */ |
| COSTS_N_INSNS (31), /* ddiv */ |
| 32, /* cache line size */ |
| 32, /* l1 cache */ |
| 512, /* l2 cache */ |
| 1, /* streams */ |
| 0, /* SF->DF convert */ |
| }; |
| |
| /* Instruction costs on PPC7450 processors. */ |
| static const |
| struct processor_costs ppc7450_cost = { |
| COSTS_N_INSNS (4), /* mulsi */ |
| COSTS_N_INSNS (3), /* mulsi_const */ |
| COSTS_N_INSNS (3), /* mulsi_const9 */ |
| COSTS_N_INSNS (4), /* muldi */ |
| COSTS_N_INSNS (23), /* divsi */ |
| COSTS_N_INSNS (23), /* divdi */ |
| COSTS_N_INSNS (5), /* fp */ |
| COSTS_N_INSNS (5), /* dmul */ |
| COSTS_N_INSNS (21), /* sdiv */ |
| COSTS_N_INSNS (35), /* ddiv */ |
| 32, /* cache line size */ |
| 32, /* l1 cache */ |
| 1024, /* l2 cache */ |
| 1, /* streams */ |
| 0, /* SF->DF convert */ |
| }; |
| |
| /* Instruction costs on PPC8540 processors. */ |
| static const |
| struct processor_costs ppc8540_cost = { |
| COSTS_N_INSNS (4), /* mulsi */ |
| COSTS_N_INSNS (4), /* mulsi_const */ |
| COSTS_N_INSNS (4), /* mulsi_const9 */ |
| COSTS_N_INSNS (4), /* muldi */ |
| COSTS_N_INSNS (19), /* divsi */ |
| COSTS_N_INSNS (19), /* divdi */ |
| COSTS_N_INSNS (4), /* fp */ |
| COSTS_N_INSNS (4), /* dmul */ |
| COSTS_N_INSNS (29), /* sdiv */ |
| COSTS_N_INSNS (29), /* ddiv */ |
| 32, /* cache line size */ |
| 32, /* l1 cache */ |
| 256, /* l2 cache */ |
| 1, /* prefetch streams /*/ |
| 0, /* SF->DF convert */ |
| }; |
| |
| /* Instruction costs on E300C2 and E300C3 cores. */ |
| static const |
| struct processor_costs ppce300c2c3_cost = { |
| COSTS_N_INSNS (4), /* mulsi */ |
| COSTS_N_INSNS (4), /* mulsi_const */ |
| COSTS_N_INSNS (4), /* mulsi_const9 */ |
| COSTS_N_INSNS (4), /* muldi */ |
| COSTS_N_INSNS (19), /* divsi */ |
| COSTS_N_INSNS (19), /* divdi */ |
| COSTS_N_INSNS (3), /* fp */ |
| COSTS_N_INSNS (4), /* dmul */ |
| COSTS_N_INSNS (18), /* sdiv */ |
| COSTS_N_INSNS (33), /* ddiv */ |
| 32, |
| 16, /* l1 cache */ |
| 16, /* l2 cache */ |
| 1, /* prefetch streams /*/ |
| 0, /* SF->DF convert */ |
| }; |
| |
| /* Instruction costs on PPCE500MC processors. */ |
| static const |
| struct processor_costs ppce500mc_cost = { |
| COSTS_N_INSNS (4), /* mulsi */ |
| COSTS_N_INSNS (4), /* mulsi_const */ |
| COSTS_N_INSNS (4), /* mulsi_const9 */ |
| COSTS_N_INSNS (4), /* muldi */ |
| COSTS_N_INSNS (14), /* divsi */ |
| COSTS_N_INSNS (14), /* divdi */ |
| COSTS_N_INSNS (8), /* fp */ |
| COSTS_N_INSNS (10), /* dmul */ |
| COSTS_N_INSNS (36), /* sdiv */ |
| COSTS_N_INSNS (66), /* ddiv */ |
| 64, /* cache line size */ |
| 32, /* l1 cache */ |
| 128, /* l2 cache */ |
| 1, /* prefetch streams /*/ |
| 0, /* SF->DF convert */ |
| }; |
| |
| /* Instruction costs on PPCE500MC64 processors. */ |
| static const |
| struct processor_costs ppce500mc64_cost = { |
| COSTS_N_INSNS (4), /* mulsi */ |
| COSTS_N_INSNS (4), /* mulsi_const */ |
| COSTS_N_INSNS (4), /* mulsi_const9 */ |
| COSTS_N_INSNS (4), /* muldi */ |
| COSTS_N_INSNS (14), /* divsi */ |
| COSTS_N_INSNS (14), /* divdi */ |
| COSTS_N_INSNS (4), /* fp */ |
| COSTS_N_INSNS (10), /* dmul */ |
| COSTS_N_INSNS (36), /* sdiv */ |
| COSTS_N_INSNS (66), /* ddiv */ |
| 64, /* cache line size */ |
| 32, /* l1 cache */ |
| 128, /* l2 cache */ |
| 1, /* prefetch streams /*/ |
| 0, /* SF->DF convert */ |
| }; |
| |
| /* Instruction costs on PPCE5500 processors. */ |
| static const |
| struct processor_costs ppce5500_cost = { |
| COSTS_N_INSNS (5), /* mulsi */ |
| COSTS_N_INSNS (5), /* mulsi_const */ |
| COSTS_N_INSNS (4), /* mulsi_const9 */ |
| COSTS_N_INSNS (5), /* muldi */ |
| COSTS_N_INSNS (14), /* divsi */ |
| COSTS_N_INSNS (14), /* divdi */ |
| COSTS_N_INSNS (7), /* fp */ |
| COSTS_N_INSNS (10), /* dmul */ |
| COSTS_N_INSNS (36), /* sdiv */ |
| COSTS_N_INSNS (66), /* ddiv */ |
| 64, /* cache line size */ |
| 32, /* l1 cache */ |
| 128, /* l2 cache */ |
| 1, /* prefetch streams /*/ |
| 0, /* SF->DF convert */ |
| }; |
| |
| /* Instruction costs on PPCE6500 processors. */ |
| static const |
| struct processor_costs ppce6500_cost = { |
| COSTS_N_INSNS (5), /* mulsi */ |
| COSTS_N_INSNS (5), /* mulsi_const */ |
| COSTS_N_INSNS (4), /* mulsi_const9 */ |
| COSTS_N_INSNS (5), /* muldi */ |
| COSTS_N_INSNS (14), /* divsi */ |
| COSTS_N_INSNS (14), /* divdi */ |
| COSTS_N_INSNS (7), /* fp */ |
| COSTS_N_INSNS (10), /* dmul */ |
| COSTS_N_INSNS (36), /* sdiv */ |
| COSTS_N_INSNS (66), /* ddiv */ |
| 64, /* cache line size */ |
| 32, /* l1 cache */ |
| 128, /* l2 cache */ |
| 1, /* prefetch streams /*/ |
| 0, /* SF->DF convert */ |
| }; |
| |
| /* Instruction costs on AppliedMicro Titan processors. */ |
| static const |
| struct processor_costs titan_cost = { |
| COSTS_N_INSNS (5), /* mulsi */ |
| COSTS_N_INSNS (5), /* mulsi_const */ |
| COSTS_N_INSNS (5), /* mulsi_const9 */ |
| COSTS_N_INSNS (5), /* muldi */ |
| COSTS_N_INSNS (18), /* divsi */ |
| COSTS_N_INSNS (18), /* divdi */ |
| COSTS_N_INSNS (10), /* fp */ |
| COSTS_N_INSNS (10), /* dmul */ |
| COSTS_N_INSNS (46), /* sdiv */ |
| COSTS_N_INSNS (72), /* ddiv */ |
| 32, /* cache line size */ |
| 32, /* l1 cache */ |
| 512, /* l2 cache */ |
| 1, /* prefetch streams /*/ |
| 0, /* SF->DF convert */ |
| }; |
| |
| /* Instruction costs on POWER4 and POWER5 processors. */ |
| static const |
| struct processor_costs power4_cost = { |
| COSTS_N_INSNS (3), /* mulsi */ |
| COSTS_N_INSNS (2), /* mulsi_const */ |
| COSTS_N_INSNS (2), /* mulsi_const9 */ |
| COSTS_N_INSNS (4), /* muldi */ |
| COSTS_N_INSNS (18), /* divsi */ |
| COSTS_N_INSNS (34), /* divdi */ |
| COSTS_N_INSNS (3), /* fp */ |
| COSTS_N_INSNS (3), /* dmul */ |
| COSTS_N_INSNS (17), /* sdiv */ |
| COSTS_N_INSNS (17), /* ddiv */ |
| 128, /* cache line size */ |
| 32, /* l1 cache */ |
| 1024, /* l2 cache */ |
| 8, /* prefetch streams /*/ |
| 0, /* SF->DF convert */ |
| }; |
| |
| /* Instruction costs on POWER6 processors. */ |
| static const |
| struct processor_costs power6_cost = { |
| COSTS_N_INSNS (8), /* mulsi */ |
| COSTS_N_INSNS (8), /* mulsi_const */ |
| COSTS_N_INSNS (8), /* mulsi_const9 */ |
| COSTS_N_INSNS (8), /* muldi */ |
| COSTS_N_INSNS (22), /* divsi */ |
| COSTS_N_INSNS (28), /* divdi */ |
| COSTS_N_INSNS (3), /* fp */ |
| COSTS_N_INSNS (3), /* dmul */ |
| COSTS_N_INSNS (13), /* sdiv */ |
| COSTS_N_INSNS (16), /* ddiv */ |
| 128, /* cache line size */ |
| 64, /* l1 cache */ |
| 2048, /* l2 cache */ |
| 16, /* prefetch streams */ |
| 0, /* SF->DF convert */ |
| }; |
| |
| /* Instruction costs on POWER7 processors. */ |
| static const |
| struct processor_costs power7_cost = { |
| COSTS_N_INSNS (2), /* mulsi */ |
| COSTS_N_INSNS (2), /* mulsi_const */ |
| COSTS_N_INSNS (2), /* mulsi_const9 */ |
| COSTS_N_INSNS (2), /* muldi */ |
| COSTS_N_INSNS (18), /* divsi */ |
| COSTS_N_INSNS (34), /* divdi */ |
| COSTS_N_INSNS (3), /* fp */ |
| COSTS_N_INSNS (3), /* dmul */ |
| COSTS_N_INSNS (13), /* sdiv */ |
| COSTS_N_INSNS (16), /* ddiv */ |
| 128, /* cache line size */ |
| 32, /* l1 cache */ |
| 256, /* l2 cache */ |
| 12, /* prefetch streams */ |
| COSTS_N_INSNS (3), /* SF->DF convert */ |
| }; |
| |
| /* Instruction costs on POWER8 processors. */ |
| static const |
| struct processor_costs power8_cost = { |
| COSTS_N_INSNS (3), /* mulsi */ |
| COSTS_N_INSNS (3), /* mulsi_const */ |
| COSTS_N_INSNS (3), /* mulsi_const9 */ |
| COSTS_N_INSNS (3), /* muldi */ |
| COSTS_N_INSNS (19), /* divsi */ |
| COSTS_N_INSNS (35), /* divdi */ |
| COSTS_N_INSNS (3), /* fp */ |
| COSTS_N_INSNS (3), /* dmul */ |
| COSTS_N_INSNS (14), /* sdiv */ |
| COSTS_N_INSNS (17), /* ddiv */ |
| 128, /* cache line size */ |
| 32, /* l1 cache */ |
| 256, /* l2 cache */ |
| 12, /* prefetch streams */ |
| COSTS_N_INSNS (3), /* SF->DF convert */ |
| }; |
| |
| /* Instruction costs on POWER9 processors. */ |
| static const |
| struct processor_costs power9_cost = { |
| COSTS_N_INSNS (3), /* mulsi */ |
| COSTS_N_INSNS (3), /* mulsi_const */ |
| COSTS_N_INSNS (3), /* mulsi_const9 */ |
| COSTS_N_INSNS (3), /* muldi */ |
| COSTS_N_INSNS (8), /* divsi */ |
| COSTS_N_INSNS (12), /* divdi */ |
| COSTS_N_INSNS (3), /* fp */ |
| COSTS_N_INSNS (3), /* dmul */ |
| COSTS_N_INSNS (13), /* sdiv */ |
| COSTS_N_INSNS (18), /* ddiv */ |
| 128, /* cache line size */ |
| 32, /* l1 cache */ |
| 512, /* l2 cache */ |
| 8, /* prefetch streams */ |
| COSTS_N_INSNS (3), /* SF->DF convert */ |
| }; |
| |
| /* Instruction costs on POWER A2 processors. */ |
| static const |
| struct processor_costs ppca2_cost = { |
| COSTS_N_INSNS (16), /* mulsi */ |
| COSTS_N_INSNS (16), /* mulsi_const */ |
| COSTS_N_INSNS (16), /* mulsi_const9 */ |
| COSTS_N_INSNS (16), /* muldi */ |
| COSTS_N_INSNS (22), /* divsi */ |
| COSTS_N_INSNS (28), /* divdi */ |
| COSTS_N_INSNS (3), /* fp */ |
| COSTS_N_INSNS (3), /* dmul */ |
| COSTS_N_INSNS (59), /* sdiv */ |
| COSTS_N_INSNS (72), /* ddiv */ |
| 64, |
| 16, /* l1 cache */ |
| 2048, /* l2 cache */ |
| 16, /* prefetch streams */ |
| 0, /* SF->DF convert */ |
| }; |
| |
| |
| /* Table that classifies rs6000 builtin functions (pure, const, etc.). */ |
| #undef RS6000_BUILTIN_0 |
| #undef RS6000_BUILTIN_1 |
| #undef RS6000_BUILTIN_2 |
| #undef RS6000_BUILTIN_3 |
| #undef RS6000_BUILTIN_A |
| #undef RS6000_BUILTIN_D |
| #undef RS6000_BUILTIN_H |
| #undef RS6000_BUILTIN_P |
| #undef RS6000_BUILTIN_Q |
| #undef RS6000_BUILTIN_X |
| |
| #define RS6000_BUILTIN_0(ENUM, NAME, MASK, ATTR, ICODE) \ |
| { NAME, ICODE, MASK, ATTR }, |
| |
| #define RS6000_BUILTIN_1(ENUM, NAME, MASK, ATTR, ICODE) \ |
| { NAME, ICODE, MASK, ATTR }, |
| |
| #define RS6000_BUILTIN_2(ENUM, NAME, MASK, ATTR, ICODE) \ |
| { NAME, ICODE, MASK, ATTR }, |
| |
| #define RS6000_BUILTIN_3(ENUM, NAME, MASK, ATTR, ICODE) \ |
| { NAME, ICODE, MASK, ATTR }, |
| |
| #define RS6000_BUILTIN_A(ENUM, NAME, MASK, ATTR, ICODE) \ |
| { NAME, ICODE, MASK, ATTR }, |
| |
| #define RS6000_BUILTIN_D(ENUM, NAME, MASK, ATTR, ICODE) \ |
| { NAME, ICODE, MASK, ATTR }, |
| |
| #define RS6000_BUILTIN_H(ENUM, NAME, MASK, ATTR, ICODE) \ |
| { NAME, ICODE, MASK, ATTR }, |
| |
| #define RS6000_BUILTIN_P(ENUM, NAME, MASK, ATTR, ICODE) \ |
| { NAME, ICODE, MASK, ATTR }, |
| |
| #define RS6000_BUILTIN_Q(ENUM, NAME, MASK, ATTR, ICODE) \ |
| { NAME, ICODE, MASK, ATTR }, |
| |
| #define RS6000_BUILTIN_X(ENUM, NAME, MASK, ATTR, ICODE) \ |
| { NAME, ICODE, MASK, ATTR }, |
| |
| struct rs6000_builtin_info_type { |
| const char *name; |
| const enum insn_code icode; |
| const HOST_WIDE_INT mask; |
| const unsigned attr; |
| }; |
| |
| static const struct rs6000_builtin_info_type rs6000_builtin_info[] = |
| { |
| #include "rs6000-builtin.def" |
| }; |
| |
| #undef RS6000_BUILTIN_0 |
| #undef RS6000_BUILTIN_1 |
| #undef RS6000_BUILTIN_2 |
| #undef RS6000_BUILTIN_3 |
| #undef RS6000_BUILTIN_A |
| #undef RS6000_BUILTIN_D |
| #undef RS6000_BUILTIN_H |
| #undef RS6000_BUILTIN_P |
| #undef RS6000_BUILTIN_Q |
| #undef RS6000_BUILTIN_X |
| |
| /* Support for -mveclibabi=<xxx> to control which vector library to use. */ |
| static tree (*rs6000_veclib_handler) (combined_fn, tree, tree); |
| |
| |
| static bool rs6000_debug_legitimate_address_p (machine_mode, rtx, bool); |
| static struct machine_function * rs6000_init_machine_status (void); |
| 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 tree rs6000_handle_struct_attribute (tree *, tree, tree, int, bool *); |
| static tree rs6000_builtin_vectorized_libmass (combined_fn, tree, tree); |
| static void rs6000_emit_set_long_const (rtx, HOST_WIDE_INT); |
| static int rs6000_memory_move_cost (machine_mode, reg_class_t, bool); |
| static bool rs6000_debug_rtx_costs (rtx, machine_mode, int, int, int *, bool); |
| static int rs6000_debug_address_cost (rtx, machine_mode, addr_space_t, |
| bool); |
| static int rs6000_debug_adjust_cost (rtx_insn *, int, rtx_insn *, int, |
| unsigned int); |
| static bool is_microcoded_insn (rtx_insn *); |
| static bool is_nonpipeline_insn (rtx_insn *); |
| static bool is_cracked_insn (rtx_insn *); |
| static bool is_load_insn (rtx, rtx *); |
| static bool is_store_insn (rtx, rtx *); |
| static bool set_to_load_agen (rtx_insn *,rtx_insn *); |
| static bool insn_terminates_group_p (rtx_insn *, enum group_termination); |
| static bool insn_must_be_first_in_group (rtx_insn *); |
| static bool insn_must_be_last_in_group (rtx_insn *); |
| static void altivec_init_builtins (void); |
| static tree builtin_function_type (machine_mode, machine_mode, |
| machine_mode, machine_mode, |
| enum rs6000_builtins, const char *name); |
| static void rs6000_common_init_builtins (void); |
| static void paired_init_builtins (void); |
| static rtx paired_expand_predicate_builtin (enum insn_code, tree, rtx); |
| static void htm_init_builtins (void); |
| static rs6000_stack_t *rs6000_stack_info (void); |
| static void is_altivec_return_reg (rtx, void *); |
| int easy_vector_constant (rtx, machine_mode); |
| static rtx rs6000_debug_legitimize_address (rtx, rtx, machine_mode); |
| static rtx rs6000_legitimize_tls_address (rtx, enum tls_model); |
| static rtx rs6000_darwin64_record_arg (CUMULATIVE_ARGS *, const_tree, |
| bool, bool); |
| #if TARGET_MACHO |
| static void macho_branch_islands (void); |
| #endif |
| static rtx rs6000_legitimize_reload_address (rtx, machine_mode, int, int, |
| int, int *); |
| static rtx rs6000_debug_legitimize_reload_address (rtx, machine_mode, int, |
| int, int, int *); |
| static bool rs6000_mode_dependent_address (const_rtx); |
| static bool rs6000_debug_mode_dependent_address (const_rtx); |
| static bool rs6000_offsettable_memref_p (rtx, machine_mode, bool); |
| static enum reg_class rs6000_secondary_reload_class (enum reg_class, |
| machine_mode, rtx); |
| static enum reg_class rs6000_debug_secondary_reload_class (enum reg_class, |
| machine_mode, |
| rtx); |
| static enum reg_class rs6000_preferred_reload_class (rtx, enum reg_class); |
| static enum reg_class rs6000_debug_preferred_reload_class (rtx, |
| enum reg_class); |
| static bool rs6000_debug_secondary_memory_needed (machine_mode, |
| reg_class_t, |
| reg_class_t); |
| static bool rs6000_debug_can_change_mode_class (machine_mode, |
| machine_mode, |
| reg_class_t); |
| static bool rs6000_save_toc_in_prologue_p (void); |
| static rtx rs6000_internal_arg_pointer (void); |
| |
| rtx (*rs6000_legitimize_reload_address_ptr) (rtx, machine_mode, int, int, |
| int, int *) |
| = rs6000_legitimize_reload_address; |
| |
| static bool (*rs6000_mode_dependent_address_ptr) (const_rtx) |
| = rs6000_mode_dependent_address; |
| |
| enum reg_class (*rs6000_secondary_reload_class_ptr) (enum reg_class, |
| machine_mode, rtx) |
| = rs6000_secondary_reload_class; |
| |
| enum reg_class (*rs6000_preferred_reload_class_ptr) (rtx, enum reg_class) |
| = rs6000_preferred_reload_class; |
| |
| const int INSN_NOT_AVAILABLE = -1; |
| |
| static void rs6000_print_isa_options (FILE *, int, const char *, |
| HOST_WIDE_INT); |
| static void rs6000_print_builtin_options (FILE *, int, const char *, |
| HOST_WIDE_INT); |
| static HOST_WIDE_INT rs6000_disable_incompatible_switches (void); |
| |
| static enum rs6000_reg_type register_to_reg_type (rtx, bool *); |
| static bool rs6000_secondary_reload_move (enum rs6000_reg_type, |
| enum rs6000_reg_type, |
| machine_mode, |
| secondary_reload_info *, |
| bool); |
| rtl_opt_pass *make_pass_analyze_swaps (gcc::context*); |
| static bool rs6000_keep_leaf_when_profiled () __attribute__ ((unused)); |
| static tree rs6000_fold_builtin (tree, int, tree *, bool); |
| |
| /* Hash table stuff for keeping track of TOC entries. */ |
| |
| struct GTY((for_user)) toc_hash_struct |
| { |
| /* `key' will satisfy CONSTANT_P; in fact, it will satisfy |
| ASM_OUTPUT_SPECIAL_POOL_ENTRY_P. */ |
| rtx key; |
| machine_mode key_mode; |
| int labelno; |
| }; |
| |
| struct toc_hasher : ggc_ptr_hash<toc_hash_struct> |
| { |
| static hashval_t hash (toc_hash_struct *); |
| static bool equal (toc_hash_struct *, toc_hash_struct *); |
| }; |
| |
| static GTY (()) hash_table<toc_hasher> *toc_hash_table; |
| |
| /* Hash table to keep track of the argument types for builtin functions. */ |
| |
| struct GTY((for_user)) builtin_hash_struct |
| { |
| tree type; |
| machine_mode mode[4]; /* return value + 3 arguments. */ |
| unsigned char uns_p[4]; /* and whether the types are unsigned. */ |
| }; |
| |
| struct builtin_hasher : ggc_ptr_hash<builtin_hash_struct> |
| { |
| static hashval_t hash (builtin_hash_struct *); |
| static bool equal (builtin_hash_struct *, builtin_hash_struct *); |
| }; |
| |
| static GTY (()) hash_table<builtin_hasher> *builtin_hash_table; |
| |
| |
| /* Default register names. */ |
| char rs6000_reg_names[][8] = |
| { |
| "0", "1", "2", "3", "4", "5", "6", "7", |
| "8", "9", "10", "11", "12", "13", "14", "15", |
| "16", "17", "18", "19", "20", "21", "22", "23", |
| "24", "25", "26", "27", "28", "29", "30", "31", |
| "0", "1", "2", "3", "4", "5", "6", "7", |
| "8", "9", "10", "11", "12", "13", "14", "15", |
| "16", "17", "18", "19", "20", "21", "22", "23", |
| "24", "25", "26", "27", "28", "29", "30", "31", |
| "mq", "lr", "ctr","ap", |
| "0", "1", "2", "3", "4", "5", "6", "7", |
| "ca", |
| /* AltiVec registers. */ |
| "0", "1", "2", "3", "4", "5", "6", "7", |
| "8", "9", "10", "11", "12", "13", "14", "15", |
| "16", "17", "18", "19", "20", "21", "22", "23", |
| "24", "25", "26", "27", "28", "29", "30", "31", |
| "vrsave", "vscr", |
| /* Soft frame pointer. */ |
| "sfp", |
| /* HTM SPR registers. */ |
| "tfhar", "tfiar", "texasr" |
| }; |
| |
| #ifdef TARGET_REGNAMES |
| static const char alt_reg_names[][8] = |
| { |
| "%r0", "%r1", "%r2", "%r3", "%r4", "%r5", "%r6", "%r7", |
| "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", |
| "%r16", "%r17", "%r18", "%r19", "%r20", "%r21", "%r22", "%r23", |
| "%r24", "%r25", "%r26", "%r27", "%r28", "%r29", "%r30", "%r31", |
| "%f0", "%f1", "%f2", "%f3", "%f4", "%f5", "%f6", "%f7", |
| "%f8", "%f9", "%f10", "%f11", "%f12", "%f13", "%f14", "%f15", |
| "%f16", "%f17", "%f18", "%f19", "%f20", "%f21", "%f22", "%f23", |
| "%f24", "%f25", "%f26", "%f27", "%f28", "%f29", "%f30", "%f31", |
| "mq", "lr", "ctr", "ap", |
| "%cr0", "%cr1", "%cr2", "%cr3", "%cr4", "%cr5", "%cr6", "%cr7", |
| "ca", |
| /* AltiVec registers. */ |
| "%v0", "%v1", "%v2", "%v3", "%v4", "%v5", "%v6", "%v7", |
| "%v8", "%v9", "%v10", "%v11", "%v12", "%v13", "%v14", "%v15", |
| "%v16", "%v17", "%v18", "%v19", "%v20", "%v21", "%v22", "%v23", |
| "%v24", "%v25", "%v26", "%v27", "%v28", "%v29", "%v30", "%v31", |
| "vrsave", "vscr", |
| /* Soft frame pointer. */ |
| "sfp", |
| /* HTM SPR registers. */ |
| "tfhar", "tfiar", "texasr" |
| }; |
| #endif |
| |
| /* Table of valid machine attributes. */ |
| |
| static const struct attribute_spec rs6000_attribute_table[] = |
| { |
| /* { name, min_len, max_len, decl_req, type_req, fn_type_req, |
| affects_type_identity, handler, exclude } */ |
| { "altivec", 1, 1, false, true, false, false, |
| rs6000_handle_altivec_attribute, NULL }, |
| { "longcall", 0, 0, false, true, true, false, |
| rs6000_handle_longcall_attribute, NULL }, |
| { "shortcall", 0, 0, false, true, true, false, |
| rs6000_handle_longcall_attribute, NULL }, |
| { "ms_struct", 0, 0, false, false, false, false, |
| rs6000_handle_struct_attribute, NULL }, |
| { "gcc_struct", 0, 0, false, false, false, false, |
| rs6000_handle_struct_attribute, NULL }, |
| #ifdef SUBTARGET_ATTRIBUTE_TABLE |
| SUBTARGET_ATTRIBUTE_TABLE, |
| #endif |
| { NULL, 0, 0, false, false, false, false, NULL, NULL } |
| }; |
| |
| #ifndef TARGET_PROFILE_KERNEL |
| #define TARGET_PROFILE_KERNEL 0 |
| #endif |
| |
| /* The VRSAVE bitmask puts bit %v0 as the most significant bit. */ |
| #define ALTIVEC_REG_BIT(REGNO) (0x80000000 >> ((REGNO) - FIRST_ALTIVEC_REGNO)) |
| |
| /* Initialize the GCC target structure. */ |
| #undef TARGET_ATTRIBUTE_TABLE |
| #define TARGET_ATTRIBUTE_TABLE rs6000_attribute_table |
| #undef TARGET_SET_DEFAULT_TYPE_ATTRIBUTES |
| #define TARGET_SET_DEFAULT_TYPE_ATTRIBUTES rs6000_set_default_type_attributes |
| #undef TARGET_ATTRIBUTE_TAKES_IDENTIFIER_P |
| #define TARGET_ATTRIBUTE_TAKES_IDENTIFIER_P rs6000_attribute_takes_identifier_p |
| |
| #undef TARGET_ASM_ALIGNED_DI_OP |
| #define TARGET_ASM_ALIGNED_DI_OP DOUBLE_INT_ASM_OP |
| |
| /* Default unaligned ops are only provided for ELF. Find the ops needed |
| for non-ELF systems. */ |
| #ifndef OBJECT_FORMAT_ELF |
| #if TARGET_XCOFF |
| /* For XCOFF. rs6000_assemble_integer will handle unaligned DIs on |
| 64-bit targets. */ |
| #undef TARGET_ASM_UNALIGNED_HI_OP |
| #define TARGET_ASM_UNALIGNED_HI_OP "\t.vbyte\t2," |
| #undef TARGET_ASM_UNALIGNED_SI_OP |
| #define TARGET_ASM_UNALIGNED_SI_OP "\t.vbyte\t4," |
| #undef TARGET_ASM_UNALIGNED_DI_OP |
| #define TARGET_ASM_UNALIGNED_DI_OP "\t.vbyte\t8," |
| #else |
| /* For Darwin. */ |
| #undef TARGET_ASM_UNALIGNED_HI_OP |
| #define TARGET_ASM_UNALIGNED_HI_OP "\t.short\t" |
| #undef TARGET_ASM_UNALIGNED_SI_OP |
| #define TARGET_ASM_UNALIGNED_SI_OP "\t.long\t" |
| #undef TARGET_ASM_UNALIGNED_DI_OP |
| #define TARGET_ASM_UNALIGNED_DI_OP "\t.quad\t" |
| #undef TARGET_ASM_ALIGNED_DI_OP |
| #define TARGET_ASM_ALIGNED_DI_OP "\t.quad\t" |
| #endif |
| #endif |
| |
| /* This hook deals with fixups for relocatable code and DI-mode objects |
| in 64-bit code. */ |
| #undef TARGET_ASM_INTEGER |
| #define TARGET_ASM_INTEGER rs6000_assemble_integer |
| |
| #if defined (HAVE_GAS_HIDDEN) && !TARGET_MACHO |
| #undef TARGET_ASM_ASSEMBLE_VISIBILITY |
| #define TARGET_ASM_ASSEMBLE_VISIBILITY rs6000_assemble_visibility |
| #endif |
| |
| #undef TARGET_SET_UP_BY_PROLOGUE |
| #define TARGET_SET_UP_BY_PROLOGUE rs6000_set_up_by_prologue |
| |
| #undef TARGET_SHRINK_WRAP_GET_SEPARATE_COMPONENTS |
| #define TARGET_SHRINK_WRAP_GET_SEPARATE_COMPONENTS rs6000_get_separate_components |
| #undef TARGET_SHRINK_WRAP_COMPONENTS_FOR_BB |
| #define TARGET_SHRINK_WRAP_COMPONENTS_FOR_BB rs6000_components_for_bb |
| #undef TARGET_SHRINK_WRAP_DISQUALIFY_COMPONENTS |
| #define TARGET_SHRINK_WRAP_DISQUALIFY_COMPONENTS rs6000_disqualify_components |
| #undef TARGET_SHRINK_WRAP_EMIT_PROLOGUE_COMPONENTS |
| #define TARGET_SHRINK_WRAP_EMIT_PROLOGUE_COMPONENTS rs6000_emit_prologue_components |
| #undef TARGET_SHRINK_WRAP_EMIT_EPILOGUE_COMPONENTS |
| #define TARGET_SHRINK_WRAP_EMIT_EPILOGUE_COMPONENTS rs6000_emit_epilogue_components |
| #undef TARGET_SHRINK_WRAP_SET_HANDLED_COMPONENTS |
| #define TARGET_SHRINK_WRAP_SET_HANDLED_COMPONENTS rs6000_set_handled_components |
| |
| #undef TARGET_EXTRA_LIVE_ON_ENTRY |
| #define TARGET_EXTRA_LIVE_ON_ENTRY rs6000_live_on_entry |
| |
| #undef TARGET_INTERNAL_ARG_POINTER |
| #define TARGET_INTERNAL_ARG_POINTER rs6000_internal_arg_pointer |
| |
| #undef TARGET_HAVE_TLS |
| #define TARGET_HAVE_TLS HAVE_AS_TLS |
| |
| #undef TARGET_CANNOT_FORCE_CONST_MEM |
| #define TARGET_CANNOT_FORCE_CONST_MEM rs6000_cannot_force_const_mem |
| |
| #undef TARGET_DELEGITIMIZE_ADDRESS |
| #define TARGET_DELEGITIMIZE_ADDRESS rs6000_delegitimize_address |
| |
| #undef TARGET_CONST_NOT_OK_FOR_DEBUG_P |
| #define TARGET_CONST_NOT_OK_FOR_DEBUG_P rs6000_const_not_ok_for_debug_p |
| |
| #undef TARGET_LEGITIMATE_COMBINED_INSN |
| #define TARGET_LEGITIMATE_COMBINED_INSN rs6000_legitimate_combined_insn |
| |
| #undef TARGET_ASM_FUNCTION_PROLOGUE |
| #define TARGET_ASM_FUNCTION_PROLOGUE rs6000_output_function_prologue |
| #undef TARGET_ASM_FUNCTION_EPILOGUE |
| #define TARGET_ASM_FUNCTION_EPILOGUE rs6000_output_function_epilogue |
| |
| #undef TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA |
| #define TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA rs6000_output_addr_const_extra |
| |
| #undef TARGET_LEGITIMIZE_ADDRESS |
| #define TARGET_LEGITIMIZE_ADDRESS rs6000_legitimize_address |
| |
| #undef TARGET_SCHED_VARIABLE_ISSUE |
| #define TARGET_SCHED_VARIABLE_ISSUE rs6000_variable_issue |
| |
| #undef TARGET_SCHED_ISSUE_RATE |
| #define TARGET_SCHED_ISSUE_RATE rs6000_issue_rate |
| #undef TARGET_SCHED_ADJUST_COST |
| #define TARGET_SCHED_ADJUST_COST rs6000_adjust_cost |
| #undef TARGET_SCHED_ADJUST_PRIORITY |
| #define TARGET_SCHED_ADJUST_PRIORITY rs6000_adjust_priority |
| #undef TARGET_SCHED_IS_COSTLY_DEPENDENCE |
| #define TARGET_SCHED_IS_COSTLY_DEPENDENCE rs6000_is_costly_dependence |
| #undef TARGET_SCHED_INIT |
| #define TARGET_SCHED_INIT rs6000_sched_init |
| #undef TARGET_SCHED_FINISH |
| #define TARGET_SCHED_FINISH rs6000_sched_finish |
| #undef TARGET_SCHED_REORDER |
| #define TARGET_SCHED_REORDER rs6000_sched_reorder |
| #undef TARGET_SCHED_REORDER2 |
| #define TARGET_SCHED_REORDER2 rs6000_sched_reorder2 |
| |
| #undef TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD |
| #define TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD rs6000_use_sched_lookahead |
| |
| #undef TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD_GUARD |
| #define TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD_GUARD rs6000_use_sched_lookahead_guard |
| |
| #undef TARGET_SCHED_ALLOC_SCHED_CONTEXT |
| #define TARGET_SCHED_ALLOC_SCHED_CONTEXT rs6000_alloc_sched_context |
| #undef TARGET_SCHED_INIT_SCHED_CONTEXT |
| #define TARGET_SCHED_INIT_SCHED_CONTEXT rs6000_init_sched_context |
| #undef TARGET_SCHED_SET_SCHED_CONTEXT |
| #define TARGET_SCHED_SET_SCHED_CONTEXT rs6000_set_sched_context |
| #undef TARGET_SCHED_FREE_SCHED_CONTEXT |
| #define TARGET_SCHED_FREE_SCHED_CONTEXT rs6000_free_sched_context |
| |
| #undef TARGET_SCHED_CAN_SPECULATE_INSN |
| #define TARGET_SCHED_CAN_SPECULATE_INSN rs6000_sched_can_speculate_insn |
| |
| #undef TARGET_VECTORIZE_BUILTIN_MASK_FOR_LOAD |
| #define TARGET_VECTORIZE_BUILTIN_MASK_FOR_LOAD rs6000_builtin_mask_for_load |
| #undef TARGET_VECTORIZE_SUPPORT_VECTOR_MISALIGNMENT |
| #define TARGET_VECTORIZE_SUPPORT_VECTOR_MISALIGNMENT \ |
| rs6000_builtin_support_vector_misalignment |
| #undef TARGET_VECTORIZE_VECTOR_ALIGNMENT_REACHABLE |
| #define TARGET_VECTORIZE_VECTOR_ALIGNMENT_REACHABLE rs6000_vector_alignment_reachable |
| #undef TARGET_VECTORIZE_BUILTIN_VECTORIZATION_COST |
| #define TARGET_VECTORIZE_BUILTIN_VECTORIZATION_COST \ |
| rs6000_builtin_vectorization_cost |
| #undef TARGET_VECTORIZE_PREFERRED_SIMD_MODE |
| #define TARGET_VECTORIZE_PREFERRED_SIMD_MODE \ |
| rs6000_preferred_simd_mode |
| #undef TARGET_VECTORIZE_INIT_COST |
| #define TARGET_VECTORIZE_INIT_COST rs6000_init_cost |
| #undef TARGET_VECTORIZE_ADD_STMT_COST |
| #define TARGET_VECTORIZE_ADD_STMT_COST rs6000_add_stmt_cost |
| #undef TARGET_VECTORIZE_FINISH_COST |
| #define TARGET_VECTORIZE_FINISH_COST rs6000_finish_cost |
| #undef TARGET_VECTORIZE_DESTROY_COST_DATA |
| #define TARGET_VECTORIZE_DESTROY_COST_DATA rs6000_destroy_cost_data |
| |
| #undef TARGET_INIT_BUILTINS |
| #define TARGET_INIT_BUILTINS rs6000_init_builtins |
| #undef TARGET_BUILTIN_DECL |
| #define TARGET_BUILTIN_DECL rs6000_builtin_decl |
| |
| #undef TARGET_FOLD_BUILTIN |
| #define TARGET_FOLD_BUILTIN rs6000_fold_builtin |
| #undef TARGET_GIMPLE_FOLD_BUILTIN |
| #define TARGET_GIMPLE_FOLD_BUILTIN rs6000_gimple_fold_builtin |
| |
| #undef TARGET_EXPAND_BUILTIN |
| #define TARGET_EXPAND_BUILTIN rs6000_expand_builtin |
| |
| #undef TARGET_MANGLE_TYPE |
| #define TARGET_MANGLE_TYPE rs6000_mangle_type |
| |
| #undef TARGET_INIT_LIBFUNCS |
| #define TARGET_INIT_LIBFUNCS rs6000_init_libfuncs |
| |
| #if TARGET_MACHO |
| #undef TARGET_BINDS_LOCAL_P |
| #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 |
| |
| #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK |
| #define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_const_tree_hwi_hwi_const_tree_true |
| |
| #undef TARGET_FUNCTION_OK_FOR_SIBCALL |
| #define TARGET_FUNCTION_OK_FOR_SIBCALL rs6000_function_ok_for_sibcall |
| |
| #undef TARGET_REGISTER_MOVE_COST |
| #define TARGET_REGISTER_MOVE_COST rs6000_register_move_cost |
| #undef TARGET_MEMORY_MOVE_COST |
| #define TARGET_MEMORY_MOVE_COST rs6000_memory_move_cost |
| #undef TARGET_CANNOT_COPY_INSN_P |
| #define TARGET_CANNOT_COPY_INSN_P rs6000_cannot_copy_insn_p |
| #undef TARGET_RTX_COSTS |
| #define TARGET_RTX_COSTS rs6000_rtx_costs |
| #undef TARGET_ADDRESS_COST |
| #define TARGET_ADDRESS_COST hook_int_rtx_mode_as_bool_0 |
| #undef TARGET_INSN_COST |
| #define TARGET_INSN_COST rs6000_insn_cost |
| |
| #undef TARGET_INIT_DWARF_REG_SIZES_EXTRA |
| #define TARGET_INIT_DWARF_REG_SIZES_EXTRA rs6000_init_dwarf_reg_sizes_extra |
| |
| #undef TARGET_PROMOTE_FUNCTION_MODE |
| #define TARGET_PROMOTE_FUNCTION_MODE rs6000_promote_function_mode |
| |
| #undef TARGET_RETURN_IN_MEMORY |
| #define TARGET_RETURN_IN_MEMORY rs6000_return_in_memory |
| |
| #undef TARGET_RETURN_IN_MSB |
| #define TARGET_RETURN_IN_MSB rs6000_return_in_msb |
| |
| #undef TARGET_SETUP_INCOMING_VARARGS |
| #define TARGET_SETUP_INCOMING_VARARGS setup_incoming_varargs |
| |
| /* Always strict argument naming on rs6000. */ |
| #undef TARGET_STRICT_ARGUMENT_NAMING |
| #define TARGET_STRICT_ARGUMENT_NAMING hook_bool_CUMULATIVE_ARGS_true |
| #undef TARGET_PRETEND_OUTGOING_VARARGS_NAMED |
| #define TARGET_PRETEND_OUTGOING_VARARGS_NAMED hook_bool_CUMULATIVE_ARGS_true |
| #undef TARGET_SPLIT_COMPLEX_ARG |
| #define TARGET_SPLIT_COMPLEX_ARG hook_bool_const_tree_true |
| #undef TARGET_MUST_PASS_IN_STACK |
| #define TARGET_MUST_PASS_IN_STACK rs6000_must_pass_in_stack |
| #undef TARGET_PASS_BY_REFERENCE |
| #define TARGET_PASS_BY_REFERENCE rs6000_pass_by_reference |
| #undef TARGET_ARG_PARTIAL_BYTES |
| #define TARGET_ARG_PARTIAL_BYTES rs6000_arg_partial_bytes |
| #undef TARGET_FUNCTION_ARG_ADVANCE |
| #define TARGET_FUNCTION_ARG_ADVANCE rs6000_function_arg_advance |
| #undef TARGET_FUNCTION_ARG |
| #define TARGET_FUNCTION_ARG rs6000_function_arg |
| #undef TARGET_FUNCTION_ARG_PADDING |
| #define TARGET_FUNCTION_ARG_PADDING rs6000_function_arg_padding |
| #undef TARGET_FUNCTION_ARG_BOUNDARY |
| #define TARGET_FUNCTION_ARG_BOUNDARY rs6000_function_arg_boundary |
| |
| #undef TARGET_BUILD_BUILTIN_VA_LIST |
| #define TARGET_BUILD_BUILTIN_VA_LIST rs6000_build_builtin_va_list |
| |
| #undef TARGET_EXPAND_BUILTIN_VA_START |
| #define TARGET_EXPAND_BUILTIN_VA_START rs6000_va_start |
| |
| #undef TARGET_GIMPLIFY_VA_ARG_EXPR |
| #define TARGET_GIMPLIFY_VA_ARG_EXPR rs6000_gimplify_va_arg |
| |
| #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 |
| |
| #undef TARGET_FLOATN_MODE |
| #define TARGET_FLOATN_MODE rs6000_floatn_mode |
| |
| #undef TARGET_INVALID_ARG_FOR_UNPROTOTYPED_FN |
| #define TARGET_INVALID_ARG_FOR_UNPROTOTYPED_FN invalid_arg_for_unprototyped_fn |
| |
| #undef TARGET_ASM_LOOP_ALIGN_MAX_SKIP |
| #define TARGET_ASM_LOOP_ALIGN_MAX_SKIP rs6000_loop_align_max_skip |
| |
| #undef TARGET_MD_ASM_ADJUST |
| #define TARGET_MD_ASM_ADJUST rs6000_md_asm_adjust |
| |
| #undef TARGET_OPTION_OVERRIDE |
| #define TARGET_OPTION_OVERRIDE rs6000_option_override |
| |
| #undef TARGET_VECTORIZE_BUILTIN_VECTORIZED_FUNCTION |
| #define TARGET_VECTORIZE_BUILTIN_VECTORIZED_FUNCTION \ |
| rs6000_builtin_vectorized_function |
| |
| #undef TARGET_VECTORIZE_BUILTIN_MD_VECTORIZED_FUNCTION |
| #define TARGET_VECTORIZE_BUILTIN_MD_VECTORIZED_FUNCTION \ |
| rs6000_builtin_md_vectorized_function |
| |
| #undef TARGET_STACK_PROTECT_GUARD |
| #define TARGET_STACK_PROTECT_GUARD rs6000_init_stack_protect_guard |
| |
| #if !TARGET_MACHO |
| #undef TARGET_STACK_PROTECT_FAIL |
| #define TARGET_STACK_PROTECT_FAIL rs6000_stack_protect_fail |
| #endif |
| |
| #ifdef HAVE_AS_TLS |
| #undef TARGET_ASM_OUTPUT_DWARF_DTPREL |
| #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 |
| #undef TARGET_USE_BLOCKS_FOR_DECL_P |
| #define TARGET_USE_BLOCKS_FOR_DECL_P rs6000_use_blocks_for_decl_p |
| |
| #undef TARGET_BUILTIN_RECIPROCAL |
| #define TARGET_BUILTIN_RECIPROCAL rs6000_builtin_reciprocal |
| |
| #undef TARGET_SECONDARY_RELOAD |
| #define TARGET_SECONDARY_RELOAD rs6000_secondary_reload |
| #undef TARGET_SECONDARY_MEMORY_NEEDED |
| #define TARGET_SECONDARY_MEMORY_NEEDED rs6000_secondary_memory_needed |
| #undef TARGET_SECONDARY_MEMORY_NEEDED_MODE |
| #define TARGET_SECONDARY_MEMORY_NEEDED_MODE rs6000_secondary_memory_needed_mode |
| |
| #undef TARGET_LEGITIMATE_ADDRESS_P |
| #define TARGET_LEGITIMATE_ADDRESS_P rs6000_legitimate_address_p |
| |
| #undef TARGET_MODE_DEPENDENT_ADDRESS_P |
| #define TARGET_MODE_DEPENDENT_ADDRESS_P rs6000_mode_dependent_address_p |
| |
| #undef TARGET_COMPUTE_PRESSURE_CLASSES |
| #define TARGET_COMPUTE_PRESSURE_CLASSES rs6000_compute_pressure_classes |
| |
| #undef TARGET_CAN_ELIMINATE |
| #define TARGET_CAN_ELIMINATE rs6000_can_eliminate |
| |
| #undef TARGET_CONDITIONAL_REGISTER_USAGE |
| #define TARGET_CONDITIONAL_REGISTER_USAGE rs6000_conditional_register_usage |
| |
| #undef TARGET_SCHED_REASSOCIATION_WIDTH |
| #define TARGET_SCHED_REASSOCIATION_WIDTH rs6000_reassociation_width |
| |
| #undef TARGET_TRAMPOLINE_INIT |
| #define TARGET_TRAMPOLINE_INIT rs6000_trampoline_init |
| |
| #undef TARGET_FUNCTION_VALUE |
| #define TARGET_FUNCTION_VALUE rs6000_function_value |
| |
| #undef TARGET_OPTION_VALID_ATTRIBUTE_P |
| #define TARGET_OPTION_VALID_ATTRIBUTE_P rs6000_valid_attribute_p |
| |
| #undef TARGET_OPTION_SAVE |
| #define TARGET_OPTION_SAVE rs6000_function_specific_save |
| |
| #undef TARGET_OPTION_RESTORE |
| #define TARGET_OPTION_RESTORE rs6000_function_specific_restore |
| |
| #undef TARGET_OPTION_PRINT |
| #define TARGET_OPTION_PRINT rs6000_function_specific_print |
| |
| #undef TARGET_CAN_INLINE_P |
| #define TARGET_CAN_INLINE_P rs6000_can_inline_p |
| |
| #undef TARGET_SET_CURRENT_FUNCTION |
| #define TARGET_SET_CURRENT_FUNCTION rs6000_set_current_function |
| |
| #undef TARGET_LEGITIMATE_CONSTANT_P |
| #define TARGET_LEGITIMATE_CONSTANT_P rs6000_legitimate_constant_p |
| |
| #undef TARGET_VECTORIZE_VEC_PERM_CONST |
| #define TARGET_VECTORIZE_VEC_PERM_CONST rs6000_vectorize_vec_perm_const |
| |
| #undef TARGET_CAN_USE_DOLOOP_P |
| #define TARGET_CAN_USE_DOLOOP_P can_use_doloop_if_innermost |
| |
| #undef TARGET_ATOMIC_ASSIGN_EXPAND_FENV |
| #define TARGET_ATOMIC_ASSIGN_EXPAND_FENV rs6000_atomic_assign_expand_fenv |
| |
| #undef TARGET_LIBGCC_CMP_RETURN_MODE |
| #define TARGET_LIBGCC_CMP_RETURN_MODE rs6000_abi_word_mode |
| #undef TARGET_LIBGCC_SHIFT_COUNT_MODE |
| #define TARGET_LIBGCC_SHIFT_COUNT_MODE rs6000_abi_word_mode |
| #undef TARGET_UNWIND_WORD_MODE |
| #define TARGET_UNWIND_WORD_MODE rs6000_abi_word_mode |
| |
| #undef TARGET_OFFLOAD_OPTIONS |
| #define TARGET_OFFLOAD_OPTIONS rs6000_offload_options |
| |
| #undef TARGET_C_MODE_FOR_SUFFIX |
| #define TARGET_C_MODE_FOR_SUFFIX rs6000_c_mode_for_suffix |
| |
| #undef TARGET_INVALID_BINARY_OP |
| #define TARGET_INVALID_BINARY_OP rs6000_invalid_binary_op |
| |
| #undef TARGET_OPTAB_SUPPORTED_P |
| #define TARGET_OPTAB_SUPPORTED_P rs6000_optab_supported_p |
| |
| #undef TARGET_CUSTOM_FUNCTION_DESCRIPTORS |
| #define TARGET_CUSTOM_FUNCTION_DESCRIPTORS 1 |
| |
| #undef TARGET_COMPARE_VERSION_PRIORITY |
| #define TARGET_COMPARE_VERSION_PRIORITY rs6000_compare_version_priority |
| |
| #undef TARGET_GENERATE_VERSION_DISPATCHER_BODY |
| #define TARGET_GENERATE_VERSION_DISPATCHER_BODY \ |
| rs6000_generate_version_dispatcher_body |
| |
| #undef TARGET_GET_FUNCTION_VERSIONS_DISPATCHER |
| #define TARGET_GET_FUNCTION_VERSIONS_DISPATCHER \ |
| rs6000_get_function_versions_dispatcher |
| |
| #undef TARGET_OPTION_FUNCTION_VERSIONS |
| #define TARGET_OPTION_FUNCTION_VERSIONS common_function_versions |
| |
| #undef TARGET_HARD_REGNO_NREGS |
| #define TARGET_HARD_REGNO_NREGS rs6000_hard_regno_nregs_hook |
| #undef TARGET_HARD_REGNO_MODE_OK |
| #define TARGET_HARD_REGNO_MODE_OK rs6000_hard_regno_mode_ok |
| |
| #undef TARGET_MODES_TIEABLE_P |
| #define TARGET_MODES_TIEABLE_P rs6000_modes_tieable_p |
| |
| #undef TARGET_HARD_REGNO_CALL_PART_CLOBBERED |
| #define TARGET_HARD_REGNO_CALL_PART_CLOBBERED \ |
| rs6000_hard_regno_call_part_clobbered |
| |
| #undef TARGET_SLOW_UNALIGNED_ACCESS |
| #define TARGET_SLOW_UNALIGNED_ACCESS rs6000_slow_unaligned_access |
| |
| #undef TARGET_CAN_CHANGE_MODE_CLASS |
| #define TARGET_CAN_CHANGE_MODE_CLASS rs6000_can_change_mode_class |
| |
| #undef TARGET_CONSTANT_ALIGNMENT |
| #define TARGET_CONSTANT_ALIGNMENT rs6000_constant_alignment |
| |
| #undef TARGET_STARTING_FRAME_OFFSET |
| #define TARGET_STARTING_FRAME_OFFSET rs6000_starting_frame_offset |
| |
| #if TARGET_ELF && RS6000_WEAK |
| #undef TARGET_ASM_GLOBALIZE_DECL_NAME |
| #define TARGET_ASM_GLOBALIZE_DECL_NAME rs6000_globalize_decl_name |
| #endif |
| |
| |
| /* Processor table. */ |
| struct rs6000_ptt |
| { |
| const char *const name; /* Canonical processor name. */ |
| const enum processor_type processor; /* Processor type enum value. */ |
| const HOST_WIDE_INT target_enable; /* Target flags to enable. */ |
| }; |
| |
| static struct rs6000_ptt const processor_target_table[] = |
| { |
| #define RS6000_CPU(NAME, CPU, FLAGS) { NAME, CPU, FLAGS }, |
| #include "rs6000-cpus.def" |
| #undef RS6000_CPU |
| }; |
| |
| /* Look up a processor name for -mcpu=xxx and -mtune=xxx. Return -1 if the |
| name is invalid. */ |
| |
| static int |
| rs6000_cpu_name_lookup (const char *name) |
| { |
| size_t i; |
| |
| if (name != NULL) |
| { |
| for (i = 0; i < ARRAY_SIZE (processor_target_table); i++) |
| if (! strcmp (name, processor_target_table[i].name)) |
| return (int)i; |
| } |
| |
| return -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 |
| but can be less for certain modes in special long registers. |
| |
| POWER and PowerPC GPRs hold 32 bits worth; |
| PowerPC64 GPRs and FPRs point register holds 64 bits worth. */ |
| |
| static int |
| rs6000_hard_regno_nregs_internal (int regno, machine_mode mode) |
| { |
| unsigned HOST_WIDE_INT reg_size; |
| |
| /* 128-bit floating point usually takes 2 registers, unless it is IEEE |
| 128-bit floating point that can go in vector registers, which has VSX |
| memory addressing. */ |
| if (FP_REGNO_P (regno)) |
| reg_size = (VECTOR_MEM_VSX_P (mode) || FLOAT128_VECTOR_P (mode) |
| ? UNITS_PER_VSX_WORD |
| : UNITS_PER_FP_WORD); |
| |
| else if (ALTIVEC_REGNO_P (regno)) |
| reg_size = UNITS_PER_ALTIVEC_WORD; |
| |
| else |
| reg_size = UNITS_PER_WORD; |
| |
| return (GET_MODE_SIZE (mode) + reg_size - 1) / reg_size; |
| } |
| |
| /* Value is 1 if hard register REGNO can hold a value of machine-mode |
| MODE. */ |
| static int |
| rs6000_hard_regno_mode_ok_uncached (int regno, machine_mode mode) |
| { |
| int last_regno = regno + rs6000_hard_regno_nregs[mode][regno] - 1; |
| |
| if (COMPLEX_MODE_P (mode)) |
| mode = GET_MODE_INNER (mode); |
| |
| /* PTImode can only go in GPRs. Quad word memory operations require even/odd |
| register combinations, and use PTImode where we need to deal with quad |
| word memory operations. Don't allow quad words in the argument or frame |
| pointer registers, just registers 0..31. */ |
| if (mode == PTImode) |
| return (IN_RANGE (regno, FIRST_GPR_REGNO, LAST_GPR_REGNO) |
| && IN_RANGE (last_regno, FIRST_GPR_REGNO, LAST_GPR_REGNO) |
| && ((regno & 1) == 0)); |
| |
| /* VSX registers that overlap the FPR registers are larger than for non-VSX |
| implementations. Don't allow an item to be split between a FP register |
| and an Altivec register. Allow TImode in all VSX registers if the user |
| asked for it. */ |
| if (TARGET_VSX && VSX_REGNO_P (regno) |
| && (VECTOR_MEM_VSX_P (mode) |
| || FLOAT128_VECTOR_P (mode) |
| || reg_addr[mode].scalar_in_vmx_p |
| || mode == TImode |
| || (TARGET_VADDUQM && mode == V1TImode))) |
| { |
| if (FP_REGNO_P (regno)) |
| return FP_REGNO_P (last_regno); |
| |
| if (ALTIVEC_REGNO_P (regno)) |
| { |
| if (GET_MODE_SIZE (mode) != 16 && !reg_addr[mode].scalar_in_vmx_p) |
| return 0; |
| |
| return ALTIVEC_REGNO_P (last_regno); |
| } |
| } |
| |
| /* The GPRs can hold any mode, but values bigger than one register |
| cannot go past R31. */ |
| if (INT_REGNO_P (regno)) |
| return INT_REGNO_P (last_regno); |
| |
| /* The float registers (except for VSX vector modes) can only hold floating |
| modes and DImode. */ |
| if (FP_REGNO_P (regno)) |
| { |
| if (FLOAT128_VECTOR_P (mode)) |
| return false; |
| |
| if (SCALAR_FLOAT_MODE_P (mode) |
| && (mode != TDmode || (regno % 2) == 0) |
| && FP_REGNO_P (last_regno)) |
| return 1; |
| |
| if (GET_MODE_CLASS (mode) == MODE_INT) |
| { |
| if(GET_MODE_SIZE (mode) == UNITS_PER_FP_WORD) |
| return 1; |
| |
| if (TARGET_P8_VECTOR && (mode == SImode)) |
| return 1; |
| |
| if (TARGET_P9_VECTOR && (mode == QImode || mode == HImode)) |
| return 1; |
| } |
| |
| if (PAIRED_SIMD_REGNO_P (regno) && TARGET_PAIRED_FLOAT |
| && PAIRED_VECTOR_MODE (mode)) |
| return 1; |
| |
| return 0; |
| } |
| |
| /* The CR register can only hold CC modes. */ |
| if (CR_REGNO_P (regno)) |
| return GET_MODE_CLASS (mode) == MODE_CC; |
| |
| if (CA_REGNO_P (regno)) |
| return mode == Pmode || mode == SImode; |
| |
| /* AltiVec only in AldyVec registers. */ |
| if (ALTIVEC_REGNO_P (regno)) |
| return (VECTOR_MEM_ALTIVEC_OR_VSX_P (mode) |
| || mode == V1TImode); |
| |
| /* We cannot put non-VSX TImode or PTImode anywhere except general register |
| and it must be able to fit within the register set. */ |
| |
| return GET_MODE_SIZE (mode) <= UNITS_PER_WORD; |
| } |
| |
| /* Implement TARGET_HARD_REGNO_NREGS. */ |
| |
| static unsigned int |
| rs6000_hard_regno_nregs_hook (unsigned int regno, machine_mode mode) |
| { |
| return rs6000_hard_regno_nregs[mode][regno]; |
| } |
| |
| /* Implement TARGET_HARD_REGNO_MODE_OK. */ |
| |
| static bool |
| rs6000_hard_regno_mode_ok (unsigned int regno, machine_mode mode) |
| { |
| return rs6000_hard_regno_mode_ok_p[mode][regno]; |
| } |
| |
| /* Implement TARGET_MODES_TIEABLE_P. |
| |
| PTImode cannot tie with other modes because PTImode is restricted to even |
| GPR registers, and TImode can go in any GPR as well as VSX registers (PR |
| 57744). |
| |
| Altivec/VSX vector tests were moved ahead of scalar float mode, so that IEEE |
| 128-bit floating point on VSX systems ties with other vectors. */ |
| |
| static bool |
| rs6000_modes_tieable_p (machine_mode mode1, machine_mode mode2) |
| { |
| if (mode1 == PTImode) |
| return mode2 == PTImode; |
| if (mode2 == PTImode) |
| return false; |
| |
| if (ALTIVEC_OR_VSX_VECTOR_MODE (mode1)) |
| return ALTIVEC_OR_VSX_VECTOR_MODE (mode2); |
| if (ALTIVEC_OR_VSX_VECTOR_MODE (mode2)) |
| return false; |
| |
| if (SCALAR_FLOAT_MODE_P (mode1)) |
| return SCALAR_FLOAT_MODE_P (mode2); |
| if (SCALAR_FLOAT_MODE_P (mode2)) |
| return false; |
| |
| if (GET_MODE_CLASS (mode1) == MODE_CC) |
| return GET_MODE_CLASS (mode2) == MODE_CC; |
| if (GET_MODE_CLASS (mode2) == MODE_CC) |
| return false; |
| |
| if (PAIRED_VECTOR_MODE (mode1)) |
| return PAIRED_VECTOR_MODE (mode2); |
| if (PAIRED_VECTOR_MODE (mode2)) |
| return false; |
| |
| return true; |
| } |
| |
| /* Implement TARGET_HARD_REGNO_CALL_PART_CLOBBERED. */ |
| |
| static bool |
| rs6000_hard_regno_call_part_clobbered (unsigned int regno, machine_mode mode) |
| { |
| if (TARGET_32BIT |
| && TARGET_POWERPC64 |
| && GET_MODE_SIZE (mode) > 4 |
| && INT_REGNO_P (regno)) |
| return true; |
| |
| if (TARGET_VSX |
| && FP_REGNO_P (regno) |
| && GET_MODE_SIZE (mode) > 8 |
| && !FLOAT128_2REG_P (mode)) |
| return true; |
| |
| return false; |
| } |
| |
| /* Print interesting facts about registers. */ |
| static void |
| rs6000_debug_reg_print (int first_regno, int last_regno, const char *reg_name) |
| { |
| int r, m; |
| |
| for (r = first_regno; r <= last_regno; ++r) |
| { |
| const char *comma = ""; |
| int len; |
| |
| if (first_regno == last_regno) |
| fprintf (stderr, "%s:\t", reg_name); |
| else |
| fprintf (stderr, "%s%d:\t", reg_name, r - first_regno); |
| |
| len = 8; |
| for (m = 0; m < NUM_MACHINE_MODES; ++m) |
| if (rs6000_hard_regno_mode_ok_p[m][r] && rs6000_hard_regno_nregs[m][r]) |
| { |
| if (len > 70) |
| { |
| fprintf (stderr, ",\n\t"); |
| len = 8; |
| comma = ""; |
| } |
| |
| if (rs6000_hard_regno_nregs[m][r] > 1) |
| len += fprintf (stderr, "%s%s/%d", comma, GET_MODE_NAME (m), |
| rs6000_hard_regno_nregs[m][r]); |
| else |
| len += fprintf (stderr, "%s%s", comma, GET_MODE_NAME (m)); |
| |
| comma = ", "; |
| } |
| |
| if (call_used_regs[r]) |
| { |
| if (len > 70) |
| { |
| fprintf (stderr, ",\n\t"); |
| len = 8; |
| comma = ""; |
| } |
| |
| len += fprintf (stderr, "%s%s", comma, "call-used"); |
| comma = ", "; |
| } |
| |
| if (fixed_regs[r]) |
| { |
| if (len > 70) |
| { |
| fprintf (stderr, ",\n\t"); |
| len = 8; |
| comma = ""; |
| } |
| |
| len += fprintf (stderr, "%s%s", comma, "fixed"); |
| comma = ", "; |
| } |
| |
| if (len > 70) |
| { |
| fprintf (stderr, ",\n\t"); |
| comma = ""; |
| } |
| |
| len += fprintf (stderr, "%sreg-class = %s", comma, |
| reg_class_names[(int)rs6000_regno_regclass[r]]); |
| comma = ", "; |
| |
| if (len > 70) |
| { |
| fprintf (stderr, ",\n\t"); |
| comma = ""; |
| } |
| |
| fprintf (stderr, "%sregno = %d\n", comma, r); |
| } |
| } |
| |
| static const char * |
| rs6000_debug_vector_unit (enum rs6000_vector v) |
| { |
| const char *ret; |
| |
| switch (v) |
| { |
| case VECTOR_NONE: ret = "none"; break; |
| case VECTOR_ALTIVEC: ret = "altivec"; break; |
| case VECTOR_VSX: ret = "vsx"; break; |
| case VECTOR_P8_VECTOR: ret = "p8_vector"; break; |
| case VECTOR_PAIRED: ret = "paired"; break; |
| case VECTOR_OTHER: ret = "other"; break; |
| default: ret = "unknown"; break; |
| } |
| |
| return ret; |
| } |
| |
| /* Inner function printing just the address mask for a particular reload |
| register class. */ |
| DEBUG_FUNCTION char * |
| rs6000_debug_addr_mask (addr_mask_type mask, bool keep_spaces) |
| { |
| static char ret[8]; |
| char *p = ret; |
| |
| if ((mask & RELOAD_REG_VALID) != 0) |
| *p++ = 'v'; |
| else if (keep_spaces) |
| *p++ = ' '; |
| |
| if ((mask & RELOAD_REG_MULTIPLE) != 0) |
| *p++ = 'm'; |
| else if (keep_spaces) |
| *p++ = ' '; |
| |
| if ((mask & RELOAD_REG_INDEXED) != 0) |
| *p++ = 'i'; |
| else if (keep_spaces) |
| *p++ = ' '; |
| |
| if ((mask & RELOAD_REG_QUAD_OFFSET) != 0) |
| *p++ = 'O'; |
| else if ((mask & RELOAD_REG_OFFSET) != 0) |
| *p++ = 'o'; |
| else if (keep_spaces) |
| *p++ = ' '; |
| |
| if ((mask & RELOAD_REG_PRE_INCDEC) != 0) |
| *p++ = '+'; |
| else if (keep_spaces) |
| *p++ = ' '; |
| |
| if ((mask & RELOAD_REG_PRE_MODIFY) != 0) |
| *p++ = '+'; |
| else if (keep_spaces) |
| *p++ = ' '; |
| |
| if ((mask & RELOAD_REG_AND_M16) != 0) |
| *p++ = '&'; |
| else if (keep_spaces) |
| *p++ = ' '; |
| |
| *p = '\0'; |
| |
| return ret; |
| } |
| |
| /* Print the address masks in a human readble fashion. */ |
| DEBUG_FUNCTION void |
| rs6000_debug_print_mode (ssize_t m) |
| { |
| ssize_t rc; |
| int spaces = 0; |
| bool fuse_extra_p; |
| |
| fprintf (stderr, "Mode: %-5s", GET_MODE_NAME (m)); |
| for (rc = 0; rc < N_RELOAD_REG; rc++) |
| fprintf (stderr, " %s: %s", reload_reg_map[rc].name, |
| rs6000_debug_addr_mask (reg_addr[m].addr_mask[rc], true)); |
| |
| if ((reg_addr[m].reload_store != CODE_FOR_nothing) |
| || (reg_addr[m].reload_load != CODE_FOR_nothing)) |
| fprintf (stderr, " Reload=%c%c", |
| (reg_addr[m].reload_store != CODE_FOR_nothing) ? 's' : '*', |
| (reg_addr[m].reload_load != CODE_FOR_nothing) ? 'l' : '*'); |
| else |
| spaces += sizeof (" Reload=sl") - 1; |
| |
| if (reg_addr[m].scalar_in_vmx_p) |
| { |
| fprintf (stderr, "%*s Upper=y", spaces, ""); |
| spaces = 0; |
| } |
| else |
| spaces += sizeof (" Upper=y") - 1; |
| |
| fuse_extra_p = ((reg_addr[m].fusion_gpr_ld != CODE_FOR_nothing) |
| || reg_addr[m].fused_toc); |
| if (!fuse_extra_p) |
| { |
| for (rc = 0; rc < N_RELOAD_REG; rc++) |
| { |
| if (rc != RELOAD_REG_ANY) |
| { |
| if (reg_addr[m].fusion_addi_ld[rc] != CODE_FOR_nothing |
| || reg_addr[m].fusion_addi_ld[rc] != CODE_FOR_nothing |
| || reg_addr[m].fusion_addi_st[rc] != CODE_FOR_nothing |
| || reg_addr[m].fusion_addis_ld[rc] != CODE_FOR_nothing |
| || reg_addr[m].fusion_addis_st[rc] != CODE_FOR_nothing) |
| { |
| fuse_extra_p = true; |
| break; |
| } |
| } |
| } |
| } |
| |
| if (fuse_extra_p) |
| { |
| fprintf (stderr, "%*s Fuse:", spaces, ""); |
| spaces = 0; |
| |
| for (rc = 0; rc < N_RELOAD_REG; rc++) |
| { |
| if (rc != RELOAD_REG_ANY) |
| { |
| char load, store; |
| |
| if (reg_addr[m].fusion_addis_ld[rc] != CODE_FOR_nothing) |
| load = 'l'; |
| else if (reg_addr[m].fusion_addi_ld[rc] != CODE_FOR_nothing) |
| load = 'L'; |
| else |
| load = '-'; |
| |
| if (reg_addr[m].fusion_addis_st[rc] != CODE_FOR_nothing) |
| store = 's'; |
| else if (reg_addr[m].fusion_addi_st[rc] != CODE_FOR_nothing) |
| store = 'S'; |
| else |
| store = '-'; |
| |
| if (load == '-' && store == '-') |
| spaces += 5; |
| else |
| { |
| fprintf (stderr, "%*s%c=%c%c", (spaces + 1), "", |
| reload_reg_map[rc].name[0], load, store); |
| spaces = 0; |
| } |
| } |
| } |
| |
| if (reg_addr[m].fusion_gpr_ld != CODE_FOR_nothing) |
| { |
| fprintf (stderr, "%*sP8gpr", (spaces + 1), ""); |
| spaces = 0; |
| } |
| else |
| spaces += sizeof (" P8gpr") - 1; |
| |
| if (reg_addr[m].fused_toc) |
| { |
| fprintf (stderr, "%*sToc", (spaces + 1), ""); |
| spaces = 0; |
| } |
| else |
| spaces += sizeof (" Toc") - 1; |
| } |
| else |
| spaces += sizeof (" Fuse: G=ls F=ls v=ls P8gpr Toc") - 1; |
| |
| if (rs6000_vector_unit[m] != VECTOR_NONE |
| || rs6000_vector_mem[m] != VECTOR_NONE) |
| { |
| fprintf (stderr, "%*s vector: arith=%-10s mem=%s", |
| spaces, "", |
| rs6000_debug_vector_unit (rs6000_vector_unit[m]), |
| rs6000_debug_vector_unit (rs6000_vector_mem[m])); |
| } |
| |
| fputs ("\n", stderr); |
| } |
| |
| #define DEBUG_FMT_ID "%-32s= " |
| #define DEBUG_FMT_D DEBUG_FMT_ID "%d\n" |
| #define DEBUG_FMT_WX DEBUG_FMT_ID "%#.12" HOST_WIDE_INT_PRINT "x: " |
| #define DEBUG_FMT_S DEBUG_FMT_ID "%s\n" |
| |
| /* Print various interesting information with -mdebug=reg. */ |
| static void |
| rs6000_debug_reg_global (void) |
| { |
| static const char *const tf[2] = { "false", "true" }; |
| const char *nl = (const char *)0; |
| int m; |
| size_t m1, m2, v; |
| char costly_num[20]; |
| char nop_num[20]; |
| char flags_buffer[40]; |
| const char *costly_str; |
| const char *nop_str; |
| const char *trace_str; |
| const char *abi_str; |
| const char *cmodel_str; |
| struct cl_target_option cl_opts; |
| |
| /* Modes we want tieable information on. */ |
| static const machine_mode print_tieable_modes[] = { |
| QImode, |
| HImode, |
| SImode, |
| DImode, |
| TImode, |
| PTImode, |
| SFmode, |
| DFmode, |
| TFmode, |
| IFmode, |
| KFmode, |
| SDmode, |
| DDmode, |
| TDmode, |
| V2SImode, |
| V16QImode, |
| V8HImode, |
| V4SImode, |
| V2DImode, |
| V1TImode, |
| V32QImode, |
| V16HImode, |
| V8SImode, |
| V4DImode, |
| V2TImode, |
| V2SFmode, |
| V4SFmode, |
| V2DFmode, |
| V8SFmode, |
| V4DFmode, |
| CCmode, |
| CCUNSmode, |
| CCEQmode, |
| }; |
| |
| /* Virtual regs we are interested in. */ |
| const static struct { |
| int regno; /* register number. */ |
| const char *name; /* register name. */ |
| } virtual_regs[] = { |
| { STACK_POINTER_REGNUM, "stack pointer:" }, |
| { TOC_REGNUM, "toc: " }, |
| { STATIC_CHAIN_REGNUM, "static chain: " }, |
| { RS6000_PIC_OFFSET_TABLE_REGNUM, "pic offset: " }, |
| { HARD_FRAME_POINTER_REGNUM, "hard frame: " }, |
| { ARG_POINTER_REGNUM, "arg pointer: " }, |
| { FRAME_POINTER_REGNUM, "frame pointer:" }, |
| { FIRST_PSEUDO_REGISTER, "first pseudo: " }, |
| { FIRST_VIRTUAL_REGISTER, "first virtual:" }, |
| { VIRTUAL_INCOMING_ARGS_REGNUM, "incoming_args:" }, |
| { VIRTUAL_STACK_VARS_REGNUM, "stack_vars: " }, |
| { VIRTUAL_STACK_DYNAMIC_REGNUM, "stack_dynamic:" }, |
| { VIRTUAL_OUTGOING_ARGS_REGNUM, "outgoing_args:" }, |
| { VIRTUAL_CFA_REGNUM, "cfa (frame): " }, |
| { VIRTUAL_PREFERRED_STACK_BOUNDARY_REGNUM, "stack boundry:" }, |
| { LAST_VIRTUAL_REGISTER, "last virtual: " }, |
| }; |
| |
| fputs ("\nHard register information:\n", stderr); |
| rs6000_debug_reg_print (FIRST_GPR_REGNO, LAST_GPR_REGNO, "gr"); |
| rs6000_debug_reg_print (FIRST_FPR_REGNO, LAST_FPR_REGNO, "fp"); |
| rs6000_debug_reg_print (FIRST_ALTIVEC_REGNO, |
| LAST_ALTIVEC_REGNO, |
| "vs"); |
| rs6000_debug_reg_print (LR_REGNO, LR_REGNO, "lr"); |
| rs6000_debug_reg_print (CTR_REGNO, CTR_REGNO, "ctr"); |
| rs6000_debug_reg_print (CR0_REGNO, CR7_REGNO, "cr"); |
| rs6000_debug_reg_print (CA_REGNO, CA_REGNO, "ca"); |
| rs6000_debug_reg_print (VRSAVE_REGNO, VRSAVE_REGNO, "vrsave"); |
| rs6000_debug_reg_print (VSCR_REGNO, VSCR_REGNO, "vscr"); |
| |
| fputs ("\nVirtual/stack/frame registers:\n", stderr); |
| for (v = 0; v < ARRAY_SIZE (virtual_regs); v++) |
| fprintf (stderr, "%s regno = %3d\n", virtual_regs[v].name, virtual_regs[v].regno); |
| |
| fprintf (stderr, |
| "\n" |
| "d reg_class = %s\n" |
| "f reg_class = %s\n" |
| "v reg_class = %s\n" |
| "wa reg_class = %s\n" |
| "wb reg_class = %s\n" |
| "wd reg_class = %s\n" |
| "we reg_class = %s\n" |
| "wf reg_class = %s\n" |
| "wg reg_class = %s\n" |
| "wh reg_class = %s\n" |
| "wi reg_class = %s\n" |
| "wj reg_class = %s\n" |
| "wk reg_class = %s\n" |
| "wl reg_class = %s\n" |
| "wm reg_class = %s\n" |
| "wo reg_class = %s\n" |
| "wp reg_class = %s\n" |
| "wq reg_class = %s\n" |
| "wr reg_class = %s\n" |
| "ws reg_class = %s\n" |
| "wt reg_class = %s\n" |
| "wu reg_class = %s\n" |
| "wv reg_class = %s\n" |
| "ww reg_class = %s\n" |
| "wx reg_class = %s\n" |
| "wy reg_class = %s\n" |
| "wz reg_class = %s\n" |
| "wA reg_class = %s\n" |
| "wH reg_class = %s\n" |
| "wI reg_class = %s\n" |
| "wJ reg_class = %s\n" |
| "wK reg_class = %s\n" |
| "\n", |
| reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_d]], |
| reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_f]], |
| reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_v]], |
| reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_wa]], |
| reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_wb]], |
| reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_wd]], |
| reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_we]], |
| reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_wf]], |
| reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_wg]], |
| reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_wh]], |
| reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_wi]], |
| reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_wj]], |
| reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_wk]], |
| reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_wl]], |
| reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_wm]], |
| reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_wo]], |
| reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_wp]], |
| reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_wq]], |
| reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_wr]], |
| reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_ws]], |
| reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_wt]], |
| reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_wu]], |
| reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_wv]], |
| reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_ww]], |
| reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_wx]], |
| reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_wy]], |
| reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_wz]], |
| reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_wA]], |
| reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_wH]], |
| reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_wI]], |
| reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_wJ]], |
| reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_wK]]); |
| |
| nl = "\n"; |
| for (m = 0; m < NUM_MACHINE_MODES; ++m) |
| rs6000_debug_print_mode (m); |
| |
| fputs ("\n", stderr); |
| |
| for (m1 = 0; m1 < ARRAY_SIZE (print_tieable_modes); m1++) |
| { |
| machine_mode mode1 = print_tieable_modes[m1]; |
| bool first_time = true; |
| |
| nl = (const char *)0; |
| for (m2 = 0; m2 < ARRAY_SIZE (print_tieable_modes); m2++) |
| { |
| machine_mode mode2 = print_tieable_modes[m2]; |
| if (mode1 != mode2 && rs6000_modes_tieable_p (mode1, mode2)) |
| { |
| if (first_time) |
| { |
| fprintf (stderr, "Tieable modes %s:", GET_MODE_NAME (mode1)); |
| nl = "\n"; |
| first_time = false; |
| } |
| |
| fprintf (stderr, " %s", GET_MODE_NAME (mode2)); |
| } |
| } |
| |
| if (!first_time) |
| fputs ("\n", stderr); |
| } |
| |
| if (nl) |
| fputs (nl, stderr); |
| |
| if (rs6000_recip_control) |
| { |
| fprintf (stderr, "\nReciprocal mask = 0x%x\n", rs6000_recip_control); |
| |
| for (m = 0; m < NUM_MACHINE_MODES; ++m) |
| if (rs6000_recip_bits[m]) |
| { |
| fprintf (stderr, |
| "Reciprocal estimate mode: %-5s divide: %s rsqrt: %s\n", |
| GET_MODE_NAME (m), |
| (RS6000_RECIP_AUTO_RE_P (m) |
| ? "auto" |
| : (RS6000_RECIP_HAVE_RE_P (m) ? "have" : "none")), |
| (RS6000_RECIP_AUTO_RSQRTE_P (m) |
| ? "auto" |
| : (RS6000_RECIP_HAVE_RSQRTE_P (m) ? "have" : "none"))); |
| } |
| |
| fputs ("\n", stderr); |
| } |
| |
| if (rs6000_cpu_index >= 0) |
| { |
| const char *name = processor_target_table[rs6000_cpu_index].name; |
| HOST_WIDE_INT flags |
| = processor_target_table[rs6000_cpu_index].target_enable; |
| |
| sprintf (flags_buffer, "-mcpu=%s flags", name); |
| rs6000_print_isa_options (stderr, 0, flags_buffer, flags); |
| } |
| else |
| fprintf (stderr, DEBUG_FMT_S, "cpu", "<none>"); |
| |
| if (rs6000_tune_index >= 0) |
| { |
| const char *name = processor_target_table[rs6000_tune_index].name; |
| HOST_WIDE_INT flags |
| = processor_target_table[rs6000_tune_index].target_enable; |
| |
| sprintf (flags_buffer, "-mtune=%s flags", name); |
| rs6000_print_isa_options (stderr, 0, flags_buffer, flags); |
| } |
| else |
| fprintf (stderr, DEBUG_FMT_S, "tune", "<none>"); |
| |
| cl_target_option_save (&cl_opts, &global_options); |
| rs6000_print_isa_options (stderr, 0, "rs6000_isa_flags", |
| rs6000_isa_flags); |
| |
| rs6000_print_isa_options (stderr, 0, "rs6000_isa_flags_explicit", |
| rs6000_isa_flags_explicit); |
| |
| rs6000_print_builtin_options (stderr, 0, "rs6000_builtin_mask", |
| rs6000_builtin_mask); |
| |
| rs6000_print_isa_options (stderr, 0, "TARGET_DEFAULT", TARGET_DEFAULT); |
| |
| fprintf (stderr, DEBUG_FMT_S, "--with-cpu default", |
| OPTION_TARGET_CPU_DEFAULT ? OPTION_TARGET_CPU_DEFAULT : "<none>"); |
| |
| switch (rs6000_sched_costly_dep) |
| { |
| case max_dep_latency: |
| costly_str = "max_dep_latency"; |
| break; |
| |
| case no_dep_costly: |
| costly_str = "no_dep_costly"; |
| break; |
| |
| case all_deps_costly: |
| costly_str = "all_deps_costly"; |
| break; |
| |
| case true_store_to_load_dep_costly: |
| costly_str = "true_store_to_load_dep_costly"; |
| break; |
| |
| case store_to_load_dep_costly: |
| costly_str = "store_to_load_dep_costly"; |
| break; |
| |
| default: |
| costly_str = costly_num; |
| sprintf (costly_num, "%d", (int)rs6000_sched_costly_dep); |
| break; |
| } |
| |
| fprintf (stderr, DEBUG_FMT_S, "sched_costly_dep", costly_str); |
| |
| switch (rs6000_sched_insert_nops) |
| { |
| case sched_finish_regroup_exact: |
| nop_str = "sched_finish_regroup_exact"; |
| break; |
| |
| case sched_finish_pad_groups: |
| nop_str = "sched_finish_pad_groups"; |
| break; |
| |
| case sched_finish_none: |
| nop_str = "sched_finish_none"; |
| break; |
| |
| default: |
| nop_str = nop_num; |
| sprintf (nop_num, "%d", (int)rs6000_sched_insert_nops); |
| break; |
| } |
| |
| fprintf (stderr, DEBUG_FMT_S, "sched_insert_nops", nop_str); |
| |
| switch (rs6000_sdata) |
| { |
| default: |
| case SDATA_NONE: |
| break; |
| |
| case SDATA_DATA: |
| fprintf (stderr, DEBUG_FMT_S, "sdata", "data"); |
| break; |
| |
| case SDATA_SYSV: |
| fprintf (stderr, DEBUG_FMT_S, "sdata", "sysv"); |
| break; |
| |
| case SDATA_EABI: |
| fprintf (stderr, DEBUG_FMT_S, "sdata", "eabi"); |
| break; |
| |
| } |
| |
| switch (rs6000_traceback) |
| { |
| case traceback_default: trace_str = "default"; break; |
| case traceback_none: trace_str = "none"; break; |
| case traceback_part: trace_str = "part"; break; |
| case traceback_full: trace_str = "full"; break; |
| default: trace_str = "unknown"; break; |
| } |
| |
| fprintf (stderr, DEBUG_FMT_S, "traceback", trace_str); |
| |
| switch (rs6000_current_cmodel) |
| { |
| case CMODEL_SMALL: cmodel_str = "small"; break; |
| case CMODEL_MEDIUM: cmodel_str = "medium"; break; |
| case CMODEL_LARGE: cmodel_str = "large"; break; |
| default: cmodel_str = "unknown"; break; |
| } |
| |
| fprintf (stderr, DEBUG_FMT_S, "cmodel", cmodel_str); |
| |
| switch (rs6000_current_abi) |
| { |
| case ABI_NONE: abi_str = "none"; break; |
| case ABI_AIX: abi_str = "aix"; break; |
| case ABI_ELFv2: abi_str = "ELFv2"; break; |
| case ABI_V4: abi_str = "V4"; break; |
| case ABI_DARWIN: abi_str = "darwin"; break; |
| default: abi_str = "unknown"; break; |
| } |
| |
| fprintf (stderr, DEBUG_FMT_S, "abi", abi_str); |
| |
| if (rs6000_altivec_abi) |
| fprintf (stderr, DEBUG_FMT_S, "altivec_abi", "true"); |
| |
| if (rs6000_darwin64_abi) |
| fprintf (stderr, DEBUG_FMT_S, "darwin64_abi", "true"); |
| |
| fprintf (stderr, DEBUG_FMT_S, "single_float", |
| (TARGET_SINGLE_FLOAT ? "true" : "false")); |
| |
| fprintf (stderr, DEBUG_FMT_S, "double_float", |
| (TARGET_DOUBLE_FLOAT ? "true" : "false")); |
| |
| fprintf (stderr, DEBUG_FMT_S, "soft_float", |
| (TARGET_SOFT_FLOAT ? "true" : "false")); |
| |
| if (TARGET_LINK_STACK) |
| fprintf (stderr, DEBUG_FMT_S, "link_stack", "true"); |
| |
| if (TARGET_P8_FUSION) |
| { |
| char options[80]; |
| |
| strcpy (options, (TARGET_P9_FUSION) ? "power9" : "power8"); |
| if (TARGET_TOC_FUSION) |
| strcat (options, ", toc"); |
| |
| if (TARGET_P8_FUSION_SIGN) |
| strcat (options, ", sign"); |
| |
| fprintf (stderr, DEBUG_FMT_S, "fusion", options); |
| } |
| |
| fprintf (stderr, DEBUG_FMT_S, "plt-format", |
| TARGET_SECURE_PLT ? "secure" : "bss"); |
| fprintf (stderr, DEBUG_FMT_S, "struct-return", |
| aix_struct_return ? "aix" : "sysv"); |
| fprintf (stderr, DEBUG_FMT_S, "always_hint", tf[!!rs6000_always_hint]); |
| fprintf (stderr, DEBUG_FMT_S, "sched_groups", tf[!!rs6000_sched_groups]); |
| fprintf (stderr, DEBUG_FMT_S, "align_branch", |
| tf[!!rs6000_align_branch_targets]); |
| fprintf (stderr, DEBUG_FMT_D, "tls_size", rs6000_tls_size); |
| fprintf (stderr, DEBUG_FMT_D, "long_double_size", |
| rs6000_long_double_type_size); |
| if (rs6000_long_double_type_size > 64) |
| { |
| fprintf (stderr, DEBUG_FMT_S, "long double type", |
| TARGET_IEEEQUAD ? "IEEE" : "IBM"); |
| fprintf (stderr, DEBUG_FMT_S, "default long double type", |
| TARGET_IEEEQUAD_DEFAULT ? "IEEE" : "IBM"); |
| } |
| fprintf (stderr, DEBUG_FMT_D, "sched_restricted_insns_priority", |
| (int)rs6000_sched_restricted_insns_priority); |
| fprintf (stderr, DEBUG_FMT_D, "Number of standard builtins", |
| (int)END_BUILTINS); |
| fprintf (stderr, DEBUG_FMT_D, "Number of rs6000 builtins", |
| (int)RS6000_BUILTIN_COUNT); |
| |
| fprintf (stderr, DEBUG_FMT_D, "Enable float128 on VSX", |
| (int)TARGET_FLOAT128_ENABLE_TYPE); |
| |
| if (TARGET_VSX) |
| fprintf (stderr, DEBUG_FMT_D, "VSX easy 64-bit scalar element", |
| (int)VECTOR_ELEMENT_SCALAR_64BIT); |
| |
| if (TARGET_DIRECT_MOVE_128) |
| fprintf (stderr, DEBUG_FMT_D, "VSX easy 64-bit mfvsrld element", |
| (int)VECTOR_ELEMENT_MFVSRLD_64BIT); |
| } |
| |
| |
| /* Update the addr mask bits in reg_addr to help secondary reload and go if |
| legitimate address support to figure out the appropriate addressing to |
| use. */ |
| |
| static void |
| rs6000_setup_reg_addr_masks (void) |
| { |
| ssize_t rc, reg, m, nregs; |
| addr_mask_type any_addr_mask, addr_mask; |
| |
| for (m = 0; m < NUM_MACHINE_MODES; ++m) |
| { |
| machine_mode m2 = (machine_mode) m; |
| bool complex_p = false; |
| bool small_int_p = (m2 == QImode || m2 == HImode || m2 == SImode); |
| size_t msize; |
| |
| if (COMPLEX_MODE_P (m2)) |
| { |
| complex_p = true; |
| m2 = GET_MODE_INNER (m2); |
| } |
| |
| msize = GET_MODE_SIZE (m2); |
| |
| /* SDmode is special in that we want to access it only via REG+REG |
| addressing on power7 and above, since we want to use the LFIWZX and |
| STFIWZX instructions to load it. */ |
| bool indexed_only_p = (m == SDmode && TARGET_NO_SDMODE_STACK); |
| |
| any_addr_mask = 0; |
| for (rc = FIRST_RELOAD_REG_CLASS; rc <= LAST_RELOAD_REG_CLASS; rc++) |
| { |
| addr_mask = 0; |
| reg = reload_reg_map[rc].reg; |
| |
| /* Can mode values go in the GPR/FPR/Altivec registers? */ |
| if (reg >= 0 && rs6000_hard_regno_mode_ok_p[m][reg]) |
| { |
| bool small_int_vsx_p = (small_int_p |
| && (rc == RELOAD_REG_FPR |
| || rc == RELOAD_REG_VMX)); |
| |
| nregs = rs6000_hard_regno_nregs[m][reg]; |
| addr_mask |= RELOAD_REG_VALID; |
| |
| /* Indicate if the mode takes more than 1 physical register. If |
| it takes a single register, indicate it can do REG+REG |
| addressing. Small integers in VSX registers can only do |
| REG+REG addressing. */ |
| if (small_int_vsx_p) |
| addr_mask |= RELOAD_REG_INDEXED; |
| else if (nregs > 1 || m == BLKmode || complex_p) |
| addr_mask |= RELOAD_REG_MULTIPLE; |
| else |
| addr_mask |= RELOAD_REG_INDEXED; |
| |
| /* Figure out if we can do PRE_INC, PRE_DEC, or PRE_MODIFY |
| addressing. If we allow scalars into Altivec registers, |
| don't allow PRE_INC, PRE_DEC, or PRE_MODIFY. |
| |
| For VSX systems, we don't allow update addressing for |
| DFmode/SFmode if those registers can go in both the |
| traditional floating point registers and Altivec registers. |
| The load/store instructions for the Altivec registers do not |
| have update forms. If we allowed update addressing, it seems |
| to break IV-OPT code using floating point if the index type is |
| int instead of long (PR target/81550 and target/84042). */ |
| |
| if (TARGET_UPDATE |
| && (rc == RELOAD_REG_GPR || rc == RELOAD_REG_FPR) |
| && msize <= 8 |
| && !VECTOR_MODE_P (m2) |
| && !FLOAT128_VECTOR_P (m2) |
| && !complex_p |
| && (m != E_DFmode || !TARGET_VSX) |
| && (m != E_SFmode || !TARGET_P8_VECTOR) |
| && !small_int_vsx_p) |
| { |
| addr_mask |= RELOAD_REG_PRE_INCDEC; |
| |
| /* PRE_MODIFY is more restricted than PRE_INC/PRE_DEC in that |
| we don't allow PRE_MODIFY for some multi-register |
| operations. */ |
| switch (m) |
| { |
| default: |
| addr_mask |= RELOAD_REG_PRE_MODIFY; |
| break; |
| |
| case E_DImode: |
| if (TARGET_POWERPC64) |
| addr_mask |= RELOAD_REG_PRE_MODIFY; |
| break; |
| |
| case E_DFmode: |
| case E_DDmode: |
| if (TARGET_DF_INSN) |
| addr_mask |= RELOAD_REG_PRE_MODIFY; |
| break; |
| } |
| } |
| } |
| |
| /* GPR and FPR registers can do REG+OFFSET addressing, except |
| possibly for SDmode. ISA 3.0 (i.e. power9) adds D-form addressing |
| for 64-bit scalars and 32-bit SFmode to altivec registers. */ |
| if ((addr_mask != 0) && !indexed_only_p |
| && msize <= 8 |
| && (rc == RELOAD_REG_GPR |
| || ((msize == 8 || m2 == SFmode) |
| && (rc == RELOAD_REG_FPR |
| || (rc == RELOAD_REG_VMX && TARGET_P9_VECTOR))))) |
| addr_mask |= RELOAD_REG_OFFSET; |
| |
| /* VSX registers can do REG+OFFSET addresssing if ISA 3.0 |
| instructions are enabled. The offset for 128-bit VSX registers is |
| only 12-bits. While GPRs can handle the full offset range, VSX |
| registers can only handle the restricted range. */ |
| else if ((addr_mask != 0) && !indexed_only_p |
| && msize == 16 && TARGET_P9_VECTOR |
| && (ALTIVEC_OR_VSX_VECTOR_MODE (m2) |
| || (m2 == TImode && TARGET_VSX))) |
| { |
| addr_mask |= RELOAD_REG_OFFSET; |
| if (rc == RELOAD_REG_FPR || rc == RELOAD_REG_VMX) |
| addr_mask |= RELOAD_REG_QUAD_OFFSET; |
| } |
| |
| /* VMX registers can do (REG & -16) and ((REG+REG) & -16) |
| addressing on 128-bit types. */ |
| if (rc == RELOAD_REG_VMX && msize == 16 |
| && (addr_mask & RELOAD_REG_VALID) != 0) |
| addr_mask |= RELOAD_REG_AND_M16; |
| |
| reg_addr[m].addr_mask[rc] = addr_mask; |
| any_addr_mask |= addr_mask; |
| } |
| |
| reg_addr[m].addr_mask[RELOAD_REG_ANY] = any_addr_mask; |
| } |
| } |
| |
| |
| /* Initialize the various global tables that are based on register size. */ |
| static void |
| rs6000_init_hard_regno_mode_ok (bool global_init_p) |
| { |
| ssize_t r, m, c; |
| int align64; |
| int align32; |
| |
| /* Precalculate REGNO_REG_CLASS. */ |
| rs6000_regno_regclass[0] = GENERAL_REGS; |
| for (r = 1; r < 32; ++r) |
| rs6000_regno_regclass[r] = BASE_REGS; |
| |
| for (r = 32; r < 64; ++r) |
| rs6000_regno_regclass[r] = FLOAT_REGS; |
| |
| for (r = 64; r < FIRST_PSEUDO_REGISTER; ++r) |
| rs6000_regno_regclass[r] = NO_REGS; |
| |
| for (r = FIRST_ALTIVEC_REGNO; r <= LAST_ALTIVEC_REGNO; ++r) |
| rs6000_regno_regclass[r] = ALTIVEC_REGS; |
| |
| rs6000_regno_regclass[CR0_REGNO] = CR0_REGS; |
| for (r = CR1_REGNO; r <= CR7_REGNO; ++r) |
| rs6000_regno_regclass[r] = CR_REGS; |
| |
| rs6000_regno_regclass[LR_REGNO] = LINK_REGS; |
| rs6000_regno_regclass[CTR_REGNO] = CTR_REGS; |
| rs6000_regno_regclass[CA_REGNO] = NO_REGS; |
| rs6000_regno_regclass[VRSAVE_REGNO] = VRSAVE_REGS; |
| rs6000_regno_regclass[VSCR_REGNO] = VRSAVE_REGS; |
| rs6000_regno_regclass[TFHAR_REGNO] = SPR_REGS; |
| rs6000_regno_regclass[TFIAR_REGNO] = SPR_REGS; |
| rs6000_regno_regclass[TEXASR_REGNO] = SPR_REGS; |
|