storage-model-actuals

Storage-model component actuals

Selected and indexed actuals rooted at Designated_Storage_Model dereferences bypass Copy_From and Copy_To.

AcceptedApplies standaloneSince 1.0.0

Where it applies.

How each patchset treats this bundle on each GCC major
PatchsetGCC 13GCC 14GCC 15GCC 16
1.2.0 (latest)Known-good control13.2.0Patchedgcc-14-1614.2.0Patchedgcc-14-1615.3.0Patchedgcc-14-1616.2.0
1.1.0Known-good control13.2.0Patchedgcc-14-1614.2.0Patchedgcc-14-1615.3.0Patchedgcc-14-1616.2.0
1.0.1Known-good control13.2.0Patchedgcc-14-1614.2.0Patchedgcc-14-1615.3.0Patchedgcc-14-1616.1.0
1.0.0Known-good control13.2.0Patchedgcc-14-1614.2.0Patchedgcc-14-1615.3.0Patchedgcc-14-1616.1.0

Explanation.

The Ada front end correctly copies a bare object using a nonnative designated storage model into host memory before a call. GCC 14 through 16 fail to detect selected, indexed, and slice actuals rooted at the same dereference, so those forms can be lowered as native memory accesses.

The patch walks component prefixes to the nearest explicit dereference and uses that storage-model object to select the existing call-by-copy path. Its gnat.dg test is executable and covers explicit and implicit selected and indexed components, nested components, scalar and record copy-back, ordinary assignments, and access-value operations.

patches/gcc-14-16.patch is canonical for the pinned 14.2.0, 15.3.0, 16.1.0, and 16.2.0 FSF and Darwin source baselines. tests/storage_model_actuals.adb is a byte-identical runnable copy of the test added by that patch. GCC 13.2.0 uses the fixture only as an unpatched known-good control.

Patch.

Variant gcc-14-16

Applies to 14.2.0, 15.3.0, 16.1.0, 16.2.0. Source flavors: linux, darwin_arm64.

+318 −9 2 files

Download the patch

