This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Ada] Improve handling of null-exclusion access types


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  <ebotcazou@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.  */

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]