comp.lang.ada
 help / color / mirror / Atom feed
* Re: Bug in AdaEd???
@ 1993-09-06 14:06 Gene Ouye
  0 siblings, 0 replies; 12+ messages in thread
From: Gene Ouye @ 1993-09-06 14:06 UTC (permalink / raw)


Zoltan Sugar (omega@fsz.bme.hu) wrote:
: 	I wrote a liitle test program in Ada with AdaEd translator. 


: 	declare

: 		subtype t is boolean range true .. true;

: 		a: t;

: 	begin

: 		a:= true;
: 		a:= not a;

: 	end;

: 	And this program didn't cause constraint error exception;
: 	A have a question. It is correct or not???

This SHOULD have raised CONSTRAINT_ERROR.  Just out of curiosity, were
you able to print the value of A after the negation and see FALSE?
Eg,	Text_Io.Put_Line ("Value of a => " & Boolean'Image (A));

: 	If a wrote this program with integer type (range 1 .. 1, and using abs 
instead 
: 	of not) there was constraint error exception. I don't understand it.

To the best of my understanding of abs, this SHOULD NOT have raised an
exception.  If this is what is really happening, these sound like bugs
to me.

: 					Zoltan Sugar

: 					omega@fix.fsz.bme.hu		

--
Gene Ouye (geneo@rational.com)   Rational, Bethesda, MD, USA
(301) 897-4014

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

* Re: Bug in AdaEd???
@ 1993-09-07  3:20 Robert Dewar
  0 siblings, 0 replies; 12+ messages in thread
From: Robert Dewar @ 1993-09-07  3:20 UTC (permalink / raw)


This probably is a bug in Ada Ed. However, it is interesting to note that
there is NO requirement for this program to raise CE. Why not? Well 11.6
optimizations allow the removal of the dead assignments so the offending
expression need never be evaluated.

Most programs that try to raise CE deliberately like this are wrong!

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

* Re: Bug in AdaEd???
@ 1993-09-21  4:19 Gene Ouye
  0 siblings, 0 replies; 12+ messages in thread
From: Gene Ouye @ 1993-09-21  4:19 UTC (permalink / raw)


> I (geneo@Rational.COM (Gene Ouye)) responded to someone's question:

[deleted in Robert's response was the definition of a Boolean subtype that
 was constrained to only one value, "True..True", I think, and a declaration
 of "a" to be of that subtype]

>    :        a:= not a;

>   > This SHOULD have raised CONSTRAINT_ERROR.  Just out of curiosity, were
>   > you able to print the value of A after the negation and see FALSE?
>   > Eg, Text_Io.Put_Line ("Value of a => " & Boolean'Image (A));
                                          

eachus@spectre.mitre.org (Robert I. Eachus) responded:

>      The reason that Ada/ED does not check for CONSTRAINT_ERROR is
> that that is the way that "not" is defined in Ada 83 and for that
> matter will be in Ada 9X.  (Operators like "not" work on values of the
> base type so, for example, "A = not A" can never propagate
> CONSTRAINT_ERROR.)

I've looked at this about six different times since it was posted, and I
don't see how this makes a difference.  It's true that the base type of
"a" is Boolean, but when the result of the Boolean expression "not a" is
assigned to the object "a", the result is outside the range of the
subtype to which "a" belongs.  I can see how the expression "not a"
would never raise an exception (because "not" operates on the base type
(Boolean) and returns a value of the base Boolean type), but it seems
that assigning it to something belonging to a constrained subtype should
raise Constraint_Error (except possibly in cases where the compiler can
assume that the value to be assigned is invalid, as described below).
Your Boolean expression "A = not A" should not propagate Constraint_Error
but instead should evaluate to False.

In fact this seems little different from the following:

    declare

        I : Natural := 5;

    begin                               

        -- other statements could go here that muck with I so that it
        -- is not trivially optimized away in accordance with RM 11.6(7)
        -- as described later in Robert's response.
    
        I := -I; -- Shouldn't this raise CONSTRAINT_ERROR?

    end;
        

>      Now if you read RM 11.6(7), compilers are not only allowed, but
> encouraged to remove predefined operations whose only possible effect
> is to raise an exception.  "A predefined operation need not be invoked
> at all, if its only possible effect is to propagate a predefined
> exception." (RM 11.6)  So not raising CONSTRAINT_ERROR is appropriate.
> (Incidently, we are still working on a better version of (old))
> section 11.6 for Ada 9X.  Coming up with a rule which allows
> appropriate optimizations without surprising the user is tough.)

>     However, when the Ada 83 RM was written, no one thought of the
> possibility of arrays whose component is subtype of Boolean.
> Technically there is in Ada 83 a check on values of type Boolean done
> on the assignment, but for arrays there is no subtype check done for
> arrays of Booleans.  AI-535 fixed this, but well after the last Ada/ED
> validation.

On first reading, RM 11.6(7) does seem to be a valid reason for a
compiler to do nothing with "a := not a;" as it was originally posted
(but see my later comments), but what about the following:

  with Calendar, Text_Io; use Calendar;
  procedure Will_I_Die is

      subtype Only_True is Boolean range True .. True;
      I_Should_Be_Always_True : Only_True;

  begin

      I_Should_Be_Always_True := (Day (Clock) = 21);
      I_Should_Be_Always_True := not I_Should_Be_Always_True;
      Text_Io.Put_Line ("Nope, didn't die!!");

  exception
      when Constraint_Error =>
          Text_Io.Put_Line ("OK, I got Constraint_Error, is today the 21st?");
  end Will_I_Die;

On any day except the 21st, this program should raise Constraint_Error
on the first statement.  If Ada/ED is using RM 11.6(7) as a reason for
not raising Constraint_Error in the original poster's example, it should
still raise Constraint_Error when the second assignment is executed (on
the 21st, of course!), no?  Or is Ada/ED smart enough to catch this
inevitable exception too?

I don't have Ada/ED, so I can't try this myself to see.

One more question on RM 11.6(7): isn't it supposed to be saying that the
operation need not be invoked (because we know the operation will result
in an exception), but that the exception should still be raised (ie, the
statement may be replaced by an explicit "raise" statement)?

> --

>                     Robert I. Eachus

> with Standard_Disclaimer;
> use  Standard_Disclaimer;
> function Message (Text: in Clever_Ideas) return Better_Ideas is...

--
Gene Ouye (geneo@rational.com)    Rational, Bethesda, MD, USA
(301) 897-4014

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

* Re: Bug in AdaEd???
@ 1993-09-22  0:21 Robert I. Eachus
  0 siblings, 0 replies; 12+ messages in thread
From: Robert I. Eachus @ 1993-09-22  0:21 UTC (permalink / raw)


In article <1993Sep21.041912.10460@rational.com> geneo@Rational.COM (Gene Ouye)
 writes:

   > I can see how the expression "not a" would never raise an exception
   > (because "not" operates on the base type (Boolean) and returns a
   > value of the base Boolean type), but it seems that assigning it to
   > something belonging to a constrained subtype should raise
   > Constraint_Error (except possibly in cases where the compiler can
   > assume that the value to be assigned is invalid, as described
   > below).

     I think you understand, you just find the situation very
uncomfortable.  That's just how the ARG feels. (IMHO in any case.)
Let me drag the logic out into plain (ugly) sight.
 
   1) The value of A can never be other than True.

   2) Therefore an optimizing compiler can eliminate any assignments
      to A.

   3) If the compiler eliminates the assignment, it can also (see
      11.6) eliminate the check.

   4) So in both this example and your new example the compiler is
      allowed and encouraged to eliminate the check.

   5) The program author IN WHOSE MIND the check was meaningful is
      upset.

   When Ada 83 was being defined, the principle reason for the
