In Ada, access types (the equivalent of pointer types) are checked before being 
dereferenced.  You can eliminate these checks, or more precisely replace them 
with checks on assignments, by putting a null-exclusion marker on them.  As a 
result, the compiler can guarantee that some access values are never null at 
run time.  This patch changes gigi so as to use this information.

Tested on i586-suse-linux, applied on the mainline.


2011-09-26  Eric Botcazou  <ebotca...@adacore.com>

        * gcc-interface/ada-tree.h (DECL_CAN_NEVER_BE_NULL_P): New macro.
        * gcc-interface/decl.c (gnat_to_gnu_entity) <object>: Set the flag.
        (gnat_to_gnu_param): Likewise.
        * gcc-interface/utils.c (convert) <UNCONSTRAINED_ARRAY_REF>: Invoke
        maybe_unconstrained_array instead of doing the work manually.
        (maybe_unconstrained_array): Propagate the TREE_THIS_NOTRAP flag.
        * gcc-interface/utils2.c (build_unary_op) <INDIRECT_REF>: If operand
        is a DECL with the flag, set TREE_THIS_NOTRAP on the reference.
        (gnat_stabilize_reference_1): Propagate the TREE_THIS_NOTRAP flag.
        (gnat_stabilize_reference): Likewise.


-- 
Eric Botcazou
Index: gcc-interface/utils.c
===================================================================
--- gcc-interface/utils.c	(revision 179180)
+++ gcc-interface/utils.c	(working copy)
@@ -3819,8 +3819,7 @@ convert (tree type, tree expr)
       return gnat_build_constructor (type, v);
     }
 
