msp430.c (TARGET_GIMPLIFY_VA_ARG_EXPR): Define.
authorNick Clifton <nickc@redhat.com>
Tue, 20 May 2014 16:51:58 +0000 (16:51 +0000)
committerNick Clifton <nickc@gcc.gnu.org>
Tue, 20 May 2014 16:51:58 +0000 (16:51 +0000)
* config/msp430/msp430.c (TARGET_GIMPLIFY_VA_ARG_EXPR): Define.
(msp430_gimplify_va_arg_expr): New function.
(msp430_print_operand): Handle (CONST (ZERO_EXTRACT)).

From-SVN: r210648

gcc/ChangeLog
gcc/config/msp430/msp430.c

index 7d518b8abcee1efe306c790b9320253416392f56..6f2db11adc0cab34c50f34f3f103f4b603c32552 100644 (file)
 
 2014-05-20  Nick Clifton  <nickc@redhat.com>
 
+       * config/msp430/msp430.c (TARGET_GIMPLIFY_VA_ARG_EXPR): Define.
+       (msp430_gimplify_va_arg_expr): New function.
+       (msp430_print_operand): Handle (CONST (ZERO_EXTRACT)).
+
        * config/msp430/msp430.md (zero_extendpsisi2): Use + constraint on
        operand 0 in order to prevent confusion about the number of
        registers involved.
index e851a1440ec84c015ad4d4e5f43e5efada0b2a50..0f6114c1ee8e817006491c4a673d2afea4084bf8 100644 (file)
@@ -730,6 +730,97 @@ msp430_get_raw_result_mode (int regno ATTRIBUTE_UNUSED)
 {
   return Pmode;
 }
+
+#undef  TARGET_GIMPLIFY_VA_ARG_EXPR
+#define TARGET_GIMPLIFY_VA_ARG_EXPR msp430_gimplify_va_arg_expr
+
+#include "gimplify.h"
+#include "gimple-expr.h"
+
+static tree
+msp430_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p,
+                         gimple_seq *post_p)
+{
+  tree addr, t, type_size, rounded_size, valist_tmp;
+  unsigned HOST_WIDE_INT align, boundary;
+  bool indirect;
+
+  indirect = pass_by_reference (NULL, TYPE_MODE (type), type, false);
+  if (indirect)
+    type = build_pointer_type (type);
+
+  align = PARM_BOUNDARY / BITS_PER_UNIT;
+  boundary = targetm.calls.function_arg_boundary (TYPE_MODE (type), type);
+
+  /* When we align parameter on stack for caller, if the parameter
+     alignment is beyond MAX_SUPPORTED_STACK_ALIGNMENT, it will be
+     aligned at MAX_SUPPORTED_STACK_ALIGNMENT.  We will match callee
+     here with caller.  */
+  if (boundary > MAX_SUPPORTED_STACK_ALIGNMENT)
+    boundary = MAX_SUPPORTED_STACK_ALIGNMENT;
+
+  boundary /= BITS_PER_UNIT;
+
+  /* Hoist the valist value into a temporary for the moment.  */
+  valist_tmp = get_initialized_tmp_var (valist, pre_p, NULL);
+
+  /* va_list pointer is aligned to PARM_BOUNDARY.  If argument actually
+     requires greater alignment, we must perform dynamic alignment.  */
+  if (boundary > align
+      && !integer_zerop (TYPE_SIZE (type)))
+    {
+      /* FIXME: This is where this function diverts from targhooks.c:
+        std_gimplify_va_arg_expr().  It works, but I do not know why...  */
+      if (! POINTER_TYPE_P (type))
+       {
+         t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist_tmp,
+                     fold_build_pointer_plus_hwi (valist_tmp, boundary - 1));
+         gimplify_and_add (t, pre_p);
+
+         t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist_tmp,
+                     fold_build2 (BIT_AND_EXPR, TREE_TYPE (valist),
+                                  valist_tmp,
+                                  build_int_cst (TREE_TYPE (valist), -boundary)));
+         gimplify_and_add (t, pre_p);
+       }
+    }
+  else
+    boundary = align;
+
+  /* If the actual alignment is less than the alignment of the type,
+     adjust the type accordingly so that we don't assume strict alignment
+     when dereferencing the pointer.  */
+  boundary *= BITS_PER_UNIT;
+  if (boundary < TYPE_ALIGN (type))
+    {
+      type = build_variant_type_copy (type);
+      TYPE_ALIGN (type) = boundary;
+    }
+
+  /* Compute the rounded size of the type.  */
+  type_size = size_in_bytes (type);
+  rounded_size = round_up (type_size, align);
+
+  /* Reduce rounded_size so it's sharable with the postqueue.  */
+  gimplify_expr (&rounded_size, pre_p, post_p, is_gimple_val, fb_rvalue);
+
+  /* Get AP.  */
+  addr = valist_tmp;
+
+  /* Compute new value for AP.  */
+  t = fold_build_pointer_plus (valist_tmp, rounded_size);
+  t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist, t);
+  gimplify_and_add (t, pre_p);
+
+  addr = fold_convert (build_pointer_type (type), addr);
+
+  if (indirect)
+    addr = build_va_arg_indirect_ref (addr);
+
+  addr = build_va_arg_indirect_ref (addr);
+
+  return addr;
+}
 \f
 /* Addressing Modes */
 
@@ -2308,8 +2399,32 @@ msp430_print_operand (FILE * file, rtx op, int letter)
       msp430_print_operand_addr (file, addr);
       break;
 
-    case CONST_INT:
     case CONST:
+      if (GET_CODE (XEXP (op, 0)) == ZERO_EXTRACT)
+       {
+         op = XEXP (op, 0);
+         switch (INTVAL (XEXP (op, 2)))
+           {
+           case 0:
+             fprintf (file, "#lo (");
+             msp430_print_operand_raw (file, XEXP (op, 0));
+             fprintf (file, ")");
+             break;
+         
+           case 16:
+             fprintf (file, "#hi (");
+             msp430_print_operand_raw (file, XEXP (op, 0));
+             fprintf (file, ")");
+             break;
+
+           default:
+             output_operand_lossage ("invalid zero extract");
+             break;
+           }
+         break;
+       }
+      /* Fall through.  */
+    case CONST_INT:
     case SYMBOL_REF:
     case LABEL_REF:
       if (letter == 0)