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