OSDN Git Service

* c-decl.c, config/avr/avr.c, config/avr/avr.h,
[pf3gnuchains/gcc-fork.git] / gcc / config / spu / spu.c
index 70f09c5..5297a7b 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2006 Free Software Foundation, Inc.
+/* Copyright (C) 2006, 2007 Free Software Foundation, Inc.
 
    This file 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
@@ -128,6 +128,11 @@ static unsigned char spu_rtx_costs (rtx x, int code, int outer_code,
 static unsigned char spu_function_ok_for_sibcall (tree decl, tree exp);
 static void spu_init_libfuncs (void);
 static bool spu_return_in_memory (tree type, tree fntype);
+static void fix_range (const char *);
+static void spu_encode_section_info (tree, rtx, int);
+static tree spu_builtin_mul_widen_even (tree);
+static tree spu_builtin_mul_widen_odd (tree);
+static tree spu_builtin_mask_for_load (void);
 
 extern const char *reg_names[];
 rtx spu_compare_op0, spu_compare_op1;
@@ -243,6 +248,18 @@ const struct attribute_spec spu_attribute_table[];
 #undef TARGET_RETURN_IN_MEMORY
 #define TARGET_RETURN_IN_MEMORY spu_return_in_memory
 
+#undef  TARGET_ENCODE_SECTION_INFO
+#define TARGET_ENCODE_SECTION_INFO spu_encode_section_info
+
+#undef TARGET_VECTORIZE_BUILTIN_MUL_WIDEN_EVEN
+#define TARGET_VECTORIZE_BUILTIN_MUL_WIDEN_EVEN spu_builtin_mul_widen_even
+
+#undef TARGET_VECTORIZE_BUILTIN_MUL_WIDEN_ODD
+#define TARGET_VECTORIZE_BUILTIN_MUL_WIDEN_ODD spu_builtin_mul_widen_odd
+
+#undef TARGET_VECTORIZE_BUILTIN_MASK_FOR_LOAD
+#define TARGET_VECTORIZE_BUILTIN_MASK_FOR_LOAD spu_builtin_mask_for_load
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 /* Sometimes certain combinations of command options do not make sense
@@ -252,7 +269,6 @@ struct gcc_target targetm = TARGET_INITIALIZER;
 void
 spu_override_options (void)
 {
-
   /* Override some of the default param values.  With so many registers
      larger values are better for these params.  */
   if (MAX_UNROLLED_INSNS == 100)
@@ -264,6 +280,9 @@ spu_override_options (void)
 
   if (align_functions < 8)
     align_functions = 8;
+
+  if (spu_fixed_range_string)
+    fix_range (spu_fixed_range_string);
 }
 \f
 /* Handle an attribute requiring a FUNCTION_DECL; arguments as in
@@ -1587,7 +1606,7 @@ spu_expand_prologue (void)
     {
       if (flag_stack_check)
        {
-         /* We compare agains total_size-1 because
+         /* We compare against total_size-1 because
             ($sp >= total_size) <=> ($sp > total_size-1) */
          rtx scratch_v4si = gen_rtx_REG (V4SImode, REGNO (scratch_reg_0));
          rtx sp_v4si = gen_rtx_REG (V4SImode, STACK_POINTER_REGNUM);
@@ -1610,21 +1629,18 @@ spu_expand_prologue (void)
        {
          /* In this case we save the back chain first. */
          insn = frame_emit_store (STACK_POINTER_REGNUM, sp_reg, -total_size);
-         RTX_FRAME_RELATED_P (insn) = 1;
          insn =
            frame_emit_add_imm (sp_reg, sp_reg, -total_size, scratch_reg_0);
        }
       else if (satisfies_constraint_K (GEN_INT (-total_size)))
        {
          insn = emit_move_insn (scratch_reg_0, sp_reg);
-         RTX_FRAME_RELATED_P (insn) = 1;
          insn =
            emit_insn (gen_addsi3 (sp_reg, sp_reg, GEN_INT (-total_size)));
        }
       else
        {
          insn = emit_move_insn (scratch_reg_0, sp_reg);
-         RTX_FRAME_RELATED_P (insn) = 1;
          insn =
            frame_emit_add_imm (sp_reg, sp_reg, -total_size, scratch_reg_1);
        }
@@ -1637,7 +1653,6 @@ spu_expand_prologue (void)
        {
          /* Save the back chain ptr */
          insn = frame_emit_store (REGNO (scratch_reg_0), sp_reg, 0);
-         RTX_FRAME_RELATED_P (insn) = 1;
        }
 
       if (frame_pointer_needed)
@@ -1646,7 +1661,12 @@ spu_expand_prologue (void)
          HOST_WIDE_INT fp_offset = STACK_POINTER_OFFSET
            + current_function_outgoing_args_size;
          /* Set the new frame_pointer */
