diff options
Diffstat (limited to 'gcc/config/rs6000')
-rw-r--r-- | gcc/config/rs6000/rs6000-protos.h | 5 | ||||
-rw-r--r-- | gcc/config/rs6000/rs6000.c | 196 | ||||
-rw-r--r-- | gcc/config/rs6000/rs6000.h | 36 | ||||
-rw-r--r-- | gcc/config/rs6000/rs6000.md | 14 | ||||
-rw-r--r-- | gcc/config/rs6000/vector.md | 10 | ||||
-rw-r--r-- | gcc/config/rs6000/vsx.md | 145 | ||||
-rw-r--r-- | gcc/config/rs6000/xcoff.h | 14 |
7 files changed, 346 insertions, 74 deletions
diff --git a/gcc/config/rs6000/rs6000-protos.h b/gcc/config/rs6000/rs6000-protos.h index 8f07450d72b..989557f76c9 100644 --- a/gcc/config/rs6000/rs6000-protos.h +++ b/gcc/config/rs6000/rs6000-protos.h @@ -187,8 +187,13 @@ extern rtx rs6000_libcall_value (machine_mode); extern rtx rs6000_va_arg (tree, tree); extern int function_ok_for_sibcall (tree); extern int rs6000_reg_parm_stack_space (tree, bool); +extern void rs6000_asm_weaken_decl (FILE *, tree, const char *, const char *); extern void rs6000_xcoff_declare_function_name (FILE *, const char *, tree); extern void rs6000_xcoff_declare_object_name (FILE *, const char *, tree); +extern void rs6000_xcoff_asm_output_aligned_decl_common (FILE *, tree, + const char *, + unsigned HOST_WIDE_INT, + unsigned HOST_WIDE_INT); extern void rs6000_elf_declare_function_name (FILE *, const char *, tree); extern bool rs6000_elf_in_small_data_p (const_tree); #ifdef ARGS_SIZE_RTX diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index f9e47393288..b0c2b2e69ee 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -56,6 +56,7 @@ #include "sched-int.h" #include "gimplify.h" #include "gimple-iterator.h" +#include "gimple-ssa.h" #include "gimple-walk.h" #include "intl.h" #include "params.h" @@ -1632,6 +1633,8 @@ static const struct attribute_spec rs6000_attribute_table[] = #undef TARGET_FOLD_BUILTIN #define TARGET_FOLD_BUILTIN rs6000_fold_builtin +#undef TARGET_GIMPLE_FOLD_BUILTIN +#define TARGET_GIMPLE_FOLD_BUILTIN rs6000_gimple_fold_builtin #undef TARGET_EXPAND_BUILTIN #define TARGET_EXPAND_BUILTIN rs6000_expand_builtin @@ -16391,6 +16394,46 @@ rs6000_fold_builtin (tree fndecl, int n_args ATTRIBUTE_UNUSED, #endif } +/* Fold a machine-dependent built-in in GIMPLE. (For folding into + a constant, use rs6000_fold_builtin.) */ + +bool +rs6000_gimple_fold_builtin (gimple_stmt_iterator *gsi) +{ + gimple *stmt = gsi_stmt (*gsi); + tree fndecl = gimple_call_fndecl (stmt); + gcc_checking_assert (fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD); + enum rs6000_builtins fn_code + = (enum rs6000_builtins) DECL_FUNCTION_CODE (fndecl); + tree arg0, arg1, lhs; + + switch (fn_code) + { + /* Flavors of vec_add. We deliberately don't expand + P8V_BUILTIN_VADDUQM as it gets lowered from V1TImode to + TImode, resulting in much poorer code generation. */ + case ALTIVEC_BUILTIN_VADDUBM: + case ALTIVEC_BUILTIN_VADDUHM: + case ALTIVEC_BUILTIN_VADDUWM: + case P8V_BUILTIN_VADDUDM: + case ALTIVEC_BUILTIN_VADDFP: + case VSX_BUILTIN_XVADDDP: + { + arg0 = gimple_call_arg (stmt, 0); + arg1 = gimple_call_arg (stmt, 1); + lhs = gimple_call_lhs (stmt); + gimple *g = gimple_build_assign (lhs, PLUS_EXPR, arg0, arg1); + gimple_set_location (g, gimple_location (stmt)); + gsi_replace (gsi, g, true); + return true; + } + default: + break; + } + + return false; +} + /* Expand an expression EXP that calls a built-in function, with result going to TARGET if that's convenient (and in mode MODE if that's convenient). @@ -16939,11 +16982,10 @@ rs6000_init_builtins (void) def_builtin ("__builtin_cpu_is", ftype, RS6000_BUILTIN_CPU_IS); def_builtin ("__builtin_cpu_supports", ftype, RS6000_BUILTIN_CPU_SUPPORTS); -#if TARGET_XCOFF /* AIX libm provides clog as __clog. */ - if ((tdecl = builtin_decl_explicit (BUILT_IN_CLOG)) != NULL_TREE) + if (TARGET_XCOFF && + (tdecl = builtin_decl_explicit (BUILT_IN_CLOG)) != NULL_TREE) set_user_assembler_name (tdecl, "__clog"); -#endif #ifdef SUBTARGET_INIT_BUILTINS SUBTARGET_INIT_BUILTINS; @@ -26996,8 +27038,8 @@ output_probe_stack_range (rtx reg1, rtx reg2) pointer. That fails when saving regs off r1, and sched moves the r31 setup past the reg saves. */ -static rtx -rs6000_frame_related (rtx insn, rtx reg, HOST_WIDE_INT val, +static rtx_insn * +rs6000_frame_related (rtx_insn *insn, rtx reg, HOST_WIDE_INT val, rtx reg2, rtx repl2) { rtx repl; @@ -27161,11 +27203,11 @@ gen_frame_store (rtx reg, rtx frame_reg, int offset) /* Save a register into the frame, and emit RTX_FRAME_RELATED_P notes. Save REGNO into [FRAME_REG + OFFSET] in mode MODE. */ -static rtx +static rtx_insn * emit_frame_save (rtx frame_reg, machine_mode mode, unsigned int regno, int offset, HOST_WIDE_INT frame_reg_to_sp) { - rtx reg, insn; + rtx reg; /* Some cases that need register indexed addressing. */ gcc_checking_assert (!((TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (mode)) @@ -27176,7 +27218,7 @@ emit_frame_save (rtx frame_reg, machine_mode mode, && !SPE_CONST_OFFSET_OK (offset)))); reg = gen_rtx_REG (mode, regno); - insn = emit_insn (gen_frame_store (reg, frame_reg, offset)); + rtx_insn *insn = emit_insn (gen_frame_store (reg, frame_reg, offset)); return rs6000_frame_related (insn, frame_reg, frame_reg_to_sp, NULL_RTX, NULL_RTX); } @@ -27444,7 +27486,7 @@ ptr_regno_for_savres (int sel) out-of-line register save/restore routine, and emit the insn or jump_insn as appropriate. */ -static rtx +static rtx_insn * rs6000_emit_savres_rtx (rs6000_stack_t *info, rtx frame_reg_rtx, int save_area_offset, int lr_offset, machine_mode reg_mode, int sel) @@ -27454,7 +27496,8 @@ rs6000_emit_savres_rtx (rs6000_stack_t *info, int reg_size = GET_MODE_SIZE (reg_mode); rtx sym; rtvec p; - rtx par, insn; + rtx par; + rtx_insn *insn; offset = 0; start_reg = ((sel & SAVRES_REG) == SAVRES_GPR @@ -27633,6 +27676,9 @@ rs6000_get_separate_components (void) if (WORLD_SAVE_P (info)) return NULL; + if (TARGET_SPE_ABI) + return NULL; + sbitmap components = sbitmap_alloc (32); bitmap_clear (components); @@ -27854,7 +27900,7 @@ rs6000_emit_prologue (void) rtx frame_reg_rtx = sp_reg_rtx; unsigned int cr_save_regno; rtx cr_save_rtx = NULL_RTX; - rtx insn; + rtx_insn *insn; int strategy; int using_static_chain_p = (cfun->static_chain_decl != NULL_TREE && df_regs_ever_live_p (STATIC_CHAIN_REGNUM) @@ -28360,12 +28406,12 @@ rs6000_emit_prologue (void) if (regno == INVALID_REGNUM) break; - insn + rtx set = gen_frame_store (gen_rtx_REG (reg_mode, regno), sp_reg_rtx, info->ehrd_offset + sp_off + reg_size * (int) i); - RTVEC_ELT (p, i) = insn; - RTX_FRAME_RELATED_P (insn) = 1; + RTVEC_ELT (p, i) = set; + RTX_FRAME_RELATED_P (set) = 1; } insn = emit_insn (gen_blockage ()); @@ -28377,7 +28423,8 @@ rs6000_emit_prologue (void) if (TARGET_AIX && crtl->calls_eh_return) { rtx tmp_reg, tmp_reg_si, hi, lo, compare_result, toc_save_done, jump; - rtx save_insn, join_insn, note; + rtx join_insn, note; + rtx_insn *save_insn; long toc_restore_insn; tmp_reg = gen_rtx_REG (Pmode, 11); @@ -35316,6 +35363,31 @@ rs6000_declare_alias (struct symtab_node *n, void *d) return false; } + +#ifdef HAVE_GAS_HIDDEN +/* Helper function to calculate visibility of a DECL + and return the value as a const string. */ + +static const char * +rs6000_xcoff_visibility (tree decl) +{ + static const char * const visibility_types[] = { + "", ",protected", ",hidden", ",internal" + }; + + enum symbol_visibility vis = DECL_VISIBILITY (decl); + + if (TREE_CODE (decl) == FUNCTION_DECL + && cgraph_node::get (decl) + && cgraph_node::get (decl)->instrumentation_clone + && cgraph_node::get (decl)->instrumented_version) + vis = DECL_VISIBILITY (cgraph_node::get (decl)->instrumented_version->decl); + + return visibility_types[vis]; +} +#endif + + /* This macro produces the initial definition of a function name. On the RS/6000, we need to place an extra '.' in the function name and output the function descriptor. @@ -35355,6 +35427,9 @@ rs6000_xcoff_declare_function_name (FILE *file, const char *name, tree decl) } fputs ("\t.globl .", file); RS6000_OUTPUT_BASENAME (file, buffer); +#ifdef HAVE_GAS_HIDDEN + fputs (rs6000_xcoff_visibility (decl), file); +#endif putc ('\n', file); } } @@ -35399,6 +35474,52 @@ rs6000_xcoff_declare_function_name (FILE *file, const char *name, tree decl) return; } + +/* Output assembly language to globalize a symbol from a DECL, + possibly with visibility. */ + +void +rs6000_xcoff_asm_globalize_decl_name (FILE *stream, tree decl) +{ + const char *name = XSTR (XEXP (DECL_RTL (decl), 0), 0); + fputs (GLOBAL_ASM_OP, stream); + RS6000_OUTPUT_BASENAME (stream, name); +#ifdef HAVE_GAS_HIDDEN + fputs (rs6000_xcoff_visibility (decl), stream); +#endif + putc ('\n', stream); +} + +/* Output assembly language to define a symbol as COMMON from a DECL, + possibly with visibility. */ + +void +rs6000_xcoff_asm_output_aligned_decl_common (FILE *stream, + tree decl ATTRIBUTE_UNUSED, + const char *name, + unsigned HOST_WIDE_INT size, + unsigned HOST_WIDE_INT align) +{ + unsigned HOST_WIDE_INT align2 = 2; + + if (align > 32) + align2 = floor_log2 (align / BITS_PER_UNIT); + else if (size > 4) + align2 = 3; + + fputs (COMMON_ASM_OP, stream); + RS6000_OUTPUT_BASENAME (stream, name); + + fprintf (stream, + "," HOST_WIDE_INT_PRINT_UNSIGNED "," HOST_WIDE_INT_PRINT_UNSIGNED, + size, align2); + +#ifdef HAVE_GAS_HIDDEN + fputs (rs6000_xcoff_visibility (decl), stream); +#endif + putc ('\n', stream); +} + /* This macro produces the initial definition of a object (variable) name. Because AIX assembler's .set command has unexpected semantics, we output all aliases as alternative labels in front of the definition. */ @@ -35409,8 +35530,8 @@ rs6000_xcoff_declare_object_name (FILE *file, const char *name, tree decl) struct declare_alias_data data = {file, false}; RS6000_OUTPUT_BASENAME (file, name); fputs (":\n", file); - symtab_node::get (decl)->call_for_symbol_and_aliases (rs6000_declare_alias, - &data, true); + symtab_node::get_create (decl)->call_for_symbol_and_aliases (rs6000_declare_alias, + &data, true); } /* Overide the default 'SYMBOL-.' syntax with AIX compatible 'SYMBOL-$'. */ @@ -35480,6 +35601,45 @@ rs6000_xcoff_encode_section_info (tree decl, rtx rtl, int first) #endif /* HAVE_AS_TLS */ #endif /* TARGET_XCOFF */ +void +rs6000_asm_weaken_decl (FILE *stream, tree decl, + const char *name, const char *val) +{ + fputs ("\t.weak\t", stream); + RS6000_OUTPUT_BASENAME (stream, name); + if (decl && TREE_CODE (decl) == FUNCTION_DECL + && DEFAULT_ABI == ABI_AIX && DOT_SYMBOLS) + { + if (TARGET_XCOFF) + fputs ("[DS]", stream); +#if TARGET_XCOFF && HAVE_GAS_HIDDEN + if (TARGET_XCOFF) + fputs (rs6000_xcoff_visibility (decl), stream); +#endif + fputs ("\n\t.weak\t.", stream); + RS6000_OUTPUT_BASENAME (stream, name); + } +#if TARGET_XCOFF && HAVE_GAS_HIDDEN + if (TARGET_XCOFF) + fputs (rs6000_xcoff_visibility (decl), stream); +#endif + fputc ('\n', stream); + if (val) + { + ASM_OUTPUT_DEF (stream, name, val); + if (decl && TREE_CODE (decl) == FUNCTION_DECL + && DEFAULT_ABI == ABI_AIX && DOT_SYMBOLS) + { + fputs ("\t.set\t.", stream); + RS6000_OUTPUT_BASENAME (stream, name); + fputs (",.", stream); + RS6000_OUTPUT_BASENAME (stream, val); + fputc ('\n', stream); + } + } +} + + /* Return true if INSN should not be copied. */ static bool @@ -38651,7 +38811,7 @@ rs6000_code_end (void) TREE_STATIC (decl) = 1; #if RS6000_WEAK - if (USE_HIDDEN_LINKONCE) + if (USE_HIDDEN_LINKONCE && !TARGET_XCOFF) { cgraph_node::create (decl)->set_comdat_group (DECL_ASSEMBLER_NAME (decl)); targetm.asm_out.unique_section (decl, 0); diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h index 4b83abdf753..1148212c7ff 100644 --- a/gcc/config/rs6000/rs6000.h +++ b/gcc/config/rs6000/rs6000.h @@ -442,14 +442,15 @@ extern const char *host_detect_local_cpu (int argc, const char **argv); point. KFmode was added as a way to represent IEEE 128-bit floating point, even if the default for long double is the IBM long double format. Similarly IFmode is the IBM long double format even if the default is IEEE - 128-bit. */ + 128-bit. Don't allow IFmode if -msoft-float. */ #define FLOAT128_IEEE_P(MODE) \ ((TARGET_IEEEQUAD && ((MODE) == TFmode || (MODE) == TCmode)) \ || ((MODE) == KFmode) || ((MODE) == KCmode)) #define FLOAT128_IBM_P(MODE) \ ((!TARGET_IEEEQUAD && ((MODE) == TFmode || (MODE) == TCmode)) \ - || ((MODE) == IFmode) || ((MODE) == ICmode)) + || (TARGET_HARD_FLOAT && TARGET_FPRS \ + && ((MODE) == IFmode || (MODE) == ICmode))) /* Helper macros to say whether a 128-bit floating point type can go in a single vector register, or whether it needs paired scalar values. */ @@ -2281,35 +2282,8 @@ extern int toc_initialized; #if RS6000_WEAK /* Used in lieu of ASM_WEAKEN_LABEL. */ -#define ASM_WEAKEN_DECL(FILE, DECL, NAME, VAL) \ - do \ - { \ - fputs ("\t.weak\t", (FILE)); \ - RS6000_OUTPUT_BASENAME ((FILE), (NAME)); \ - if ((DECL) && TREE_CODE (DECL) == FUNCTION_DECL \ - && DEFAULT_ABI == ABI_AIX && DOT_SYMBOLS) \ - { \ - if (TARGET_XCOFF) \ - fputs ("[DS]", (FILE)); \ - fputs ("\n\t.weak\t.", (FILE)); \ - RS6000_OUTPUT_BASENAME ((FILE), (NAME)); \ - } \ - fputc ('\n', (FILE)); \ - if (VAL) \ - { \ - ASM_OUTPUT_DEF ((FILE), (NAME), (VAL)); \ - if ((DECL) && TREE_CODE (DECL) == FUNCTION_DECL \ - && DEFAULT_ABI == ABI_AIX && DOT_SYMBOLS) \ - { \ - fputs ("\t.set\t.", (FILE)); \ - RS6000_OUTPUT_BASENAME ((FILE), (NAME)); \ - fputs (",.", (FILE)); \ - RS6000_OUTPUT_BASENAME ((FILE), (VAL)); \ - fputc ('\n', (FILE)); \ - } \ - } \ - } \ - while (0) +#define ASM_WEAKEN_DECL(FILE, DECL, NAME, VAL) \ + rs6000_asm_weaken_decl ((FILE), (DECL), (NAME), (VAL)) #endif #if HAVE_GAS_WEAKREF diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md index bc8e52d6f6a..d4095498981 100644 --- a/gcc/config/rs6000/rs6000.md +++ b/gcc/config/rs6000/rs6000.md @@ -376,7 +376,7 @@ (TF "TARGET_HARD_FLOAT && (TARGET_FPRS || TARGET_E500_DOUBLE) && TARGET_LONG_DOUBLE_128") - (IF "TARGET_LONG_DOUBLE_128") + (IF "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_LONG_DOUBLE_128") (KF "TARGET_FLOAT128_TYPE") (DD "TARGET_DFP") (TD "TARGET_DFP")]) @@ -398,7 +398,7 @@ (define_mode_iterator FMOVE64 [DF DD]) (define_mode_iterator FMOVE64X [DI DF DD]) (define_mode_iterator FMOVE128 [(TF "TARGET_LONG_DOUBLE_128") - (IF "TARGET_LONG_DOUBLE_128") + (IF "FLOAT128_IBM_P (IFmode)") (TD "TARGET_HARD_FLOAT && TARGET_FPRS")]) (define_mode_iterator FMOVE128_FPR [(TF "FLOAT128_2REG_P (TFmode)") @@ -4460,7 +4460,15 @@ (div:SFDF (match_operand:SFDF 1 "gpc_reg_operand" "") (match_operand:SFDF 2 "gpc_reg_operand" "")))] "TARGET_<MODE>_INSN && !TARGET_SIMPLE_FPU" - "") +{ + if (RS6000_RECIP_AUTO_RE_P (<MODE>mode) + && can_create_pseudo_p () && flag_finite_math_only + && !flag_trapping_math && flag_reciprocal_math) + { + rs6000_emit_swdiv (operands[0], operands[1], operands[2], true); + DONE; + } +}) (define_insn "*div<mode>3_fpr" [(set (match_operand:SFDF 0 "gpc_reg_operand" "=<Ff>,<Fv2>") diff --git a/gcc/config/rs6000/vector.md b/gcc/config/rs6000/vector.md index 7240345bce0..05f3bdbee56 100644 --- a/gcc/config/rs6000/vector.md +++ b/gcc/config/rs6000/vector.md @@ -248,7 +248,15 @@ (div:VEC_F (match_operand:VEC_F 1 "vfloat_operand" "") (match_operand:VEC_F 2 "vfloat_operand" "")))] "VECTOR_UNIT_VSX_P (<MODE>mode)" - "") +{ + if (RS6000_RECIP_AUTO_RE_P (<MODE>mode) + && can_create_pseudo_p () && flag_finite_math_only + && !flag_trapping_math && flag_reciprocal_math) + { + rs6000_emit_swdiv (operands[0], operands[1], operands[2], true); + DONE; + } +}) (define_expand "neg<mode>2" [(set (match_operand:VEC_F 0 "vfloat_operand" "") diff --git a/gcc/config/rs6000/vsx.md b/gcc/config/rs6000/vsx.md index 18f3e86e29f..2c74a8ebbe2 100644 --- a/gcc/config/rs6000/vsx.md +++ b/gcc/config/rs6000/vsx.md @@ -288,6 +288,16 @@ (V8HI "v") (V4SI "wa")]) +;; Mode iterator for binary floating types other than double to +;; optimize convert to that floating point type from an extract +;; of an integer type +(define_mode_iterator VSX_EXTRACT_FL [SF + (IF "FLOAT128_2REG_P (IFmode)") + (KF "TARGET_FLOAT128_HW") + (TF "FLOAT128_2REG_P (TFmode) + || (FLOAT128_IEEE_P (TFmode) + && TARGET_FLOAT128_HW)")]) + ;; Iterator for the 2 short vector types to do a splat from an integer (define_mode_iterator VSX_SPLAT_I [V16QI V8HI]) @@ -1907,6 +1917,7 @@ [(set_attr "type" "vecdouble")]) ;; Convert from 32-bit to 64-bit types +;; Provide both vector and scalar targets (define_insn "vsx_xvcvsxwdp" [(set (match_operand:V2DF 0 "vsx_register_operand" "=wd,?wa") (unspec:V2DF [(match_operand:V4SI 1 "vsx_register_operand" "wf,wa")] @@ -1915,6 +1926,14 @@ "xvcvsxwdp %x0,%x1" [(set_attr "type" "vecdouble")]) +(define_insn "vsx_xvcvsxwdp_df" + [(set (match_operand:DF 0 "vsx_register_operand" "=ws") + (unspec:DF [(match_operand:V4SI 1 "vsx_register_operand" "wa")] + UNSPEC_VSX_CVSXWDP))] + "TARGET_VSX" + "xvcvsxwdp %x0,%x1" + [(set_attr "type" "vecdouble")]) + (define_insn "vsx_xvcvuxwdp" [(set (match_operand:V2DF 0 "vsx_register_operand" "=wd,?wa") (unspec:V2DF [(match_operand:V4SI 1 "vsx_register_operand" "wf,wa")] @@ -1923,6 +1942,14 @@ "xvcvuxwdp %x0,%x1" [(set_attr "type" "vecdouble")]) +(define_insn "vsx_xvcvuxwdp_df" + [(set (match_operand:DF 0 "vsx_register_operand" "=ws") + (unspec:DF [(match_operand:V4SI 1 "vsx_register_operand" "wa")] + UNSPEC_VSX_CVUXWDP))] + "TARGET_VSX" + "xvcvuxwdp %x0,%x1" + [(set_attr "type" "vecdouble")]) + (define_insn "vsx_xvcvspsxds" [(set (match_operand:V2DI 0 "vsx_register_operand" "=v,?wa") (unspec:V2DI [(match_operand:V4SF 1 "vsx_register_operand" "wd,wa")] @@ -2559,11 +2586,10 @@ (parallel [(match_operand:QI 2 "<VSX_EXTRACT_PREDICATE>" "n")]))))] "VECTOR_MEM_VSX_P (<MODE>mode) && TARGET_VEXTRACTUB" { - int element = INTVAL (operands[2]); + /* Note, the element number has already been adjusted for endianness, so we + don't have to adjust it here. */ int unit_size = GET_MODE_UNIT_SIZE (<MODE>mode); - int offset = ((VECTOR_ELT_ORDER_BIG) - ? unit_size * element - : unit_size * (GET_MODE_NUNITS (<MODE>mode) - 1 - element)); + HOST_WIDE_INT offset = unit_size * INTVAL (operands[2]); operands[2] = GEN_INT (offset); if (unit_size == 4) @@ -2574,11 +2600,11 @@ [(set_attr "type" "vecsimple")]) (define_insn_and_split "*vsx_extract_si" - [(set (match_operand:SI 0 "nonimmediate_operand" "=r,Z,Z,wJwK") + [(set (match_operand:SI 0 "nonimmediate_operand" "=r,wHwI,Z") (vec_select:SI - (match_operand:V4SI 1 "gpc_reg_operand" "v,wJwK,v,v") - (parallel [(match_operand:QI 2 "const_0_to_3_operand" "n,n,n,n")]))) - (clobber (match_scratch:V4SI 3 "=v,wJwK,v,v"))] + (match_operand:V4SI 1 "gpc_reg_operand" "wJv,wJv,wJv") + (parallel [(match_operand:QI 2 "const_0_to_3_operand" "n,n,n")]))) + (clobber (match_scratch:V4SI 3 "=wJv,wJv,wJv"))] "VECTOR_MEM_VSX_P (V4SImode) && TARGET_DIRECT_MOVE_64BIT" "#" "&& reload_completed" @@ -2628,7 +2654,7 @@ DONE; } - [(set_attr "type" "mftgpr,fpstore,fpstore,vecsimple") + [(set_attr "type" "mftgpr,vecperm,fpstore") (set_attr "length" "8")]) (define_insn_and_split "*vsx_extract_<mode>_p8" @@ -2714,6 +2740,107 @@ DONE; }) +;; VSX_EXTRACT optimizations +;; Optimize double d = (double) vec_extract (vi, <n>) +;; Get the element into the top position and use XVCVSWDP/XVCVUWDP +(define_insn_and_split "*vsx_extract_si_<uns>float_df" + [(set (match_operand:DF 0 "gpc_reg_operand" "=ws") + (any_float:DF + (vec_select:SI + (match_operand:V4SI 1 "gpc_reg_operand" "v") + (parallel [(match_operand:QI 2 "const_0_to_3_operand" "n")])))) + (clobber (match_scratch:V4SI 3 "=v"))] + "VECTOR_MEM_VSX_P (V4SImode) && TARGET_DIRECT_MOVE_64BIT" + "#" + "&& 1" + [(const_int 0)] +{ + rtx dest = operands[0]; + rtx src = operands[1]; + rtx element = operands[2]; + rtx v4si_tmp = operands[3]; + int value; + + if (!VECTOR_ELT_ORDER_BIG) + element = GEN_INT (GET_MODE_NUNITS (V4SImode) - 1 - INTVAL (element)); + + /* If the value is in the correct position, we can avoid doing the VSPLT<x> + instruction. */ + value = INTVAL (element); + if (value != 0) + { + if (GET_CODE (v4si_tmp) == SCRATCH) + v4si_tmp = gen_reg_rtx (V4SImode); + emit_insn (gen_altivec_vspltw_direct (v4si_tmp, src, element)); + } + else + v4si_tmp = src; + + emit_insn (gen_vsx_xvcv<su>xwdp_df (dest, v4si_tmp)); + DONE; +}) + +;; Optimize <type> f = (<type>) vec_extract (vi, <n>) +;; where <type> is a floating point type that supported by the hardware that is +;; not double. First convert the value to double, and then to the desired +;; type. +(define_insn_and_split "*vsx_extract_si_<uns>float_<mode>" + [(set (match_operand:VSX_EXTRACT_FL 0 "gpc_reg_operand" "=ww") + (any_float:VSX_EXTRACT_FL + (vec_select:SI + (match_operand:V4SI 1 "gpc_reg_operand" "v") + (parallel [(match_operand:QI 2 "const_0_to_3_operand" "n")])))) + (clobber (match_scratch:V4SI 3 "=v")) + (clobber (match_scratch:DF 4 "=ws"))] + "VECTOR_MEM_VSX_P (V4SImode) && TARGET_DIRECT_MOVE_64BIT" + "#" + "&& 1" + [(const_int 0)] +{ + rtx dest = operands[0]; + rtx src = operands[1]; + rtx element = operands[2]; + rtx v4si_tmp = operands[3]; + rtx df_tmp = operands[4]; + int value; + + if (!VECTOR_ELT_ORDER_BIG) + element = GEN_INT (GET_MODE_NUNITS (V4SImode) - 1 - INTVAL (element)); + + /* If the value is in the correct position, we can avoid doing the VSPLT<x> + instruction. */ + value = INTVAL (element); + if (value != 0) + { + if (GET_CODE (v4si_tmp) == SCRATCH) + v4si_tmp = gen_reg_rtx (V4SImode); + emit_insn (gen_altivec_vspltw_direct (v4si_tmp, src, element)); + } + else + v4si_tmp = src; + + if (GET_CODE (df_tmp) == SCRATCH) + df_tmp = gen_reg_rtx (DFmode); + + emit_insn (gen_vsx_xvcv<su>xwdp_df (df_tmp, v4si_tmp)); + + if (<MODE>mode == SFmode) + emit_insn (gen_truncdfsf2 (dest, df_tmp)); + else if (<MODE>mode == TFmode && FLOAT128_IBM_P (TFmode)) + emit_insn (gen_extenddftf2_vsx (dest, df_tmp)); + else if (<MODE>mode == TFmode && FLOAT128_IEEE_P (TFmode) + && TARGET_FLOAT128_HW) + emit_insn (gen_extenddftf2_hw (dest, df_tmp)); + else if (<MODE>mode == IFmode && FLOAT128_IBM_P (IFmode)) + emit_insn (gen_extenddfif2 (dest, df_tmp)); + else if (<MODE>mode == KFmode && TARGET_FLOAT128_HW) + emit_insn (gen_extenddfkf2_hw (dest, df_tmp)); + else + gcc_unreachable (); + + DONE; +}) + ;; Expanders for builtins (define_expand "vsx_mergel_<mode>" [(use (match_operand:VSX_D 0 "vsx_register_operand" "")) diff --git a/gcc/config/rs6000/xcoff.h b/gcc/config/rs6000/xcoff.h index cfdc528ef95..f63d28720ce 100644 --- a/gcc/config/rs6000/xcoff.h +++ b/gcc/config/rs6000/xcoff.h @@ -89,6 +89,7 @@ #undef TARGET_DEBUG_UNWIND_INFO #define TARGET_DEBUG_UNWIND_INFO rs6000_xcoff_debug_unwind_info #define TARGET_ASM_OUTPUT_ANCHOR rs6000_xcoff_asm_output_anchor +#define TARGET_ASM_GLOBALIZE_DECL_NAME rs6000_xcoff_asm_globalize_decl_name #define TARGET_ASM_GLOBALIZE_LABEL rs6000_xcoff_asm_globalize_label #define TARGET_ASM_INIT_SECTIONS rs6000_xcoff_asm_init_sections #define TARGET_ASM_RELOC_RW_MASK rs6000_xcoff_reloc_rw_mask @@ -102,6 +103,7 @@ #ifdef HAVE_AS_TLS #define TARGET_ENCODE_SECTION_INFO rs6000_xcoff_encode_section_info #endif +#define ASM_OUTPUT_ALIGNED_DECL_COMMON rs6000_xcoff_asm_output_aligned_decl_common /* FP save and restore routines. */ #define SAVE_FP_PREFIX "._savef" @@ -217,18 +219,6 @@ #define COMMON_ASM_OP "\t.comm " -#define ASM_OUTPUT_ALIGNED_COMMON(FILE, NAME, SIZE, ALIGN) \ - do { fputs (COMMON_ASM_OP, (FILE)); \ - RS6000_OUTPUT_BASENAME ((FILE), (NAME)); \ - if ((ALIGN) > 32) \ - fprintf ((FILE), "," HOST_WIDE_INT_PRINT_UNSIGNED",%u\n", (SIZE), \ - floor_log2 ((ALIGN) / BITS_PER_UNIT)); \ - else if ((SIZE) > 4) \ - fprintf ((FILE), "," HOST_WIDE_INT_PRINT_UNSIGNED",3\n", (SIZE)); \ - else \ - fprintf ((FILE), "," HOST_WIDE_INT_PRINT_UNSIGNED"\n", (SIZE)); \ - } while (0) - /* This says how to output an assembler line to define a local common symbol. The assembler in AIX 6.1 and later supports an alignment argument. |