comp.lang.ada
 help / color / mirror / Atom feed
* Re: Right of Optimize Eager Evaluation Away
  1999-11-28  0:00 Right of Optimize Eager Evaluation Away Laurent Guerby
@ 1999-11-28  0:00 ` Robert A Duff
  1999-11-28  0:00   ` Laurent Guerby
  1999-11-29  0:00 ` Jean-Pierre Rosen
  1 sibling, 1 reply; 11+ messages in thread
From: Robert A Duff @ 1999-11-28  0:00 UTC (permalink / raw)


Laurent Guerby <guerby@acm.org> writes:

> The question is: is a smart Ada 95 compiler allowed to generate code
> that looks like this:
> 
>    if C then
>       X := Super_Expensive_Function_Call_1;
>    else
>       X := Super_Expensive_Function_Call_2;
>    end if;
> 
> that is to say, be lazy about its argument, and so might
> save execution time.

No.  The function arguments may be evaluated in either order, so in case
of exception, the other one might not happen.  But without exceptions,
both arguments will be evaluated.

- Bob




^ permalink raw reply	[flat|nested] 11+ messages in thread

* Right of Optimize Eager Evaluation Away
@ 1999-11-28  0:00 Laurent Guerby
  1999-11-28  0:00 ` Robert A Duff
  1999-11-29  0:00 ` Jean-Pierre Rosen
  0 siblings, 2 replies; 11+ messages in thread
From: Laurent Guerby @ 1999-11-28  0:00 UTC (permalink / raw)


[I originally posted this in the 11.6 thread, but got no answer]

If we have the following function:
   
   function Cond_T (C : in Boolean; If_True, If_False : in T) return T;
   pragma Inline (Cond_T);

   function Cond_T (C : in Boolean; If_True, If_False : in T) return T is
   begin
      if C then
         return If_True;
      else
         return If_False;
      end if;
   end Cond_T;

And the following expression:

   C : constant Boolean := Some_Run_Time_Value_That_The_Compiler_Cannot_Guess;

   X : constant T := Cont_T (C, If_True => Super_Expensive_Function_Call_1, 
                                If_False => Super_Expensive_Function_Call_2);

The question is: is a smart Ada 95 compiler allowed to generate code
that looks like this:

   if C then
      X := Super_Expensive_Function_Call_1;
   else
      X := Super_Expensive_Function_Call_2;
   end if;

that is to say, be lazy about its argument, and so might
save execution time.

If one of the Super_Expensive function has side effects, or raises an
exception (so Pure won't help here), the code is not identical to the
original code:

   X1 := Super_Expensive_Function_Call_1;
   X2 := Super_Expensive_Function_Call_2;
   if C then
      return X1;
   else
      return X2;
   end if;

--LG




^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Right of Optimize Eager Evaluation Away
  1999-11-28  0:00 ` Robert A Duff
@ 1999-11-28  0:00   ` Laurent Guerby
  1999-11-29  0:00     ` Nick Roberts
  0 siblings, 1 reply; 11+ messages in thread
From: Laurent Guerby @ 1999-11-28  0:00 UTC (permalink / raw)


Robert A Duff <bobduff@world.std.com> writes:
> Laurent Guerby <guerby@acm.org> writes:
> > The question is: is a smart Ada 95 compiler allowed to generate code
> > that looks like this:
> > 
> >    if C then
> >       X := Super_Expensive_Function_Call_1;
> >    else
> >       X := Super_Expensive_Function_Call_2;
> >    end if;
> > 
> > that is to say, be lazy about its argument, and so might
> > save execution time.
> No.  The function arguments may be evaluated in either order, so in case
> of exception, the other one might not happen.  But without exceptions,
> both arguments will be evaluated.

Is the potential raising of an exception the only language barrier
here (since as you mention the compiler is free to swap calls
defeating a class of side effects)? This seams easy to fix (via a
pragma), if one is interested in keeping the functional aspect of the
code instead of resorting to statements of course.

> - Bob

--LG




