| /* Subroutines used for code generation on IBM RS/6000. |
| Copyright (C) 1991-2015 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/>. */ |
| |
| #include "config.h" |
| #include "system.h" |
| #include "coretypes.h" |
| #include "tm.h" |
| #include "rtl.h" |
| #include "regs.h" |
| #include "hard-reg-set.h" |
| #include "insn-config.h" |
| #include "conditions.h" |
| #include "insn-attr.h" |
| #include "flags.h" |
| #include "recog.h" |
| #include "obstack.h" |
| #include "hash-set.h" |
| #include "machmode.h" |
| #include "vec.h" |
| #include "double-int.h" |
| #include "input.h" |
| #include "alias.h" |
| #include "symtab.h" |
| #include "wide-int.h" |
| #include "inchash.h" |
| #include "tree.h" |
| #include "fold-const.h" |
| #include "stringpool.h" |
| #include "stor-layout.h" |
| #include "calls.h" |
| #include "print-tree.h" |
| #include "varasm.h" |
| #include "hashtab.h" |
| #include "function.h" |
| #include "statistics.h" |
| #include "real.h" |
| #include "fixed-value.h" |
| #include "expmed.h" |
| #include "dojump.h" |
| #include "explow.h" |
| #include "emit-rtl.h" |
| #include "stmt.h" |
| #include "expr.h" |
| #include "insn-codes.h" |
| #include "optabs.h" |
| #include "except.h" |
| #include "output.h" |
| #include "dbxout.h" |
| #include "predict.h" |
| #include "dominance.h" |
| #include "cfg.h" |
| #include "cfgrtl.h" |
| #include "cfganal.h" |
| #include "lcm.h" |
| #include "cfgbuild.h" |
| #include "cfgcleanup.h" |
| #include "basic-block.h" |
| #include "diagnostic-core.h" |
| #include "toplev.h" |
| #include "ggc.h" |
| #include "tm_p.h" |
| #include "target.h" |
| #include "target-def.h" |
| #include "common/common-target.h" |
| #include "langhooks.h" |
| #include "reload.h" |
| #include "cfgloop.h" |
| #include "sched-int.h" |
| #include "hash-table.h" |
| #include "tree-ssa-alias.h" |
| #include "internal-fn.h" |
| #include "gimple-fold.h" |
| #include "tree-eh.h" |
| #include "gimple-expr.h" |
| #include "is-a.h" |
| #include "gimple.h" |
| #include "gimplify.h" |
| #include "gimple-iterator.h" |
| #include "gimple-walk.h" |
| #include "intl.h" |
| #include "params.h" |
| #include "tm-constrs.h" |
| #include "ira.h" |
| #include "opts.h" |
| #include "tree-vectorizer.h" |
| #include "dumpfile.h" |
| #include "hash-map.h" |
| #include "plugin-api.h" |
| #include "ipa-ref.h" |
| #include "cgraph.h" |
| #include "target-globals.h" |
| #include "builtins.h" |
| #include "context.h" |
| #include "tree-pass.h" |
| #if TARGET_XCOFF |
| #include "xcoffout.h" /* get declarations of xcoff_*_section_name */ |
| #endif |
| #if TARGET_MACHO |
| #include "gstab.h" /* for N_SLINE */ |
| #endif |
| |
| #ifndef TARGET_NO_PROTOTYPE |
| #define TARGET_NO_PROTOTYPE 0 |
| #endif |
| |
| #define min(A,B) ((A) < (B) ? (A) : (B)) |
| #define max(A,B) ((A) > (B) ? (A) : (B)) |
| |
| /* 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 spe_gp_save_offset; /* offset to save spe 64-bit gprs */ |
| 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 save_size */ |
| int vrsave_size; /* size to hold VRSAVE if not in save_size */ |
| int altivec_padding_size; /* size of altivec alignment padding if |
| not in save_size */ |
| int spe_gp_size; /* size of 64-bit GPR save size for SPE */ |
| int spe_padding_size; |
| HOST_WIDE_INT total_size; /* total bytes allocated for stack */ |
| int spe_64bit_regs_used; |
| 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 |
| { |
| /* Whether the instruction chain has been scanned already. */ |
| int insn_chain_scanned_p; |
| /* 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; |
| /* Temporary stack slot to use for SDmode copies. This slot is |
| 64-bits wide and is allocated early enough so that the offset |
| does not overflow the 16-bit load/store offset field. */ |
| rtx sdmode_stack_slot; |
| /* Flag if r2 setup is needed with ELFv2 ABI. */ |
| bool r2_setup_needed; |
| } 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. The type is unsigned since not all things that |
| include rs6000.h also include machmode.h. */ |
| unsigned rs6000_pmode; |
| |
| /* Width in bits of a pointer. */ |
| unsigned rs6000_pointer_size; |
| |
| #ifdef HAVE_AS_GNU_ATTRIBUTE |
| /* Flag whether floating point values have been passed/returned. */ |
| static bool rs6000_passes_float; |
| /* 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. */ |
| 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; |
| 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) }, |
| }; |
| |
| /* 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, |
| SPE_ACC_TYPE, |
| SPEFSCR_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. */ |
| |
| /* 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. */ |
| addr_mask_type addr_mask[(int)N_RELOAD_REG]; /* Valid address masks. */ |
| bool scalar_in_vmx_p; /* Scalar value can go in VMX. */ |
| }; |
| |
| 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); |
| } |
| |
| |
| /* Target cpu costs. */ |
| |
| struct processor_costs { |
| const int mulsi; /* cost of SImode multiplication. */ |
| const int mulsi_const; /* cost of SImode multiplication by constant. */ |
| const int mulsi_const9; /* cost of SImode mult by short constant. */ |
| const int muldi; /* cost of DImode multiplication. */ |
| const int divsi; /* cost of SImode division. */ |
| const int divdi; /* cost of DImode division. */ |
| const int fp; /* cost of simple SFmode and DFmode insns. */ |
| const int dmul; /* cost of DFmode multiplication (and fmadd). */ |
| const int sdiv; /* cost of SFmode division (fdivs). */ |
| const int ddiv; /* cost of DFmode division (fdiv). */ |
| const int cache_line_size; /* cache line size in bytes. */ |
| const int l1_cache_size; /* size of l1 cache, in kilobytes. */ |
| const int l2_cache_size; /* size of l2 cache, in kilobytes. */ |
| const int simultaneous_prefetches; /* number of parallel prefetch |
| operations. */ |
| const int sfdf_convert; /* cost of SF->DF conversion. */ |
| }; |
| |
| const struct processor_costs *rs6000_cost; |
| |
| /* Processor costs (relative to an add) */ |
| |
| /* 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 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_1 |
| #undef RS6000_BUILTIN_2 |
| #undef RS6000_BUILTIN_3 |
| #undef RS6000_BUILTIN_A |
| #undef RS6000_BUILTIN_D |
| #undef RS6000_BUILTIN_E |
| #undef RS6000_BUILTIN_H |
| #undef RS6000_BUILTIN_P |
| #undef RS6000_BUILTIN_Q |
| #undef RS6000_BUILTIN_S |
| #undef RS6000_BUILTIN_X |
| |
| #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_E(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_S(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_1 |
| #undef RS6000_BUILTIN_2 |
| #undef RS6000_BUILTIN_3 |
| #undef RS6000_BUILTIN_A |
| #undef RS6000_BUILTIN_D |
| #undef RS6000_BUILTIN_E |
| #undef RS6000_BUILTIN_H |
| #undef RS6000_BUILTIN_P |
| #undef RS6000_BUILTIN_Q |
| #undef RS6000_BUILTIN_S |
| #undef RS6000_BUILTIN_X |
| |
| /* Support for -mveclibabi=<xxx> to control which vector library to use. */ |
| static tree (*rs6000_veclib_handler) (tree, tree, tree); |
| |
| |
| static bool rs6000_debug_legitimate_address_p (machine_mode, rtx, bool); |
| static bool spe_func_has_64bit_regs_p (void); |
| 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 (tree, 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, int, 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 *, rtx, rtx_insn *, 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 spe_init_builtins (void); |
| static void htm_init_builtins (void); |
| static rtx spe_expand_predicate_builtin (enum insn_code, tree, rtx); |
| static rtx spe_expand_evsel_builtin (enum insn_code, tree, rtx); |
| static int rs6000_emit_int_cmove (rtx, rtx, rtx, rtx); |
| 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 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_secondary_memory_needed (enum reg_class, enum reg_class, |
| machine_mode); |
| static bool rs6000_debug_secondary_memory_needed (enum reg_class, |
| enum reg_class, |
| machine_mode); |
| static bool rs6000_cannot_change_mode_class (machine_mode, |
| machine_mode, |
| enum reg_class); |
| static bool rs6000_debug_cannot_change_mode_class (machine_mode, |
| machine_mode, |
| enum reg_class); |
| static bool rs6000_save_toc_in_prologue_p (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; |
| |
| bool (*rs6000_secondary_memory_needed_ptr) (enum reg_class, enum reg_class, |
| machine_mode) |
| = rs6000_secondary_memory_needed; |
| |
| bool (*rs6000_cannot_change_mode_class_ptr) (machine_mode, |
| machine_mode, |
| enum reg_class) |
| = rs6000_cannot_change_mode_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 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*); |
| |
| /* 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_hasher<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_hasher<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", |
| /* SPE registers. */ |
| "spe_acc", "spefscr", |
| /* Soft frame pointer. */ |
| "sfp", |
| /* HTM SPR registers. */ |
| "tfhar", "tfiar", "texasr", |
| /* SPE High 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" |
| }; |
| |
| #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", |
| /* SPE registers. */ |
| "spe_acc", "spefscr", |
| /* Soft frame pointer. */ |
| "sfp", |
| /* HTM SPR registers. */ |
| "tfhar", "tfiar", "texasr", |
| /* SPE High registers. */ |
| "%rh0", "%rh1", "%rh2", "%rh3", "%rh4", "%rh5", "%rh6", "%rh7", |
| "%rh8", "%rh9", "%rh10", "%r11", "%rh12", "%rh13", "%rh14", "%rh15", |
| "%rh16", "%rh17", "%rh18", "%rh19", "%rh20", "%rh21", "%rh22", "%rh23", |
| "%rh24", "%rh25", "%rh26", "%rh27", "%rh28", "%rh29", "%rh30", "%rh31" |
| }; |
| #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, handler, |
| affects_type_identity } */ |
| { "altivec", 1, 1, false, true, false, rs6000_handle_altivec_attribute, |
| false }, |
| { "longcall", 0, 0, false, true, true, rs6000_handle_longcall_attribute, |
| false }, |
| { "shortcall", 0, 0, false, true, true, rs6000_handle_longcall_attribute, |
| false }, |
| { "ms_struct", 0, 0, false, false, false, rs6000_handle_struct_attribute, |
| false }, |
| { "gcc_struct", 0, 0, false, false, false, rs6000_handle_struct_attribute, |
| false }, |
| #ifdef SUBTARGET_ATTRIBUTE_TABLE |
| SUBTARGET_ATTRIBUTE_TABLE, |
| #endif |
| { NULL, 0, 0, false, false, false, NULL, false } |
| }; |
| |
| #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_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_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_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_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_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_DWARF_REGISTER_SPAN |
| #define TARGET_DWARF_REGISTER_SPAN rs6000_dwarf_register_span |
| |
| #undef TARGET_INIT_DWARF_REG_SIZES_EXTRA |
| #define TARGET_INIT_DWARF_REG_SIZES_EXTRA rs6000_init_dwarf_reg_sizes_extra |
| |
| #undef TARGET_MEMBER_TYPE_FORCES_BLK |
| #define TARGET_MEMBER_TYPE_FORCES_BLK rs6000_member_type_forces_blk |
| |
| #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_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_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_CLOBBERS |
| #define TARGET_MD_ASM_CLOBBERS rs6000_md_asm_clobbers |
| |
| #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 |
| |
| #if !TARGET_MACHO |
| #undef TARGET_STACK_PROTECT_FAIL |
| #define TARGET_STACK_PROTECT_FAIL rs6000_stack_protect_fail |
| #endif |
| |
| /* MPC604EUM 3.5.2 Weak Consistency between Multiple Processors |
| The PowerPC architecture requires only weak consistency among |
| processors--that is, memory accesses between processors need not be |
| sequentially consistent and memory accesses among processors can occur |
| in any order. The ability to order memory accesses weakly provides |
| opportunities for more efficient use of the system bus. Unless a |
| dependency exists, the 604e allows read operations to precede store |
| operations. */ |
| #undef TARGET_RELAXED_ORDERING |
| #define TARGET_RELAXED_ORDERING true |
| |
| #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_EXPAND_TO_RTL_HOOK |
| #define TARGET_EXPAND_TO_RTL_HOOK rs6000_alloc_sdmode_stack_slot |
| |
| #undef TARGET_INSTANTIATE_DECLS |
| #define TARGET_INSTANTIATE_DECLS rs6000_instantiate_decls |
| |
| #undef TARGET_SECONDARY_RELOAD |
| #define TARGET_SECONDARY_RELOAD rs6000_secondary_reload |
| |
| #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_LRA_P |
| #define TARGET_LRA_P rs6000_lra_p |
| |
| #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_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_OK |
| #define TARGET_VECTORIZE_VEC_PERM_CONST_OK rs6000_vectorize_vec_perm_const_ok |
| |
| #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 |
| |
| |
| /* 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. |
| |
| For the SPE, GPRs are 64 bits but only 32 bits are visible in |
| scalar instructions. The upper 32 bits are only available to the |
| SIMD instructions. |
| |
| 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; |
| |
| /* TF/TD modes are special in that they always take 2 registers. */ |
| if (FP_REGNO_P (regno)) |
| reg_size = ((VECTOR_MEM_VSX_P (mode) && mode != TDmode && mode != TFmode) |
| ? UNITS_PER_VSX_WORD |
| : UNITS_PER_FP_WORD); |
| |
| else if (SPE_SIMD_REGNO_P (regno) && TARGET_SPE && SPE_VECTOR_MODE (mode)) |
| reg_size = UNITS_PER_SPE_WORD; |
| |
| else if (ALTIVEC_REGNO_P (regno)) |
| reg_size = UNITS_PER_ALTIVEC_WORD; |
| |
| /* The value returned for SCmode in the E500 double case is 2 for |
| ABI compatibility; storing an SCmode value in a single register |
| would require function_arg and rs6000_spe_function_arg to handle |
| SCmode so as to pass the value correctly in a pair of |
| registers. */ |
| else if (TARGET_E500_DOUBLE && FLOAT_MODE_P (mode) && mode != SCmode |
| && !DECIMAL_FLOAT_MODE_P (mode) && SPE_SIMD_REGNO_P (regno)) |
| reg_size = UNITS_PER_FP_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 (int regno, machine_mode mode) |
| { |
| int last_regno = regno + rs6000_hard_regno_nregs[mode][regno] - 1; |
| |
| /* 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) |
| || reg_addr[mode].scalar_in_vmx_p |
| || (TARGET_VSX_TIMODE && 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 (SCALAR_FLOAT_MODE_P (mode) |
| && (mode != TDmode || (regno % 2) == 0) |
| && FP_REGNO_P (last_regno)) |
| return 1; |
| |
| if (GET_MODE_CLASS (mode) == MODE_INT |
| && GET_MODE_SIZE (mode) == UNITS_PER_FP_WORD) |
| 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); |
| |
| /* ...but GPRs can hold SIMD data on the SPE in one register. */ |
| if (SPE_SIMD_REGNO_P (regno) && TARGET_SPE && SPE_VECTOR_MODE (mode)) |
| return 1; |
| |
| /* 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; |
| } |
| |
| /* 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_SPE: ret = "spe"; 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_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; |
| |
| 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 (rs6000_vector_unit[m] != VECTOR_NONE |
| || rs6000_vector_mem[m] != VECTOR_NONE |
| || (reg_addr[m].reload_store != CODE_FOR_nothing) |
| || (reg_addr[m].reload_load != CODE_FOR_nothing) |
| || reg_addr[m].scalar_in_vmx_p) |
| { |
| fprintf (stderr, |
| " Vector-arith=%-10s Vector-mem=%-10s Reload=%c%c Upper=%c", |
| rs6000_debug_vector_unit (rs6000_vector_unit[m]), |
| rs6000_debug_vector_unit (rs6000_vector_mem[m]), |
| (reg_addr[m].reload_store != CODE_FOR_nothing) ? 's' : '*', |
| (reg_addr[m].reload_load != CODE_FOR_nothing) ? 'l' : '*', |
| (reg_addr[m].scalar_in_vmx_p) ? 'y' : 'n'); |
| } |
| |
| 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, |
| SDmode, |
| DDmode, |
| TDmode, |
| V8QImode, |
| V4HImode, |
| 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"); |
| rs6000_debug_reg_print (SPE_ACC_REGNO, SPE_ACC_REGNO, "spe_a"); |
| rs6000_debug_reg_print (SPEFSCR_REGNO, SPEFSCR_REGNO, "spe_f"); |
| |
| 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" |
| "wd 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" |
| "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" |
| "\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_wd]], |
| 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_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]]); |
| |
| 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 && 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_spe_abi) |
| fprintf (stderr, DEBUG_FMT_S, "spe_abi", "true"); |
| |
| if (rs6000_darwin64_abi) |
| fprintf (stderr, DEBUG_FMT_S, "darwin64_abi", "true"); |
| |
| if (rs6000_float_gprs) |
| fprintf (stderr, DEBUG_FMT_S, "float_gprs", "true"); |
| |
| fprintf (stderr, DEBUG_FMT_S, "fprs", |
| (TARGET_FPRS ? "true" : "false")); |
| |
| 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")); |
| |
| fprintf (stderr, DEBUG_FMT_S, "e500_single", |
| (TARGET_E500_SINGLE ? "true" : "false")); |
| |
| fprintf (stderr, DEBUG_FMT_S, "e500_double", |
| (TARGET_E500_DOUBLE ? "true" : "false")); |
| |
| if (TARGET_LINK_STACK) |
| fprintf (stderr, DEBUG_FMT_S, "link_stack", "true"); |
| |
| if (targetm.lra_p ()) |
| fprintf (stderr, DEBUG_FMT_S, "lra", "true"); |
| |
| if (TARGET_P8_FUSION) |
| fprintf (stderr, DEBUG_FMT_S, "p8 fusion", |
| (TARGET_P8_FUSION_SIGN) ? "zero+sign" : "zero"); |
| |
| 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); |
| 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); |
| |
| if (TARGET_VSX) |
| fprintf (stderr, DEBUG_FMT_D, "VSX easy 64-bit scalar element", |
| (int)VECTOR_ELEMENT_SCALAR_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; |
| |
| /* 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]) |
| { |
| 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. */ |
| if (nregs > 1 || m == BLKmode) |
| 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. Restrict addressing on SPE for 64-bit types |
| because of the SUBREG hackery used to address 64-bit floats in |
| '32-bit' GPRs. */ |
| |
| if (TARGET_UPDATE |
| && (rc == RELOAD_REG_GPR || rc == RELOAD_REG_FPR) |
| && GET_MODE_SIZE (m2) <= 8 |
| && !VECTOR_MODE_P (m2) |
| && !COMPLEX_MODE_P (m2) |
| && !indexed_only_p |
| && !(TARGET_E500_DOUBLE && GET_MODE_SIZE (m2) == 8)) |
| { |
| 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 DImode: |
| if (TARGET_POWERPC64) |
| addr_mask |= RELOAD_REG_PRE_MODIFY; |
| break; |
| |
| case DFmode: |
| case 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. */ |
| if ((addr_mask != 0) && !indexed_only_p |
| && (rc == RELOAD_REG_GPR || rc == RELOAD_REG_FPR)) |
| addr_mask |= RELOAD_REG_OFFSET; |
| |
| /* VMX registers can do (REG & -16) and ((REG+REG) & -16) |
| addressing on 128-bit types. */ |
| if (rc == RELOAD_REG_VMX && GET_MODE_SIZE (m2) == 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[SPE_ACC_REGNO] = SPE_ACC_REGS; |
| rs6000_regno_regclass[SPEFSCR_REGNO] = SPEFSCR_REGS; |
| rs6000_regno_regclass[TFHAR_REGNO] = SPR_REGS; |
| rs6000_regno_regclass[TFIAR_REGNO] = SPR_REGS; |
| rs6000_regno_regclass[TEXASR_REGNO] = SPR_REGS; |
| rs6000_regno_regclass[ARG_POINTER_REGNUM] = BASE_REGS; |
| rs6000_regno_regclass[FRAME_POINTER_REGNUM] = BASE_REGS; |
| |
| /* Precalculate register class to simpler reload register class. We don't |
| need all of the register classes that are combinations of different |
| classes, just the simple ones that have constraint letters. */ |
| for (c = 0; c < N_REG_CLASSES; c++) |
| reg_class_to_reg_type[c] = NO_REG_TYPE; |
| |
| reg_class_to_reg_type[(int)GENERAL_REGS] = GPR_REG_TYPE; |
| reg_class_to_reg_type[(int)BASE_REGS] = GPR_REG_TYPE; |
| reg_class_to_reg_type[(int)VSX_REGS] = VSX_REG_TYPE; |
| reg_class_to_reg_type[(int)VRSAVE_REGS] = SPR_REG_TYPE; |
| reg_class_to_reg_type[(int)VSCR_REGS] = SPR_REG_TYPE; |
| reg_class_to_reg_type[(int)LINK_REGS] = SPR_REG_TYPE; |
| reg_class_to_reg_type[(int)CTR_REGS] = SPR_REG_TYPE; |
| reg_class_to_reg_type[(int)LINK_OR_CTR_REGS] = SPR_REG_TYPE; |
| reg_class_to_reg_type[(int)CR_REGS] = CR_REG_TYPE; |
| reg_class_to_reg_type[(int)CR0_REGS] = CR_REG_TYPE; |
| reg_class_to_reg_type[(int)SPE_ACC_REGS] = SPE_ACC_TYPE; |
| reg_class_to_reg_type[(int)SPEFSCR_REGS] = SPEFSCR_REG_TYPE; |
| |
| if (TARGET_VSX) |
| { |
| reg_class_to_reg_type[(int)FLOAT_REGS] = VSX_REG_TYPE; |
| reg_class_to_reg_type[(int)ALTIVEC_REGS] = VSX_REG_TYPE; |
| } |
| else |
| { |
| reg_class_to_reg_type[(int)FLOAT_REGS] = FPR_REG_TYPE; |
| reg_class_to_reg_type[(int)ALTIVEC_REGS] = ALTIVEC_REG_TYPE; |
| } |
| |
| /* Precalculate the valid memory formats as well as the vector information, |
| this must be set up before the rs6000_hard_regno_nregs_internal calls |
| below. */ |
| gcc_assert ((int)VECTOR_NONE == 0); |
| memset ((void *) &rs6000_vector_unit[0], '\0', sizeof (rs6000_vector_unit)); |
| memset ((void *) &rs6000_vector_mem[0], '\0', sizeof (rs6000_vector_unit)); |
| |
| gcc_assert ((int)CODE_FOR_nothing == 0); |
| memset ((void *) ®_addr[0], '\0', sizeof (reg_addr)); |
| |
| gcc_assert ((int)NO_REGS == 0); |
| memset ((void *) &rs6000_constraints[0], '\0', sizeof (rs6000_constraints)); |
| |
| /* The VSX hardware allows native alignment for vectors, but control whether the compiler |
| believes it can use native alignment or still uses 128-bit alignment. */ |
| if (TARGET_VSX && !TARGET_VSX_ALIGN_128) |
| { |
| align64 = 64; |
| align32 = 32; |
| } |
| else |
| { |
| align64 = 128; |
| align32 = 128; |
| } |
| |
| /* V2DF mode, VSX only. */ |
| if (TARGET_VSX) |
| { |
| rs6000_vector_unit[V2DFmode] = VECTOR_VSX; |
| rs6000_vector_mem[V2DFmode] = VECTOR_VSX; |
| rs6000_vector_align[V2DFmode] = align64; |
| } |
| |
| /* V4SF mode, either VSX or Altivec. */ |
| if (TARGET_VSX) |
| { |
| rs6000_vector_unit[V4SFmode] = VECTOR_VSX; |
| rs6000_vector_mem[V4SFmode] = VECTOR_VSX; |
| rs6000_vector_align[V4SFmode] = align32; |
| } |
| else if (TARGET_ALTIVEC) |
| { |
| rs6000_vector_unit[V4SFmode] = VECTOR_ALTIVEC; |
| rs6000_vector_mem[V4SFmode] = VECTOR_ALTIVEC; |
| rs6000_vector_align[V4SFmode] = align32; |
| } |
| |
| /* V16QImode, V8HImode, V4SImode are Altivec only, but possibly do VSX loads |
| and stores. */ |
| if (TARGET_ALTIVEC) |
| { |
| rs6000_vector_unit[V4SImode] = VECTOR_ALTIVEC; |
| rs6000_vector_unit[V8HImode] = VECTOR_ALTIVEC; |
| rs6000_vector_unit[V16QImode] = VECTOR_ALTIVEC; |
| rs6000_vector_align[V4SImode] = align32; |
| rs6000_vector_align[V8HImode] = align32; |
| rs6000_vector_align[V16QImode] = align32; |
| |
| if (TARGET_VSX) |
| { |
| rs6000_vector_mem[V4SImode] = VECTOR_VSX; |
| rs6000_vector_mem[V8HImode] = VECTOR_VSX; |
| rs6000_vector_mem[V16QImode] = VECTOR_VSX; |
| } |
| else |
| { |
| rs6000_vector_mem[V4SImode] = VECTOR_ALTIVEC; |
| rs6000_vector_mem[V8HImode] = VECTOR_ALTIVEC; |
| rs6000_vector_mem[V16QImode] = VECTOR_ALTIVEC; |
| } |
| } |
| |
| /* V2DImode, full mode depends on ISA 2.07 vector mode. Allow under VSX to |
| do insert/splat/extract. Altivec doesn't have 64-bit integer support. */ |
| if (TARGET_VSX) |
| { |
| rs6000_vector_mem[V2DImode] = VECTOR_VSX; |
| rs6000_vector_unit[V2DImode] |
| = (TARGET_P8_VECTOR) ? VECTOR_P8_VECTOR : VECTOR_NONE; |
| rs6000_vector_align[V2DImode] = align64; |
| |
| rs6000_vector_mem[V1TImode] = VECTOR_VSX; |
| rs6000_vector_unit[V1TImode] |
| = (TARGET_P8_VECTOR) ? VECTOR_P8_VECTOR : VECTOR_NONE; |
| rs6000_vector_align[V1TImode] = 128; |
| } |
| |
| /* DFmode, see if we want to use the VSX unit. Memory is handled |
| differently, so don't set rs6000_vector_mem. */ |
| if (TARGET_VSX && TARGET_VSX_SCALAR_DOUBLE) |
| { |
| rs6000_vector_unit[DFmode] = VECTOR_VSX; |
| rs6000_vector_align[DFmode] = 64; |
| } |
| |
| /* SFmode, see if we want to use the VSX unit. */ |
| if (TARGET_P8_VECTOR && TARGET_VSX_SCALAR_FLOAT) |
| { |
| rs6000_vector_unit[SFmode] = VECTOR_VSX; |
| rs6000_vector_align[SFmode] = 32; |
| } |
| |
| /* Allow TImode in VSX register and set the VSX memory macros. */ |
| if (TARGET_VSX && TARGET_VSX_TIMODE) |
| { |
| rs6000_vector_mem[TImode] = VECTOR_VSX; |
| rs6000_vector_align[TImode] = align64; |
| } |
| |
| /* TODO add SPE and paired floating point vector support. */ |
| |
| /* Register class constraints for the constraints that depend on compile |
| switches. When the VSX code was added, different constraints were added |
| based on the type (DFmode, V2DFmode, V4SFmode). For the vector types, all |
| of the VSX registers are used. The register classes for scalar floating |
| point types is set, based on whether we allow that type into the upper |
| (Altivec) registers. GCC has register classes to target the Altivec |
| registers for load/store operations, to select using a VSX memory |
| operation instead of the traditional floating point operation. The |
| constraints are: |
| |
| d - Register class to use with traditional DFmode instructions. |
| f - Register class to use with traditional SFmode instructions. |
| v - Altivec register. |
| wa - Any VSX register. |
| wc - Reserved to represent individual CR bits (used in LLVM). |
| wd - Preferred register class for V2DFmode. |
| wf - Preferred register class for V4SFmode. |
| wg - Float register for power6x move insns. |
| wh - FP register for direct move instructions. |
| wi - FP or VSX register to hold 64-bit integers for VSX insns. |
| wj - FP or VSX register to hold 64-bit integers for direct moves. |
| wk - FP or VSX register to hold 64-bit doubles for direct moves. |
| wl - Float register if we can do 32-bit signed int loads. |
| wm - VSX register for ISA 2.07 direct move operations. |
| wn - always NO_REGS. |
| wr - GPR if 64-bit mode is permitted. |
| ws - Register class to do ISA 2.06 DF operations. |
| wt - VSX register for TImode in VSX registers. |
| wu - Altivec register for ISA 2.07 VSX SF/SI load/stores. |
| wv - Altivec register for ISA 2.06 VSX DF/DI load/stores. |
| ww - Register class to do SF conversions in with VSX operations. |
| wx - Float register if we can do 32-bit int stores. |
| wy - Register class to do ISA 2.07 SF operations. |
| wz - Float register if we can do 32-bit unsigned int loads. */ |
| |
| if (TARGET_HARD_FLOAT && TARGET_FPRS) |
| rs6000_constraints[RS6000_CONSTRAINT_f] = FLOAT_REGS; /* SFmode */ |
| |
| if (TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT) |
| rs6000_constraints[RS6000_CONSTRAINT_d] = FLOAT_REGS; /* DFmode */ |
| |
| if (TARGET_VSX) |
| { |
| rs6000_constraints[RS6000_CONSTRAINT_wa] = VSX_REGS; |
| rs6000_constraints[RS6000_CONSTRAINT_wd] = VSX_REGS; /* V2DFmode */ |
| rs6000_constraints[RS6000_CONSTRAINT_wf] = VSX_REGS; /* V4SFmode */ |
| rs6000_constraints[RS6000_CONSTRAINT_wi] = FLOAT_REGS; /* DImode */ |
| |
| if (TARGET_VSX_TIMODE) |
| rs6000_constraints[RS6000_CONSTRAINT_wt] = VSX_REGS; /* TImode */ |
| |
| if (TARGET_UPPER_REGS_DF) /* DFmode */ |
| { |
| rs6000_constraints[RS6000_CONSTRAINT_ws] = VSX_REGS; |
| rs6000_constraints[RS6000_CONSTRAINT_wv] = ALTIVEC_REGS; |
| } |
| else |
| rs6000_constraints[RS6000_CONSTRAINT_ws] = FLOAT_REGS; |
| } |
| |
| /* Add conditional constraints based on various options, to allow us to |
| collapse multiple insn patterns. */ |
| if (TARGET_ALTIVEC) |
| rs6000_constraints[RS6000_CONSTRAINT_v] = ALTIVEC_REGS; |
| |
| if (TARGET_MFPGPR) /* DFmode */ |
| rs6000_constraints[RS6000_CONSTRAINT_wg] = FLOAT_REGS; |
| |
| if (TARGET_LFIWAX) |
| rs6000_constraints[RS6000_CONSTRAINT_wl] = FLOAT_REGS; /* DImode */ |
| |
| if (TARGET_DIRECT_MOVE) |
| { |
| rs6000_constraints[RS6000_CONSTRAINT_wh] = FLOAT_REGS; |
| rs6000_constraints[RS6000_CONSTRAINT_wj] /* DImode */ |
| = rs6000_constraints[RS6000_CONSTRAINT_wi]; |
| rs6000_constraints[RS6000_CONSTRAINT_wk] /* DFmode */ |
| = rs6000_constraints[RS6000_CONSTRAINT_ws]; |
| rs6000_constraints[RS6000_CONSTRAINT_wm] = VSX_REGS; |
| } |
| |
| if (TARGET_POWERPC64) |
| rs6000_constraints[RS6000_CONSTRAINT_wr] = GENERAL_REGS; |
| |
| if (TARGET_P8_VECTOR && TARGET_UPPER_REGS_SF) /* SFmode */ |
| { |
| rs6000_constraints[RS6000_CONSTRAINT_wu] = ALTIVEC_REGS; |
| rs6000_constraints[RS6000_CONSTRAINT_wy] = VSX_REGS; |
| rs6000_constraints[RS6000_CONSTRAINT_ww] = VSX_REGS; |
| } |
| else if (TARGET_P8_VECTOR) |
| { |
| rs6000_constraints[RS6000_CONSTRAINT_wy] = FLOAT_REGS; |
| rs6000_constraints[RS6000_CONSTRAINT_ww] = FLOAT_REGS; |
| } |
| else if (TARGET_VSX) |
| rs6000_constraints[RS6000_CONSTRAINT_ww] = FLOAT_REGS; |
| |
| if (TARGET_STFIWX) |
| rs6000_constraints[RS6000_CONSTRAINT_wx] = FLOAT_REGS; /* DImode */ |
| |
| if (TARGET_LFIWZX) |
| rs6000_constraints[RS6000_CONSTRAINT_wz] = FLOAT_REGS; /* DImode */ |
| |
| /* Set up the reload helper and direct move functions. */ |
| if (TARGET_VSX || TARGET_ALTIVEC) |
| { |
| if (TARGET_64BIT) |
| { |
| reg_addr[V16QImode].reload_store = CODE_FOR_reload_v16qi_di_store; |
| reg_addr[V16QImode].reload_load = CODE_FOR_reload_v16qi_di_load; |
| reg_addr[V8HImode].reload_store = CODE_FOR_reload_v8hi_di_store; |
| reg_addr[V8HImode].reload_load = CODE_FOR_reload_v8hi_di_load; |
| reg_addr[V4SImode].reload_store = CODE_FOR_reload_v4si_di_store; |
| reg_addr[V4SImode].reload_load = CODE_FOR_reload_v4si_di_load; |
| reg_addr[V2DImode].reload_store = CODE_FOR_reload_v2di_di_store; |
| reg_addr[V2DImode].reload_load = CODE_FOR_reload_v2di_di_load; |
| reg_addr[V1TImode].reload_store = CODE_FOR_reload_v1ti_di_store; |
| reg_addr[V1TImode].reload_load = CODE_FOR_reload_v1ti_di_load; |
| reg_addr[V4SFmode].reload_store = CODE_FOR_reload_v4sf_di_store; |
| reg_addr[V4SFmode].reload_load = CODE_FOR_reload_v4sf_di_load; |
| reg_addr[V2DFmode].reload_store = CODE_FOR_reload_v2df_di_store; |
| reg_addr[V2DFmode].reload_load = CODE_FOR_reload_v2df_di_load; |
| reg_addr[DFmode].reload_store = CODE_FOR_reload_df_di_store; |
| reg_addr[DFmode].reload_load = CODE_FOR_reload_df_di_load; |
| reg_addr[DDmode].reload_store = CODE_FOR_reload_dd_di_store; |
| reg_addr[DDmode].reload_load = CODE_FOR_reload_dd_di_load; |
| reg_addr[SFmode].reload_store = CODE_FOR_reload_sf_di_store; |
| reg_addr[SFmode].reload_load = CODE_FOR_reload_sf_di_load; |
| |
| /* Only provide a reload handler for SDmode if lfiwzx/stfiwx are |
| available. */ |
| if (TARGET_NO_SDMODE_STACK) |
| { |
| reg_addr[SDmode].reload_store = CODE_FOR_reload_sd_di_store; |
| reg_addr[SDmode].reload_load = CODE_FOR_reload_sd_di_load; |
| } |
| |
| if (TARGET_VSX_TIMODE) |
| { |
| reg_addr[TImode].reload_store = CODE_FOR_reload_ti_di_store; |
| reg_addr[TImode].reload_load = CODE_FOR_reload_ti_di_load; |
| } |
| |
| if (TARGET_DIRECT_MOVE) |
| { |
| reg_addr[TImode].reload_gpr_vsx = CODE_FOR_reload_gpr_from_vsxti; |
| reg_addr[V1TImode].reload_gpr_vsx = CODE_FOR_reload_gpr_from_vsxv1ti; |
| reg_addr[V2DFmode].reload_gpr_vsx = CODE_FOR_reload_gpr_from_vsxv2df; |
| reg_addr[V2DImode].reload_gpr_vsx = CODE_FOR_reload_gpr_from_vsxv2di; |
| reg_addr[V4SFmode].reload_gpr_vsx = CODE_FOR_reload_gpr_from_vsxv4sf; |
| reg_addr[V4SImode].reload_gpr_vsx = CODE_FOR_reload_gpr_from_vsxv4si; |
| reg_addr[V8HImode].reload_gpr_vsx = CODE_FOR_reload_gpr_from_vsxv8hi; |
| reg_addr[V16QImode].reload_gpr_vsx = CODE_FOR_reload_gpr_from_vsxv16qi; |
| reg_addr[SFmode].reload_gpr_vsx = CODE_FOR_reload_gpr_from_vsxsf; |
| |
| reg_addr[TImode].reload_vsx_gpr = CODE_FOR_reload_vsx_from_gprti; |
| reg_addr[V1TImode].reload_vsx_gpr = CODE_FOR_reload_vsx_from_gprv1ti; |
| reg_addr[V2DFmode].reload_vsx_gpr = CODE_FOR_reload_vsx_from_gprv2df; |
| reg_addr[V2DImode].reload_vsx_gpr = CODE_FOR_reload_vsx_from_gprv2di; |
| reg_addr[V4SFmode].reload_vsx_gpr = CODE_FOR_reload_vsx_from_gprv4sf; |
| reg_addr[V4SImode].reload_vsx_gpr = CODE_FOR_reload_vsx_from_gprv4si; |
| reg_addr[V8HImode].reload_vsx_gpr = CODE_FOR_reload_vsx_from_gprv8hi; |
| reg_addr[V16QImode].reload_vsx_gpr = CODE_FOR_reload_vsx_from_gprv16qi; |
| reg_addr[SFmode].reload_vsx_gpr = CODE_FOR_reload_vsx_from_gprsf; |
| } |
| } |
| else |
| { |
| reg_addr[V16QImode].reload_store = CODE_FOR_reload_v16qi_si_store; |
| reg_addr[V16QImode].reload_load = CODE_FOR_reload_v16qi_si_load; |
| reg_addr[V8HImode].reload_store = CODE_FOR_reload_v8hi_si_store; |
| reg_addr[V8HImode].reload_load = CODE_FOR_reload_v8hi_si_load; |
| reg_addr[V4SImode].reload_store = CODE_FOR_reload_v4si_si_store; |
| reg_addr[V4SImode].reload_load = CODE_FOR_reload_v4si_si_load; |
| reg_addr[V2DImode].reload_store = CODE_FOR_reload_v2di_si_store; |
| reg_addr[V2DImode].reload_load = CODE_FOR_reload_v2di_si_load; |
| reg_addr[V1TImode].reload_store = CODE_FOR_reload_v1ti_si_store; |
| reg_addr[V1TImode].reload_load = CODE_FOR_reload_v1ti_si_load; |
| reg_addr[V4SFmode].reload_store = CODE_FOR_reload_v4sf_si_store; |
| reg_addr[V4SFmode].reload_load = CODE_FOR_reload_v4sf_si_load; |
| reg_addr[V2DFmode].reload_store = CODE_FOR_reload_v2df_si_store; |
| reg_addr[V2DFmode].reload_load = CODE_FOR_reload_v2df_si_load; |
| reg_addr[DFmode].reload_store = CODE_FOR_reload_df_si_store; |
| reg_addr[DFmode].reload_load = CODE_FOR_reload_df_si_load; |
| reg_addr[DDmode].reload_store = CODE_FOR_reload_dd_si_store; |
| reg_addr[DDmode].reload_load = CODE_FOR_reload_dd_si_load; |
| reg_addr[SFmode].reload_store = CODE_FOR_reload_sf_si_store; |
| reg_addr[SFmode].reload_load = CODE_FOR_reload_sf_si_load; |
| |
| /* Only provide a reload handler for SDmode if lfiwzx/stfiwx are |
| available. */ |
| if (TARGET_NO_SDMODE_STACK) |
| { |
| reg_addr[SDmode].reload_store = CODE_FOR_reload_sd_si_store; |
| reg_addr[SDmode].reload_load = CODE_FOR_reload_sd_si_load; |
| } |
| |
| if (TARGET_VSX_TIMODE) |
| { |
| reg_addr[TImode].reload_store = CODE_FOR_reload_ti_si_store; |
| reg_addr[TImode].reload_load = CODE_FOR_reload_ti_si_load; |
| } |
| |
| if (TARGET_DIRECT_MOVE) |
| { |
| reg_addr[DImode].reload_fpr_gpr = CODE_FOR_reload_fpr_from_gprdi; |
| reg_addr[DDmode].reload_fpr_gpr = CODE_FOR_reload_fpr_from_gprdd; |
| reg_addr[DFmode].reload_fpr_gpr = CODE_FOR_reload_fpr_from_gprdf; |
| } |
| } |
| |
| if (TARGET_UPPER_REGS_DF) |
| reg_addr[DFmode].scalar_in_vmx_p = true; |
| |
| if (TARGET_UPPER_REGS_SF) |
| reg_addr[SFmode].scalar_in_vmx_p = true; |
| } |
| |
| /* Precalculate HARD_REGNO_NREGS. */ |
| for (r = 0; r < FIRST_PSEUDO_REGISTER; ++r) |
| for (m = 0; m < NUM_MACHINE_MODES; ++m) |
| rs6000_hard_regno_nregs[m][r] |
| = rs6000_hard_regno_nregs_internal (r, (machine_mode)m); |
| |
| /* Precalculate HARD_REGNO_MODE_OK. */ |
| for (r = 0; r < FIRST_PSEUDO_REGISTER; ++r) |
| for (m = 0; m < NUM_MACHINE_MODES; ++m) |
| if (rs6000_hard_regno_mode_ok (r, (machine_mode)m)) |
| rs6000_hard_regno_mode_ok_p[m][r] = true; |
| |
| /* Precalculate CLASS_MAX_NREGS sizes. */ |
| for (c = 0; c < LIM_REG_CLASSES; ++c) |
| { |
| int reg_size; |
| |
| if (TARGET_VSX && VSX_REG_CLASS_P (c)) |
| reg_size = UNITS_PER_VSX_WORD; |
| |
| else if (c == ALTIVEC_REGS) |
| reg_size = UNITS_PER_ALTIVEC_WORD; |
| |
| else if (c == FLOAT_REGS) |
| reg_size = UNITS_PER_FP_WORD; |
| |
| else |
| reg_size = UNITS_PER_WORD; |
| |
| for (m = 0; m < NUM_MACHINE_MODES; ++m) |
| { |
| machine_mode m2 = (machine_mode)m; |
| int reg_size2 = reg_size; |
| |
| /* TFmode/TDmode always takes 2 registers, even in VSX. */ |
| if (TARGET_VSX && VSX_REG_CLASS_P (c) |
| && (m == TDmode || m == TFmode)) |
| reg_size2 = UNITS_PER_FP_WORD; |
| |
| rs6000_class_max_nregs[m][c] |
| = (GET_MODE_SIZE (m2) + reg_size2 - 1) / reg_size2; |
| } |
| } |
| |
| if (TARGET_E500_DOUBLE) |
| rs6000_class_max_nregs[DFmode][GENERAL_REGS] = 1; |
| |
| /* Calculate which modes to automatically generate code to use a the |
| reciprocal divide and square root instructions. In the future, possibly |
| automatically generate the instructions even if the user did not specify |
| -mrecip. The older machines double precision reciprocal sqrt estimate is |
| not accurate enough. */ |
| memset (rs6000_recip_bits, 0, sizeof (rs6000_recip_bits)); |
| if (TARGET_FRES) |
| rs6000_recip_bits[SFmode] = RS6000_RECIP_MASK_HAVE_RE; |
| if (TARGET_FRE) |
| rs6000_recip_bits[DFmode] = RS6000_RECIP_MASK_HAVE_RE; |
| if (VECTOR_UNIT_ALTIVEC_OR_VSX_P (V4SFmode)) |
| rs6000_recip_bits[V4SFmode] = RS6000_RECIP_MASK_HAVE_RE; |
| if (VECTOR_UNIT_VSX_P (V2DFmode)) |
| rs6000_recip_bits[V2DFmode] = RS6000_RECIP_MASK_HAVE_RE; |
| |
| if (TARGET_FRSQRTES) |
| rs6000_recip_bits[SFmode] |= RS6000_RECIP_MASK_HAVE_RSQRTE; |
| if (TARGET_FRSQRTE) |
| rs6000_recip_bits[DFmode] |= RS6000_RECIP_MASK_HAVE_RSQRTE; |
| if (VECTOR_UNIT_ALTIVEC_OR_VSX_P (V4SFmode)) |
| rs6000_recip_bits[V4SFmode] |= RS6000_RECIP_MASK_HAVE_RSQRTE; |
| if (VECTOR_UNIT_VSX_P (V2DFmode)) |
| rs6000_recip_bits[V2DFmode] |= RS6000_RECIP_MASK_HAVE_RSQRTE; |
| |
| if (rs6000_recip_control) |
| { |
| if (!flag_finite_math_only) |
| warning (0, "-mrecip requires -ffinite-math or -ffast-math"); |
| if (flag_trapping_math) |
| warning (0, "-mrecip requires -fno-trapping-math or -ffast-math"); |
| if (!flag_reciprocal_math) |
| warning (0, "-mrecip requires -freciprocal-math or -ffast-math"); |
| if (flag_finite_math_only && !flag_trapping_math && flag_reciprocal_math) |
| { |
| if (RS6000_RECIP_HAVE_RE_P (SFmode) |
| && (rs6000_recip_control & RECIP_SF_DIV) != 0) |
| rs6000_recip_bits[SFmode] |= RS6000_RECIP_MASK_AUTO_RE; |
| |
| if (RS6000_RECIP_HAVE_RE_P (DFmode) |
| && (rs6000_recip_control & RECIP_DF_DIV) != 0) |
| rs6000_recip_bits[DFmode] |= RS6000_RECIP_MASK_AUTO_RE; |
| |
| if (RS6000_RECIP_HAVE_RE_P (V4SFmode) |
| && (rs6000_recip_control & RECIP_V4SF_DIV) != 0) |
| rs6000_recip_bits[V4SFmode] |= RS6000_RECIP_MASK_AUTO_RE; |
| |
| if (RS6000_RECIP_HAVE_RE_P (V2DFmode) |
| && (rs6000_recip_control & RECIP_V2DF_DIV) != 0) |
| rs6000_recip_bits[V2DFmode] |= RS6000_RECIP_MASK_AUTO_RE; |
| |
| if (RS6000_RECIP_HAVE_RSQRTE_P (SFmode) |
| && (r
|