constraint checks on assignments was to prevent objects from having
invalid values.  In the tradeoffs between speed and correctness, the
compromise was that initial values need not be checked (the raw bits
in memory allocated to the object, not the initial value expression)
for objects other than access types, but all subsequent assignments
would be.  The case of assignments which were eliminated by
optimization was discussed, and 11.6(7) was the result.  If you don't
do the assignment, you don't need to do the check.

   But there are nasty examples where you need to rely on
CONSTRAINT_ERROR being raised.  The worst example we came up with was:

   declare
     subtype My_Int is Integer range 1..10_000;
     X,Y: My_Int;
     Junk: My_Int;
   begin
     Read(X);
     Read(Y);
     Junk := X*Y;
     if Junk > 10_000 then Do_Something; end if;
   exception
     when others => Do_Something;
   end;

   It seems clear that if you enter 999 and 1234, Do_Something will be
called.  But on some compilers, at some optimization levels, it won't
be!  The condition is obviously always false, so the if statement can
be eliminated.  The value of Junk is now never read and therefore Junk
can be elimiated, as can the assignment to it.  You finish by
eliminating the multiplication of X and Y.  (This example is not
pathological.  One place where similar code occurs frequently is in
compilers.  You want to warn the author of the program being compiled
that his array is too big, but you don't really care what the actual
size is...at least not in the front end of the compiler.)

   Obviously, we as human readers can see that the progammer wanted
