with Instrument;
use Instrument;

--------------------
-- Fuse Index Reference
--------------------

--  This test evaluates a code improvement potential similar to  that
--  resulting  from  the  Fuse Scalar Reference benchmark except that
--  the redefinition references the loop parameter of  the  enclosing
--  loop.

--  The test procedures contain a component by component redefinition
--  of two local arrays, Local_1  and  Local_3, using the local array
--  Local_2.  Each redefinition is enclosed in a separate loop with a
--  loop  parameter  that  has  a  static discrete range of the array
--  index  subtype.   This  range  is  sufficiently  large  to  elide
--  unrolling the loops.

--  In the nonoptimized test procedure a camouflaged redefinition  of
--  a  component of  Local_2  is interleaved between the two loops to
--  void  the  optimization  for  fusing  the  two  loops.   A  local
--  variable,  Index_N,  is  defined  to  ensure  that  this selected
--  component must  be  evaluated  at  execution  time.    When  this
--  redefinition  is  relocated  to  follow  the  two  loops  in  the
--  optimized test procedure, the  optimization  is  evidenced  by  a
--  difference  in  the  execution time and space requirements of the
--  two procedures.

--  The  camouflaged  redefinition  of Global_1 using components from
--  each  local  array ensures that other unexpected optimizations do
--  not invalidate the benchmark.

procedure Lfira1 is

    package New_Procs is new Procs (Integer);
    use New_Procs;

    Index_N : Integer;

    Local_1, Local_2, Local_3 : array (Integer range 1 .. 100) of T :=
       (others => Ident (Init / Init));

begin

    Start ("LFIRA1", "Loop Fuse, Index Ref. (control)");
    for I in 1 .. 10000 loop

        Let (Global, Ident (Init));
        Index_N := Ident (T (100));

        for J in Local_1'Range loop

            Local_1 (J) := Local_2 (J);

        end loop;

        Let (Local_2 (Index_N),
             Ident (Init / Init));      -- included in control version

        for J in Local_3'Range loop

            Local_3 (J) := Local_2 (J);

        end loop;

        --  Let(Local_2(Index_N), Ident(Init/Init));      -- included in test version
        Let (Global, Ident (Local_1 (Index_N) + Local_2 (Index_N) -
                            Local_3 (Index_N)));
        Let (Global, Ident (Init));

    end loop;
    Stop;

end Lfira1;