comp.lang.ada
 help / color / mirror / Atom feed
* 'size attribute inheritance
@ 1997-08-09  0:00 Carlos Palenzuela
  1997-08-10  0:00 ` Matthew Heaney
                   ` (2 more replies)
  0 siblings, 3 replies; 22+ messages in thread
From: Carlos Palenzuela @ 1997-08-09  0:00 UTC (permalink / raw)



Our software group has run across a problem with types and subtypes 
and their sizes that is confusing me.  I have read what I believe to 
be the appropriate sections of the ARM, but I still need some 
clarification and would like to hear some informed opinions.
     
Following is a simplified version of our example.  We are using Green 
Hills Ada 95 targeted to Sun/Solaris. 
     
     type Integer_16 is range -(2**15) .. (2**15)-1; 
     for Integer_16'size use 16;
     
     subtype Natural_16 is Integer_16 range 0 .. Integer_16'last;
     
     subtype Month_Type is Natural_16 range 0..11;
     
     type Date_Type is
     record
     Year  : Natural_16;
     Month : Month_Type;
     end record;
     
     for Date_Type use
     record
     Year  at 0 range 0 .. 15;
     Month at 0 range 16 .. 31;
     end record;
     ...
     When running this code, we get a bus alignment error.  We tracked
it 
     down to the fact that the compiler does NOT really allocate 16 bits 
     for Month with subtype Month_Type.  We assumed that since
Integer_16 
     had been set up with 'size attribute of 16, subtype Natural_16
would 
     inherit that and so Month_Type would also inherit it. I might
expect 
     based on 13.3 (55) that Month_Type'size = 4 and then on 13.3 (43)
that 
     Month'size >= 4.  Perhaps the confusion is that only the attribute 
     itself and not its specific value is what is inherited; I don't see 
     anything in the ARM which says one way or the other.
     
     Putting a 'size attribute on the subtype resulted in a syntax error 
     [assumedly based on 13.3 (48)].  It's not necessarily so bad that 
     Month_type'size and Month'size are different from Integer_16'size,
but 
     I would at least expect the values of Month to be right-justified
in 
     the record-component field if Month'size < Integer_16'size (as
here), 
     but instead it is left-justified!  Is there a justification in the
ARM 
     for this or is this a compiler issue?   We worked around this
problem 
     by setting up Month_Type as a type, rather than a subtype, and 
     assigning it a 'size of 16, but the issue still has me perplexed. 
I 
     would appreciate any informed opinions as to what I can or should 
     expect about the inheritance of the 'size attribute. 
     
     Thank you for your help,
     Lizbeth Palenzuela
     
     (working at but not speaking for)
     Lockheed Martin Integrated Systems
     Orlando, FL




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

* Re: 'size attribute inheritance
  1997-08-09  0:00 'size attribute inheritance Carlos Palenzuela
  1997-08-10  0:00 ` Matthew Heaney
@ 1997-08-10  0:00 ` Robert A Duff
  1997-08-10  0:00 ` Robert Dewar
  2 siblings, 0 replies; 22+ messages in thread
From: Robert A Duff @ 1997-08-10  0:00 UTC (permalink / raw)



In article <33ECF679.4B5D@lmco.com>,
Carlos Palenzuela  <cpalenzuela@sprintmail.com> wrote:
>     type Integer_16 is range -(2**15) .. (2**15)-1; 
>     for Integer_16'size use 16;

This is the Size that should be chosen by default, anyway, because of
RM-13.3(55).

But the sizes of the various subtypes in this example seem completely
irrelevant, since what you care about is the size of the components Year
and Month, and you've set those to 16 using a record rep clause.  So
even if you set Integer_16'Size to 999 (and can get the compiler to
listen), the size of both components will still be 16.

The ARG has had endless arguments about the exact meaning of 'Size.
See AI95-109, if you're interested.

>     subtype Natural_16 is Integer_16 range 0 .. Integer_16'last;
>     
>     subtype Month_Type is Natural_16 range 0..11;
>     
>     type Date_Type is
>     record
>     Year  : Natural_16;
>     Month : Month_Type;
>     end record;
>     
>     for Date_Type use
>     record
>     Year  at 0 range 0 .. 15;
>     Month at 0 range 16 .. 31;
>     end record;
>     ...
>     When running this code, we get a bus alignment error.  We tracked
>it 
>     down to the fact that the compiler does NOT really allocate 16 bits 
>     for Month with subtype Month_Type.  We assumed that since
>Integer_16 
>     had been set up with 'size attribute of 16, subtype Natural_16
>would 
>     inherit that and so Month_Type would also inherit it. I might
>expect 
>     based on 13.3 (55) that Month_Type'size = 4 and then on 13.3 (43)
>that 
>     Month'size >= 4.

That would be true if there were no record rep clause, but there is, so
Month'Size = 16.  See also AARM-13.5.2(4.b).

>...Perhaps the confusion is that only the attribute 
>     itself and not its specific value is what is inherited; I don't see 
>     anything in the ARM which says one way or the other.
>     
>     Putting a 'size attribute on the subtype resulted in a syntax error 
>     [assumedly based on 13.3 (48)].

Correct.

>...It's not necessarily so bad that 
>     Month_type'size and Month'size are different from Integer_16'size,
>but 
>     I would at least expect the values of Month to be right-justified
>in 
>     the record-component field if Month'size < Integer_16'size (as
>here), 
>     but instead it is left-justified!  Is there a justification in the
>ARM 
>     for this or is this a compiler issue?

The RM says how many bits there are (in this case anyway), but it
doesn't say anything about how the compiler uses those bits.  I guess
the presumption is that the compiler will use a reasonable
representation.

>...We worked around this
>problem 
>     by setting up Month_Type as a type, rather than a subtype, and 
>     assigning it a 'size of 16, but the issue still has me perplexed. 

Strange.  I suspect a compiler bug, but I'm not exactly sure what you
meant by "right justified" above -- is that an endian-independent term?

By the way, if you're using this record to interface to the rest of the
world (input from outside Ada, such as hardware or C code), then I
suggest you don't use ranges like 0..11.  I think it's generally safer
(less likely to cause erroneous execution) if you make sure all the
record fields have ranges that *exactly* fit within the number of bits
allotted.  Once the data is inside the Ada world, you can then range
check it, and put it into a more reasonable data structure, if desired.

- Bob




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

* Re: 'size attribute inheritance
  1997-08-09  0:00 'size attribute inheritance Carlos Palenzuela
@ 1997-08-10  0:00 ` Matthew Heaney
  1997-08-11  0:00   ` Robert Dewar
  1997-08-10  0:00 ` Robert A Duff
  1997-08-10  0:00 ` Robert Dewar
  2 siblings, 1 reply; 22+ messages in thread
From: Matthew Heaney @ 1997-08-10  0:00 UTC (permalink / raw)



In article <33ECF679.4B5D@lmco.com>, cpalenzuela@sprintmail.com wrote:

>Following is a simplified version of our example.  We are using Green 
>Hills Ada 95 targeted to Sun/Solaris. 
>     
>     type Integer_16 is range -(2**15) .. (2**15)-1; 
>     for Integer_16'size use 16;

As Bob pointed out, you don't need the size clause, as that is the size
already.  The "default" size is the number of bits needed to represent all
values in the range, no more, and no less.
    
>     subtype Natural_16 is Integer_16 range 0 .. Integer_16'last;
>     
>     subtype Month_Type is Natural_16 range 0..11;
>     
>     type Date_Type is
>     record
>     Year  : Natural_16;
>     Month : Month_Type;
>     end record;
>     
>     for Date_Type use
>     record
>     Year  at 0 range 0 .. 15;
>     Month at 0 range 16 .. 31;
>     end record;

I would put a size clause on the record, too, and an alignment clause:

for Data_Type'Size use 32;
for Data_Type'Alignment use 4;  -- I think that's the syntax

>     ...
>     When running this code, we get a bus alignment error.  We tracked
>it 
>     down to the fact that the compiler does NOT really allocate 16 bits 
>     for Month with subtype Month_Type.  We assumed that since
>Integer_16 
>     had been set up with 'size attribute of 16, subtype Natural_16
>would 
>     inherit that and so Month_Type would also inherit it. I might
>expect 
>     based on 13.3 (55) that Month_Type'size = 4 and then on 13.3 (43)
>that 
>     Month'size >= 4.  Perhaps the confusion is that only the attribute 
>     itself and not its specific value is what is inherited; I don't see 
>     anything in the ARM which says one way or the other.

(Sub)type Month_Type really is 4 bits, as that's all that is required to
represent all the values in the range 0 .. 11.  It is definately not 16
bits, even though it's a subtype of a subtype that does have a size of 16.

But you explicitly allocated 16 bits for the Month component of the
Date_Type record, so that's what you got for that component.  But read on.

Given that you're using representation clauses on a type, I assume your
reason for doing so is because you're going to read or write an object of
this type across an external interface.  As Bob also pointed out,

YOU SHOULD NEVER USE CONSTRAINED SUBTYPES TO TRANSMIT OR RECIEVE DATA
ACROSS AN EXTERNAL INTERFACE.

I'll say this another way:

USE ONLY FIRST NAMED SUBTYPES WHOSE RANGE EXACTLY MATCHES THE RANGE
REPRESENTABLE BY ITS SIZE, WHEN PERFORMING EXTERNAL I/O.

Some more advice

USE THE TYPES IN PACKAGE INTERFACES TO PERFORM EXTERNAL I/O.

I'm not trying to scream at anyone or be rude or anything, but this issue
is so important that I have to get your attention, because most Ada
programmers don't completely understand it.

The correct way to declare your date type is as follows:

type Date_Type is
   record
      Year   : Interfaces.Integer_16;
      Month : Interfaces.Integer_16;
   end record;

for Date_Type use
   record
      Year at 0 range 0 .. 15; 
      Month at 0 range 16 .. 31;
   end record;

for Date_Type'Size use 32;

for Date_Type'Alignment use 4;

When declaring actual objects of the type, for use when executing the I/O
statement, then specify a size for the object:

declare
   The_Date : Date_Type;
   for The_Date'Size use 32;
begin
   read (The_Date'Address, nbytes => 4);
end;

I'm not sure, but it might help too to declare the object as aliased and
volatile:

declare
   The_Date : aliased Date_Type;
   for The_Date'Size use 32;
   pragma Volatile (The_Date);
begin
   read (The_Date'Address, nbytes => 4);
end;


>     Putting a 'size attribute on the subtype resulted in a syntax error 
>     [assumedly based on 13.3 (48)].  It's not necessarily so bad that 
>     Month_type'size and Month'size are different from Integer_16'size,
>but 
>     I would at least expect the values of Month to be right-justified
>in 
>     the record-component field if Month'size < Integer_16'size (as
>here), 
>     but instead it is left-justified!  Is there a justification in the
>ARM 
>     for this or is this a compiler issue?   

You can only specify a size clause in the declaration of the first subtype
(the declaration "type T is...").

I'm not sure what you meant by values being "left justified" or "right
justified."

Make sure you're not having any problems with endianness, either.  On a
big-endian machine, your declaration is layed out as

                     0    15  16      31
   The_Date : year     month

on a little endian machine:

   31    16  15      0
     month    year   :  The_Date

If the value for month is at at wrong end of the month component, perhaps
that's becuase you and the device have a different endianness?  (The UNIX
guys call this "getting NUXIed.")


>We worked around this
>problem 
>     by setting up Month_Type as a type, rather than a subtype, and 
>     assigning it a 'size of 16, but the issue still has me perplexed. 
>I 
>     would appreciate any informed opinions as to what I can or should 
>     expect about the inheritance of the 'size attribute. 

Technically, you meant to say "setting up Month_Type as a first named subtype."

And no, size is not "inherited."  The size is always only what is required
to exactly represent all values of the subtype.  For example,

   type Byte is range 0 .. 255;
   for Byte'Size use 8;

   subtype Nibble is Byte range 0 .. 15;

Byte'Size is 8, and Nibble'Size is 4.

Which is the reason you should always specify a size for objects (not just
the type) used for external I/O (ie whenever you say "O'Address", you
should already have said "for O'Size use ...").

This makes sense, if you consider this

declare
   O : Nibble;
begin

A compiler can only allocate an integral number of "storage elements" for
O.  On a machine with byte addressing, O would "probably" have a size of 8,
although it could have 16 or 32.  There's no way object O could have a size
of 4, in spite of the fact that Nibble has a size of 4.  You the programmer
must specify explictly what the size of the object needs to be,
irrespective of whether the type has a size clause.

As I said (loudly, but not to be rude), never ever do I/O using other than
a first named subtype whose range exactly matches the values representable
in its size.  Types with this very characteristic are already defined for
you in package Interfaces.

If you did use a subtype with a range constraint to do external I/O, and
you got garbage over the interface, now your program is erroneous (or maybe
it's a "bounded error" now - check the AARM).  For example,  if I had a
Date_Type object, and the device put the value 16#0000_00FF# at that
address, then Date.Month has the value 255, even though it is constrained
to only have the values 0 .. 11.  If you ever try to deference that
component, then all bets are off as to the program's behavior.  (Think of
the disaster that could happen if Month were in a case statement, or used
to index an array.)

Many, many new and experienced Ada programmers naively think that
Constraint_Error will get raised.  This is completely and totally
incorrect.  Program behavior is UNDEFINED.

Perhaps your "bus alignment" error is really the result of erroneous
execution, because you have garbage in the month component of date.

You the programmer must manually check the object to make sure its value is
in the correct range.  So here's what you can do for the date:

subtype Month_Type is Natural range 0 .. 11;

declare
   The_Date : Date_Type; -- the declaration I wrote above
   for The_Date'Size use 32;
begin
   read (The_Date'Address, nbytes => 4);

   if The_Date.Month not in 0 .. 11 then
      <handle garbage value for month>
   end if;

...
end;


Another possibility is that there was already garbage in the object when
declared (because it wasn't given a default value), and the device wrote
fewer bytes than the number of bytes in the object.  For example
 
declare
   Month : Month_Type;  -- 16 bit object
begin
  <read 1 byte into Month>
end;

Now if there were garbage in the most significant byte of Month, Month
would be outside its correct range, even though the device returned a
correct value.

Here's yet another reason to not use constrained subtypes.  If I tried to
check to make sure the object had a value in the correct range:

if Month not in Month_Type'Range then
   <handle error>
end if;

the compiler might optimize the check away, under the assumption that since
Month is of subtype Month_Type, it can't be outside that subtype's range,
and therefore we can just get rid of this unnecessary check.  (There's a
T'Value attribute too, but I'm still not sure a use of it won't get
optimized away.)  Which is why I always read into unconstrained subtypes,
and do the constraint checking manually.

Hope that helps,
Matt

--------------------------------------------------------------------
Matthew Heaney
Software Development Consultant
<mailto:matthew_heaney@acm.org>
(818) 985-1271




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

* Re: 'size attribute inheritance
  1997-08-09  0:00 'size attribute inheritance Carlos Palenzuela
  1997-08-10  0:00 ` Matthew Heaney
  1997-08-10  0:00 ` Robert A Duff
@ 1997-08-10  0:00 ` Robert Dewar
  1997-08-11  0:00   ` Ken Garlington
  1997-08-11  0:00   ` Matthew Heaney
  2 siblings, 2 replies; 22+ messages in thread
From: Robert Dewar @ 1997-08-10  0:00 UTC (permalink / raw)



<<     When running this code, we get a bus alignment error.  We tracked
it
     down to the fact that the compiler does NOT really allocate 16 bits
     for Month with subtype Month_Type.  We assumed that since>>


This is definitely a compiler bug, there is no way that legal declarations
that are accepted by the compiler can lead to bus errors.

However, the treatment of the size attribute seems to be quite in accord
with the RM. Ada 95 effectively introduced pretty serious incompatibilites
in the handling of 'Size by requiring an interpretaytion that was legal
in Ada 83 (and happened by no mere coincidence to be the one used by
the Intermetrics compiler :-) but was not typical of Ada 83 compilers.

So a lot of old code breaks but the break should consist of rejections
at compile time: NOT bus errors!

GNAT has introduced new attributes Value_Size and Object_Size wjhich can
be applied to subtypes as well as first named types, to provide complete
control over sizes, and allow old code to be easily ported no matter what
conventions the compiler on which it was compiled was using.

Our default conventions are as close as we are allowed to the VADS compiler,
but we are not allowed to be 100% compatible. In any case the bus error
is a serious bug. From the description, it does not sound like you are
using GNAT, and certainly the current version of GNAT does what you
expect with the declarations you gave.





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

* Re: 'size attribute inheritance
  1997-08-10  0:00 ` Robert Dewar
@ 1997-08-11  0:00   ` Ken Garlington
  1997-08-11  0:00   ` Matthew Heaney
  1 sibling, 0 replies; 22+ messages in thread
From: Ken Garlington @ 1997-08-11  0:00 UTC (permalink / raw)



Robert Dewar wrote:
> 
> <<     When running this code, we get a bus alignment error.  We tracked
> it
>      down to the fact that the compiler does NOT really allocate 16 bits
>      for Month with subtype Month_Type.  We assumed that since>>
> 
> This is definitely a compiler bug, there is no way that legal declarations
> that are accepted by the compiler can lead to bus errors.

This seems like an odd statement. Maybe I'm not understanding the
problem,
but I thought the real issue was code like the following:

  package A_Test is

    Word : constant := 4;

    type Small_Value is range 0 .. 15;

    type A_Record is record
      Component_1 : Integer;
      Component_2 : Small_Value;
    end record;

    for A_Record use record
      Component_1 at 0*Word range 0 .. 31;
      Component_2 at 1*Word range 0 .. 31;
    end record;

    My_Record : A_Record := (3, 15);

  end A_Test;

For this code, will My_Record.Component_2 be stored in
bits 0 .. 3 of word 1, bits 28 .. 31, or elsewhere?
I know in Ada83 that this sometimes ended up on one
side, and something like

  type B_Array is array(0 .. 3) of Boolean;
  pragma Pack(B_Array);

sometimes ended up on the other side.

Is there something in the Ada83/Ada RMs that discuss this?
I couldn't find it.

> 
> However, the treatment of the size attribute seems to be quite in accord
> with the RM. Ada 95 effectively introduced pretty serious incompatibilites
> in the handling of 'Size by requiring an interpretaytion that was legal
> in Ada 83 (and happened by no mere coincidence to be the one used by
> the Intermetrics compiler :-) but was not typical of Ada 83 compilers.
> 
> So a lot of old code breaks but the break should consist of rejections
> at compile time: NOT bus errors!

Yeah, I don't think 'Size is really the issue here. It's the behavior
when a record representation clause allocates more space to a component
that it needs. Unless there's something in the RM that controls this,
I could see where a compiler might do something different than you might
expect. For example, storing it in an "unconventional" manner might
allow for fewer shift/mask instructions.

> 
> GNAT has introduced new attributes Value_Size and Object_Size wjhich can
> be applied to subtypes as well as first named types, to provide complete
> control over sizes, and allow old code to be easily ported no matter what
> conventions the compiler on which it was compiled was using.
> 
> Our default conventions are as close as we are allowed to the VADS compiler,
> but we are not allowed to be 100% compatible. In any case the bus error
> is a serious bug. From the description, it does not sound like you are
> using GNAT, and certainly the current version of GNAT does what you
> expect with the declarations you gave.




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

* Re: 'size attribute inheritance
  1997-08-10  0:00 ` Robert Dewar
  1997-08-11  0:00   ` Ken Garlington
@ 1997-08-11  0:00   ` Matthew Heaney
  1 sibling, 0 replies; 22+ messages in thread
From: Matthew Heaney @ 1997-08-11  0:00 UTC (permalink / raw)



In article <dewar.871238340@merv>, dewar@merv.cs.nyu.edu (Robert Dewar) wrote:


>Our default conventions are as close as we are allowed to the VADS compiler,
>but we are not allowed to be 100% compatible.

What do you mean by that, "not allowed to be compatible"?

