[M3devel] opacity of Target.Int, overflow of Target.Int

Tony Hosking hosking at cs.purdue.edu
Sun Feb 21 20:23:20 CET 2010


On 21 Feb 2010, at 05:31, Jay K wrote:

> 1) Tony, I claim that if Target.Int is really opaque, then values of it should only be formed in Target.i3/Target.m3.
> Or TInt/TWord/.i3/.m3, since they know deeply about it.
> Having m3back know about them seems a bit off.
> Granted, pushing constants that only m3back uses into Target/TInt/TWord isn't great either, pollutes them some.
> This is a minor dilemna though.

Yeah, but it doesn't need to be totally opaque does it?  An array of sign-extended bytes in little-endian order seems pretty general.  You don't even need to specify the length of the array.  I actually contemplated having TInt take open arrays of arbitrary length, with the result array length indicating the precision desired, but didn't do that just to maintain a simple implementation.

>  2) Are you sure having a fixed precision of 8 bytes is correct here?

There is nothing to stop it having more precision.  In fact, increasing the size shouldn't affect any client code (so long as it uses appropriate array constructors to fill the sign in to the end, and performs bounds-checking to results to the desired precision, as well as checking the return values for potential overflow in whatever precision is implemented by TInt).

> More generally are you sure TInt has the right interface?
> How does one check for overflow within the precision one cares about?

Bounds check.

> I think I know.
> I think Chop should return a boolean, as to if the value fits.

No, because you may choose to ignore the high bits yet still want to sign-extend from the precision desired.  That is exactly what I do for word operations in the front-end.

> For that matter, have SignedChop and UnsignedChop.

You should not need these.

>  Or TInt.Chop and TWord.Chop.

What do you need TWord.Chop for.  For example, TWord.And(val, Target.Word.max) gives me just the bits I need for a Word.Size full value.

Take a look at the (relatively small number of) changes I made to the front-end to do the appropriate checks and conversions.

> TInt.Chop is already SignedChop.
>  
> Do the math in 64bits, if that overflows, then overflow.
> And then truncate to whatever, and that can overflow too.
> This is related to "you all have convinced me that overflow isn't
> all that important really, but range checking is".
> So you in sense defer the overflow. You don't do the complete
> overflow check at Add or whatever, but then you do a range
> check converting to a small size.
>  
> But hm. This will skip "intermediate overflow". Does that matter?
> 1 billion * 8 / 8
>  
>  
> Should that overflow in 32bits?
>  
>  
> Well, easy enough, do the chop after each operation.
> I said "defer", but it is brief.
> 1B * 8 / 8
> isn't written as
> 1* 8 / 8
> convert to 32bits
>  
> but rather
> 1B * 8
> convert to 32bits
>  => failure here 
> / 8
> convert to 32bits
>  
> ?
>  
>  
> 3) Related to #2.
> Where should RightShift insert zeros?
> I guess you chop first, and then it works.
>  
>  
> Proposed something like:
>  
> 
> TInt:
> PROCEDURE Chop (VAR r: Int;  n: CARDINAL): BOOLEAN =
>   VAR extension := Mask * ORD(And (r [n-1], SignMask) = 0);
>         result := TRUE;
>   BEGIN
>      FOR i := n TO LAST(Int) DO
>       result := (result AND (r[i] # extension));
>       r[i] := extension;
>     END;
>     return result;
>   END Chop;
> 
> TWord:
> PROCEDURE Chop (VAR r: Int;  n: CARDINAL): BOOLEAN =
>   CONST extension = 0;
>   VAR result := TRUE;
>   BEGIN
>      FOR i := n TO LAST(Int) DO
>       result := (result AND (r[i] # extension));
>       r[i] := extension;
>     END;
>     return result;
>   END Chop;
> 
>  
>  
> But I have to back to your version of m3back and try these out.
> Very speculative at the moment.
>  
> Could also leave the data alone upon failure, trivially related to previous:
>  
> TInt:
> PROCEDURE Chop (VAR r: Int;  n: CARDINAL): BOOLEAN =
>   VAR extension := Mask * ORD(And (r [n-1], SignMask) = 0);
>   BEGIN
>      FOR i := n TO LAST(Int) DO
>       IF r[i] # extension THEN
>         RETURN FALSE;
>       END;
>     END;
>     FOR i := n TO LAST(Int) DO
>       r[i] := extension;
>     END;
>     RETURN TRUE;
>   END Chop;
> 
>  
> TWord:
> PROCEDURE Chop (VAR r: Int;  n: CARDINAL): BOOLEAN =
>   VAR result := TRUE;
>   BEGIN
>      FOR i := n TO LAST(Int) DO
>       IF r[i] # 0 THEN
>         RETURN FALSE;
>        END;
>     END;
>      FOR i := n TO LAST(Int) DO
>       r[i] := 0;
>     END;
>     return TRUE;
>   END Chop;
> 
>  
> I'm not sure I like the subtlety of TInt.Chop vs. TWord.Chop.
> I'd prefer TInt.UnsignedChop and TInt.SignedChop.
> Granted, "Un" doesn't exactly stand out, but at least "signed" does and makes you wonder about and discover the existance of signed vs. unsigned.
>  
>  
> Alternatively Chop and UChop. More subtle, but I think plenty programmars are used to the names "uchar", "ushort", "uint", "ulong". "u" is pretty widely recognized as meaning "unsigned". More so I believe than "Word".
> (I still don't like the name "interface Long"!, it doesn't imply unsigned at all!)
>  
>  
>  - Jay

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://m3lists.elegosoft.com/pipermail/m3devel/attachments/20100221/90e90b7d/attachment-0002.html>


More information about the M3devel mailing list