rs6000.c (rs6000_emit_move): #if 0 splitting slow, unaligned loads and stores while...
[platform/upstream/gcc.git] / gcc / config / rs6000 / rs6000.c
index 5f24cf8..4969cd1 100644 (file)
@@ -230,7 +230,7 @@ int toc_initialized;
 char toc_label_name[10];
 
 /* Alias set for saves and restores from the rs6000 stack.  */
-static int rs6000_sr_alias_set;
+static GTY(()) int rs6000_sr_alias_set;
 
 /* Call distance, overridden by -mlongcall and #pragma longcall(1).
    The only place that looks at this is rs6000_set_default_type_attributes;
@@ -2317,6 +2317,26 @@ input_operand (rtx op, enum machine_mode mode)
   return 0;
 }
 
+
+/* Darwin, AIX increases natural record alignment to doubleword if the first
+   field is an FP double while the FP fields remain word aligned.  */
+
+unsigned int
+rs6000_special_round_type_align (tree type, int computed, int specified)
+{
+  tree field = TYPE_FIELDS (type);
+
+  /* Skip all the static variables only if ABI is greater than
+     1 or equal to 0.   */
+  while (field != NULL && TREE_CODE (field) == VAR_DECL)
+    field = TREE_CHAIN (field);
+
+  if (field == NULL || field == type || DECL_MODE (field) != DFmode)
+    return MAX (computed, specified);
+
+  return MAX (MAX (computed, specified), 64);
+}
+
 /* Return 1 for an operand in small memory on V.4/eabi.  */
 
 int
@@ -3406,6 +3426,47 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
                      adjust_address (operands[1], SImode, 4));
       return;
     }
+#if 0
+    else if (mode == DImode && TARGET_POWERPC64
+               && GET_CODE (operands[0]) == REG
+               && GET_CODE (operands[1]) == MEM && optimize > 0
+               && SLOW_UNALIGNED_ACCESS (DImode,
+                                         MEM_ALIGN (operands[1]) > 32
+                                         ? 32
+                                         : MEM_ALIGN (operands[1]))
+               && !no_new_pseudos)
+      {
+        rtx reg = gen_reg_rtx (SImode);
+       emit_insn (gen_rtx_SET (SImode, reg,
+                               adjust_address (operands[1], SImode, 0)));
+        reg = simplify_gen_subreg (DImode, reg, SImode, 0);
+        emit_insn (gen_insvdi (operands[0], GEN_INT (32), const0_rtx, reg));
+        reg = gen_reg_rtx (SImode);
+       emit_insn (gen_rtx_SET (SImode, reg,
+                               adjust_address (operands[1], SImode, 4)));
+        reg = simplify_gen_subreg (DImode, reg, SImode, 0);
+        emit_insn (gen_insvdi (operands[0], GEN_INT (32), GEN_INT (32), reg));
+        return;
+      }
+      else if (mode == DImode && TARGET_POWERPC64
+               && GET_CODE (operands[1]) == REG
+               && GET_CODE (operands[0]) == MEM && optimize > 0
+               && SLOW_UNALIGNED_ACCESS (DImode,
+                                         MEM_ALIGN (operands[0]) > 32
+                                         ? 32
+                                         : MEM_ALIGN (operands[0]))
+               && !no_new_pseudos)
+      {
+        rtx reg = gen_reg_rtx (DImode);
+        emit_move_insn (reg,
+                       gen_rtx_LSHIFTRT (DImode, operands[1], GEN_INT (32)));
+        emit_move_insn (adjust_address (operands[0], SImode, 0),
+                       simplify_gen_subreg (SImode, reg, DImode, 0));
+        emit_move_insn (adjust_address (operands[0], SImode, 4),
+                       simplify_gen_subreg (SImode, operands[1], DImode, 0));
+        return;
+      }
+#endif
   
   if (!no_new_pseudos)
     {
@@ -3921,10 +3982,12 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
       if (USE_ALTIVEC_FOR_ARG_P (cum, mode, type, named))
        cum->vregno++;
       
-      /* In variable-argument functions, vector arguments get GPRs allocated
-        even if they are going to be passed in a vector register.  */
-      if (cum->stdarg && DEFAULT_ABI != ABI_V4)
-       {
+      /* PowerPC64 Linux and AIX allocates GPRs for a vector argument
+        even if it is going to be passed in a vector register.  
+        Darwin does the same for variable-argument functions.  */
+      if ((DEFAULT_ABI == ABI_AIX && TARGET_64BIT)
+                  || (cum->stdarg && DEFAULT_ABI != ABI_V4))
+        {
          int align;
          
          /* Vector parameters must be 16-byte aligned.  This places
@@ -4228,7 +4291,32 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
     }
 
   if (USE_ALTIVEC_FOR_ARG_P (cum, mode, type, named))
-    return gen_rtx_REG (mode, cum->vregno);
+    if (TARGET_64BIT && ! cum->prototype)
+      {
+       /* Vector parameters get passed in vector register
+          and also in GPRs or memory, in absence of prototype.  */
+       int align_words;
+       rtx slot;
+       align_words = (cum->words + 1) & ~1;
+
+       if (align_words >= GP_ARG_NUM_REG)
+         {
+           slot = NULL_RTX;
+         }
+       else
+         {
+           slot = gen_rtx_REG (mode, GP_ARG_MIN_REG + align_words);
+         }
+       return gen_rtx_PARALLEL (mode,
+                gen_rtvec (2,
+                           gen_rtx_EXPR_LIST (VOIDmode,
+                                              slot, const0_rtx),
+                           gen_rtx_EXPR_LIST (VOIDmode,
+                                              gen_rtx_REG (mode, cum->vregno),
+                                              const0_rtx)));
+      }
+    else
+      return gen_rtx_REG (mode, cum->vregno);
   else if (TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (mode))
     {
       if (named || abi == ABI_V4)
@@ -4413,7 +4501,7 @@ function_arg_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
 }
 
 static void
-rs6000_move_block_from_reg(int regno, rtx x, int nregs)
+rs6000_move_block_from_reg (int regno, rtx x, int nregs)
 {
   int i;
   enum machine_mode reg_mode = TARGET_32BIT ? SImode : DImode;
@@ -4678,29 +4766,7 @@ rs6000_va_arg (tree valist, tree type)
          return expand_expr (t, NULL_RTX, VOIDmode, EXPAND_NORMAL);
        }
       else
-       {
-         /* Altivec arguments must be aligned to a 128-bit boundary.  */
-         if (TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (TYPE_MODE (type)))
-           {
-             tree vtype = TREE_TYPE (valist);
-             tree new_valist, modify;
-             
-             /* Round address up to multiple of 16.  Computes
-                (addr+15)&~0xf.  */
-             new_valist = fold (build (BIT_AND_EXPR, vtype,
-                                       fold (build (PLUS_EXPR, vtype, valist,
-                                                    build_int_2 (15, 0))),
-                                       build_int_2 (~15, -1)));
-
-             /* Update valist.  */
-             modify = build (MODIFY_EXPR, TREE_TYPE (valist), valist,
-                             new_valist);
-             TREE_SIDE_EFFECTS (modify) = 1;
-             expand_expr (modify, const0_rtx, VOIDmode, EXPAND_NORMAL);
-           }
-         
-         return std_expand_builtin_va_arg (valist, type);
-       }
+       return std_expand_builtin_va_arg (valist, type);
     }
 
   f_gpr = TYPE_FIELDS (TREE_TYPE (va_list_type_node));
@@ -10508,16 +10574,15 @@ rs6000_stack_info (void)
   else
     info_ptr->spe_gp_size = 0;
 
-  if (TARGET_ALTIVEC_ABI && TARGET_ALTIVEC_VRSAVE)
-    {
-      info_ptr->vrsave_mask = compute_vrsave_mask ();
-      info_ptr->vrsave_size  = info_ptr->vrsave_mask ? 4 : 0;
-    }
+  if (TARGET_ALTIVEC_ABI)
+    info_ptr->vrsave_mask = compute_vrsave_mask ();
   else
-    {
-      info_ptr->vrsave_mask = 0;
-      info_ptr->vrsave_size = 0;
-    }
+    info_ptr->vrsave_mask = 0;
+
+  if (TARGET_ALTIVEC_VRSAVE && info_ptr->vrsave_mask)
+    info_ptr->vrsave_size  = 4;
+  else
+    info_ptr->vrsave_size  = 0;
 
   /* Calculate the offsets.  */
   switch (DEFAULT_ABI)
@@ -11129,21 +11194,21 @@ rs6000_emit_eh_reg_restore (rtx source, rtx scratch)
     emit_move_insn (gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM), operands[0]);
 }
 