gcc/ada/exp_ch6.adb +38−9modified
Unified diff for gcc/ada/exp_ch6.adb: original line, patched line, change, source
@@ -1828 +1828 @@package body Exp_Ch6 is
18281828 N_Node : Node_Id;
18291829 E_Actual : Entity_Id;
18301830 E_Formal : Entity_Id;
1831Added line. Actual_Storage_Model : Entity_Id;
1832Added line.
1833Added line. function Storage_Model_Of_Actual (N : Node_Id) return Entity_Id;
1834Added line. -- Return the storage model of the innermost dereference underlying N,
1835Added line. -- if any. Components are part of the designated object and must use
1836Added line. -- the model of their nearest dereference. Conversions in a component
1837Added line. -- prefix do not change that model.
18311838
18321839 procedure Add_Call_By_Copy_Code;
18331840 -- For cases where the parameter must be passed by copy, this routine
@@ -2604 +2611 @@package body Exp_Ch6 is
26042611 end if;
26052612 end Make_Var;
26062613
2614Added line. -----------------------------
2615Added line. -- Storage_Model_Of_Actual --
2616Added line. -----------------------------
2617Added line.
2618Added line. function Storage_Model_Of_Actual (N : Node_Id) return Entity_Id is
2619Added line. Obj : Node_Id := N;
2620Added line.
2621Added line. begin
2622Added line. while Nkind (Obj) in N_Indexed_Component
2623Added line. | N_Selected_Component
2624Added line. | N_Slice
2625Added line. loop
2626Added line. Obj := Unqual_Conv (Prefix (Obj));
2627Added line. end loop;
2628Added line.
2629Added line. if Nkind (Obj) = N_Explicit_Dereference
2630Added line. and then
2631Added line. Has_Designated_Storage_Model_Aspect (Etype (Prefix (Obj)))
2632Added line. then
2633Added line. return Storage_Model_Object (Etype (Prefix (Obj)));
2634Added line. else
2635Added line. return Empty;
2636Added line. end if;
2637Added line. end Storage_Model_Of_Actual;
2638Added line.
26072639 -------------------------
26082640 -- Reset_Packed_Prefix --
26092641 -------------------------
@@ -2682 +2714 @@package body Exp_Ch6 is
26822714 while Present (Formal) loop
26832715 E_Formal := Etype (Formal);
26842716 E_Actual := Etype (Actual);
2717Added line. Actual_Storage_Model := Storage_Model_Of_Actual (Actual);
26852718
26862719 -- Handle formals whose type comes from the limited view
26872720
@@ -2804 +2837 @@package body Exp_Ch6 is
28042837
28052838 -- If the actual has a nonnative storage model, we need a copy
28062839
2807Removed line. elsif Nkind (Actual) = N_Explicit_Dereference
2808Removed line. and then
2809Removed line. Has_Designated_Storage_Model_Aspect (Etype (Prefix (Actual)))
2840Added line. elsif Present (Actual_Storage_Model)
28102841 and then
28112842 (Present (Storage_Model_Copy_To
2812Removed line. (Storage_Model_Object (Etype (Prefix (Actual)))))
2843Added line. (Actual_Storage_Model))
28132844 or else
28142845 (Ekind (Formal) = E_In_Out_Parameter
28152846 and then
28162847 Present (Storage_Model_Copy_From
2817Removed line. (Storage_Model_Object (Etype (Prefix (Actual)))))))
2848Added line. (Actual_Storage_Model))))
28182849 then
28192850 Add_Simple_Call_By_Copy_Code (Force => True);
28202851
@@ -2970 +3001 @@package body Exp_Ch6 is
29703001
29713002 -- If the actual has a nonnative storage model, we need a copy
29723003
2973Removed line. elsif Nkind (Actual) = N_Explicit_Dereference
2974Removed line. and then
2975Removed line. Has_Designated_Storage_Model_Aspect (Etype (Prefix (Actual)))
3004Added line. elsif Present (Actual_Storage_Model)
29763005 and then
29773006 Present (Storage_Model_Copy_From
2978Removed line. (Storage_Model_Object (Etype (Prefix (Actual)))))
3007Added line. (Actual_Storage_Model))
29793008 then
29803009 Add_Simple_Call_By_Copy_Code (Force => True);
29813010
gcc/testsuite/gnat.dg/storage_model_actuals.adb +280−0new file
Unified diff for gcc/testsuite/gnat.dg/storage_model_actuals.adb: original line, patched line, change, source
@@ -0 +1 @@
1Added line. -- { dg-do run }
2Added line. -- { dg-options "-gnatX0 -gnata" }
3Added line.
4Added line. with Ada.Text_IO; use Ada.Text_IO;
5Added line. with Interfaces; use Interfaces;
6Added line. with Interfaces.C;
7Added line. with System;
8Added line. with System.Storage_Elements; use System.Storage_Elements;
9Added line.
10Added line. procedure Storage_Model_Actuals is
11Added line. type Shared_Address is mod 2 ** 64;
12Added line. Null_Shared_Address : constant Shared_Address := 0;
13Added line.
14Added line. type Byte_Array is array (Storage_Offset range 0 .. 8_191)
15Added line. of aliased Unsigned_8;
16Added line.
17Added line. type Shared_Model is limited record
18Added line. Bytes : Byte_Array := (others => 0);
19Added line. Next : Storage_Offset := 8;
20Added line. Reads : Natural := 0;
21Added line. Writes : Natural := 0;
22Added line. Read_Bytes : Storage_Count := 0;
23Added line. Write_Bytes : Storage_Count := 0;
24Added line. end record
25Added line. with Storage_Model_Type =>
26Added line. (Address_Type => Shared_Address,
27Added line. Allocate => Allocate,
28Added line. Deallocate => Deallocate,
29Added line. Copy_To => Copy_To,
30Added line. Copy_From => Copy_From,
31Added line. Storage_Size => Storage_Size,
32Added line. Null_Address => Null_Shared_Address);
33Added line.
34Added line. procedure Allocate
35Added line. (Model : in out Shared_Model;
36Added line. Storage_Address : out Shared_Address;
37Added line. Size : Storage_Count;
38Added line. Alignment : Storage_Count);
39Added line.
40Added line. procedure Deallocate
41Added line. (Model : in out Shared_Model;
42Added line. Storage_Address : Shared_Address;
43Added line. Size : Storage_Count;
44Added line. Alignment : Storage_Count);
45Added line.
46Added line. procedure Copy_To
47Added line. (Model : in out Shared_Model;
48Added line. Target : Shared_Address;
49Added line. Source : System.Address;
50Added line. Size : Storage_Count);
51Added line.
52Added line. procedure Copy_From
53Added line. (Model : in out Shared_Model;
54Added line. Target : System.Address;
55Added line. Source : Shared_Address;
56Added line. Size : Storage_Count);
57Added line.
58Added line. function Storage_Size (Model : Shared_Model) return Storage_Count;
59Added line.
60Added line. function C_Memcpy
61Added line. (Destination : System.Address;
62Added line. Source : System.Address;
63Added line. Size : Interfaces.C.size_t) return System.Address
64Added line. with Import, Convention => C, External_Name => "memcpy";
65Added line.
66Added line. procedure Allocate
67Added line. (Model : in out Shared_Model;
68Added line. Storage_Address : out Shared_Address;
69Added line. Size : Storage_Count;
70Added line. Alignment : Storage_Count)
71Added line. is
72Added line. Aligned : constant Storage_Offset :=
73Added line. ((Model.Next + Storage_Offset (Alignment) - 1)
74Added line. / Storage_Offset (Alignment)) * Storage_Offset (Alignment);
75Added line. begin
76Added line. Storage_Address := Shared_Address (Aligned);
77Added line. Model.Next := Aligned + Storage_Offset (Size);
78Added line. end Allocate;
79Added line.
80Added line. procedure Deallocate
81Added line. (Model : in out Shared_Model;
82Added line. Storage_Address : Shared_Address;
83Added line. Size : Storage_Count;
84Added line. Alignment : Storage_Count)
85Added line. is
86Added line. pragma Unreferenced (Model, Storage_Address, Size, Alignment);
87Added line. begin
88Added line. null;
89Added line. end Deallocate;
90Added line.
91Added line. procedure Copy_To
92Added line. (Model : in out Shared_Model;
93Added line. Target : Shared_Address;
94Added line. Source : System.Address;
95Added line. Size : Storage_Count)
96Added line. is
97Added line. Ignored : System.Address;
98Added line. begin
99Added line. Model.Writes := Model.Writes + 1;
100Added line. Model.Write_Bytes := Model.Write_Bytes + Size;
101Added line. Ignored := C_Memcpy
102Added line. (Model.Bytes (0)'Address + Storage_Offset (Target),
103Added line. Source,
104Added line. Interfaces.C.size_t (Size));
105Added line. end Copy_To;
106Added line.
107Added line. procedure Copy_From
108Added line. (Model : in out Shared_Model;
109Added line. Target : System.Address;
110Added line. Source : Shared_Address;
111Added line. Size : Storage_Count)
112Added line. is
113Added line. Ignored : System.Address;
114Added line. begin
115Added line. Model.Reads := Model.Reads + 1;
116Added line. Model.Read_Bytes := Model.Read_Bytes + Size;
117Added line. Put_Line
118Added line. ("Copy_From source=" & Shared_Address'Image (Source)
119Added line. & " size=" & Storage_Count'Image (Size));
120Added line. Flush;
121Added line. Ignored := C_Memcpy
122Added line. (Target,
123Added line. Model.Bytes (0)'Address + Storage_Offset (Source),
124Added line. Interfaces.C.size_t (Size));
125Added line. end Copy_From;
126Added line.
127Added line. function Storage_Size (Model : Shared_Model) return Storage_Count is
128Added line. begin
129Added line. return Storage_Count (Model.Bytes'Length) - Storage_Count (Model.Next);
130Added line. end Storage_Size;
131Added line.
132Added line. Arena : Shared_Model;
133Added line.
134Added line. type Node;
135Added line. type Node_Pointer is access Node
136Added line. with Designated_Storage_Model => Arena;
137Added line. type Node is record
138Added line. Value : Integer;
139Added line. Next : Node_Pointer;
140Added line. end record;
141Added line.
142Added line. type Integer_Array is array (Positive range <>) of Integer;
143Added line. subtype Three_Integers is Integer_Array (1 .. 3);
144Added line. type Array_Pointer is access Three_Integers
145Added line. with Designated_Storage_Model => Arena;
146Added line.
147Added line. P : Node_Pointer := new Node'(Value => 10, Next => null);
148Added line. Q : Node_Pointer := new Node'(Value => 20, Next => null);
149Added line. A : Array_Pointer := new Three_Integers'(1, 2, 3);
150Added line.
151Added line. procedure Consume_Integer (Item, Expected : Integer) is
152Added line. begin
153Added line. pragma Assert (Item = Expected);
154Added line. end Consume_Integer;
155Added line.
156Added line. procedure Increment_Integer (Item : in out Integer) is
157Added line. begin
158Added line. Item := Item + 1;
159Added line. end Increment_Integer;
160Added line.
161Added line. procedure Consume_Node (Item : Node; Expected : Integer) is
162Added line. begin
163Added line. pragma Assert (Item.Value = Expected);
164Added line. end Consume_Node;
165Added line.
166Added line. procedure Increment_Node (Item : in out Node) is
167Added line. begin
168Added line. Item.Value := Item.Value + 1;
169Added line. end Increment_Node;
170Added line.
171Added line. procedure Assert_Read (Before : Natural) is
172Added line. begin
173Added line. pragma Assert (Arena.Reads > Before);
174Added line. end Assert_Read;
175Added line.
176Added line. procedure Assert_Write (Before : Natural) is
177Added line. begin
178Added line. pragma Assert (Arena.Writes > Before);
179Added line. end Assert_Write;
180Added line.
181Added line. Before_Reads : Natural;
182Added line. Before_Writes : Natural;
183Added line. Got : Integer;
184Added line. begin
185Added line. -- Whole designated object as an IN actual.
186Added line. Put_Line ("STEP whole-in");
187Added line. Flush;
188Added line. Before_Reads := Arena.Reads;
189Added line. Consume_Node (P.all, 10);
190Added line. Assert_Read (Before_Reads);
191Added line.
192Added line. -- Explicit and implicit selected-component IN actuals.
193Added line. Put_Line ("STEP selected-in");
194Added line. Flush;
195Added line. Before_Reads := Arena.Reads;
196Added line. Consume_Integer (P.all.Value, 10);
197Added line. Assert_Read (Before_Reads);
198Added line.
199Added line. Put_Line ("STEP implicit-selected-in");
200Added line. Flush;
201Added line.
202Added line. Before_Reads := Arena.Reads;
203Added line. Consume_Integer (P.Value, 10);
204Added line. Assert_Read (Before_Reads);
205Added line.
206Added line. -- Nested selected component, rooted at two model access values.
207Added line. Put_Line ("STEP nested-in");
208Added line. Flush;
209Added line. P.Next := Q;
210Added line. Before_Reads := Arena.Reads;
211Added line. Consume_Integer (P.Next.Value, 20);
212Added line. Assert_Read (Before_Reads);
213Added line.
214Added line. -- Indexed component rooted at a model access value.
215Added line. Put_Line ("STEP indexed-in");
216Added line. Flush;
217Added line. Before_Reads := Arena.Reads;
218Added line. Consume_Integer (A.all (2), 2);
219Added line. Assert_Read (Before_Reads);
220Added line.
221Added line. Before_Reads := Arena.Reads;
222Added line. Consume_Integer (A (3), 3);
223Added line. Assert_Read (Before_Reads);
224Added line.
225Added line. -- Scalar IN OUT host copy and copyback.
226Added line. Put_Line ("STEP scalar-in-out");
227Added line. Flush;
228Added line. Before_Reads := Arena.Reads;
229Added line. Before_Writes := Arena.Writes;
230Added line. Increment_Integer (P.Value);
231Added line. Assert_Read (Before_Reads);
232Added line. Assert_Write (Before_Writes);
233Added line. Got := P.Value;
234Added line. pragma Assert (Got = 11);
235Added line.
236Added line. -- Whole-record IN OUT host copy and copyback.
237Added line. Put_Line ("STEP whole-in-out");
238Added line. Flush;
239Added line. Before_Reads := Arena.Reads;
240Added line. Before_Writes := Arena.Writes;
241Added line. Increment_Node (P.all);
242Added line. Assert_Read (Before_Reads);
243Added line. Assert_Write (Before_Writes);
244Added line. Got := P.Value;
245Added line. pragma Assert (Got = 12);
246Added line.
247Added line. -- Assignment reads and writes retain normal source syntax.
248Added line. Put_Line ("STEP assignments");
249Added line. Flush;
250Added line. Before_Reads := Arena.Reads;
251Added line. Got := P.Value;
252Added line. Assert_Read (Before_Reads);
253Added line. pragma Assert (Got = 12);
254Added line.
255Added line. Before_Writes := Arena.Writes;
256Added line. P.Value := 30;
257Added line. Assert_Write (Before_Writes);
258Added line. Got := P.Value;
259Added line. pragma Assert (Got = 30);
260Added line.
261Added line. Before_Writes := Arena.Writes;
262Added line. A (2) := 40;
263Added line. Assert_Write (Before_Writes);
264Added line. Got := A (2);
265Added line. pragma Assert (Got = 40);
266Added line.
267Added line. -- Access-value null and equality do not dereference the offset.
268Added line. Put_Line ("STEP access-values");
269Added line. Flush;
270Added line. pragma Assert (P /= null);
271Added line. pragma Assert (Q /= null);
272Added line. pragma Assert (P = P);
273Added line. pragma Assert (P /= Q);
274Added line.
275Added line. Put_Line
276Added line. ("PASS reads=" & Natural'Image (Arena.Reads)
277Added line. & " writes=" & Natural'Image (Arena.Writes)
278Added line. & " read_bytes=" & Storage_Count'Image (Arena.Read_Bytes)
279Added line. & " write_bytes=" & Storage_Count'Image (Arena.Write_Bytes));
280Added line. end Storage_Model_Actuals;
281

Tests.

storage_model_actuals.adb Ada · 280 lines
--  { dg-do run }
--  { dg-options "-gnatX0 -gnata" }

with Ada.Text_IO;             use Ada.Text_IO;
with Interfaces;              use Interfaces;
with Interfaces.C;
with System;
with System.Storage_Elements; use System.Storage_Elements;

procedure Storage_Model_Actuals is
   type Shared_Address is mod 2 ** 64;
   Null_Shared_Address : constant Shared_Address := 0;

   type Byte_Array is array (Storage_Offset range 0 .. 8_191)
     of aliased Unsigned_8;

   type Shared_Model is limited record
      Bytes       : Byte_Array := (others => 0);
      Next        : Storage_Offset := 8;
      Reads       : Natural := 0;
      Writes      : Natural := 0;
      Read_Bytes  : Storage_Count := 0;
      Write_Bytes : Storage_Count := 0;
   end record
     with Storage_Model_Type =>
       (Address_Type => Shared_Address,
        Allocate     => Allocate,
        Deallocate   => Deallocate,
        Copy_To      => Copy_To,
        Copy_From    => Copy_From,
        Storage_Size => Storage_Size,
        Null_Address => Null_Shared_Address);

   procedure Allocate
     (Model           : in out Shared_Model;
      Storage_Address : out Shared_Address;
      Size            : Storage_Count;
      Alignment       : Storage_Count);

   procedure Deallocate
     (Model           : in out Shared_Model;
      Storage_Address : Shared_Address;
      Size            : Storage_Count;
      Alignment       : Storage_Count);

   procedure Copy_To
     (Model  : in out Shared_Model;
      Target : Shared_Address;
      Source : System.Address;
      Size   : Storage_Count);

   procedure Copy_From
     (Model  : in out Shared_Model;
      Target : System.Address;
      Source : Shared_Address;
      Size   : Storage_Count);

   function Storage_Size (Model : Shared_Model) return Storage_Count;

   function C_Memcpy
     (Destination : System.Address;
      Source      : System.Address;
      Size        : Interfaces.C.size_t) return System.Address
     with Import, Convention => C, External_Name => "memcpy";

   procedure Allocate
     (Model           : in out Shared_Model;
      Storage_Address : out Shared_Address;
      Size            : Storage_Count;
      Alignment       : Storage_Count)
   is
      Aligned : constant Storage_Offset :=
        ((Model.Next + Storage_Offset (Alignment) - 1)
         / Storage_Offset (Alignment)) * Storage_Offset (Alignment);
   begin
      Storage_Address := Shared_Address (Aligned);
      Model.Next := Aligned + Storage_Offset (Size);
   end Allocate;

   procedure Deallocate
     (Model           : in out Shared_Model;
      Storage_Address : Shared_Address;
      Size            : Storage_Count;
      Alignment       : Storage_Count)
   is
      pragma Unreferenced (Model, Storage_Address, Size, Alignment);
   begin
      null;
   end Deallocate;

   procedure Copy_To
     (Model  : in out Shared_Model;
      Target : Shared_Address;
      Source : System.Address;
      Size   : Storage_Count)
   is
      Ignored : System.Address;
   begin
      Model.Writes := Model.Writes + 1;
      Model.Write_Bytes := Model.Write_Bytes + Size;
      Ignored := C_Memcpy
        (Model.Bytes (0)'Address + Storage_Offset (Target),
         Source,
         Interfaces.C.size_t (Size));
   end Copy_To;

   procedure Copy_From
     (Model  : in out Shared_Model;
      Target : System.Address;
      Source : Shared_Address;
      Size   : Storage_Count)
   is
      Ignored : System.Address;
   begin
      Model.Reads := Model.Reads + 1;
      Model.Read_Bytes := Model.Read_Bytes + Size;
      Put_Line
        ("Copy_From source=" & Shared_Address'Image (Source)
         & " size=" & Storage_Count'Image (Size));
      Flush;
      Ignored := C_Memcpy
        (Target,
         Model.Bytes (0)'Address + Storage_Offset (Source),
         Interfaces.C.size_t (Size));
   end Copy_From;

   function Storage_Size (Model : Shared_Model) return Storage_Count is
   begin
      return Storage_Count (Model.Bytes'Length) - Storage_Count (Model.Next);
   end Storage_Size;

   Arena : Shared_Model;

   type Node;
   type Node_Pointer is access Node
     with Designated_Storage_Model => Arena;
   type Node is record
      Value : Integer;
      Next  : Node_Pointer;
   end record;

   type Integer_Array is array (Positive range <>) of Integer;
   subtype Three_Integers is Integer_Array (1 .. 3);
   type Array_Pointer is access Three_Integers
     with Designated_Storage_Model => Arena;

   P : Node_Pointer := new Node'(Value => 10, Next => null);
   Q : Node_Pointer := new Node'(Value => 20, Next => null);
   A : Array_Pointer := new Three_Integers'(1, 2, 3);

   procedure Consume_Integer (Item, Expected : Integer) is
   begin
      pragma Assert (Item = Expected);
   end Consume_Integer;

   procedure Increment_Integer (Item : in out Integer) is
   begin
      Item := Item + 1;
   end Increment_Integer;

   procedure Consume_Node (Item : Node; Expected : Integer) is
   begin
      pragma Assert (Item.Value = Expected);
   end Consume_Node;

   procedure Increment_Node (Item : in out Node) is
   begin
      Item.Value := Item.Value + 1;
   end Increment_Node;

   procedure Assert_Read (Before : Natural) is
   begin
      pragma Assert (Arena.Reads > Before);
   end Assert_Read;

   procedure Assert_Write (Before : Natural) is
   begin
      pragma Assert (Arena.Writes > Before);
   end Assert_Write;

   Before_Reads  : Natural;
   Before_Writes : Natural;
   Got           : Integer;
begin
   --  Whole designated object as an IN actual.
   Put_Line ("STEP whole-in");
   Flush;
   Before_Reads := Arena.Reads;
   Consume_Node (P.all, 10);
   Assert_Read (Before_Reads);

   --  Explicit and implicit selected-component IN actuals.
   Put_Line ("STEP selected-in");
   Flush;
   Before_Reads := Arena.Reads;
   Consume_Integer (P.all.Value, 10);
   Assert_Read (Before_Reads);

   Put_Line ("STEP implicit-selected-in");
   Flush;

   Before_Reads := Arena.Reads;
   Consume_Integer (P.Value, 10);
   Assert_Read (Before_Reads);

   --  Nested selected component, rooted at two model access values.
   Put_Line ("STEP nested-in");
   Flush;
   P.Next := Q;
   Before_Reads := Arena.Reads;
   Consume_Integer (P.Next.Value, 20);
   Assert_Read (Before_Reads);

   --  Indexed component rooted at a model access value.
   Put_Line ("STEP indexed-in");
   Flush;
   Before_Reads := Arena.Reads;
   Consume_Integer (A.all (2), 2);
   Assert_Read (Before_Reads);

   Before_Reads := Arena.Reads;
   Consume_Integer (A (3), 3);
   Assert_Read (Before_Reads);

   --  Scalar IN OUT host copy and copyback.
   Put_Line ("STEP scalar-in-out");
   Flush;
   Before_Reads := Arena.Reads;
   Before_Writes := Arena.Writes;
   Increment_Integer (P.Value);
   Assert_Read (Before_Reads);
   Assert_Write (Before_Writes);
   Got := P.Value;
   pragma Assert (Got = 11);

   --  Whole-record IN OUT host copy and copyback.
   Put_Line ("STEP whole-in-out");
   Flush;
   Before_Reads := Arena.Reads;
   Before_Writes := Arena.Writes;
   Increment_Node (P.all);
   Assert_Read (Before_Reads);
   Assert_Write (Before_Writes);
   Got := P.Value;
   pragma Assert (Got = 12);

   --  Assignment reads and writes retain normal source syntax.
   Put_Line ("STEP assignments");
   Flush;
   Before_Reads := Arena.Reads;
   Got := P.Value;
   Assert_Read (Before_Reads);
   pragma Assert (Got = 12);

   Before_Writes := Arena.Writes;
   P.Value := 30;
   Assert_Write (Before_Writes);
   Got := P.Value;
   pragma Assert (Got = 30);

   Before_Writes := Arena.Writes;
   A (2) := 40;
   Assert_Write (Before_Writes);
   Got := A (2);
   pragma Assert (Got = 40);

   --  Access-value null and equality do not dereference the offset.
   Put_Line ("STEP access-values");
   Flush;
   pragma Assert (P /= null);
   pragma Assert (Q /= null);
   pragma Assert (P = P);
   pragma Assert (P /= Q);

   Put_Line
     ("PASS reads=" & Natural'Image (Arena.Reads)
      & " writes=" & Natural'Image (Arena.Writes)
      & " read_bytes=" & Storage_Count'Image (Arena.Read_Bytes)
      & " write_bytes=" & Storage_Count'Image (Arena.Write_Bytes));
end Storage_Model_Actuals;

Download · View in repository

run-test.sh shell · 60 lines
#!/usr/bin/env bash
set -euo pipefail

if [[ $# -ne 3 ]]; then
  echo "usage: $0 TOOLCHAIN_ROOT GCC_VERSION unpatched|patched" >&2
  exit 2
fi

root=$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)
source "$root/scripts/regression-common.sh"
resolve_regression_toolchain "$1"
version=$2
state=$3
[[ "$state" == unpatched || "$state" == patched ]] || {
  echo "error: state must be unpatched or patched" >&2
  exit 2
}

fixture="$root/bundles/storage-model-actuals/tests/storage_model_actuals.adb"
work=$(mktemp -d "${TMPDIR:-/tmp}/gnat-storage-model-test.XXXXXX")
trap 'rm -rf "$work"' EXIT

for optimization in 0 2; do
  case_dir="$work/O$optimization"
  mkdir -p "$case_dir"
  cp "$fixture" "$case_dir/storage_model_actuals.adb"
  (
    cd "$case_dir"
    "${REGRESSION_ENV[@]}" "$REGRESSION_GNATMAKE" -q -gnatX0 -gnata \
      "-O$optimization" storage_model_actuals.adb
  )
  set +e
  "${REGRESSION_ENV[@]}" "$case_dir/storage_model_actuals" \
    >"$case_dir/output.log" 2>&1
  status=$?
  set -e

  if [[ "$version" == 13.2.0 ]]; then
    [[ $status -eq 0 ]] || { cat "$case_dir/output.log"; exit 1; }
    grep -F "PASS reads= 15 writes= 8 read_bytes= 92 write_bytes= 80" \
      "$case_dir/output.log"
    expected=known-good-control
  elif [[ "$state" == patched ]]; then
    [[ $status -eq 0 ]] || { cat "$case_dir/output.log"; exit 1; }
    grep -F "PASS reads= 16 writes= 8 read_bytes= 100 write_bytes= 80" \
      "$case_dir/output.log"
    expected=patched
  else
    [[ $status -ne 0 ]] || {
      echo "error: unpatched storage-model regression unexpectedly passed at -O$optimization"
      exit 1
    }
    grep -Eiq 'CONSTRAINT_ERROR|erroneous memory access' "$case_dir/output.log" || {
      cat "$case_dir/output.log"
      exit 1
    }
    expected=expected-failure
  fi
  echo "storage-model-actuals -O$optimization: $expected"
done

Download · View in repository

Commands.

Apply the patch
patch --fuzz=0 -p1 -i bundles/storage-model-actuals/patches/gcc-14-16.patch
Build the compiler
PATH=/path/to/bootstrap/bin:$PATH ./scripts/build-gnat.sh SOURCE BUILD INSTALL
Run the regression
./scripts/run-regressions.sh INSTALL 1.1.0 GCC_MAJOR patched

Metadata.