--------------------------------------------------------------------
Matthew Heaney
Software Development Consultant
<mailto:matthew_heaney@acm.org>
(818) 985-1271




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

* Re: 'size attribute inheritance
  1997-08-10  0:00 ` Matthew Heaney
@ 1997-08-11  0:00   ` Robert Dewar
  1997-08-12  0:00     ` Matthew Heaney
  0 siblings, 1 reply; 22+ messages in thread
From: Robert Dewar @ 1997-08-11  0:00 UTC (permalink / raw)



Matthew says

<<YOU SHOULD NEVER USE CONSTRAINED SUBTYPES TO TRANSMIT OR RECIEVE DATA
ACROSS AN EXTERNAL INTERFACE.>>

There is no possible justification for such a rule (in caps or otherwise)
in my opinion. Sure you have to be careful to know what you are doing,
but this rule is entirely unsupportable. What is important is to use
appropriate representation clauses and pragmas. If this is done, the
above rule is not helpful.





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

* Re: 'size attribute inheritance
  1997-08-11  0:00   ` Robert Dewar
@ 1997-08-12  0:00     ` Matthew Heaney
  1997-08-13  0:00       ` Robert A Duff
  1997-08-13  0:00       ` Ken Garlington
  0 siblings, 2 replies; 22+ messages in thread
From: Matthew Heaney @ 1997-08-12  0:00 UTC (permalink / raw)



In article <dewar.871345653@merv>, dewar@merv.cs.nyu.edu (Robert Dewar) wrote:

>Matthew says
>
><<YOU SHOULD NEVER USE CONSTRAINED SUBTYPES TO TRANSMIT OR RECIEVE DATA
>ACROSS AN EXTERNAL INTERFACE.>>
>

Robert reponds:

>There is no possible justification for such a rule (in caps or otherwise)
>in my opinion. Sure you have to be careful to know what you are doing,
>but this rule is entirely unsupportable. What is important is to use
>appropriate representation clauses and pragmas. If this is done, the
>above rule is not helpful.

Matthew replies:

I stated this guideline under the assumption that your external device is
unreliable.  I have had many occasions when I got spurious I/O completion
(say, the power was cycled), and the resulting data at the address was
complete garbage.

If you trust your device (perhaps it's a UNIX-domain socket, or a VMS
mailbox), then you could put constraints on the data, knowing it could
never be out of range.  I don't recommend it, but you could.

However, Robert's statement that "there is no possible justification for
such a rule" is a bit strong.  I think it's downright scary to think that
an object of a constrained subtype can have a value outside its range. 
What is the behavior of the program if that object is used to dereference
an array, or used in a case statement?

Here's a related example, something that happened to a member of our
development team just last week.  The code was something like this

declare
   type Atype is array (Itype) of T;
   AO : Atype;

   Index : Itype;  -- note that this doesn't have a default
begin
   if P then

      Index := <a valid value>;
      ... AO (Index)...

   else

      ... AO (Index);  -- oops!

   end if;
...
end;

From time to time, the program was getting a core dump.  He carefully
traced the execution of the program, and it always dumped when it reached
the dereference of array object AO in the else part of the if statement.

The problem was that Index hadn't been initialized at that point at which
it was used to dereference the array, so the application was touching
memory that it wasn't supposed to, and so, for this compiler and operating
system, the application dumped core.

The developer assumed that a Constraint_Error would be raised, but as I
pointed out in the previous post, this is never a safe, portable assumption
to make.  The compiler can legally omit a range check, reasoning that since
Index is an object of type Itype, and Itype is the array index subtype, no
check is required, because Index has to be in the array's range.

In fact, this is the very reason programmers are admonished to write their
for loops by explicitly stating the array index subtype in the declaration
if the loop index, because that will turn range checks off inside the loop,
when dereferencing the array using the loop index.

Robert may be thinking of GNAT, which I think always puts in a range check,
no matter what (or at least more often than other compilers).  But you
can't depend on this behavior.

My own lesson was learned the hard way on a VAX.  I was reading into an
object of an enumeration type, and using that object in a case statement. 
I would get ACCVIO (equivalent to a segmentation fault under UNIX) when I
got a flakey value from the hardware, which could happen at startup, and
when power was cycled.

Your mileage may vary, but I really, really recommend you err on the side
of safety here, and not read data from an external device into an object of
a contrained subtype.  Think of how many UNIX security breaches have been
caused by deliberately overflowing data into certain areas of memory.

Consider yourself fortunate that you get any indication that a value is
outside its constrained range.  But even then, if you're flying a plane
controlled by software that has an illegal value for an object, is a core
dump really want you'd want to happen?

Please be very, very careful with data from an external source.

--------------------------------------------------------------------
Matthew Heaney
Software Development Consultant
<mailto:matthew_heaney@acm.org>
(818) 985-1271




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

* Re: 'size attribute inheritance
  1997-08-12  0:00     ` Matthew Heaney
  1997-08-13  0:00       ` Robert A Duff
@ 1997-08-13  0:00       ` Ken Garlington
  1997-08-13  0:00         ` Matthew Heaney
  1 sibling, 1 reply; 22+ messages in thread
From: Ken Garlington @ 1997-08-13  0:00 UTC (permalink / raw)



Matthew Heaney wrote:
> 
> >Matthew says
> >
> ><<YOU SHOULD NEVER USE CONSTRAINED SUBTYPES TO TRANSMIT OR RECIEVE DATA
> >ACROSS AN EXTERNAL INTERFACE.>>
>

[snip]

> My own lesson was learned the hard way on a VAX.  I was reading into an
> object of an enumeration type, and using that object in a case statement.
> I would get ACCVIO (equivalent to a segmentation fault under UNIX) when I
> got a flakey value from the hardware, which could happen at startup, and
> when power was cycled.

Note that this can happen even if your rule is followed. For example,
if you provide an address to the hardware, the device can "flake" and
write the result to a different address. Also, the device may mislead
you as to the number of consecutive storage units it will write.

On the other hand, a constrained subtype is just as useful as a base
type
if it matches the size of the expected storage units to be written (in
Ada or
Ada 83), or if you use 'Valid (Ada only), which is intended for this
case.

> Consider yourself fortunate that you get any indication that a value is
> outside its constrained range.  But even then, if you're flying a plane
> controlled by software that has an illegal value for an object, is a core
> dump really want you'd want to happen?

No; on the other hand, you don't want to either weaken the typing
abilities
of Ada, nor do you want to introduce too many base types. The intent of
your rule can be followed with constrained subtypes, so long as you
understand the nature of your I/O device.

> Please be very, very careful with data from an external source.

As always!

> 
> --------------------------------------------------------------------
> Matthew Heaney
> Software Development Consultant
> <mailto:matthew_heaney@acm.org>
> (818) 985-1271




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

* Re: 'size attribute inheritance
  1997-08-12  0:00     ` Matthew Heaney
@ 1997-08-13  0:00       ` Robert A Duff
  1997-08-13  0:00         ` Matthew Heaney
  1997-08-13  0:00       ` Ken Garlington
  1 sibling, 1 reply; 22+ messages in thread
From: Robert A Duff @ 1997-08-13  0:00 UTC (permalink / raw)



In article <mheaney-ya023680001208971859210001@news.ni.net>,
Matthew Heaney <mheaney@ni.net> wrote:
>Here's a related example, something that happened to a member of our
>development team just last week.

You're mixing two issues here.  The next example is about uninitialized
variables, whereas stuff after that talks about input from hardware and
so forth.  In Ada 83, these were similar, in that any resulting garbage
would cause execution to be erroneous.  In Ada 95, however, use of
uninit vars is *not* erroneous.  Many cases of interfacing to hardware
remain erroneous, in Ada 95.

The difference makes sense, to me.  Interfacing to the outside world can
be isolated in specific modules, and carefully checked, whereas an
uninitialized variable is something that might happen anywhere in the
program.

>...The code was something like this
>
>declare
>   type Atype is array (Itype) of T;
>   AO : Atype;
>
>   Index : Itype;  -- note that this doesn't have a default
>begin
>   if P then
>
>      Index := <a valid value>;
>      ... AO (Index)...
>
>   else
>
>      ... AO (Index);  -- oops!
>
>   end if;
>...
>end;

>The problem was that Index hadn't been initialized at that point at which
>it was used to dereference the array, so the application was touching
>memory that it wasn't supposed to, and so, for this compiler and operating
>system, the application dumped core.

This was correct behavior for Ada 83, but if it's an Ada 95 compiler, it
has a bug.  The indexing expression must either raise C_E or P_E or else
return some value.  It can't dump core.

>The developer assumed that a Constraint_Error would be raised, but as I
>pointed out in the previous post, this is never a safe, portable assumption
>to make.  The compiler can legally omit a range check, reasoning that since
>Index is an object of type Itype, and Itype is the array index subtype, no
>check is required, because Index has to be in the array's range.

No longer true in Ada 95.

>Robert may be thinking of GNAT, which I think always puts in a range check,
>no matter what (or at least more often than other compilers).  But you
>can't depend on this behavior.

GNAT eliminates range checks that it can prove won't fail.  (I don't
really know how smart it is about that.)  In order to prove that
properly, the initial value of a variable, or lack thereof, has to be
taken into account.  For "... A(I) ...", if I contains random stack
junk, the compiler cannot eliminate the check, since it cannot prove I
is in range.  (In Ada 83, it could eliminate the check, because all it
had to prove is "either I is in range, or uninitialized", since the
uninitialized case was erroneous.)

>My own lesson was learned the hard way on a VAX.  I was reading into an
>object of an enumeration type, and using that object in a case statement. 
>I would get ACCVIO (equivalent to a segmentation fault under UNIX) when I
>got a flakey value from the hardware, which could happen at startup, and
>when power was cycled.

Ah, but this is a completely different issue (in Ada 95).  I agree with
you that when doing I/O or otherwise interfacing to the outside world,
one must be very careful to avoid erroneousness.  And I agree that part
of that carefulness should be making certain interface variables exactly
fill up the space allotted -- no extra bits lying around to cause
trouble.

- Bob




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

* Re: 'size attribute inheritance
  1997-08-13  0:00       ` Ken Garlington
@ 1997-08-13  0:00         ` Matthew Heaney
  0 siblings, 0 replies; 22+ messages in thread
From: Matthew Heaney @ 1997-08-13  0:00 UTC (permalink / raw)



In article <33F250A4.2B42@flash.net>, Ken.Garlington@computer.org wrote:


>> Consider yourself fortunate that you get any indication that a value is
>> outside its constrained range.  But even then, if you're flying a plane
>> controlled by software that has an illegal value for an object, is a core
>> dump really want you'd want to happen?
>
>No; on the other hand, you don't want to either weaken the typing
>abilities
>of Ada, nor do you want to introduce too many base types. The intent of
>your rule can be followed with constrained subtypes, so long as you
>understand the nature of your I/O device.

I wouldn't suggest giving up strong typing completely, only at the
interface layer of the system, where you're touching the metal (ie whenever
you write O'Address).  Whatever data an interface abstraction presents to
the rest of the system should be strongly typed, but I recommend that in
the implementation of that abstraction, weak types be used to read in the
data, and that the range of the input data be checked manually.

--------------------------------------------------------------------
Matthew Heaney
Software Development Consultant
<mailto:matthew_heaney@acm.org>
(818) 985-1271




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

* Re: 'size attribute inheritance
  1997-08-13  0:00       ` Robert A Duff
@ 1997-08-13  0:00         ` Matthew Heaney
  1997-08-14  0:00           ` Robert A Duff
  1997-08-16  0:00           ` Robert Dewar
  0 siblings, 2 replies; 22+ messages in thread
From: Matthew Heaney @ 1997-08-13  0:00 UTC (permalink / raw)



In article <EEv8xA.HqH@world.std.com>, bobduff@world.std.com (Robert A
Duff) wrote:

>This was correct behavior for Ada 83, but if it's an Ada 95 compiler, it
>has a bug.  The indexing expression must either raise C_E or P_E or else
>return some value.  It can't dump core.

Wow!  I didn't realize the language had changed that way.  (Yes, the
compiler I'm talking about is Ada 83.)

>>The developer assumed that a Constraint_Error would be raised, but as I
>>pointed out in the previous post, this is never a safe, portable assumption
>>to make.  The compiler can legally omit a range check, reasoning that since
>>Index is an object of type Itype, and Itype is the array index subtype, no
>>check is required, because Index has to be in the array's range.
>
>No longer true in Ada 95.

I figured to get this behavior you'd require support of the Safety Annex. 
I didn't know Ada 95 comes that way out of the box.

Does unitialized variable checking only apply to array index variables? 
And do you have an AARM reference?

--------------------------------------------------------------------
Matthew Heaney
Software Development Consultant
<mailto:matthew_heaney@acm.org>
(818) 985-1271




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

* Re: 'size attribute inheritance
  1997-08-13  0:00         ` Matthew Heaney
@ 1997-08-14  0:00           ` Robert A Duff
  1997-08-14  0:00             ` Dale Stanbrough
  1997-08-16  0:00           ` Robert Dewar
  1 sibling, 1 reply; 22+ messages in thread
From: Robert A Duff @ 1997-08-14  0:00 UTC (permalink / raw)



In article <mheaney-ya023680001308972242460001@news.ni.net>,
Matthew Heaney <mheaney@ni.net> wrote:
>I figured to get this behavior you'd require support of the Safety Annex. 
>I didn't know Ada 95 comes that way out of the box.

What the Safety annex gives you is pragma Normalize_Scalars.  Given
"X: Natural;" without pragma N_S, X could be initialized to a valid or
invalid value.  With N_S, it will be initialized to some negative
number, which will increase the probability of getting an exception when
you use X.  But the rules about which uses of X need to do a range check
are the same, with or without N_S.

>Does unitialized variable checking only apply to array index variables?

No, but that's where it makes the most difference.  That and case
statements.  Array indexing can cause writes to arbitrary memory
locations, and case statements can cause wild jumps, and these things
make the error unbounded.

It's a bounded error to read from an uninit var.  You might get an
in-range value, an out-of-range value, or an exception.  If you say "if
X in Natural then ..." an Ada 83 compiler can optimize this into "if
True then ...", but an Ada 95 compiler must first prove that X was
initialized before doing such an optimization.

The Ada 9X team had a mandate to eliminate some erroneous situations.
That's why the concept of "bounded error" exists -- it's like
"erroneous", in that you can't be sure the error will be caught, but at
least you know it won't do as much damage as something erroneous might
(such as writing upon arbitrary memory locations, or taking wild jumps).
For a bounded error, you know that if the error is detected, you'll get
an exception, and otherwise, you'll get a well-defined effect.  The
point is to allow the compiler enough freedom to generate efficient
code, without doing "too much" damage when things go wrong.

>And do you have an AARM reference?

AARM-3.3.1(21-21.b), 13.9.1(2,9-11).

- Bob




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

* Re: 'size attribute inheritance
  1997-08-14  0:00           ` Robert A Duff
@ 1997-08-14  0:00             ` Dale Stanbrough
  0 siblings, 0 replies; 22+ messages in thread
From: Dale Stanbrough @ 1997-08-14  0:00 UTC (permalink / raw)



Matthew Heaney, mheaney@ni.net writes:
 I wouldn't suggest giving up strong typing completely, only at the
 interface layer of the system, where you're touching the metal (ie whenever
 you write O'Address).  Whatever data an interface abstraction presents to
 the rest of the system should be strongly typed, but I recommend that in
 the implementation of that abstraction, weak types be used to read in the
>data, and that the range of the input data be checked manually.


I would still use strong typing even at this level. Obviously out of range
values are a big problem, so don't declare types that could have out of range
values.

E.g. if you are reading in a 12 bit value from an A/D then declare...


	type AD_Reading is mod 2**12;


You still get the benefits of strong typing (can't accidentally convert to
an appropriately scaled/biased value) and no risk of Constraint_Error.


Dale




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

* Re: 'size attribute inheritance
  1997-08-16  0:00           ` Robert Dewar
@ 1997-08-16  0:00             ` Ken Garlington
  1997-08-17  0:00               ` Robert A Duff
  1997-08-17  0:00               ` Robert Dewar
  0 siblings, 2 replies; 22+ messages in thread
From: Ken Garlington @ 1997-08-16  0:00 UTC (permalink / raw)



Robert Dewar wrote:
> 
> Matthew said
> 
> <<Does unitialized variable checking only apply to array index variables?
> And do you have an AARM reference?>.
> 
> There is no "checking for uninitialized
> " variable feature in Ada 95.
> 
> There are requirements to check for values being in range in certain cases,
> don't get confused between these two, an uninitialized variable may well
> be in range!

I suppose this is technically true, but couldn't the effect of
pragam Normalize_Scalars, when combined with 'Valid and/or range
checking, be informally described as checking for uninitialized
variables?




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

* Re: 'size attribute inheritance
  1997-08-13  0:00         ` Matthew Heaney
  1997-08-14  0:00           ` Robert A Duff
@ 1997-08-16  0:00           ` Robert Dewar
  1997-08-16  0:00             ` Ken Garlington
  1 sibling, 1 reply; 22+ messages in thread
From: Robert Dewar @ 1997-08-16  0:00 UTC (permalink / raw)



Matthew said

<<Does unitialized variable checking only apply to array index variables?
And do you have an AARM reference?>.

There is no "checking for uninitialized
" variable feature in Ada 95.

There are requirements to check for values being in range in certain cases,
don't get confused between these two, an uninitialized variable may well
be in range!





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

* Re: 'size attribute inheritance
  1997-08-16  0:00             ` Ken Garlington
@ 1997-08-17  0:00               ` Robert A Duff
  1997-08-17  0:00               ` Robert Dewar
  1 sibling, 0 replies; 22+ messages in thread
From: Robert A Duff @ 1997-08-17  0:00 UTC (permalink / raw)



In article <33F670EF.4F65@flash.net>,
Ken Garlington  <Ken.Garlington@computer.org> wrote:
>I suppose this is technically true, but couldn't the effect of
>pragam Normalize_Scalars, when combined with 'Valid and/or range
>checking, be informally described as checking for uninitialized
>variables?

Sort of, but you have to remember that (1) the check doesn't happen when
you read the uninit var -- it happens *if* and when you use it in some
way that requires a range check, and (2) it only works if there are
enough bits to store the out-of-range value (it probably won't work for
a variable of type Character or Integer, for example).

- Bob




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

* Re: 'size attribute inheritance
  1997-08-16  0:00             ` Ken Garlington
  1997-08-17  0:00               ` Robert A Duff
@ 1997-08-17  0:00               ` Robert Dewar
  1997-08-18  0:00                 ` Robert A Duff
  1 sibling, 1 reply; 22+ messages in thread
From: Robert Dewar @ 1997-08-17  0:00 UTC (permalink / raw)



Ken said

<<I suppose this is technically true, but couldn't the effect of
pragam Normalize_Scalars, when combined with 'Valid and/or range
checking, be informally described as checking for uninitialized
variables?>>

Be careful! First, Normalize_Scalars does not guarantee that the variable
will be initialized with an out of range value (and indeed for a type
like Integer, it is almost certain that there is no such thing as an 
out of range value).

Second, the compiler is in many cases allowed to assume that a variable
is in range, so it may not always do a check where you expect it. In
particular, for a simple assignment, where the subtype is the same on
both sides, there is no requirement to perform a check, since assigning
the out of range value is an acceptable behavior for the error of
referencing an uninitialized variable.

Still, you are generally right, NS will approximate a check for 
uninitialized variables in practice.





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

* Re: 'size attribute inheritance
  1997-08-17  0:00               ` Robert Dewar
@ 1997-08-18  0:00                 ` Robert A Duff
       [not found]                   ` <dewar.872433846@merv>
  0 siblings, 1 reply; 22+ messages in thread
From: Robert A Duff @ 1997-08-18  0:00 UTC (permalink / raw)



In article <dewar.871839941@merv>, Robert Dewar <dewar@merv.cs.nyu.edu> wrote:
>Be careful! First, Normalize_Scalars does not guarantee that the variable
>will be initialized with an out of range value (and indeed for a type
>like Integer, it is almost certain that there is no such thing as an 
>out of range value).

Quite right.

>Second, the compiler is in many cases allowed to assume that a variable
>is in range, so it may not always do a check where you expect it. In
>particular, for a simple assignment, where the subtype is the same on
>both sides, there is no requirement to perform a check, since assigning
>the out of range value is an acceptable behavior for the error of
>referencing an uninitialized variable.

That's not quite right.  For example:

    with Text_IO;
    procedure Main is
        subtype S is Integer range 1..10;
        X, Y: S; -- uninitialized
    begin
        X := Y;
        Text_Put(Integer'Image(X));
    end Main;

The above program must either print out a value in the range 1 to 10, or
else raise C_E.  The above program must *not* print out the number 11,
for example.

Since Y is not explicitly initialized, it will be initialized to some
value, which might be in range, or might not.  The compiler cannot
remove the check on the assignment statement, unless it can prove that Y
is in range.  If the generated code allows Y to be initialized to
who-knows-what stack junk, then no such proof is possible, so the check
cannot be removed.

This is very different from Ada 83, where (in order to remove the check)
the compiler merely had to prove that "either Y is in range, or else Y
is uninitialized", which is much easier to prove.

If Normalize_Scalars is in effect, then Y *should* be initialized to
something out-of-bounds, so the above program *will* raise C_E, assuming
the compiler obeys the Implementation Advice about Normalize_Scalars
(which it ought to do).

>Still, you are generally right, NS will approximate a check for 
>uninitialized variables in practice.

Agreed.

- Bob




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

* Re: 'size attribute inheritance
       [not found]                   ` <dewar.872433846@merv>
@ 1997-09-03  0:00                     ` Robert A Duff
  1997-09-06  0:00                       ` Robert Dewar
  0 siblings, 1 reply; 22+ messages in thread
From: Robert A Duff @ 1997-09-03  0:00 UTC (permalink / raw)



In article <dewar.872433846@merv>, Robert Dewar <dewar@merv.cs.nyu.edu> wrote:

I said:

><<That's not quite right.  For example:
>
>    with Text_IO;
>    procedure Main is
>        subtype S is Integer range 1..10;
>        X, Y: S; -- uninitialized
>    begin
>        X := Y;
>        Text_Put(Integer'Image(X));
>    end Main;
>
>The above program must either print out a value in the range 1 to 10, or
>else raise C_E.  The above program must *not* print out the number 11,
>for example.>>

Robert replied:

>I disagree with this analysis for two reasons.

I must admit that Robert is correct to disagree.  I was wrong about what
the RM says, and what it was intended to say.

>1. Requiring range checks for the assignment of identical subtypes would
>   damage code quality severely.

That part, I don't buy, and I won't buy unless I see measurements of
real code.  My wild guess is that the damage would be not-much-worse
than the damage due to any of the other range checks and whatnot defined
by the language.  Robert's wild guess is that the damage would be much
worse.  The only way to know who's right would be to implement a
compiler that does the "extra" checks, and measure the speed of typical
programs with and without those checks.

>... In the most common cases (array elements
>   and procedure parameters), it is impossible for a compiler to prove
>   that data is initialized, so these checks would be all over the place.

I'm not sure what "most common" means here.  People don't copy arrays
one element at a time, usually.  They use whole-array assignment, which
happily copies uninitialized components just fine (and it must -- the RM
is clear on that point, and that's good).  As for parameters, the
compiler ought to do the checks at the call site, so that inside the
subprogram body, it can assume that the variable is within its subtype.
At the call site, more information is usually available, so that the
check can often be omitted.

>   While it is clear that damage can be done with some uses of uninitialized
>   variables, e.g. using them in case statements, so that checks are needed
>   there, the damage of a simple copy seems minimal, and the design idea 
>   behind the Ada 95 changes was to avoid extreme damage from erroneous
>   constructs in Ada 83 where practical, without introducing unacceptable
>   overhead.

Agreed (now).

>   If the language did require checks in such cases, then to me, it would
>   be a clear mistake in the language requirements (we have found a few
>   so far, the RM is not infallible), and would have to be fixed.
>
>2. The RM, in section 13.9.1, seems clear enough:

I disagree that it's *clear*, but I can agree with Robert's reading
below.

Note that the key thing is when the representation of the object
represents a value of its *type*, but not its *subtype*.  The RM says
that the values of an integer type are the *infinite* set of integers
(the ones we all learned about in grade school, before being polluted by
computers ;-)).  So if we have "type T is range 1..10;", the values of
subtype T are 1..10, but the values of the *type* are all the integers.
So if a given bit pattern represents 11, then its a value of the type,
but not the subtype, and must raise C_E when assigned to a variable of
subtype T.  However, the compiler is free to claim that this pattern
does not represent 11 (even though you might think it does).  In that
case, no C_E need be raised, which is Robert's point.

It gets more interesting with floating point, because an uninitialized
variable might contain a NaN.

>                          Bounded (Run-Time) Errors
>
>9   If the representation of a scalar object does not represent a value of
>the object's subtype (perhaps because the object was not initialized), the
>object is said to have an invalid representation.  It is a bounded error to
>evaluate the value of such an object.  If the error is detected, either
>Constraint_Error or Program_Error is raised.  Otherwise, execution continues
>using the invalid representation.  The rules of the language outside this
>subclause assume that all objects have valid representations.  The semantics
>of operations on invalid representations are as follows:
>
>   10  If the representation of the object represents a value of the
>       object's type, the value of the type is used.
>
>   11  If the representation of the object does not represent a value of
>       the object's type, the semantics of operations on such
>       representations is implementation-defined, but does not by itself
>       lead to erroneous or unpredictable execution, or to other objects
>       becoming abnormal.
>
>If we take the test program, it seems quite reasonable for an implementation
>to define the following behavior:
>
>  An assignment of an uninitialized value (that may be out of range) copies
>  the (possibly out of range) value into the target.
>
>  The conversion of an out of range value to a subtype that legitimately
>  includes the value simply gives the expected value, which is now in range
>  and hence cannot "lead to erroneous or unpredictable execution".

For the above reasoning to work, one must claim that all bit patterns
(other than the ones that represent 1..10) do not represent integer
values at all.  That is, the bit pattern (on a 32-bit machine):
"0000 0000 0000 0000  0000 0000 0000 1011" does *not* represent 11.  It
represents some non-Integer thing.  I find that interpretation slightly
surprising, but Tucker assured me (in private e-mail) that the *intent*
of the RM agrees with what Robert says here.

>One could I suppose argue that the output is unpredictable, but I would
>disagree. The predictable outcome of the above program is that some value
>in the range of Integer will be output. Yes, the output is non-deterministic,
>as are many legitimate Ada 95 programs, but non-deterministic is not the
>same as unpredictable!

Agreed.

>Bob Duff and I have always disagreed in this area. His balance of thinking
>is far over on the side of checking everything and to heck with the efficiency
>consequences. I take a more balanced (:-) view which worries about the
>efficiency of generated code more.

We've always disagreed on what the rule *should* say -- but I would hope
we could agree on what it *does* say.  (FWIW, I think the rule should be
that any read of an uninit scalar raises an exception.  Yes, this would
be a big efficiency hit.  But it would catch bugs, and if you don't like
it for efficiency reasons, you could pragma-Suppress it.  You also want
to avoid such checks when interfacing to the outside world.  Clearly,
this is not what the RM says, and I certainly wouldn't claim it does.  I
was hoping that my opinions about what it *ought* to say did not color
what it *does* say.)

>That being said, I think there are good arguments for making Normalize_Scalars
>push a compiler into a more agggressive mode when it comes to detecting
>out of range values.

I agree (there are good arguments), but none of those arguments are
supported by the RM, which is unfortunate.

- Bob




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

* Re: 'size attribute inheritance
  1997-09-03  0:00                     ` Robert A Duff
@ 1997-09-06  0:00                       ` Robert Dewar
  1997-09-08  0:00                         ` Robert A Duff
  0 siblings, 1 reply; 22+ messages in thread
From: Robert Dewar @ 1997-09-06  0:00 UTC (permalink / raw)




<<That part, I don't buy, and I won't buy unless I see measurements of
real code.  My wild guess is that the damage would be not-much-worse
than the damage due to any of the other range checks and whatnot defined
by the language.  Robert's wild guess is that the damage would be much
worse.  The only way to know who's right would be to implement a
compiler that does the "extra" checks, and measure the speed of typical
programs with and without those checks.>>

These are not "wild guesses", they are based on data obtained from looking
at the Alsys compiler on the x86 when I was working on that. I am recalling
that introducing simple assignment subrange checks resulted in an increase
by a significant factor of the penalty due to checks. This is not surprising.
Particularly in the floating-point case, range checks are extremely
expensive, because they may break the pipeline, and a comparison takes
as much time as a multiply on typical machines. I am sorry, I no long
er have the exact data, because I discarded all this material when I
stopped working for Alsys.

But just think about a bit, and I think you will see why it is a significant
extra hit. Consider a loop

   for J in ....
     S := S + A(J)*B(J);
   end loop;

Now on a typical high performance RISC machine, with a multiply add
instruction, we are seeing in the loop

two loads -- which can be scheduled if the loop is unrolled
one fused-multiply-add
one increment-and-loop operation

Now on many modern RISC machines with super scalar capability, we can
approach 1 clock to issue all these instructions, and certainly 2 clocks
is achievable on a number of architectures.

But Bob wants to add two comparison instructions (yes, you need them, 
because the uninitialized value may look like a Nan or infinity).

This can easily double the number of instructions in the loop, and on
some architectures, would triple the number of instructions in the loop.

Note that the requirement for checking that actually is *in* the RM adds
virtually no overhead to this loop, but Bob's wished for change in the RM
could double or triple the execution time of this very typical fpt inner
loop.





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

* Re: 'size attribute inheritance
  1997-09-06  0:00                       ` Robert Dewar
@ 1997-09-08  0:00                         ` Robert A Duff
  0 siblings, 0 replies; 22+ messages in thread
From: Robert A Duff @ 1997-09-08  0:00 UTC (permalink / raw)



In article <dewar.873602116@merv>, Robert Dewar <dewar@merv.cs.nyu.edu> wrote:
>But just think about a bit, and I think you will see why it is a significant
>extra hit. Consider a loop
>
>   for J in ....
>     S := S + A(J)*B(J);
>   end loop;

Can you please clarify this example?  Which of S, or A's or B's
components are you assuming are, or might be, uninitialized?
And is the subtype constrained or not?

>Now on a typical high performance RISC machine, with a multiply add
>instruction, we are seeing in the loop
>
>two loads -- which can be scheduled if the loop is unrolled
>one fused-multiply-add
>one increment-and-loop operation
>
>Now on many modern RISC machines with super scalar capability, we can
>approach 1 clock to issue all these instructions, and certainly 2 clocks
>is achievable on a number of architectures.
>
>But Bob wants to add two comparison instructions (yes, you need them, 
>because the uninitialized value may look like a Nan or infinity).

I must admit I was thinking about integer operations, not floating
point.  I'm not an expert in floating point.  What will NaN's do in this
case?  Trap?  Or simply proagate through?

>This can easily double the number of instructions in the loop, and on
>some architectures, would triple the number of instructions in the loop.
>
>Note that the requirement for checking that actually is *in* the RM adds
>virtually no overhead to this loop, but Bob's wished for change in the RM
>could double or triple the execution time of this very typical fpt inner
>loop.

Perhaps our philosophical difference is that I'm perfectly happy to have
2X or 3X efficiency hit on *some* operations, so long as I have the
ability to suppress checks when these operations happen to be in an
inner loop (or whatever), and therefore affect the efficiency of the
application in an important way.  I'm perfectly happy to test my code
twice (once with checks on, once with checks off).

Would you be happy with my "wished-for" rules if applied only to
non-floats?

Please don't confuse my position with those who say, "what the heck?
computers are fast, and getting faster, so efficiency doesn't matter
(much)".  Efficiency *does* matter.  It matters a lot.  It matters as
much as correctness.

- Bob




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

end of thread, other threads:[~1997-09-08  0:00 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
1997-08-09  0:00 'size attribute inheritance Carlos Palenzuela
1997-08-10  0:00 ` Matthew Heaney
1997-08-11  0:00   ` Robert Dewar
1997-08-12  0:00     ` Matthew Heaney
1997-08-13  0:00       ` Robert A Duff
1997-08-13  0:00         ` Matthew Heaney
1997-08-14  0:00           ` Robert A Duff
1997-08-14  0:00             ` Dale Stanbrough
1997-08-16  0:00           ` Robert Dewar
1997-08-16  0:00             ` Ken Garlington
1997-08-17  0:00               ` Robert A Duff
1997-08-17  0:00               ` Robert Dewar
1997-08-18  0:00                 ` Robert A Duff
     [not found]                   ` <dewar.872433846@merv>
1997-09-03  0:00                     ` Robert A Duff
1997-09-06  0:00                       ` Robert Dewar
1997-09-08  0:00                         ` Robert A Duff
1997-08-13  0:00       ` Ken Garlington
1997-08-13  0:00         ` Matthew Heaney
1997-08-10  0:00 ` Robert A Duff
1997-08-10  0:00 ` Robert Dewar
1997-08-11  0:00   ` Ken Garlington
1997-08-11  0:00   ` Matthew Heaney

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