-         frame_emit_add_imm (fp_reg, sp_reg, fp_offset, scratch_reg_0);
+         insn = frame_emit_add_imm (fp_reg, sp_reg, fp_offset, scratch_reg_0);
+         RTX_FRAME_RELATED_P (insn) = 1;
+         real = gen_addsi3 (fp_reg, sp_reg, GEN_INT (fp_offset));
+         REG_NOTES (insn) = 
+           gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
+                              real, REG_NOTES (insn));
        }
     }
 
@@ -1682,8 +1702,6 @@ spu_expand_epilogue (bool sibcall_p)
   if (total_size > 0)
     {
       if (current_function_calls_alloca)
-       /* Load it from the back chain because our save_stack_block and
-          restore_stack_block do nothing. */
        frame_emit_load (STACK_POINTER_REGNUM, sp_reg, 0);
       else
        frame_emit_add_imm (sp_reg, sp_reg, total_size, scratch_reg_0);
@@ -2242,7 +2260,7 @@ spu_sched_adjust_cost (rtx insn, rtx link ATTRIBUTE_UNUSED,
      jump_insn.  We adjust here so higher cost insns will get scheduled
      earlier. */
   if (GET_CODE (insn) == JUMP_INSN && REG_NOTE_KIND (link) == REG_DEP_ANTI)
-    return INSN_COST (dep_insn) - 3;
+    return insn_cost (dep_insn) - 3;
   return cost;
 }
 \f
@@ -2352,7 +2370,7 @@ cpat_info(unsigned char *arr, int size, int *prun, int *pstart)
        else
          cpat = 0;
       }
-  if (cpat)
+  if (cpat && (run || size < 16))
     {
       if (run == 0)
        run = 1;
@@ -2366,7 +2384,7 @@ cpat_info(unsigned char *arr, int size, int *prun, int *pstart)
 }
 
 /* OP is a CONSTANT_P.  Determine what instructions can be used to load
-   it into a regiser.  MODE is only valid when OP is a CONST_INT. */
+   it into a register.  MODE is only valid when OP is a CONST_INT. */
 static enum immediate_class
 classify_immediate (rtx op, enum machine_mode mode)
 {
@@ -2774,7 +2792,7 @@ spu_handle_vector_attribute (tree * node, tree name,
   return NULL_TREE;
 }
 
-/* Return non-zero if FUNC is a naked function.  */
+/* Return nonzero if FUNC is a naked function.  */
 static int
 spu_naked_function_p (tree func)
 {
@@ -3174,6 +3192,20 @@ aligned_mem_p (rtx mem)
   return 0;
 }
 
+/* Encode symbol attributes (local vs. global, tls model) of a SYMBOL_REF
+   into its SYMBOL_REF_FLAGS.  */
+static void
+spu_encode_section_info (tree decl, rtx rtl, int first)
+{
+  default_encode_section_info (decl, rtl, first);
+
+  /* If a variable has a forced alignment to < 16 bytes, mark it with
+     SYMBOL_FLAG_ALIGN1.  */
+  if (TREE_CODE (decl) == VAR_DECL
+      && DECL_USER_ALIGN (decl) && DECL_ALIGN (decl) < 128)
+    SYMBOL_REF_FLAGS (XEXP (rtl, 0)) |= SYMBOL_FLAG_ALIGN1;
+}
+
 /* Return TRUE if we are certain the mem refers to a complete object
    which is both 16-byte aligned and padded to a 16-byte boundary.  This
    would make it safe to store with a single instruction. 
@@ -3574,6 +3606,68 @@ mem_is_padded_component_ref (rtx x)
   return 0;
 }
 
+/* Parse the -mfixed-range= option string.  */
+static void
+fix_range (const char *const_str)
+{
+  int i, first, last;
+  char *str, *dash, *comma;
+  
+  /* str must be of the form REG1'-'REG2{,REG1'-'REG} where REG1 and
+     REG2 are either register names or register numbers.  The effect
+     of this option is to mark the registers in the range from REG1 to
+     REG2 as ``fixed'' so they won't be used by the compiler.  */
+  
+  i = strlen (const_str);
+  str = (char *) alloca (i + 1);
+  memcpy (str, const_str, i + 1);
+  
+  while (1)
+    {
+      dash = strchr (str, '-');
+      if (!dash)
+       {
+         warning (0, "value of -mfixed-range must have form REG1-REG2");
+         return;
+       }
+      *dash = '\0';
+      comma = strchr (dash + 1, ',');
+      if (comma)
+       *comma = '\0';
+      
+      first = decode_reg_name (str);
+      if (first < 0)
+       {
+         warning (0, "unknown register name: %s", str);
+         return;
+       }
+      
+      last = decode_reg_name (dash + 1);
+      if (last < 0)
+       {
+         warning (0, "unknown register name: %s", dash + 1);
+         return;
+       }
+      
+      *dash = '-';
+      
+      if (first > last)
+       {
+         warning (0, "%s-%s is an empty range", str, dash + 1);
+         return;
+       }
+      
+      for (i = first; i <= last; ++i)
+       fixed_regs[i] = call_used_regs[i] = 1;
+
+      if (!comma)
+       break;
+
+      *comma = ',';
+      str = comma + 1;
+    }
+}
+
 int
 spu_valid_move (rtx * ops)
 {
@@ -4205,9 +4299,37 @@ spu_init_builtins (void)
       d->fndecl =
        add_builtin_function (name, p, END_BUILTINS + i, BUILT_IN_MD,
                              NULL, NULL_TREE);
+      if (d->fcode == SPU_MASK_FOR_LOAD)
+       TREE_READONLY (d->fndecl) = 1;  
     }
 }
 