CONSTRAINT_ERROR to occur in some conditions.  But try to write code
that a compiler which knows little outside the RM rules (including
11.6) rules cannot optimize away.  It's not easy.


--

					Robert I. Eachus

with Standard_Disclaimer;
use  Standard_Disclaimer;
function Message (Text: in Clever_Ideas) return Better_Ideas is...

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

* Re: Bug in AdaEd???
@ 1993-09-22 11:45 Wes Groleau x1240 C73-8
  0 siblings, 0 replies; 12+ messages in thread
From: Wes Groleau x1240 C73-8 @ 1993-09-22 11:45 UTC (permalink / raw)


>>      Now if you read RM 11.6(7), compilers are not only allowed, but
>> encouraged to remove predefined operations whose only possible effect
>> is to raise an exception.  "A predefined operation need not be invoked
>> at all, if its only possible effect is to propagate a predefined
>> exception." (RM 11.6)  So not raising CONSTRAINT_ERROR is appropriate.
>
>One more question on RM 11.6(7): isn't it supposed to be saying that the
>operation need not be invoked (because we know the operation will result
>in an exception), but that the exception should still be raised (ie, the
>statement may be replaced by an explicit "raise" statement)?

Language lawyers please explain in short words if I'm wrong, but I can't 
for the life of me think of ANY reason why optimization of code with
predetermined results would intentionally be done to give different results!

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

* Re: Bug in AdaEd???
@ 1993-09-22 13:36 cis.ohio-state.edu!news.sei.cmu.edu!firth
  0 siblings, 0 replies; 12+ messages in thread
From: cis.ohio-state.edu!news.sei.cmu.edu!firth @ 1993-09-22 13:36 UTC (permalink / raw)


In article <EACHUS.93Sep21192111@spectre.mitre.org> eachus@spectre.mitre.org (R
obert I. Eachus) writes:

>   But there are nasty examples where you need to rely on
>CONSTRAINT_ERROR being raised.  The worst example we came up with was:
>
>   declare
>     subtype My_Int is Integer range 1..10_000;
>     X,Y: My_Int;
>     Junk: My_Int;
>   begin
>     Read(X);
>     Read(Y);
>     Junk := X*Y;
>     if Junk > 10_000 then Do_Something; end if;
>   exception
>     when others => Do_Something;
>   end;

Indeed a nasty example!  However, isn't the solution fairly simple:
eliminate the variable Junk and rewrite the test as

	if X*Y > 10_000 then ...

As far as I can see, that has to work regardless of whether X*Y
overflows.  Moreover, isn't it the obvious way to write the code?

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

