diff mbox

[Ada] Lift restriction on renaming with Volatile_Full_Access

Message ID 5291119.moas55ffRM@polaris
State New
Headers show

Commit Message

Eric Botcazou May 26, 2015, 7:39 p.m. UTC
> An arbitrary restriction was imposed on renaming in conjunction with the new
> Aspect/Pragma Volatile_Full_Access for implementation reasons: the compiler
> was rejecting renamings of components of Volatile_Full_Access objects.

This is the second part of the overhaul, tested on x86_64-suse-linux, applied 
on the mainline.


2015-05-26  Eric Botcazou  <ebotcazou@adacore.com>

	* gcc-interface/ada-tree.h (DECL_GLOBAL_NONCONSTANT_RENAMING_P): Delete
	(DECL_RENAMED_OBJECT): Adjust comment.
	* gcc-interface/gigi.h (record_global_nonconstant_renaming): Delete.
	(invalidate_global_nonconstant_renamings): Likewise.
	(gnat_constant_reference_p): Likewise.
	(rewrite_fn): New function type.
	(gnat_rewrite_reference): Declare.
	(call_is_atomic_load): New inline predicate.
	* gcc-interface/decl.c (elaborate_reference_1): New function.
	(elaborate_reference): Likewise.
	(gnat_to_gnu_entity): Call elaborate_reference to elaborate renamings
	and simplify associated code.  Set const_flag to true consistently in
 	conjunction with used_by_ref.
	* gcc-interface/trans.c (Identifier_to_gnu): Always replace renaming
	pointers by renamed objects.
	(outer_atomic_access_required_p): Deal with renamings.
	(Compilation_Unit_to_gnu): Do not call
	invalidate_global_nonconstant_renamings.
	(gnat_to_gnu) <N_Object_Renaming_Declaration>: Adjust comment.
	(gnat_gimplify_expr): Deal with atomic loads.
	* gcc-interface/utils.c (global_nonconstant_renamings): Delete.
	(destroy_gnat_utils): Do not call
	invalidate_global_nonconstant_renamings.
	(record_global_nonconstant_renaming): Delete.
	(invalidate_global_nonconstant_renamings): Likewise.
	* gcc-interface/utils2.c (call_is_atomic_load): Move to gigi.h.
	(build_load_modify_store): Build a copy of the destination.
	(gnat_stabilize_reference_1): Adjust.
	(gnat_stabilize_reference): Call gnat_stabilize_reference_1 through
	gnat_rewrite_reference and move bulk of code to...
	(gnat_rewrite_reference): ...here.  New global function.
	(gnat_constant_reference_p): Delete.
diff mbox

Patch

Index: gcc-interface/utils.c
===================================================================
--- gcc-interface/utils.c	(revision 223704)
+++ gcc-interface/utils.c	(working copy)
@@ -233,9 +233,6 @@  static GTY(()) vec<tree, va_gc> *global_
 /* An array of builtin function declarations.  */
 static GTY(()) vec<tree, va_gc> *builtin_decls;
 
-/* An array of global non-constant renamings.  */
-static GTY(()) vec<tree, va_gc> *global_nonconstant_renamings;
-
 /* A chain of unused BLOCK nodes. */
 static GTY((deletable)) tree free_block_chain;
 
@@ -322,9 +319,6 @@  destroy_gnat_utils (void)
   /* Destroy the hash table of padded types.  */
   pad_type_hash_table->empty ();
   pad_type_hash_table = NULL;
-
-  /* Invalidate the global non-constant renamings.   */
-  invalidate_global_nonconstant_renamings ();
 }
 
 /* GNAT_ENTITY is a GNAT tree node for an entity.  Associate GNU_DECL, a GCC
@@ -2717,33 +2711,6 @@  process_attributes (tree *node, struct a
 
   *attr_list = NULL;
 }
-
-/* Record DECL as a global non-constant renaming.  */
-
-void
-record_global_nonconstant_renaming (tree decl)
-{
-  gcc_assert (!DECL_LOOP_PARM_P (decl) && DECL_RENAMED_OBJECT (decl));
-  vec_safe_push (global_nonconstant_renamings, decl);
-}
-
-/* Invalidate the global non-constant renamings, lest their renamed object
-   contains SAVE_EXPRs tied to an elaboration routine.  */
-
-void
-invalidate_global_nonconstant_renamings (void)
-{
-  unsigned int i;
-  tree iter;
-
-  if (global_nonconstant_renamings == NULL)
-    return;
-
-  FOR_EACH_VEC_ELT (*global_nonconstant_renamings, i, iter)
-    SET_DECL_RENAMED_OBJECT (iter, NULL_TREE);
-
-  vec_free (global_nonconstant_renamings);
-}
 
 /* Return true if VALUE is a known to be a multiple of FACTOR, which must be
    a power of 2. */