-  /* There are some special cases of expressions that we process
-     specially.  */
+  /* There are some cases of expressions that we process specially.  */
   switch (TREE_CODE (expr))
     {
     case ERROR_MARK:
@@ -3976,21 +3975,11 @@ convert (tree type, tree expr)
       break;
 
     case UNCONSTRAINED_ARRAY_REF:
-      {
-	/* Convert this to the type of the inner array by getting the address
-	   of the array from the template.  */
-	const bool no_trap = TREE_THIS_NOTRAP (expr);
-	expr = TREE_OPERAND (expr, 0);
-	expr = build_unary_op (INDIRECT_REF, NULL_TREE,
-			       build_component_ref (expr, NULL_TREE,
-						    TYPE_FIELDS
-						    (TREE_TYPE (expr)),
-						    false));
-	TREE_THIS_NOTRAP (expr) = no_trap;
-	etype = TREE_TYPE (expr);
-	ecode = TREE_CODE (etype);
-	break;
-      }
+      /* First retrieve the underlying array.  */
+      expr = maybe_unconstrained_array (expr);
+      etype = TREE_TYPE (expr);
+      ecode = TREE_CODE (etype);
+      break;
 
     case VIEW_CONVERT_EXPR:
       {
@@ -4282,6 +4271,8 @@ maybe_unconstrained_array (tree exp)
       if (code == UNCONSTRAINED_ARRAY_REF)
 	{
 	  const bool read_only = TREE_READONLY (exp);
+	  const bool no_trap = TREE_THIS_NOTRAP (exp);
+
 	  exp = TREE_OPERAND (exp, 0);
 	  if (TREE_CODE (exp) == COND_EXPR)
 	    {
@@ -4306,12 +4297,16 @@ maybe_unconstrained_array (tree exp)
 			    TREE_OPERAND (exp, 0), op1, op2);
 	    }
 	  else
-	    exp = build_unary_op (INDIRECT_REF, NULL_TREE,
-				  build_component_ref (exp, NULL_TREE,
-						       TYPE_FIELDS
-						       (TREE_TYPE (exp)),
-						       false));
-	  TREE_READONLY (exp) = read_only;
+	    {
+	      exp = build_unary_op (INDIRECT_REF, NULL_TREE,
+				    build_component_ref (exp, NULL_TREE,
+						         TYPE_FIELDS
+						         (TREE_TYPE (exp)),
+						         false));
+	      TREE_READONLY (exp) = read_only;
+	      TREE_THIS_NOTRAP (exp) = no_trap;
+	    }
+
 	  return exp;
 	}
 
Index: gcc-interface/decl.c
===================================================================
--- gcc-interface/decl.c	(revision 179180)
+++ gcc-interface/decl.c	(working copy)
@@ -1417,6 +1417,7 @@ gnat_to_gnu_entity (Entity_Id gnat_entit
 			     gnat_entity);
 	DECL_BY_REF_P (gnu_decl) = used_by_ref;
 	DECL_POINTS_TO_READONLY_P (gnu_decl) = used_by_ref && inner_const_flag;
+	DECL_CAN_NEVER_BE_NULL_P (gnu_decl) = Can_Never_Be_Null (gnat_entity);
 
 	/* If we are defining an Out parameter and optimization isn't enabled,
 	   create a fake PARM_DECL for debugging purposes and make it point to
@@ -5568,6 +5569,7 @@ gnat_to_gnu_param (Entity_Id gnat_param,
                                       mech == By_Short_Descriptor);
   DECL_POINTS_TO_READONLY_P (gnu_param)
     = (ro_param && (by_ref || by_component_ptr));
+  DECL_CAN_NEVER_BE_NULL_P (gnu_param) = Can_Never_Be_Null (gnat_param);
 
   /* Save the alternate descriptor type, if any.  */
   if (gnu_param_type_alt)
Index: gcc-interface/utils2.c
===================================================================
--- gcc-interface/utils2.c	(revision 179180)
+++ gcc-interface/utils2.c	(working copy)
@@ -1276,44 +1276,60 @@ build_unary_op (enum tree_code op_code,
       break;
 
     case INDIRECT_REF:
-      /* If we want to refer to an unconstrained array, use the appropriate
-	 expression to do so.  This will never survive down to the back-end.
-	 But if TYPE is a thin pointer, first convert to a fat pointer.  */
-      if (TYPE_IS_THIN_POINTER_P (type)
-	  && TYPE_UNCONSTRAINED_ARRAY (TREE_TYPE (type)))
-	{
-	  operand
-	    = convert (TREE_TYPE (TYPE_UNCONSTRAINED_ARRAY (TREE_TYPE (type))),
+      {
+	bool can_never_be_null;
+	tree t = operand;
+
+	while (CONVERT_EXPR_P (t) || TREE_CODE (t) == VIEW_CONVERT_EXPR)
+	  t = TREE_OPERAND (t, 0);
+
+	can_never_be_null = DECL_P (t) && DECL_CAN_NEVER_BE_NULL_P (t);
+
+	/* If TYPE is a thin pointer, first convert to the fat pointer.  */
+	if (TYPE_IS_THIN_POINTER_P (type)
+	    && TYPE_UNCONSTRAINED_ARRAY (TREE_TYPE (type)))
+	  {
+	    operand = convert
+		      (TREE_TYPE (TYPE_UNCONSTRAINED_ARRAY (TREE_TYPE (type))),
 		       operand);
-	  type = TREE_TYPE (operand);
-	}
+	    type = TREE_TYPE (operand);
+	  }
 
-      if (TYPE_IS_FAT_POINTER_P (type))
-	{
-	  result = build1 (UNCONSTRAINED_ARRAY_REF,
-			   TYPE_UNCONSTRAINED_ARRAY (type), operand);
-	  TREE_READONLY (result)
-	    = TYPE_READONLY (TYPE_UNCONSTRAINED_ARRAY (type));
-	}
+	/* If we want to refer to an unconstrained array, use the appropriate
+	   expression.  But this will never survive down to the back-end.  */
+	if (TYPE_IS_FAT_POINTER_P (type))
+	  {
+	    result = build1 (UNCONSTRAINED_ARRAY_REF,
+			     TYPE_UNCONSTRAINED_ARRAY (type), operand);
+	    TREE_READONLY (result)
+	      = TYPE_READONLY (TYPE_UNCONSTRAINED_ARRAY (type));
+	  }
 
-      /* If we are dereferencing an ADDR_EXPR, return its operand.  */
-      else if (TREE_CODE (operand) == ADDR_EXPR)
-	result = TREE_OPERAND (operand, 0);
+	/* If we are dereferencing an ADDR_EXPR, return its operand.  */
+	else if (TREE_CODE (operand) == ADDR_EXPR)
+	  result = TREE_OPERAND (operand, 0);
 
-      /* Otherwise, build and fold the indirect reference.  */
-      else
-	{
-	  result = build_fold_indirect_ref (operand);
-	  TREE_READONLY (result) = TYPE_READONLY (TREE_TYPE (type));
-	}
+	/* Otherwise, build and fold the indirect reference.  */
+	else
+	  {
+	    result = build_fold_indirect_ref (operand);
+	    TREE_READONLY (result) = TYPE_READONLY (TREE_TYPE (type));
+	  }
 
-      if (!TYPE_IS_FAT_POINTER_P (type) && TYPE_VOLATILE (TREE_TYPE (type)))
-	{
-	  TREE_SIDE_EFFECTS (result) = 1;
-	  if (TREE_CODE (result) == INDIRECT_REF)
-	    TREE_THIS_VOLATILE (result) = TYPE_VOLATILE (TREE_TYPE (result));
-	}
-      break;
+	if (!TYPE_IS_FAT_POINTER_P (type) && TYPE_VOLATILE (TREE_TYPE (type)))
+	  {
+	    TREE_SIDE_EFFECTS (result) = 1;
+	    if (TREE_CODE (result) == INDIRECT_REF)
+	      TREE_THIS_VOLATILE (result) = TYPE_VOLATILE (TREE_TYPE (result));
+	  }
+
+	if ((TREE_CODE (result) == INDIRECT_REF
+	     || TREE_CODE (result) == UNCONSTRAINED_ARRAY_REF)
+	    && can_never_be_null)
+	  TREE_THIS_NOTRAP (result) = 1;
+
+	break;
+      }
 
     case NEGATE_EXPR:
     case BIT_NOT_EXPR:
@@ -2442,7 +2458,10 @@ gnat_stabilize_reference_1 (tree e, bool
   TREE_SIDE_EFFECTS (result) |= TREE_SIDE_EFFECTS (e);
   TREE_THIS_VOLATILE (result) = TREE_THIS_VOLATILE (e);
 
-  if (code == INDIRECT_REF || code == ARRAY_REF || code == ARRAY_RANGE_REF)
+  if (code == INDIRECT_REF
+      || code == UNCONSTRAINED_ARRAY_REF
+      || code == ARRAY_REF
+      || code == ARRAY_RANGE_REF)
     TREE_THIS_NOTRAP (result) = TREE_THIS_NOTRAP (e);
 
   return result;
@@ -2578,7 +2597,10 @@ gnat_stabilize_reference (tree ref, bool
   TREE_SIDE_EFFECTS (result) |= TREE_SIDE_EFFECTS (ref);
   TREE_THIS_VOLATILE (result) = TREE_THIS_VOLATILE (ref);
 
-  if (code == INDIRECT_REF || code == ARRAY_REF || code == ARRAY_RANGE_REF)
+  if (code == INDIRECT_REF
+      || code == UNCONSTRAINED_ARRAY_REF
+      || code == ARRAY_REF
+      || code == ARRAY_RANGE_REF)
     TREE_THIS_NOTRAP (result) = TREE_THIS_NOTRAP (ref);
 
   return result;
Index: gcc-interface/ada-tree.h
===================================================================
--- gcc-interface/ada-tree.h	(revision 179180)
+++ gcc-interface/ada-tree.h	(working copy)
@@ -352,6 +352,9 @@ do {						   \
    is needed to access the object.  */
 #define DECL_BY_REF_P(NODE) DECL_LANG_FLAG_1 (NODE)
 
+/* Nonzero in a DECL if it is made for a pointer that can never be null.  */
+#define DECL_CAN_NEVER_BE_NULL_P(NODE) DECL_LANG_FLAG_2 (NODE)
+
 /* Nonzero in a FIELD_DECL that is a dummy built for some internal reason.  */
 #define DECL_INTERNAL_P(NODE) DECL_LANG_FLAG_3 (FIELD_DECL_CHECK (NODE))
 
@@ -364,7 +367,7 @@ do {						   \
   DECL_LANG_FLAG_3 (FUNCTION_DECL_CHECK (NODE))
 
 /* Nonzero in a DECL if it is made for a pointer that points to something which
-   is readonly.  Used mostly for fat pointers.  */
+   is readonly.  */
 #define DECL_POINTS_TO_READONLY_P(NODE) DECL_LANG_FLAG_4 (NODE)
 
 /* Nonzero in a PARM_DECL if we are to pass by descriptor.  */

Reply via email to