* Re: Bug in AdaEd???
@ 1993-09-22 14:10 cis.ohio-state.edu!magnus.acs.ohio-state.edu!usenet.ins.cwru.edu!howland.reston.ans.net!usc!cs.utexas.edu!not-for-mail
  0 siblings, 0 replies; 12+ messages in thread
From: cis.ohio-state.edu!magnus.acs.ohio-state.edu!usenet.ins.cwru.edu!howland.reston.ans.net!usc!cs.utexas.edu!not-for-mail @ 1993-09-22 14:10 UTC (permalink / raw)


>From: eachus@spectre.mitre.org (Robert I. Eachus)
>Subject: Re: Bug in AdaEd???
>
>Let me drag the logic out into plain (ugly) sight.
> 
      ...
>   2) Therefore an optimizing compiler can eliminate any assignments
>      to A.
>
>   3) If the compiler eliminates the assignment, it can also (see
>      11.6) eliminate the check.
>

I do not see anything in the Ada83 Reference Manual or ARG resolutions allowing
 
this.

>   When Ada 83 was being defined, the principle reason for the
>constraint checks on assignments was to prevent objects from having
>invalid values.  In the tradeoffs between speed and correctness, the
>compromise was that initial values need not be checked (the raw bits
>in memory allocated to the object, not the initial value expression)
>for objects other than access types, but all subsequent assignments
>would be.  The case of assignments which were eliminated by
>optimization was discussed, and 11.6(7) was the result.  If you don't
>do the assignment, you don't need to do the check.

Paragraph 11.6(7) deals with predefined operators, but the assignment, or
the check to be performed before an assignment are not predefined operators
but "basic" operations (see Ref. Man 3.3.1).

I am not surprised if some compilers, at some optimization levels do something
illegal.  Again, I cannot see in the Reference Manual anything allowing this 
interpretation.  A confirmation of this also comes from the discussion of 
AI-00535/03 where it is clearly explained that:

" No problem arises when operating on scalar values:
 
          declare
              type NB is new BOOLEAN range TRUE .. TRUE;
              A, B : NB := TRUE;
          begin
              if (not A) or (A xor B) then     -- no exception is raised
                  A := not A;                  -- CONSTRAINT_ERROR
              end if;
          end;
 
  No  exception  is raised for NOT A or A XOR B since the NOT and XOR operators
  for type NB are the predefined operators, which return  values  of  the  base
  type. "

By the way, for a more precise picture it is possible to retrieve AI-00535/03
from host ajpo.sei.cmu.edu, directory public/ada-comment, file ai-00535-bi.wa.

- - - - - - - - - - - - - - - - - - - - - - - - - -
   Dr. Franco Mazzanti
   Istituto di Elaborazione della Informazione
   Via S.Maria 46, 56126 Pisa, ITALY
   Tel: 050-593447/593400, Fax: 050-554342
   e-mail: mazzanti@iei.pi.cnr.it
- - - - - - - - - - - - - - - - - - - - - - - - - -

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

* Re: Bug in AdaEd???
@ 1993-09-22 14:22 Norm an H. Cohen
  0 siblings, 0 replies; 12+ messages in thread
From: Norm an H. Cohen @ 1993-09-22 14:22 UTC (permalink / raw)


In article <CDr7CH.C9x@crdnns.crd.ge.com>, groleau@e7sa.crd.ge.com
(Wes Groleau x1240 C73-8) writes: 

|> Language lawyers please explain in short words if I'm wrong, but I can't
|> for the life of me think of ANY reason why optimization of code with
|> predetermined results would intentionally be done to give different results!

Here is a summary of RM 11.6 "while standing on one foot": 

   An optimizer is allowed to assume that the intended effect of a
   program is not to raise a predefined exception.

This allows optimizers to produce faster code that behaves in the same
way as unoptimized code IN ALL CASES WHERE THE UNOPTIMIZED CODE WOULD NOT
RAISE AN EXCEPTION.  To a programmer who does not intend to raise an
exception, the occurrence of an exception is a failure.  In all
executions that do not fail, the optimizations preserve the behavior of
the program.  However, if, contrary to the assumption allowed by RM 11.6,
the programmer INTENDS to raise exceptions, it will seem to him as though
the optimizations, in Wes Groleau's words, "give different results."

