with Instrument;
use Instrument;

---------------------
-- Nested Recursive Call
---------------------

-- This test evaluates the code efficiency of a nested recursive call to
-- a procedure that has no formal parameters.

-- The parameterless procedure Nested is used to make a recursive call to
-- the enclosing procedure Nested_Recursive_Procedure that initially
-- calls Nested.  Both procedures use two Boolean variables, Recursion
-- and Test, declared in the outer scope to control their execution.  The
-- variable Recursion is initialized to the value of Test, which is
-- initialized to TRUE for the test version and FALSE for the noise version.
-- When Recursion is TRUE, Nested_Recursive_Procedure calls Nested which
-- assigns Recursion the value FALSE and then executes a recursive call
-- to Nested_Recursive_Procedure.  Because Recursion is then FALSE and
-- Test is then still TRUE, the nested call returns immediately after
-- evaluating the conditional, and the test version is completed.

-- When Recursion is initially FALSE, Nested_Recursive_Procecure calls
-- Nested, which assigns Test the value FALSE, evaluates the conditional
-- that guards the execution of the recursive call, and returns without
-- having executed the recursive call.  The presence of the nonexecuted
-- text ensures that when the recursive call is removed from the noise
-- version, the compiler must still assume the potential for recursion
-- and not perform any optimization that would compromise the code
-- efficiency metrics.  In addition, the evaluation of the guarding
-- conditional ensures that the same number of if statements are executed
-- in both the test and noise versions.

-- The purpose of embedding the call to Nested in an if-elsif construct
-- is to guarantee a single nested recursive call in the test version
-- and to balance the number of if statements executed in the test and
-- noise versions.  The accompanying camouflaged assignments to different
-- local variables, Local_1 and Local_2, preclude optimizations by the
-- compiler that might eliminate the if-elsif construct or sink the
-- assignment to a single local variable.

procedure Nrpca1 is
    package Ps_Cs is new Procs (Integer);
    use Ps_Cs;
    package B is new Procs (Boolean);

    Ttrue : B.T := B.T (True);
    Tfalse : B.T := B.T (False);
    --  Test      : B.T := B.Ident(TTRUE);  -- included in test version
    Test : B.T := B.Ident (Tfalse); -- included in noise version
    Recursion : B.T := B.Ident (Test);

    procedure Nested_Recursive_Procedure is

        Local_1 : T;
        Local_2 : T;

        procedure Nested is
        begin

            if Boolean (Recursion) then
                B.Let (Recursion, B.Ident (Tfalse));
                --        Nested_Recursive_Procedure;      -- included in test version
            else
                B.Let (Test, B.Ident (Tfalse));
                if Boolean (Test) then
                    -- Always FALSE
                    Nested_Recursive_Procedure;
                end if;
            end if;

        end Nested;

    begin
        if Boolean (Recursion) then
            Let (Local_1, Ident (Init));
            Nested;
        elsif not Boolean (Test) then
            Let (Local_2, Ident (Init));
            Nested;
        end if;
    end Nested_Recursive_Procedure;

begin
    Start ("NRPCA1", "Nested Recursive Procedure Call (Control)");
    for I in 1 .. 100000 loop

        B.Let (Recursion, B.Ident (Test));

        Nested_Recursive_Procedure;

    end loop;
    Stop;

end Nrpca1;