^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Right of Optimize Eager Evaluation Away
  1999-11-28  0:00   ` Laurent Guerby
@ 1999-11-29  0:00     ` Nick Roberts
  1999-11-29  0:00       ` Robert A Duff
  0 siblings, 1 reply; 11+ messages in thread
From: Nick Roberts @ 1999-11-29  0:00 UTC (permalink / raw)


Laurent Guerby wrote:
> 
> Robert A Duff <bobduff@world.std.com> writes:
> > Laurent Guerby <guerby@acm.org> writes:
> > > The question is: is a smart Ada 95 compiler allowed to generate code
> > > that looks like this:
> > >
> > >    if C then
> > >       X := Super_Expensive_Function_Call_1;
> > >    else
> > >       X := Super_Expensive_Function_Call_2;
> > >    end if;
> > >
> > > that is to say, be lazy about its argument, and so might
> > > save execution time.
> > No.  The function arguments may be evaluated in either order, so in case
> > of exception, the other one might not happen.  But without exceptions,
> > both arguments will be evaluated.
> 
> Is the potential raising of an exception the only language barrier
> here (since as you mention the compiler is free to swap calls
> defeating a class of side effects)? This seams easy to fix (via a
> pragma), if one is interested in keeping the functional aspect of the
> code instead of resorting to statements of course.

I didn't receive Laurent's original post (poor UK feed), so - forgive me
- I must guess at what he was originally suggesting, that a call such as

   P1(X,Y);

where P1 was declared by

   procedure P1 (A: Boolean; B: T) is
   begin
      if A then
         P2;
      else
         P3(B);
      end if;
   end;

would be optimised to evaluate X first, and omit the evaluation of Y if
X turned out to be True.

The RM95 says that a conforming implementation is allowed to execute an
Ada program in any way which produces the required external effects
[RM95 1.1.3(8-15)]. (Which is plain common sense, anyway, really.)

This means that a compiler can perform any optimisation that doesn't
change the external effects of a program. So the suggested optimisation
is perfectly acceptable, provided the compiler can _guarantee_ that it
will not change the external effects of the program.

I get the impression that, in practice, there are not many Ada compilers
which 'strongly' optimise (maybe there aren't any). However, I think a
strongly optimising compiler (by today's standards) would be very
likely, in effect, to produce the suggested optimisation, in the case of
the subprogram P1 being expanded inline, or local and independent, and
provided the compiler could be sure that the evaluation of Y could not
have raised an exception or caused any external effect.

-- 
Nick Roberts
http://www.adapower.com/lab/adaos
Always call for the professionals. (If they don't help, call for me ;-)





^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Right of Optimize Eager Evaluation Away
  1999-11-29  0:00     ` Nick Roberts
@ 1999-11-29  0:00       ` Robert A Duff
  1999-11-29  0:00         ` Laurent Guerby
  0 siblings, 1 reply; 11+ messages in thread
From: Robert A Duff @ 1999-11-29  0:00 UTC (permalink / raw)


Nick Roberts <nickroberts@callnetuk.com> writes:

> Laurent Guerby wrote:

> > Is the potential raising of an exception the only language barrier
> > here (since as you mention the compiler is free to swap calls
> > defeating a class of side effects)? This seams easy to fix (via a
> > pragma), if one is interested in keeping the functional aspect of the
> > code instead of resorting to statements of course.

I don't understand Laurent's question.

> I didn't receive Laurent's original post (poor UK feed), so - forgive me
> - I must guess at what he was originally suggesting, ...

Sorry, Nick -- you guessed wrong.  ;-)