Consider the following program, where there are no references to X
after the loop, N is of subtype Positive, and Capacity is a named number
reflecting some property of the execution environment: 

   X := A * B;
   while N < Capacity loop
      [references to X]
   end loop;

The source code is written to be easily portable to environments in which
different values of Capacity are appropriate:  It is necessary only to
modify the declaration of Capacity and recompile.  Today we are
recompiling this code for a system in which Capacity is declared to be
zero.  The optimizer observes that the condition N < Capacity is
necessarily false, so the entire loop can be eliminated.  Once the loop
is eliminated, the variable X becomes "dead", that is, there is no
reference to its value.  Can the optimizer therefore go one step further
and eliminate the statement X := A * B; ?  In the absence of RM 11.6, the
answer would be no, because the multiplication might overflow and raise
Constraint_Error, so eliminating the assignment statement could change
the effect of the program.  RM 11.6 allows the optimizer to assume that
this particular aspect of the original program's behavior--ensuring that
Constraint_Error is raised whenever A * B would overflow--is not a part
of the behavior the programmer intends to achieve, but an accidental
consequence of the need to compute A * B in cases where the loop cannot
be eliminated.

Of course there is a middle ground between the programmer who says, "If
my program raises an exception, it has failed anyway.  Don't make my
program slower to ensure that it fails in one state rather than another,"
and the programmer who expects to raise an exception in certain cases
(e.g., as a method of checking whether the product A * B is within a
certain range).  That middle ground is occupied by the programmer who
doesn't expect to raise an exception, but considers the occurrence of an
exception as a recoverable error rather than a total failure.  Such a
programmer does care about the behavior of a program even in the cases
where an exception is raised.  The difficulty that the ARG has had with
RM 11.6 is attributable to this tension between the programmer who does
not expect to be able to recover when an exception is raised, and thus
does not want considerations of behavior in the presence of exceptions to
slow down his code, and the programmer who expects to be able to recover
from an exception, and thus wants to be able to predict and control the
state of a program that has raised an exception.

--
Norman H. Cohen    ncohen@watson.ibm.com

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

* Re: Bug in AdaEd???
@ 1993-09-22 21:07 Robert I. Eachus
  0 siblings, 0 replies; 12+ messages in thread
From: Robert I. Eachus @ 1993-09-22 21:07 UTC (permalink / raw)


In article <1993Sep22.093656.20606@sei.cmu.edu> firth@sei.cmu.edu (Robert Firth
) writes:

   > Indeed a nasty example!  However, isn't the solution fairly simple:
   > eliminate the variable Junk and rewrite the test as

   > 	   if X*Y > 10_000 then ...

   > As far as I can see, that has to work regardless of whether X*Y
   > overflows.  Moreover, isn't it the obvious way to write the code?

   That was where we started...I guess I should have used a larger
number in the example.  Substitute 1_000_000 for 10_000 and compile
your code on a 16-bit machine.  Do you see the problem?  The compiler
is allowed to assume the expression is false in all cases without
doing the check, and thus without raising NUMERIC_ERROR or
CONSTRAINT_ERROR on the expression evaluation.  Comparing a variable
to a bound is not a problem, it's this pesky case of an expression
whose value may be out of range of the type.  Assigning the expression
to a variable seems like the solution, but as my original example
pointed out, that is not guarenteeed to work either.

   In practice, for anyone who has to write code like this, assigning
to a global variable, or using pragma VOLITILE on the variable, etc.
works fine.  You get unoptimized code, but in this case that is
precisely what you want.  (And also, this is not just an Ada problem.
I have also run into this "feature" in PL/I and FORTRAN compilers
as well.  In all cases confusing the optimizer was enough to get
working code.  The worry in the ARG is that optimizers are contantly
getting smarter.)