+void
+spu_restore_stack_block (rtx op0 ATTRIBUTE_UNUSED, rtx op1)
+{
+  static unsigned char arr[16] =
+    { 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3 };
+
+  rtx temp = gen_reg_rtx (Pmode);
+  rtx temp2 = gen_reg_rtx (V4SImode);
+  rtx temp3 = gen_reg_rtx (V4SImode);
+  rtx pat = gen_reg_rtx (TImode);
+  rtx sp = gen_rtx_REG (V4SImode, STACK_POINTER_REGNUM);
+
+  emit_move_insn (pat, array_to_constant (TImode, arr));
+
+  /* Restore the sp.  */
+  emit_move_insn (temp, op1);
+  emit_move_insn (temp2, gen_frame_mem (V4SImode, stack_pointer_rtx));
+
+  /* Compute available stack size for sp.  */
+  emit_insn (gen_subsi3 (temp, temp, stack_pointer_rtx));
+  emit_insn (gen_shufb (temp3, temp, temp, pat));
+
+  emit_insn (gen_addv4si3 (sp, sp, temp3));
+  emit_move_insn (gen_frame_mem (V4SImode, stack_pointer_rtx), temp2);
+}
+
 int
 spu_safe_dma (HOST_WIDE_INT channel)
 {
@@ -4760,6 +4882,31 @@ spu_expand_builtin_1 (struct spu_builtin_description *d,
       i++;
     }
 
+  if (d->fcode == SPU_MASK_FOR_LOAD)
+    {
+      enum machine_mode mode = insn_data[icode].operand[1].mode;
+      tree arg;
+      rtx addr, op, pat;
+
+      /* get addr */
+      arg = TREE_VALUE (arglist);
+      gcc_assert (TREE_CODE (TREE_TYPE (arg)) == POINTER_TYPE);
+      op = expand_expr (arg, NULL_RTX, Pmode, EXPAND_NORMAL);
+      addr = memory_address (mode, op);
+
+      /* negate addr */
+      op = gen_reg_rtx (GET_MODE (addr));
+      emit_insn (gen_rtx_SET (VOIDmode, op,
+                 gen_rtx_NEG (GET_MODE (addr), addr)));
+      op = gen_rtx_MEM (mode, op);
+
+      pat = GEN_FCN (icode) (target, op);
+      if (!pat) 
+        return 0;
+      emit_insn (pat);
+      return target;
+    }   
+
   /* Ignore align_hint, but still expand it's args in case they have
      side effects. */
   if (icode == CODE_FOR_spu_align_hint)
@@ -4879,3 +5026,45 @@ spu_expand_builtin (tree exp,
   abort ();
 }
 
+/* Implement targetm.vectorize.builtin_mul_widen_even.  */
+static tree
+spu_builtin_mul_widen_even (tree type)
+{
+  switch (TYPE_MODE (type))
+    {
+    case V8HImode:
+      if (TYPE_UNSIGNED (type))
+       return spu_builtins[SPU_MULE_0].fndecl;
+      else
+       return spu_builtins[SPU_MULE_1].fndecl;
+      break;
+    default:
+      return NULL_TREE;
+    }
+}
+
+/* Implement targetm.vectorize.builtin_mul_widen_odd.  */
+static tree
+spu_builtin_mul_widen_odd (tree type)
+{
+  switch (TYPE_MODE (type))
+    {
+    case V8HImode:
+      if (TYPE_UNSIGNED (type))
+       return spu_builtins[SPU_MULO_1].fndecl;
+      else
+       return spu_builtins[SPU_MULO_0].fndecl; 
+      break;
+    default:
+      return NULL_TREE;
+    }
+}
+
+/* Implement targetm.vectorize.builtin_mask_for_load.  */
+static tree
+spu_builtin_mask_for_load (void)
+{
+  struct spu_builtin_description *d = &spu_builtins[SPU_MASK_FOR_LOAD];
+  gcc_assert (d);
+  return d->fndecl;
+}