diff mbox

[Ada] More efficient code generated for object overlays

Message ID 20151112110643.GA117606@adacore.com
State New
Headers show

Commit Message

Arnaud Charlet Nov. 12, 2015, 11:06 a.m. UTC
This change refines the use of the "volatile hammer" to implement the advice
given in RM 13.3(19) by disabling it for object overlays altogether. relying
instead on the ref-all aliasing property of reference types to achieve the
desired effect.

This will generate better code for object overlays, for example the following
function should now make no memory accesses at all on 64-bit platforms when
compiled at -O2 or above:

package Vec is

  type U64 is mod 2**64;

  function Prod (A, B : U64) return U64;

end Vec;
package body Vec is

  function Prod (A, B : U64) return U64 is
    type U16 is mod 2**16;
    type V16 is array (1..4) of U16;
    VA : V16;
    for VA'Address use A'Address;
    VB : V16;
    for VB'Address use B'Address;
    R : U64 := 0;
  begin
    for I in V16'Range loop
      R := R + U64(VA (I)) * U64(VB (I));
    end loop;
    return R;
  end;

end Vec;

Tested on x86_64-pc-linux-gnu, committed on trunk

2015-11-12  Eric Botcazou  <ebotcazou@adacore.com>

	* sem_ch13.adb (Analyze_Attribute_Definition_Clause): For a
	variable, if this is not an overlay, set on Treat_As_Volatile on it.
	* gcc-interface/decl.c (E_Variable): Do not force the type to volatile
	for address clauses. Tweak and adjust various RM references.

Comments

Duncan Sands Nov. 12, 2015, 2:24 p.m. UTC | #1
Hi Arnaud,

On 12/11/15 12:06, Arnaud Charlet wrote:
> This change refines the use of the "volatile hammer" to implement the advice
> given in RM 13.3(19) by disabling it for object overlays altogether. relying
> instead on the ref-all aliasing property of reference types to achieve the
> desired effect.
>
> This will generate better code for object overlays, for example the following
> function should now make no memory accesses at all on 64-bit platforms when
> compiled at -O2 or above:

this is great!  When doing tricks to improve performance I've several times 
resorted to address overlays, forgetting about the "volatile hammer", only to 
rediscover it for the N'th time due to the poor performance and the horrible 
code generated.

Best wishes, Duncan.
diff mbox

Patch

Index: sem_ch13.adb
===================================================================
--- sem_ch13.adb	(revision 230229)
+++ sem_ch13.adb	(working copy)
@@ -4724,10 +4724,24 @@ 
 
                   Find_Overlaid_Entity (N, O_Ent, Off);
 
-                  --  If the object overlays a constant view, mark it so
+                  if Present (O_Ent) then
+                     --  If the object overlays a constant object, mark it so
 
-                  if Present (O_Ent) and then Is_Constant_Object (O_Ent) then
-                     Set_Overlays_Constant (U_Ent);
+                     if Is_Constant_Object (O_Ent) then
+                        Set_Overlays_Constant (U_Ent);
+                     end if;
+                  else
+                     --  If this is not an overlay, mark a variable as being
+                     --  volatile to prevent unwanted optimizations. It's a
+                     --  conservative interpretation of RM 13.3(19) for the
+                     --  cases where the compiler cannot detect potential
+                     --  aliasing issues easily and it also covers the case
+                     --  of an absolute address where the volatile aspect is
+                     --  kind of implicit.
+
+                     if Ekind (U_Ent) = E_Variable then
+                        Set_Treat_As_Volatile (U_Ent);
+                     end if;
                   end if;
 
                   --  Overlaying controlled objects is erroneous.
Index: gcc-interface/decl.c
===================================================================
--- gcc-interface/decl.c	(revision 230229)
+++ gcc-interface/decl.c	(working copy)
@@ -1068,14 +1068,12 @@ 
 	  }
 
 	/* Make a volatile version of this object's type if we are to make
-	   the object volatile.  We also interpret 13.3(19) conservatively
-	   and disallow any optimizations for such a non-constant object.  */
+	   the object volatile.  We also implement RM 13.3(19) for exported
+	   and imported (non-constant) objects by making them volatile.  */
 	if ((Treat_As_Volatile (gnat_entity)
 	     || (!const_flag
 		 && gnu_type != except_type_node
-		 && (Is_Exported (gnat_entity)
-		     || imported_p
-		     || Present (Address_Clause (gnat_entity)))))
+		 && (Is_Exported (gnat_entity) || imported_p)))
 	    && !TYPE_VOLATILE (gnu_type))
 	  {
 	    const int quals
@@ -1118,7 +1116,8 @@ 
 	  gnu_expr = convert (gnu_type, gnu_expr);
 
 	/* If this is a pointer that doesn't have an initializing expression,
-	   initialize it to NULL, unless the object is imported.  */
+	   initialize it to NULL, unless the object is declared imported as
+	   per RM B.1(24).  */
 	if (definition
 	    && (POINTER_TYPE_P (gnu_type) || TYPE_IS_FAT_POINTER_P (gnu_type))
 	    && !gnu_expr
@@ -1141,7 +1140,7 @@ 
 	    save_gnu_tree (gnat_entity, NULL_TREE, false);
 
 	    /* Convert the type of the object to a reference type that can
-	       alias everything as per 13.3(19).  */
+	       alias everything as per RM 13.3(19).  */
 	    gnu_type
 	      = build_reference_type_for_mode (gnu_type, ptr_mode, true);
 	    gnu_address = convert (gnu_type, gnu_address);
@@ -1206,11 +1205,10 @@ 
 	   as an indirect object.  Likewise for Stdcall objects that are
 	   imported.  */
 	if ((!definition && Present (Address_Clause (gnat_entity)))
-	    || (Is_Imported (gnat_entity)
-		&& Has_Stdcall_Convention (gnat_entity)))
+	    || (imported_p && Has_Stdcall_Convention (gnat_entity)))
 	  {
 	    /* Convert the type of the object to a reference type that can
-	       alias everything as per 13.3(19).  */
+	       alias everything as per RM 13.3(19).  */
 	    gnu_type
 	      = build_reference_type_for_mode (gnu_type, ptr_mode, true);
 	    used_by_ref = true;
@@ -1402,10 +1400,9 @@ 
 
 	/* If this name is external or a name was specified, use it, but don't
 	   use the Interface_Name with an address clause (see cd30005).  */
-	if ((Present (Interface_Name (gnat_entity))
-	     && No (Address_Clause (gnat_entity)))
-	    || (Is_Public (gnat_entity)
-		&& (!Is_Imported (gnat_entity) || Is_Exported (gnat_entity))))
+	if ((Is_Public (gnat_entity) && !Is_Imported (gnat_entity))
+	    || (Present (Interface_Name (gnat_entity))
+		&& No (Address_Clause (gnat_entity))))
 	  gnu_ext_name = create_concat_name (gnat_entity, NULL);
 
 	/* If this is an aggregate constant initialized to a constant, force it
@@ -4618,7 +4615,7 @@ 
 	    save_gnu_tree (gnat_entity, NULL_TREE, false);
 
 	    /* Convert the type of the object to a reference type that can
-	       alias everything as per 13.3(19).  */
+	       alias everything as per RM 13.3(19).  */
 	    gnu_type
 	      = build_reference_type_for_mode (gnu_type, ptr_mode, true);
 	    if (gnu_address)