+static GTY(()) int set = -1;
+
 int   
 get_TOC_alias_set (void)
 {
-    static int set = -1;
-    if (set == -1)
-      set = new_alias_set ();
-    return set;
+  if (set == -1)
+    set = new_alias_set ();
+  return set;
 }   
 
 /* This returns nonzero if the current function uses the TOC.  This is
-   determined by the presence of (unspec ... UNSPEC_TOC) or
-   use (unspec ... UNSPEC_TOC), which are generated by the various
-   load_toc_* patterns.  */
-
-int
+   determined by the presence of (use (unspec ... UNSPEC_TOC)), which
+   is generated by the ABI_V4 load_toc_* patterns.  */
+#if TARGET_ELF
+static int
 uses_TOC (void) 
 {
   rtx insn;
@@ -11169,6 +11234,7 @@ uses_TOC (void)
       }
   return 0;
 }
+#endif
 
 rtx
 create_TOC_reference (rtx symbol) 
@@ -11679,7 +11745,8 @@ rs6000_emit_prologue (void)
      used in this function, and do the corresponding magic in the
      epilogue.  */
 
-  if (TARGET_ALTIVEC && info->vrsave_mask != 0)
+  if (TARGET_ALTIVEC && TARGET_ALTIVEC_VRSAVE
+      && info->vrsave_mask != 0)
     {
       rtx reg, mem, vrsave;
       int offset;
@@ -12141,7 +12208,8 @@ rs6000_emit_epilogue (int sibcall)
     }
 
   /* Restore VRSAVE if needed.  */
-  if (TARGET_ALTIVEC_ABI && info->vrsave_mask != 0)
+  if (TARGET_ALTIVEC_ABI && TARGET_ALTIVEC_VRSAVE 
+      && info->vrsave_mask != 0)
     {
       rtx addr, mem, reg;
 
@@ -15166,7 +15234,7 @@ rs6000_elf_declare_function_name (FILE *file, const char *name, tree decl)
 
   if (TARGET_RELOCATABLE
       && (get_pool_size () != 0 || current_function_profile)
-      && uses_TOC())
+      && uses_TOC ())
     {
       char buf[256];