--

					Robert I. Eachus

with Standard_Disclaimer;
use  Standard_Disclaimer;
function Message (Text: in Clever_Ideas) return Better_Ideas is...

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

* Re: Bug in AdaEd???
@ 1993-09-22 22:28 Robert I. Eachus
  0 siblings, 0 replies; 12+ messages in thread
From: Robert I. Eachus @ 1993-09-22 22:28 UTC (permalink / raw)


In article <9309221412.AA02787@ieipisa.iei.pi.cnr.it> mazzanti@iei.pi.cnr.it (F
ranco Mazzanti) writes:

  > Paragraph 11.6(7) deals with predefined operators, but the assignment, or
  > the check to be performed before an assignment are not predefined operators
  > but "basic" operations (see Ref. Man 3.3.1).

    There is a subtle distinction in Ada 83 between predefined
operators and predefined operations.  Predefined operations include
the basic operations, enumeration literals, and the predefined
operators. See 3.3.3 (2) where unfortunately it uses the phrase "the
remaining operations."  (You might also want to look at 8.6(1), or at
the Ada 9X RM 3.2.3, where predefined operation does appear in
italics.)

     But, in any case, in the context of 11.6, if you look at
paragraph 3, you will see the phrase "predefined operations that are
either predefined operators or basic operations other than
assignments."  At first glance this looks like a definition of
predefined operations, but it is really excluding assignments from the
scope of the optimizations in paragraphs 4 and 5.  In other words,
that exclusion is there to prevent reordering of assignments.  But
assignments were intentionally included in the scope of 11.7,
specifically to allow elimination of assignments to dead variables.

     This is why there is no easy fix to the problem.  (Ada 9X has
some fixes, but we still need a new 11.6.)  There is no intent or
desire to require that assignments to dead variables be made, and
therefore any exceptions inherent in the assignment may not occur.
What is needed is a way for a programmer to say "trust me here, you
must make this check."  In Ada 9X it will be definitely be possible to
do this in a portable manner.  Current thinking has gotten as far as
either a pragma OR a local (or maybe statically enclosing) handler for
CONSTRAINT_ERROR will indicate that statements (assignments?) which
potentially raise CONSTRAINT_ERROR should not be optimized away.

     Compiler writers would also like the freedom to make more
optimizations and users would like their programs to run faster.  Of
course no one wants any changes which make existing code incompatible.
All in all a nasty can of worms.
--

					Robert I. Eachus

with Standard_Disclaimer;
use  Standard_Disclaimer;
function Message (Text: in Clever_Ideas) return Better_Ideas is...

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

* Re: Bug in AdaEd???
@ 1993-09-23 18:46 Tucker Taft
  0 siblings, 0 replies; 12+ messages in thread
From: Tucker Taft @ 1993-09-23 18:46 UTC (permalink / raw)


In article <EACHUS.93Sep22160725@spectre.mitre.org> 
  eachus@spectre.mitre.org (Robert I. Eachus) writes:

>In article <1993Sep22.093656.20606@sei.cmu.edu> 
>  firth@sei.cmu.edu (Robert Firth) writes:
>
>   > Indeed a nasty example!  However, isn't the solution fairly simple:
>   > eliminate the variable Junk and rewrite the test as
>
>   > 	   if X*Y > 10_000 then ...
>
>   > As far as I can see, that has to work regardless of whether X*Y
>   > overflows.  Moreover, isn't it the obvious way to write the code?
>
>   That was where we started...I guess I should have used a larger
>number in the example.  Substitute 1_000_000 for 10_000 and compile
>your code on a 16-bit machine.  Do you see the problem?  The compiler
>is allowed to assume the expression is false in all cases without
>doing the check, and thus without raising NUMERIC_ERROR or
>CONSTRAINT_ERROR on the expression evaluation.  
> . . .

This thread is of course very timely as we work to finalize the definition
of Ada 9X, and in particular clause 11.6.

I suspect that this statement:

  "The compiler is allowed to assume the expression is false ..."