The original question had to do with a function with two formal
parameters.  Does 11.6 authorize the compiler to omit the evaluation of
one of the *actual* parameters in a call, if it can prove that the value
of the formal will never be used.  The answer is no.  We are assuming
the evaluation of the actual parameters produces some externally-visible
side-effect.  (Yes, of course the compiler can optimize anything it
likes, if it can prove it doesn't affect the external effect.  But
that's not the point here.)

- Bob




^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Right of Optimize Eager Evaluation Away
  1999-11-29  0:00         ` Laurent Guerby
  1999-11-29  0:00           ` Lutz Donnerhacke
  1999-11-29  0:00           ` Niklas Holsti
@ 1999-11-29  0:00           ` Robert A Duff
  1999-11-30  0:00             ` Laurent Guerby
  2 siblings, 1 reply; 11+ messages in thread
From: Robert A Duff @ 1999-11-29  0:00 UTC (permalink / raw)


Laurent Guerby <guerby@acm.org> writes:

> Is the potential raising of an exception the only language barrier
> to allow lazy evaluation for an optimizing compiler?

No.

> It looks like to me that the Ada language more or less intend that
> functions shouldn't have side effects, since by example it allows the
> compiler to evaluate arguments and thus potentially calling functions
> in any order, or allows only "in" parameters for the programmer.

Side effects are allowed in Ada.  It's true that functions can't have
'in' parameters, but they can modify globals and heap objects.  (As
Robert Dewar likes to point out, functions can have side effects, so
long as you don't document that fact in the parameter profile!)  The
rule is that the side effects must happen.

If you have two sub-expressions with side effects, they can happen in
either order.  That does make side effects less useful, but it is still
possible to write code so that the side effects are independent of each
other, so order doesn't matter.

In other words, the Ada rules encourage bugs in programs with side
effects, but they don't outlaw side effects.  Nor do they give the
optimizer permission to ignore side effects.

> The question is then, why stop at allowing any evaluation order and
> not just allow lazy evaluation as well?

Because Jean Ichbiah said so.  ;-)

It seems to me that if you're going to do lazy evaluation for all
function calls, then you really ought to be using a pure functional
language.

> It allows some "nice" optimizations, like the one I mentionned, or
> things like:
> 
> -- In some Debug package body:
> 
>    Enable_Trace : constant Boolean := True; 
>    -- or set to False when compiled in "release" mode
>    
>    procedure Trace (M : in String) is
>    begin
>       if Enable_Trace then
>           IO.Put (M);
>       end if;
>    end Trace;
> 
> -- Now you have your code full of Trace calls like:
> 
>    Trace ("index = " & Image (Index) & " value = " & Image (Value));

If you make put pragma Pure on Image, it can be optimized.
Unfortunately, you can't easily do that in all cases.

> With the current RM, even if the compilers know that the Trace call
> doesn't do anything (inlining is on, and proper unreached code
> elimination has been done), it cannot suppress the calls to Image or
> to "&" since they might potentially raise an exception. The only way
> to do a "release"/"debug" switch that does not cause a performance
> penalty for the "release" version is then to use vendor specific
> pragmas like GNAT Assert or Debug, and thus is outside of the
> language.
> 
> The "pragma" I was mentionning could look like:
> 
> pragma You_Can_Omit_Calls_To_This_If_The_Value_Is_Not_Needed (F);
> 
> (obviously a better name is needed ;-).

How about calling it Pure?  ;-)

>... If an expression involves only
> calls to pragma'ed functions (the Standard and String stuff could be
> in this category for example), then if the compiler finds out the
> result isn't needed in some run-time paths, it can omit the evaluation
> of the expression in those paths.
> 
> I don't know if I'm clearer here ;-).

Yes.

> > - Bob
> 
> --LG




^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Right of Optimize Eager Evaluation Away
  1999-11-29  0:00         ` Laurent Guerby
@ 1999-11-29  0:00           ` Lutz Donnerhacke
  1999-11-29  0:00           ` Niklas Holsti
  1999-11-29  0:00           ` Robert A Duff
  2 siblings, 0 replies; 11+ messages in thread
From: Lutz Donnerhacke @ 1999-11-29  0:00 UTC (permalink / raw)


* Laurent Guerby wrote:
>It looks like to me that the Ada language more or less intend that
>functions shouldn't have side effects, since by example it allows the
>compiler to evaluate arguments and thus potentially calling functions
>in any order, or allows only "in" parameters for the programmer.
>
>The question is then, why stop at allowing any evaluation order and
>not just allow lazy evaluation as well?

You may provide a pragma to tell the compiler that this function is really a
pure functional function. Then it is allowed to optimize this way.

>The "pragma" I was mentionning could look like:
>pragma You_Can_Omit_Calls_To_This_If_The_Value_Is_Not_Needed (F);
>
>(obviously a better name is needed ;-). If an expression involves only

pragma Pure_Function ([Entity =>] function_LOCAL_NAME);
...

     Note: All functions in a Pure' package are automatically pure, and
     there is no need to use pragma Pure_Function' in this case.

     Note: If pragma Pure_Function' is applied to a renamed function,
     it applies to the underlying renamed function. This can be used to
     disambiguate cases of overloading where some but not all functions
     in a set of overloaded functions are to be designated as pure.
     




^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Right of Optimize Eager Evaluation Away
  1999-11-29  0:00         ` Laurent Guerby
  1999-11-29  0:00           ` Lutz Donnerhacke
@ 1999-11-29  0:00           ` Niklas Holsti
  1999-11-29  0:00           ` Robert A Duff
  2 siblings, 0 replies; 11+ messages in thread
From: Niklas Holsti @ 1999-11-29  0:00 UTC (permalink / raw)


Laurent Guerby wrote:
  [ snip ]
> 
> Is the potential raising of an exception the only language barrier
> to allow lazy evaluation for an optimizing compiler?
> 
> It looks like to me that the Ada language more or less intend that
> functions shouldn't have side effects, since by example it allows the
> compiler to evaluate arguments and thus potentially calling functions
> in any order, or allows only "in" parameters for the programmer.
> 
> The question is then, why stop at allowing any evaluation order and
> not just allow lazy evaluation as well?

I think you could define a language like that. The question is
how it would be related to the (current) Ada language. It seems
sure to be incompatible with side-effecting functions, even if
differences in exception-raising are allowed.

RM 1.1.3(8) lists the external effects that should be preserved by
optimisation. There seem to be some that can be sensibly used by
programmers without knowing the evaluation order, but yet cannot
be omitted totally without harming the program's result:

   - setting the value of imported or exported objects (independent
     of order if the functions used in the parameter expressions set
     different objects)

   - reading or updating atomic or volatile objects (may be independent
     of order if the functions read/update different objects).

In other words, some programs could use side-effects of this type,
and still work whatever evaluation order is chosen. So to apply lazy
evaluation, the compiler should ensure that no such effects can
occur as side-effects of the lazily evaluated functions.

In practice, I would add any task interactions to this list. Given a
function that interacts with tasks, it seems quite unlikely that the
compiler could prove that omitting the task interactions would not
make any significant difference to the external effects, yet there
must be many cases in which the evaluation order of such functions
is not in fact significant for the correctness of the program.

> pragma You_Can_Omit_Calls_To_This_If_The_Value_Is_Not_Needed (F);
> 
> (obviously a better name is needed ;-). If an expression involves only
> calls to pragma'ed functions (the Standard and String stuff could be
> in this category for example), then if the compiler finds out the
> result isn't needed in some run-time paths, it can omit the evaluation
> of the expression in those paths.

Isn't pragma Pure (10.2.1(18)) something like this? Is it too
restrictive for you?

Regards,
Niklas

Working at but not speaking for Space Systems Finland Ltd.




^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Right of Optimize Eager Evaluation Away
  1999-11-28  0:00 Right of Optimize Eager Evaluation Away Laurent Guerby
  1999-11-28  0:00 ` Robert A Duff
@ 1999-11-29  0:00 ` Jean-Pierre Rosen
  1 sibling, 0 replies; 11+ messages in thread
From: Jean-Pierre Rosen @ 1999-11-29  0:00 UTC (permalink / raw)


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain, Size: 1511 bytes --]


Laurent Guerby <guerby@acm.org> a �crit dans le message :
863dtqfo26.fsf@ppp-173-146.villette.club-internet.fr...
> [I originally posted this in the 11.6 thread, but got no answer]
>
> If we have the following function:
>
>    function Cond_T (C : in Boolean; If_True, If_False : in T) return T;
>    pragma Inline (Cond_T);
>
>    function Cond_T (C : in Boolean; If_True, If_False : in T) return T is
>    begin
>       if C then
>          return If_True;
>       else
>          return If_False;
>       end if;
>    end Cond_T;
>
> And the following expression:
>
>    C : constant Boolean :=
Some_Run_Time_Value_That_The_Compiler_Cannot_Guess;
>
>    X : constant T := Cont_T (C, If_True =>
Super_Expensive_Function_Call_1,
>                                 If_False =>
Super_Expensive_Function_Call_2);
>
> The question is: is a smart Ada 95 compiler allowed to generate code
> that looks like this:
>
>    if C then
>       X := Super_Expensive_Function_Call_1;
>    else
>       X := Super_Expensive_Function_Call_2;
>    end if;
>
> that is to say, be lazy about its argument, and so might
> save execution time.
>
The simplest solution in this case would be to pass pointers to the
Super_Expensive_Function_Calls;
This way, only the *pointers* are evaluated at the call, the functions are
actually called only as necessary...

--
---------------------------------------------------------
           J-P. Rosen (Rosen.Adalog@wanadoo.fr)
Visit Adalog's web site at http://pro.wanadoo.fr/adalog






^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Right of Optimize Eager Evaluation Away
  1999-11-29  0:00       ` Robert A Duff
@ 1999-11-29  0:00         ` Laurent Guerby
  1999-11-29  0:00           ` Lutz Donnerhacke
                             ` (2 more replies)
  0 siblings, 3 replies; 11+ messages in thread
From: Laurent Guerby @ 1999-11-29  0:00 UTC (permalink / raw)


Robert A Duff <bobduff@world.std.com> writes:
> > Laurent Guerby wrote:
> 
> > > Is the potential raising of an exception the only language barrier
> > > here (since as you mention the compiler is free to swap calls
> > > defeating a class of side effects)? This seams easy to fix (via a
> > > pragma), if one is interested in keeping the functional aspect of the
> > > code instead of resorting to statements of course.
> 
> I don't understand Laurent's question.

I should rephrase then ;-):

Is the potential raising of an exception the only language barrier
to allow lazy evaluation for an optimizing compiler?

It looks like to me that the Ada language more or less intend that
functions shouldn't have side effects, since by example it allows the
compiler to evaluate arguments and thus potentially calling functions
in any order, or allows only "in" parameters for the programmer.

The question is then, why stop at allowing any evaluation order and
not just allow lazy evaluation as well?

It allows some "nice" optimizations, like the one I mentionned, or
things like:

-- In some Debug package body:

   Enable_Trace : constant Boolean := True; 
   -- or set to False when compiled in "release" mode
   
   procedure Trace (M : in String) is
   begin
      if Enable_Trace then
          IO.Put (M);
      end if;
   end Trace;

-- Now you have your code full of Trace calls like:

   Trace ("index = " & Image (Index) & " value = " & Image (Value));

With the current RM, even if the compilers know that the Trace call
doesn't do anything (inlining is on, and proper unreached code
elimination has been done), it cannot suppress the calls to Image or
to "&" since they might potentially raise an exception. The only way
to do a "release"/"debug" switch that does not cause a performance
penalty for the "release" version is then to use vendor specific
pragmas like GNAT Assert or Debug, and thus is outside of the
language.

The "pragma" I was mentionning could look like:

pragma You_Can_Omit_Calls_To_This_If_The_Value_Is_Not_Needed (F);

(obviously a better name is needed ;-). If an expression involves only
calls to pragma'ed functions (the Standard and String stuff could be
in this category for example), then if the compiler finds out the
result isn't needed in some run-time paths, it can omit the evaluation
of the expression in those paths.

I don't know if I'm clearer here ;-).

> - Bob

--LG




^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Right of Optimize Eager Evaluation Away
  1999-11-29  0:00           ` Robert A Duff
@ 1999-11-30  0:00             ` Laurent Guerby
  0 siblings, 0 replies; 11+ messages in thread
From: Laurent Guerby @ 1999-11-30  0:00 UTC (permalink / raw)


Robert A Duff <bobduff@world.std.com> writes:
> If you have two sub-expressions with side effects, they can happen in
> either order.  That does make side effects less useful, but it is still
> possible to write code so that the side effects are independent of each
> other, so order doesn't matter.
> 
> In other words, the Ada rules encourage bugs in programs with side
> effects, but they don't outlaw side effects.  Nor do they give the
> optimizer permission to ignore side effects.

Well, that was my point, Ada makes the life of side-effect function
writers difficult in its current incarnation, in the sake of potential
optimization. Why not make another step, and allow lazy-style
optimization for Ada, at least under the control of a pragma?

> It seems to me that if you're going to do lazy evaluation for all
> function calls, then you really ought to be using a pure functional
> language.

I never said "all", that's the point of Ada, you can use the paradigm
you find adapted to your specific problem (simple private record, full
OO, functional with Pure, ...).

The state oriented part of the so-called pure functional languages I
know is just awful.  And I think most software will do state _and_
function, so I want to have a state oriented paradigm at hand when I'm
handling state so I can write code in a "natural" way, a functional
paradigm when I'm writing pure functions, and an high-level concurrent
paradigm when I'm writing the concurrent part, etc...

> > -- Now you have your code full of Trace calls like:
> >    Trace ("index = " & Image (Index) & " value = " & Image (Value));
> If you make put pragma Pure on Image, it can be optimized.

No, see below.

> > pragma You_Can_Omit_Calls_To_This_If_The_Value_Is_Not_Needed (F);
> > (obviously a better name is needed ;-).
> How about calling it Pure?  ;-)

Because, as I said, Pure doesn't allow the compiler to omit the call
(it can call the thing only once if the parameters don't change, or be
more aggressive and generate memo-izing code), just in case an
exception might happen. That's the point I made about the potential
exception raising being the only language barrier to the lazy
evaluation feature. You added independant side effects to the list,
but I would gladly drop or restrict this dubious feature in favour of
better potential optimization.

Or having the well-named pragma I proposed, since Pure doesn't do
the job I want to here ;-).

Also, Trace package and the like are unlikely to be Pure (but you can
use the Import trick to make them Pure as I mentioned it a few years
ago on this newsgroup ;-).

--LG




^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~1999-11-30  0:00 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
1999-11-28  0:00 Right of Optimize Eager Evaluation Away Laurent Guerby
1999-11-28  0:00 ` Robert A Duff
1999-11-28  0:00   ` Laurent Guerby
1999-11-29  0:00     ` Nick Roberts
1999-11-29  0:00       ` Robert A Duff
1999-11-29  0:00         ` Laurent Guerby
1999-11-29  0:00           ` Lutz Donnerhacke
1999-11-29  0:00           ` Niklas Holsti
1999-11-29  0:00           ` Robert A Duff
1999-11-30  0:00             ` Laurent Guerby
1999-11-29  0:00 ` Jean-Pierre Rosen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox