darcs patch: Replace FastInt with unpacked/newtyped Int

Twan van Laarhoven twanvl at gmail.com
Sun Feb 3 22:10:29 EST 2008


Hello,

This patch changes Unique from

   data Unique = MkUnique FastInt

to

   newtype Unique = MkUnique Int

Since this is performance critical code, I have checked the compiler output 
(core and stg), to check that it is really the same. The only difference is an 
improvement. mkUniqueGrimely no longer has to unbox and rebox its argument:

   OldUnique.mkUniqueGrimily =
    \r [x]
      case x of wild { GHC.Base.I# x1 -> Unique.MkUnique [x1]; };

   NewUnique.mkUniqueGrimily = \r [x] x;

This simplifies this module a lot, since the ugly FastInt functions are no 
longer needed.


The second part of this patch does a similar thing for UniqSupply, changing from

   data UniqSupply = MkSplitUniqSupply FastInt MoreStuff

to

   data UniqSupply = MkSplitUniqSupply {-# UNPACK #-} !Unique MoreStuff

Again, the core and stg are the same.


When also trying to change the FastInt in Var to an unpacked Unique I ran into a 
bug (#2070); The record selector realUnique will not be optimized at all.

If I write it out manually I do get a good result, but not exactly the same. In 
particular I get:

   NewVar.varUnique =
     \r [ds]
	case ds of wild {
	  NewVar.TyVar    ds1 rb ds2 ds3 -> GHC.Base.I# [rb];
	  NewVar.TcTyVar  ds1 rb ds2 ds3 -> GHC.Base.I# [rb];
	  NewVar.GlobalId ds1 rb ds2 ds3 ds4 -> GHC.Base.I# [rb];
	  NewVar.LocalId  ds1 rb ds2 ds3 ds4 -> GHC.Base.I# [rb];
	};

Versus the previous:

   OldVar.varUnique =
     \r [var]
	case
	    case var of tpl {
	      OldVar.TyVar    ipv ipv1 ipv2 ipv3 -> ipv1;
	      OldVar.TcTyVar  ipv ipv1 ipv2 ipv3 -> ipv1;
	      OldVar.GlobalId ipv ipv1 ipv2 ipv3 ipv4 -> ipv1;
	      OldVar.LocalId  ipv ipv1 ipv2 ipv3 ipv4 -> ipv1;
	    }
	of
	wild
	{ __DEFAULT -> GHC.Base.I# [wild];
	};

In other words, the boxing is taken out of the case branches. I don't know 
whether this is an improvement or not. It might reduce code size. This function 
is inlined in the comparison operators, here the difference becomes larger. The 
new code looks like (pseudocode):

   NewVar.== a b
      = case a of
                TyVar _ c _ _ ->
                      case b of
                          TyVar    _ d _ _   -> c ==# d
                          TcTyVar  _ d _ _   -> c ==# d
                          GlobalId _ d _ _ _ -> c ==# d
                          LocalId  _ d _ _ _ -> c ==# d
                 TcTyVar _ c _ _ ->
                      etc.

Here 'varUnique b' is inlined for each branch of 'varUnique a'. Whereas the old 
code is a lot shorter, because the unique of the first parameter is first put 
into a variable,

  OldVar.== a b
      = case (case a of
                 TyVar    _ c _ _   -> c
                 TcTyVar  _ c _ _   -> c
                 GlobalId _ c _ _ _ -> c
                 LocalId  _ c _ _ _ -> c
             ) of
          c -> case (case b of
                 TyVar    _ d _ _   -> d
                 TcTyVar  _ d _ _   -> d
                 GlobalId _ d _ _ _ -> d
                 LocalId  _ d _ _ _ -> d
             ) of
          d -> c ==# d

Again, I don't know what this will do for performance, but it doesn't look like 
an improvement.

Twan
-------------- next part --------------
A non-text attachment was scrubbed...
Name: fastint-to-unpack1.patch.gz
Type: application/x-gzip
Size: 47727 bytes
Desc: not available
Url : http://www.haskell.org/pipermail/cvs-ghc/attachments/20080204/d880a31c/fastint-to-unpack1.patch-0001.bin


More information about the Cvs-ghc mailing list