reflects the heart of the problem with RM83-11.6(7) (or with the typical 
interpretation of it).

The point of 11.6(7) was *not* to allow junk or wrong 
results to be produced, but rather to allow dead variables to
be removed, even if their computation might raise an exception.
Nowhere does 11.6 say a compiler may presume an expression is True that
in fact is not True.  If one interprets 11.6(7) to imply that, then
clearly something is wrong in 11.6(7) or its interpretation.

I think the way to resolve this problem is for the compiler to
treat an expression that fails a predefined check as having an
"undefined" value (equivalent to "bottom" in some languages).

This idea is explored further below.  You might as well stop
reading here if the rest is boring or obvious to you...

All types must be extended with an extra "undefined" value, including
Boolean (in the case of Boolean, "undefined" corresponds to the "Unknown"
of three-valued logic).  Hence, the expression "X*Y > My_Int'Base'Last" 
may *not* be replaced with simply "False."  There are two possible values 
of the expression, "False" or "Undefined/Unknown."  

One needs to define the composition rules for the various predefined
operations when one or more of the operands are undefined/unknown.
For Boolean, Undefined combines as follows:

    Undefined and True => Undefined
    Undefined and False => False
    Undefined or True => True
    Undefined or False => Undefined
    not Undefined => Undefined
    Undefined xor X => Undefined

For most other operations, if any operand is undefined, the
result is undefined.  One notable exception is:

    Undefined * 0 => 0

Hence, the only way to "consume" an undefined value in an expression
and not produce an undefined result are to "and" with False, "or" with True, 
or multiply by 0 (there might be some others -- those are the ones
that come to mind right now).  In any case, Undefined > Integer'Last, 
is Undefined, not False.

Another important way to "consume" an undefined result is with
an exception handler.  Hence:

    ... Undefined ...;
 exception
    when others =>
       S;

can be transformed to:

       S;

Now of course if the exception handler is more specific about the
exception it handles, then the transformation is a bit more involved,
but you get the idea (I hope).

Rules must also be developed for how "undefined" propagates out
of expressions into statements and sequences of statements.
The naive rule would be:

    Undefined; S; ==> Undefined;

That is, if a statement is Undefined, then so is a sequence of
statements starting with that statement.   However, it has generally
been agreed (in the ARG and for Ada 9X) that the sequence  
should not be interpreted strictly, but rather the partial ordering
implied by data dependences should control the legitimate reorderings.

Hence, a legal transformation of:

    X := Undefined; <sequence without ref to X>; Y := ... X ...;

is:

    <sequence without ref to X>; Y := ... Undefined ...;

and a legal transformation of:

    X := Undefined; <rest of program with no further uses of X>;

is:

    <rest of program with no further uses of X>;

In other words, the calculation of an undefined value can be moved
around (or eliminated) just like the calculation of a defined value.

The critical thing is that an undefined value must not be allowed
to make it into the external output of the program, either directly
or by controlling the result printed.  Before this happens,
an exception must be raised.

"If" statements are not the same as assignments, but can be treated that
way by making the following transformation:

   if Cond then
       S1;
   else
       S2;
   end if;

goes to:

   Path := Cond;
   S1(Path);
   S2(not Path);

With this transformation, it should become clear that
if Cond evaluates to "Undefined," then neither S1 nor S2 may be
allowed to execute normally.  The only thing which would allow the elimination
of the evaluation of Cond would be if both S1 and S2 were empty (possibly
due to elimination of dead code by the optimizer).

Since in all of the examples mentioned earlier in this thread,
S1 was not empty, we clearly have to evaluate Cond to determine
whether it evaluates to False or to Undefined, and if it evaluates
to Undefined, we can only "consume" the Undefined by executing the
appropriate exception handler.

So... The bottom line, is that with this proposed approach
to 11.6(7), the compiler may *not* assume an expression is False 
just because it would either be False or raise an exception.
It must go ahead and determine whether or not the expression
raises an exception (i.e. evaluates to "Undefined"), unless there
is no output dependent on the result (in these examples, there
clearly was output dependent on the result).
       