Index: gcc-interface/decl.c
===================================================================
--- gcc-interface/decl.c	(revision 223708)
+++ gcc-interface/decl.c	(working copy)
@@ -179,6 +179,7 @@  static bool type_has_variable_size (tree
 static tree elaborate_expression_1 (tree, Entity_Id, const char *, bool, bool);
 static tree elaborate_expression_2 (tree, Entity_Id, const char *, bool, bool,
 				    unsigned int);
+static tree elaborate_reference (tree, Entity_Id, bool);
 static tree gnat_to_gnu_component_type (Entity_Id, bool, bool);
 static tree gnat_to_gnu_param (Entity_Id, Mechanism_Type, Entity_Id, bool,
 			       bool *);
@@ -557,11 +558,11 @@  gnat_to_gnu_entity (Entity_Id gnat_entit
 	  break;
 	}
 
-      /* If we have an external constant that we are not defining, get the
-	 expression that is was defined to represent.  We may throw it away
-	 later if it is not a constant.  But do not retrieve the expression
-	 if it is an allocator because the designated type might be dummy
-	 at this point.  */
+      /* If we have a constant that we are not defining, get the expression it
+	 was defined to represent.  This is necessary to avoid generating dumb
+	 elaboration code in simple cases, but we may throw it away later if it
+	 is not a constant.  But do not retrieve it if it is an allocator since
+	 the designated type might still be dummy at this point.  */
       if (!definition
 	  && !No_Initialization (Declaration_Node (gnat_entity))
 	  && Present (Expression (Declaration_Node (gnat_entity)))
@@ -995,32 +996,31 @@  gnat_to_gnu_entity (Entity_Id gnat_entit
 	       before the call to "=".  */
 	    if (TREE_CODE (inner) == TRUTH_ANDIF_EXPR)
 	      inner = TREE_OPERAND (inner, 1);
-	    if (TREE_CODE (inner) == CALL_EXPR
-	        || TREE_CODE (inner) == NULL_EXPR
-	        || TREE_CODE (inner) == CONSTRUCTOR
+	    if ((TREE_CODE (inner) == CALL_EXPR
+		 && !call_is_atomic_load (inner))
+		|| TREE_CODE (inner) == NULL_EXPR
+		|| TREE_CODE (inner) == CONSTRUCTOR
 		|| CONSTANT_CLASS_P (inner))
 	      ;
 
 	    /* Case 2: if the renaming entity need not be materialized, use
-	       the stabilized renamed expression for the renaming.  At the
-	       global level, we can do this only if we know no SAVE_EXPRs
-	       need be made, because otherwise the expression would be tied
-	       to a specific elaboration routine.  */
-	    else if (!Materialize_Entity (gnat_entity)
-		     && (!global_bindings_p ()
-			 || (staticp (gnu_expr)
-			     && !TREE_SIDE_EFFECTS (gnu_expr))))
+	       the elaborated renamed expression for the renaming.  But this
+	       means that the caller is responsible for evaluating the address
+	       of the renaming at the correct spot in the definition case to
+	       instantiate the SAVE_EXPRs.  */
+	    else if (!Materialize_Entity (gnat_entity))
 	      {
-		gnu_decl = gnat_stabilize_reference (gnu_expr, true);
+		gnu_decl
+		  = elaborate_reference (gnu_expr, gnat_entity, definition);
 
-		/* ??? No DECL_EXPR is created so we need to mark
-		   the expression manually lest it is shared.  */
+		/* No DECL_EXPR will be created so the expression needs to be
+		   marked manually because it will likely be shared.  */
 		if (global_bindings_p ())
 		  MARK_VISITED (gnu_decl);
 
-		/* This assertion will fail if the renamed object isn't
-		   aligned enough as to make it possible to honor the
-		   alignment set on the renaming.  */
+		/* This assertion will fail if the renamed object isn't aligned
+		   enough as to make it possible to honor the alignment set on
+		   the renaming.  */
 		if (align)
 		  {
 		    unsigned int ralign = DECL_P (gnu_decl)
@@ -1036,52 +1036,41 @@  gnat_to_gnu_entity (Entity_Id gnat_entit
 	      }
 
 	    /* Case 3: otherwise, make a constant pointer to the object we
-	       are to rename and attach the object to the pointer after it
-	       is stabilized.
-
-	       From the proper scope, attached objects will be referenced
-	       directly instead of indirectly via the pointer to avoid
-	       subtle aliasing problems with non-addressable entities.
-	       They have to be stable because we must not evaluate the
-	       variables in the expression every time the renaming is used.
-	       The pointer is called a "renaming" pointer in this case.
-
-	       Note that we need to preserve the volatility of the renamed
-	       object through the indirection.  */
+	       are renaming and attach the object to the pointer after it is
+	       elaborated.  The object will be referenced directly instead
+	       of indirectly via the pointer to avoid aliasing problems with
+	       non-addressable entities.  The pointer is called a "renaming"
+	       pointer in this case.  Note that we also need to preserve the
+	       volatility of the renamed object through the indirection.  */
 	    else
 	      {
 		if (TREE_THIS_VOLATILE (gnu_expr) && !TYPE_VOLATILE (gnu_type))
 		  gnu_type
 		    = change_qualified_type (gnu_type, TYPE_QUAL_VOLATILE);
+
 		gnu_type = build_reference_type (gnu_type);
-		inner_const_flag = TREE_READONLY (gnu_expr);
+		used_by_ref = true;
 		const_flag = true;
+		inner_const_flag = TREE_READONLY (gnu_expr);
+		gnu_size = NULL_TREE;
 
-		/* Stabilize and attach the expression to the pointer.
+		renamed_obj
+		  = elaborate_reference (gnu_expr, gnat_entity, definition);
 
-		   Note that this might introduce SAVE_EXPRs and we don't
-		   check whether we are at the global level or not.  This
-		   is fine since we are building a pointer initializer and
-		   neither the pointer nor the initializing expression can
-		   be accessed before the pointer elaboration has taken
-		   place in a correct program.
-
-		   These SAVE_EXPRs will be evaluated at the right place
-		   by either the evaluation of the initializer for the
-		   non-global case or the elaboration code for the global
-		   case, and will be attached to the elaboration procedure
-		   in the latter case.  */
-		renamed_obj = gnat_stabilize_reference (gnu_expr, true);
+		/* If we are not defining the entity, the expression will not
+		   be attached through DECL_INITIAL so it needs to be marked
+		   manually because it will likely be shared.  Likewise for a
+		   dereference as it will be folded by the ADDR_EXPR below.  */
+		if ((!definition || TREE_CODE (renamed_obj) == INDIRECT_REF)
+		    && global_bindings_p ())
+		  MARK_VISITED (renamed_obj);
 
 		if (type_annotate_only
- 		    && TREE_CODE (renamed_obj) == ERROR_MARK)
+		    && TREE_CODE (renamed_obj) == ERROR_MARK)
 		  gnu_expr = NULL_TREE;
 		else
 		  gnu_expr
 		    = build_unary_op (ADDR_EXPR, gnu_type, renamed_obj);
-
-		gnu_size = NULL_TREE;
-		used_by_ref = true;
 	      }
 	  }
 
@@ -1173,9 +1162,6 @@  gnat_to_gnu_entity (Entity_Id gnat_entit
 
 	    save_gnu_tree (gnat_entity, NULL_TREE, false);
 
-	    /* Ignore the size.  It's either meaningless or was handled
-	       above.  */
-	    gnu_size = NULL_TREE;
 	    /* Convert the type of the object to a reference type that can
 	       alias everything as per 13.3(19).  */
 	    gnu_type
@@ -1185,6 +1171,7 @@  gnat_to_gnu_entity (Entity_Id gnat_entit
 	    const_flag
 	      = !Is_Public (gnat_entity)
 		|| compile_time_known_address_p (gnat_expr);
+	    gnu_size = NULL_TREE;
 
 	    /* If this is a deferred constant, the initializer is attached to
 	       the full view.  */
@@ -1221,6 +1208,7 @@  gnat_to_gnu_entity (Entity_Id gnat_entit
 	       alias everything as per 13.3(19).  */
 	    gnu_type
 	      = build_reference_type_for_mode (gnu_type, ptr_mode, true);
+	    used_by_ref = true;
 	    gnu_size = NULL_TREE;
 
 	    /* No point in taking the address of an initializing expression
@@ -1241,8 +1229,6 @@  gnat_to_gnu_entity (Entity_Id gnat_entit
 		    const_flag = true;
 		  }
 	      }
-
-	    used_by_ref = true;
 	  }
 
 	/* If we are at top level and this object is of variable size,
@@ -1269,8 +1255,9 @@  gnat_to_gnu_entity (Entity_Id gnat_entit
 					|| static_p)))
 	  {
 	    gnu_type = build_reference_type (gnu_type);
-	    gnu_size = NULL_TREE;
 	    used_by_ref = true;
+	    const_flag = true;
+	    gnu_size = NULL_TREE;
 
 	    /* In case this was a aliased object whose nominal subtype is
 	       unconstrained, the pointer above will be a thin pointer and
@@ -1313,13 +1300,9 @@  gnat_to_gnu_entity (Entity_Id gnat_entit
 		gnu_expr
 		  = build_allocator (gnu_alloc_type, gnu_expr, gnu_type,
 				     Empty, Empty, gnat_entity, mutable_p);
-		const_flag = true;
 	      }
 	    else
-	      {
-		gnu_expr = NULL_TREE;
-		const_flag = false;
-	      }
+	      gnu_expr = NULL_TREE;
 	  }
 
 	/* If this object would go into the stack and has an alignment larger
@@ -1357,9 +1340,9 @@  gnat_to_gnu_entity (Entity_Id gnat_entit
 		 build_component_ref (gnu_new_var, NULL_TREE,
 				      TYPE_FIELDS (gnu_new_type), false));
 
-	    gnu_size = NULL_TREE;
 	    used_by_ref = true;
 	    const_flag = true;
+	    gnu_size = NULL_TREE;
 	  }
 
 	/* If this is an aliased object with an unconstrained nominal subtype,
@@ -1389,10 +1372,10 @@  gnat_to_gnu_entity (Entity_Id gnat_entit
 		  = build_unary_op (ADDR_EXPR, NULL_TREE, gnu_unc_var);
 		TREE_CONSTANT (gnu_expr) = 1;
 
-		gnu_size = NULL_TREE;
 		used_by_ref = true;
-		inner_const_flag = TREE_READONLY (gnu_unc_var);
 		const_flag = true;
+		inner_const_flag = TREE_READONLY (gnu_unc_var);
+		gnu_size = NULL_TREE;
 	      }
 
 	    gnu_type
@@ -1481,20 +1464,9 @@  gnat_to_gnu_entity (Entity_Id gnat_entit
 	else if (kind == E_Loop_Parameter)
 	  DECL_LOOP_PARM_P (gnu_decl) = 1;
 
-	/* If this is a renaming pointer, attach the renamed object to it and
-	   register it if we are at the global level and the renamed object
-	   is a non-constant reference.  */
+	/* If this is a renaming pointer, attach the renamed object to it.  */
 	if (renamed_obj)
-	  {
-	    SET_DECL_RENAMED_OBJECT (gnu_decl, renamed_obj);
-
-	    if (global_bindings_p ()
-		&& !gnat_constant_reference_p (renamed_obj))
-	      {
-		DECL_GLOBAL_NONCONSTANT_RENAMING_P (gnu_decl) = 1;
-		record_global_nonconstant_renaming (gnu_decl);
-	      }
-	  }
+	  SET_DECL_RENAMED_OBJECT (gnu_decl, renamed_obj);
 
 	/* If this is a constant and we are defining it or it generates a real
 	   symbol at the object level and we are referencing it, we may want
@@ -6109,7 +6081,7 @@  prepend_attributes (struct attrib **attr
 /* Given a GNAT tree GNAT_EXPR, for an expression which is a value within a
    type definition (either a bound or a discriminant value) for GNAT_ENTITY,
    return the GCC tree to use for that expression.  S is the suffix to use
-   if a variable needs to be created and DEFINITION is true if this is made
+   if a variable needs to be created and DEFINITION is true if this is done
    for a definition of GNAT_ENTITY.  If NEED_VALUE is true, we need a result;
    otherwise, we are just elaborating the expression for side-effects.  If
    NEED_DEBUG is true, we need a variable for debugging purposes even if it
@@ -6250,6 +6222,50 @@  elaborate_expression_2 (tree gnu_expr, E
 					need_debug),
 		unit_align);
 }
+
+/* Structure to hold internal data for elaborate_reference.  */
+
+struct er_data
+{
+  Entity_Id entity;
+  bool definition;
+};
+
+/* Wrapper function around elaborate_expression_1 for elaborate_reference.  */
+
+static tree
+elaborate_reference_1 (tree ref, void *data, int n)
+{
+  struct er_data *er = (struct er_data *)data;
+  char suffix[16];
+
+  /* This is what elaborate_expression_1 does if NEED_DEBUG is false.  */
+  if (TREE_CONSTANT (ref))
+    return ref;
+
+  /* If this is a COMPONENT_REF of a fat pointer, elaborate the entire fat
+     pointer.  This may be more efficient, but will also allow us to more
+     easily find the match for the PLACEHOLDER_EXPR.  */
+  if (TREE_CODE (ref) == COMPONENT_REF
+      && TYPE_IS_FAT_POINTER_P (TREE_TYPE (TREE_OPERAND (ref, 0))))
+    return build3 (COMPONENT_REF, TREE_TYPE (ref),
+		   elaborate_reference_1 (TREE_OPERAND (ref, 0), data, n),
+		   TREE_OPERAND (ref, 1), TREE_OPERAND (ref, 2));
+
+  sprintf (suffix, "EXP%d", n);
+  return
+    elaborate_expression_1 (ref, er->entity, suffix, er->definition, false);
+}
+
+/* Elaborate the reference REF to be used as renamed object for GNAT_ENTITY.
+   DEFINITION is true if this is done for a definition of GNAT_ENTITY.  */
+
+static tree
+elaborate_reference (tree ref, Entity_Id gnat_entity, bool definition)
+{
+  struct er_data er = { gnat_entity, definition };
+  return gnat_rewrite_reference (ref, elaborate_reference_1, &er);
+}
 
 /* Given a GNU tree and a GNAT list of choices, generate an expression to test
    the value passed against the list of choices.  */
Index: gcc-interface/utils2.c
===================================================================
--- gcc-interface/utils2.c	(revision 223708)
+++ gcc-interface/utils2.c	(working copy)
@@ -738,27 +738,15 @@  build_atomic_store (tree dest, tree src,
   return build_call_expr (t, 3, addr, src, mem_model);
 }
 
-/* Return true if EXP, a CALL_EXPR, is an atomic load.  */
-
-static bool
-call_is_atomic_load (tree exp)
-{
-  tree fndecl = get_callee_fndecl (exp);
-
-  if (!(fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL))
-    return false;
-
-  enum built_in_function code = DECL_FUNCTION_CODE (fndecl);
-  return BUILT_IN_ATOMIC_LOAD_N <= code && code <= BUILT_IN_ATOMIC_LOAD_16;
-}
-
 /* Build a load-modify-store sequence from SRC to DEST.  GNAT_NODE is used for
-   the location of the sequence.  Note that, even if the load and the store are
-   both atomic, the sequence itself is not atomic.  */
+   the location of the sequence.  Note that, even though the load and the store
+   are both atomic, the sequence itself is not atomic.  */
 
 tree
 build_load_modify_store (tree dest, tree src, Node_Id gnat_node)
 {
+  /* We will be modifying DEST below so we build a copy.  */
+  dest = copy_node (dest);
   tree ref = dest;
 
   while (handled_component_p (ref))
@@ -812,6 +800,7 @@  build_load_modify_store (tree dest, tree
 	    }
 	}
 
+      TREE_OPERAND (ref, 0) = copy_node (TREE_OPERAND (ref, 0));
       ref = TREE_OPERAND (ref, 0);
     }
 
@@ -2674,8 +2663,9 @@  gnat_protect_expr (tree exp)
    argument to force evaluation of everything.  */
 
 static tree
-gnat_stabilize_reference_1 (tree e, bool force)
+gnat_stabilize_reference_1 (tree e, void *data, int n)
 {
+  const bool force = *(bool *)data;
   enum tree_code code = TREE_CODE (e);
   tree type = TREE_TYPE (e);
   tree result;
@@ -2698,7 +2688,7 @@  gnat_stabilize_reference_1 (tree e, bool
 	  && TYPE_IS_FAT_POINTER_P (TREE_TYPE (TREE_OPERAND (e, 0))))
 	result
 	  = build3 (code, type,
-		    gnat_stabilize_reference_1 (TREE_OPERAND (e, 0), force),
+		    gnat_stabilize_reference_1 (TREE_OPERAND (e, 0), data, n),
 		    TREE_OPERAND (e, 1), TREE_OPERAND (e, 2));
       /* If the expression has side-effects, then encase it in a SAVE_EXPR
 	 so that it will only be evaluated once.  */
@@ -2714,15 +2704,15 @@  gnat_stabilize_reference_1 (tree e, bool
       /* Recursively stabilize each operand.  */
       result
 	= build2 (code, type,
-		  gnat_stabilize_reference_1 (TREE_OPERAND (e, 0), force),
-		  gnat_stabilize_reference_1 (TREE_OPERAND (e, 1), force));
+		  gnat_stabilize_reference_1 (TREE_OPERAND (e, 0), data, n),
+		  gnat_stabilize_reference_1 (TREE_OPERAND (e, 1), data, n));
       break;
 
     case tcc_unary:
       /* Recursively stabilize each operand.  */
       result
 	= build1 (code, type,
-		  gnat_stabilize_reference_1 (TREE_OPERAND (e, 0), force));
+		  gnat_stabilize_reference_1 (TREE_OPERAND (e, 0), data, n));
       break;
 
     default:
@@ -2743,6 +2733,17 @@  gnat_stabilize_reference_1 (tree e, bool
 tree
 gnat_stabilize_reference (tree ref, bool force)
 {
+  return gnat_rewrite_reference (ref, gnat_stabilize_reference_1, &force);
+}
+
+/* Rewrite reference REF and call FUNC on each expression within REF in the
+   process.  DATA is passed unmodified to FUNC and N is bumped each time it
+   is passed to FUNC, so FUNC is guaranteed to see a given N only once per
+   reference to be rewritten.  */
+
+tree
+gnat_rewrite_reference (tree ref, rewrite_fn func, void *data, int n)
+{
   tree type = TREE_TYPE (ref);
   enum tree_code code = TREE_CODE (ref);
   tree result;
@@ -2762,25 +2763,26 @@  gnat_stabilize_reference (tree ref, bool
     case VIEW_CONVERT_EXPR:
       result
 	= build1 (code, type,
-		  gnat_stabilize_reference (TREE_OPERAND (ref, 0), force));
+		  gnat_rewrite_reference (TREE_OPERAND (ref, 0), func, data,
+					  n));
       break;
 
     case INDIRECT_REF:
     case UNCONSTRAINED_ARRAY_REF:
-      result = build1 (code, type,
-		       gnat_stabilize_reference_1 (TREE_OPERAND (ref, 0),
-						   force));
+      result = build1 (code, type, func (TREE_OPERAND (ref, 0), data, n));
       break;
 
     case COMPONENT_REF:
       result = build3 (COMPONENT_REF, type,
-		       gnat_stabilize_reference (TREE_OPERAND (ref, 0), force),
+		       gnat_rewrite_reference (TREE_OPERAND (ref, 0), func,
+					       data, n),
 		       TREE_OPERAND (ref, 1), NULL_TREE);
       break;
 
     case BIT_FIELD_REF:
       result = build3 (BIT_FIELD_REF, type,
-		       gnat_stabilize_reference (TREE_OPERAND (ref, 0), force),
+		       gnat_rewrite_reference (TREE_OPERAND (ref, 0), func,
+					       data, n),
 		       TREE_OPERAND (ref, 1), TREE_OPERAND (ref, 2));
       break;
 
@@ -2788,8 +2790,9 @@  gnat_stabilize_reference (tree ref, bool
     case ARRAY_RANGE_REF:
       result
 	= build4 (code, type,
-		  gnat_stabilize_reference (TREE_OPERAND (ref, 0), force),
-		  gnat_stabilize_reference_1 (TREE_OPERAND (ref, 1), force),
+		  gnat_rewrite_reference (TREE_OPERAND (ref, 0), func, data,
+					  n + 1),
+		  func (TREE_OPERAND (ref, 1), data, n),
 		  TREE_OPERAND (ref, 2), TREE_OPERAND (ref, 3));
       break;
 
@@ -2804,9 +2807,10 @@  gnat_stabilize_reference (tree ref, bool
 	  t = TREE_OPERAND (t, 0);
 	if (TREE_CODE (t) == ADDR_EXPR)
 	  t = build1 (ADDR_EXPR, TREE_TYPE (t),
-		      gnat_stabilize_reference (TREE_OPERAND (t, 0), force));
+		      gnat_rewrite_reference (TREE_OPERAND (t, 0), func, data,
+					      n));
 	else
-	  t = gnat_stabilize_reference_1 (t, force);
+	  t = func (t, data, n);
 	t = fold_convert (TREE_TYPE (CALL_EXPR_ARG (ref, 0)), t);
 
 	result = build_call_expr (TREE_OPERAND (CALL_EXPR_FN (ref), 0), 2,
@@ -2895,22 +2899,6 @@  done:
   return exp;
 }
 
-/* Return true if REF is a constant reference, i.e. a reference (lvalue) that
-   doesn't depend on the context in which it is evaluated.  */
-
-bool
-gnat_constant_reference_p (tree ref)
-{
-  if (handled_component_p (ref))
-    {
-      ref = get_inner_constant_reference (ref);
-      if (!ref)
-	return false;
-    }
-
-  return DECL_P (ref);
-}
-
 /* If EXPR is an expression that is invariant in the current function, in the
    sense that it can be evaluated anywhere in the function and any number of
    times, return EXPR or an equivalent expression.  Otherwise return NULL.  */
Index: gcc-interface/gigi.h
===================================================================
--- gcc-interface/gigi.h	(revision 223708)
+++ gcc-interface/gigi.h	(working copy)
@@ -712,12 +712,6 @@  create_var_decl_1 (tree var_name, tree a
 		     const_flag, public_flag, extern_flag,		\
 		     static_flag, false, attr_list, gnat_node)
 
-/* Record DECL as a global non-constant renaming.  */
-extern void record_global_nonconstant_renaming (tree decl);
-
-/* Invalidate the global non-constant renamings.  */
-extern void invalidate_global_nonconstant_renamings (void);
-
 /* Return a FIELD_DECL node.  FIELD_NAME is the field's name, FIELD_TYPE is
    its type and RECORD_TYPE is the type of the enclosing record.  If SIZE is
    nonzero, it is the specified size of the field.  If POS is nonzero, it is
@@ -968,15 +962,19 @@  extern tree gnat_protect_expr (tree exp)
    force evaluation of everything.  */
 extern tree gnat_stabilize_reference (tree ref, bool force);
 
+/* Rewrite reference REF and call FUNC on each expression within REF in the
+   process.  DATA is passed unmodified to FUNC and N is bumped each time it
+   is passed to FUNC, so FUNC is guaranteed to see a given N only once per
+   reference to be rewritten.  */
+typedef tree (*rewrite_fn) (tree, void *, int);
+extern tree gnat_rewrite_reference (tree ref, rewrite_fn func, void *data,
+				    int n = 1);
+
 /* This is equivalent to get_inner_reference in expr.c but it returns the
    ultimate containing object only if the reference (lvalue) is constant,
    i.e. if it doesn't depend on the context in which it is evaluated.  */
 extern tree get_inner_constant_reference (tree exp);
 
-/* Return true if REF is a constant reference, i.e. a reference (lvalue) that
-   doesn't depend on the context in which it is evaluated.  */
-extern bool gnat_constant_reference_p (tree ref);
-
 /* If EXPR is an expression that is invariant in the current function, in the
    sense that it can be evaluated anywhere in the function and any number of
    times, return EXPR or an equivalent expression.  Otherwise return NULL.  */
@@ -1073,3 +1071,17 @@  ceil_pow2 (unsigned HOST_WIDE_INT x)
 {
   return (unsigned HOST_WIDE_INT) 1 << (floor_log2 (x - 1) + 1);
 }
+
+/* Return true if EXP, a CALL_EXPR, is an atomic load.  */
+
+static inline bool
+call_is_atomic_load (tree exp)
+{
+  tree fndecl = get_callee_fndecl (exp);
+
+  if (!(fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL))
+    return false;
+
+  enum built_in_function code = DECL_FUNCTION_CODE (fndecl);
+  return BUILT_IN_ATOMIC_LOAD_N <= code && code <= BUILT_IN_ATOMIC_LOAD_16;
+}
Index: gcc-interface/ada-tree.h
===================================================================
--- gcc-interface/ada-tree.h	(revision 223704)
+++ gcc-interface/ada-tree.h	(working copy)
@@ -394,10 +394,6 @@  do {						   \
    is readonly.  */
 #define DECL_POINTS_TO_READONLY_P(NODE) DECL_LANG_FLAG_4 (NODE)
 
-/* Nonzero in a VAR_DECL if it is a global non-constant renaming.  */
-#define DECL_GLOBAL_NONCONSTANT_RENAMING_P(NODE) \
-  DECL_LANG_FLAG_5 (VAR_DECL_CHECK (NODE))
-
 /* In a FIELD_DECL corresponding to a discriminant, contains the
    discriminant number.  */
 #define DECL_DISCRIMINANT_NUMBER(NODE) DECL_INITIAL (FIELD_DECL_CHECK (NODE))
@@ -439,8 +435,7 @@  do {						   \
   SET_DECL_LANG_SPECIFIC (VAR_DECL_CHECK (NODE), X)
 
 /* In a VAR_DECL without the DECL_LOOP_PARM_P flag set and that is a renaming
-   pointer, points to the object being renamed, if any.  Note that this object
-   is guaranteed to be protected against multiple evaluations.  */
+   pointer, points to the object being renamed, if any.  */
 #define DECL_RENAMED_OBJECT(NODE) \
   GET_DECL_LANG_SPECIFIC (VAR_DECL_CHECK (NODE))
 #define SET_DECL_RENAMED_OBJECT(NODE, X) \
Index: gcc-interface/trans.c
===================================================================
--- gcc-interface/trans.c	(revision 223708)
+++ gcc-interface/trans.c	(working copy)
@@ -1163,15 +1163,10 @@  Identifier_to_gnu (Node_Id gnat_node, tr
 					  true, false)))
 	gnu_result = DECL_INITIAL (gnu_result);
 
-      /* If it's a renaming pointer and not a global non-constant renaming or
-	 we are at the global level, the we can reference the renamed object
-	 directly, since it is either constant or has been protected against
-	 multiple evaluations.  */
+      /* If it's a renaming pointer, get to the renamed object.  */
       if (TREE_CODE (gnu_result) == VAR_DECL
           && !DECL_LOOP_PARM_P (gnu_result)
-	  && DECL_RENAMED_OBJECT (gnu_result)
-	  && (!DECL_GLOBAL_NONCONSTANT_RENAMING_P (gnu_result)
-	      || global_bindings_p ()))
+	  && DECL_RENAMED_OBJECT (gnu_result))
 	gnu_result = DECL_RENAMED_OBJECT (gnu_result);
 
       /* Otherwise, do the final dereference.  */
@@ -3975,16 +3970,32 @@  outer_atomic_access_required_p (Node_Id
 {
   gnat_node = gnat_strip_type_conversion (gnat_node);
 
-  while (Nkind (gnat_node) == N_Indexed_Component
-	 || Nkind (gnat_node) == N_Selected_Component
-	 || Nkind (gnat_node) == N_Slice)
+  while (true)
     {
-      gnat_node = gnat_strip_type_conversion (Prefix (gnat_node));
-      if (node_has_volatile_full_access (gnat_node))
-	return true;
+      switch (Nkind (gnat_node))
+	{
+	case N_Identifier:
+	case N_Expanded_Name:
+	  if (No (Renamed_Object (Entity (gnat_node))))
+	    return false;
+	  gnat_node
+	    = gnat_strip_type_conversion (Renamed_Object (Entity (gnat_node)));
+	  break;
+
+	case N_Indexed_Component:
+	case N_Selected_Component:
+	case N_Slice:
+	  gnat_node = gnat_strip_type_conversion (Prefix (gnat_node));
+	  if (node_has_volatile_full_access (gnat_node))
+	    return true;
+	  break;
+
+	default:
+	  return false;
+	}
     }
 
-  return false;
+  gcc_unreachable ();
 }
 
 /* Return true if GNAT_NODE requires atomic access and set SYNC according to
@@ -5290,11 +5301,6 @@  Compilation_Unit_to_gnu (Node_Id gnat_no
   info->gnat_node = gnat_node;
   elab_info_list = info;
 
-  /* Invalidate the global non-constant renamings.  This is necessary because
-     stabilization of the renamed entities may create SAVE_EXPRs which have
-     been tied to a specific elaboration routine just above.  */
-  invalidate_global_nonconstant_renamings ();
-
   /* Force the processing for all nodes that remain in the queue.  */
   process_deferred_decl_context (true);
 }
@@ -5838,8 +5844,7 @@  gnat_to_gnu (Node_Id gnat_node)
 	  tree gnu_temp
 	    = gnat_to_gnu_entity (gnat_temp,
 				  gnat_to_gnu (Renamed_Object (gnat_temp)), 1);
-	  /* We need to make sure that the side-effects of the renamed object
-	     are evaluated at this point, so we evaluate its address.  */
+	  /* See case 2 of renaming in gnat_to_gnu_entity.  */
 	  if (TREE_SIDE_EFFECTS (gnu_temp))
 	    gnu_result = build_unary_op (ADDR_EXPR, NULL_TREE, gnu_temp);
 	}
@@ -7933,6 +7938,26 @@  gnat_gimplify_expr (tree *expr_p, gimple
 	  return GS_ALL_DONE;
 	}
 
+      /* Replace atomic loads with their first argument.  That's necessary
+	 because the gimplifier would create a temporary otherwise.  */
+      if (TREE_SIDE_EFFECTS (op))
+	while (handled_component_p (op) || CONVERT_EXPR_P (op))
+	  {
+	    tree inner = TREE_OPERAND (op, 0);
+	    if (TREE_CODE (inner) == CALL_EXPR && call_is_atomic_load (inner))
+	      {
+		tree t = CALL_EXPR_ARG (inner, 0);
+		if (TREE_CODE (t) == NOP_EXPR)
+		  t = TREE_OPERAND (t, 0);
+		if (TREE_CODE (t) == ADDR_EXPR)
+		  TREE_OPERAND (op, 0) = TREE_OPERAND (t, 0);
+		else
+		  TREE_OPERAND (op, 0) = build_fold_indirect_ref (t);
+	      }
+	    else
+	      op = inner;
+	  }
+
       return GS_UNHANDLED;
 
     case VIEW_CONVERT_EXPR: