[MLton] IntInf implementation questions

Matthew Fluet fluet@cs.cornell.edu
Mon, 6 Feb 2006 14:07:59 -0500 (EST)


>> I think this is an artefact of the long-gone days before MLton
>> supported overflow.  It seems fine to replace as you suggest.
>
> In fact, since the IntInf implementation has not been substantially
> revised since those days, it probably has a number of similar
> artefacts that would benefit from rewriting to take advantage of
> overflow.

I don't see any others.  Given two IntInf integers represented as small 
integers (say, 32 bits == 31 bits data + 1 bit tag), then the small 
integer + and - (say, Int32.+ and Int32.-) can't overflow, although the 
resulting value may not be expressible as a small integer with a tag bit.

Of course, we could use overflow checking if we don't completely convert 
the small integer into it's 32 bit representation.  That is, consider 
bigPlus:

       (* Coercion to/from 32-bit representation. *)
       fun stripTag (arg: bigInt): Word.word =
          Word.~>> (Prim.toWord arg, 0w1)
       fun addTag (argw: Word.word): Word.word =
          Word.orb (Word.<< (argw, 0w1), 0w1)

       fun zeroTag (arg: bigInt): Word.word =
          Word.andb (Prim.toWord arg, 0wxFFFFFFFE)
       fun incTag (argw: Word.word): Word.word =
          Word.orb (argw, 0w1)

       (* Check if two words have the same sign bit. *)
       fun sameSign (lhs: Word.word, rhs: Word.word): bool =
          Word.toIntX (Word.xorb (lhs, rhs)) >= 0

       fun bigPlus (lhs: bigInt, rhs: bigInt): bigInt =
          let
             val res =
                if areSmall (lhs, rhs)
                   then let val ansv = Word.+ (stripTag lhs, stripTag rhs)
                            val ans = addTag ansv
                        in if sameSign (ans, ansv)
                              then SOME (Prim.fromWord ans)
                           else NONE
                        end
                else NONE
          in
             case res of
                NONE =>
                   dontInline
                   (fn () =>
                    Prim.+ (lhs, rhs, reserve (Int.max (size lhs, size rhs), 1)))
              | SOME i => i
          end

On the small fast path, I count 6 bitops and one comparison test.  (Note 
that Word.{fromInt,toIntX} are the identity functions.)  I think the 
following is equivalent:

       fun bigPlus (lhs: bigInt, rhs: bigInt): bigInt =
          let
             val res =
                if areSmall (lhs, rhs)
                   then let val ansv = Int.+ (Word.toIntX (Prim.toWord lhs),
                                              Word.toIntX (zeroTag rhs))
                        in SOME (Prim.fromWord (Word.fromInt ansv))
                        end handle Overflow => NONE
                else NONE
          in
             case res of
                NONE =>
                   dontInline
                   (fn () =>
                    Prim.+ (lhs, rhs, reserve (Int.max (size lhs, size rhs), 1)))
              | SOME i => i
          end

On the small fast path, I count 2 bitops and one overflow test.  I think 
you can do the same thing for bigMinus.