>					Robert I. Eachus

S. Tucker Taft
Ada 9X Mapping/Revision Team
Intermetrics, Inc.
Cambridge, MA  02138

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

* Re: Bug in AdaEd???
@ 1993-09-23 20:55 Tucker Taft
  0 siblings, 0 replies; 12+ messages in thread
From: Tucker Taft @ 1993-09-23 20:55 UTC (permalink / raw)


In article <CDrELy.B1E@yktnews.watson.ibm.com> ncohen@watson.ibm.com writes:

>In article <CDr7CH.C9x@crdnns.crd.ge.com>, groleau@e7sa.crd.ge.com
>(Wes Groleau x1240 C73-8) writes: 
>
>|> Language lawyers please explain in short words if I'm wrong, but I can't
>|> for the life of me think of ANY reason why optimization of code with
>|> predetermined results would intentionally be done to give different results
!
>
>Here is a summary of RM 11.6 "while standing on one foot": 
>
>   An optimizer is allowed to assume that the intended effect of a
>   program is not to raise a predefined exception.
>

Well, as indicated in another response I made, I believe an even
more important "standing on one foot" rule is:

   "language-defined checks are designed to prevent junk output"

That is, rather than just wrapping around on overflow, or trashing
random memory which later gets used in producing the answer, the 
language-defined checks catch such transgressions so that *if*
a program produces output, the output corresponds to a common-sense
interpretation of the source of the program.

Of course, checks can't prevent junk output from junk programs (that
would violate the most holy rule of garbage-in-garbage-out),
but they can prevent junk output due to wild stores, wild jumps,
and numeric overflow.

The purpose of 11.6, in my view, was to allow a computation
that might fail a language-defined check to be treated
like any other computation from the point of view of optimization
(reordering, common subexpressions, dead code elimination, etc.).
If some check does ultimately fail during execution of the
optimized code, the exception doesn't need to
look like it emanated from exactly where it would if the source
code was translated literally by the compiler.  The compiler is
allowed to do all kinds of transformations so long as they preserve
correct results, *and so long as they don't produce junk output.*
In other words, exceptions don't have to be "precise," but they
jolly well better happen if the alternative is junk output.
    
As pointed out in my other response in this thread, one "solution" to this
problem seems to be to have compilers treat a computation that
fails a language-defined check as producing an "undefined value"
(aka "bottom").  In some hypothetical hardware, each type would
actually allow for an undefined value in addition to all the other
values of the type.  The net effect of 11.6 is that the exception
need not be raised when an undefined value is calculated, but it must
be raised before an undefined value finds its way into the output
of the program (and if there are handlers for the corresponding
exception, the handler governing the sequence of statements containing
the failing computation must get control).

>Norman H. Cohen    ncohen@watson.ibm.com

S. Tucker Taft
Ada 9X Mapping/Revision Team
Intermetrics, Inc.
Cambridge, MA  02138

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

end of thread, other threads:[~1993-09-23 20:55 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
1993-09-07  3:20 Bug in AdaEd??? Robert Dewar
  -- strict thread matches above, loose matches on Subject: below --
1993-09-23 20:55 Tucker Taft
1993-09-23 18:46 Tucker Taft
1993-09-22 22:28 Robert I. Eachus
1993-09-22 21:07 Robert I. Eachus
1993-09-22 14:22 Norm an H. Cohen
1993-09-22 14:10 cis.ohio-state.edu!magnus.acs.ohio-state.edu!usenet.ins.cwru.edu!howland.reston.ans.net!usc!cs.utexas.edu!not-for-mail
1993-09-22 13:36 cis.ohio-state.edu!news.sei.cmu.edu!firth
1993-09-22 11:45 Wes Groleau x1240 C73-8
1993-09-22  0:21 Robert I. Eachus
1993-09-21  4:19 Gene Ouye
1993-09-06 14:06 Gene Ouye

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