summaryrefslogtreecommitdiff
path: root/gcc/config/rs6000
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/config/rs6000')
-rw-r--r--gcc/config/rs6000/rs6000-protos.h5
-rw-r--r--gcc/config/rs6000/rs6000.c196
-rw-r--r--gcc/config/rs6000/rs6000.h36
-rw-r--r--gcc/config/rs6000/rs6000.md14
-rw-r--r--gcc/config/rs6000/vector.md10
-rw-r--r--gcc/config/rs6000/vsx.md145
-rw-r--r--gcc/config/rs6000/xcoff.h14
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.