question about coercions between primitive types in STG level

Ömer Sinan Ağacan omeragacan at gmail.com
Thu Dec 10 02:45:59 UTC 2015


Thanks for all the answers,

Simon, do you remember anything about the ticket about converting between
floating point types and integers? I spend quite a bit of time in Trac
searching for this but couldn't find it.


Before implementing a new primop, MachOp, and code generation functions for
that I tried this: Since type signature of this new primop will be same as
float2Int# I thought maybe I should first make current implementation working,
and then I can just change the primop to coerceFloat2Int# and it would work.

However I'm still this same problem(illegal assembly). What I changed is I
looked at the GHC-generated, working STG code that uses float2Int#, and tried
to generate a very similar code myself. The change I had to make for this was
to use a case expression instead of let expression to bind result of this
primop.

Here's an example. This STG is working fine:

    sat_s1Ic :: GHC.Types.Float -> GHC.Types.IO () =
        \r srt:SRT:[0B :-> System.IO.print,
                    rUB :-> GHC.Show.$fShowInt] [ds_s1I7]
            case
                ds_s1I7 :: GHC.Types.Float :: Alg GHC.Types.Float
            of
            (wild_s1I8 :: GHC.Types.Float)
            { GHC.Types.F# (f_s1I9 :: GHC.Prim.Float#) ->
                  case
                      float2Int# [(f_s1I9 :: GHC.Prim.Float#)] :: Prim
GHC.Prim.Int#
                  of
                  (sat_s1Ia :: GHC.Prim.Int#)
                  { __DEFAULT ->
                        let {
                          sat_s1Ib :: GHC.Types.Int =
                              NO_CCS GHC.Types.I#! [(sat_s1Ia ::
GHC.Prim.Int#)];
                        } in
                          System.IO.print
                            :: forall a_aUq. GHC.Show.Show a_aUq =>
a_aUq -> GHC.Types.IO ()
                              (GHC.Show.$fShowInt :: GHC.Show.Show
GHC.Types.Int)
                              (sat_s1Ib :: GHC.Types.Int);
                  };
            };

(Sorry for extra noisy output, I changed Outputable instances to print some
extra info)

This code is generated by GHC for a program that uses the primop directly and
it's working. This is the code generated by my pass:

    Main.main2 :: [GHC.Types.Char] =
        \u srt:SRT:[r4 :-> Main.showEither2] []
            case
                case
                    float2Int# [1.2#] :: Prim GHC.Prim.Int#
                of
                (co_g21m :: GHC.Prim.Int#)
                { __DEFAULT -> (#,#) [2## (co_g21m :: GHC.Prim.Int#)];
                } :: UbxTup 2
            of
            (sat_s21b :: (# GHC.Prim.Int#, GHC.Prim.Int# #))
            { (#,#) (sat_g21R :: GHC.Prim.Int#) (sat_g21S :: GHC.Prim.Int#) ->
                  Main.showEither2
                    :: (# GHC.Prim.Int#, GHC.Prim.Int# #) -> [GHC.Types.Char]
                      (sat_g21R :: GHC.Prim.Int#) (sat_g21S :: GHC.Prim.Int#);
            };

Types look correct, and I'm using a case expression to bind the result of the
primop. But generated assembly for this is still invalid! I'm wondering if
there are some invariants that I'm invalidating here, even although -dstg-lint
is passing. Does anyone know what I might be doing wrong here?

One thing that I'm not being very careful is the information about live
variables, but I don't see how it might be related with this illegal
instruction error.

Thanks again..

2015-12-07 13:57 GMT-05:00 Simon Marlow <marlowsd at gmail.com>:
> Simon's right, you need an explicit conversion, and unfortunately those
> conversions don't currently exist.  You would have to add them to the MachOp
> type, and implement them in each of the native code generators.
>
> The good news is that if you did this, we could implement cheap conversions
> between the IEEE floating point types and their representations as unboxed
> integers, which is currently done by poking the values to memory and then
> peeking them back at the desired type. There's a ticket for this around
> somewhere....
>
> Cheers
> Simon
>
>
> On 07/12/2015 12:23, Simon Peyton Jones wrote:
>>
>> If memory serves, there are primops for converting between unboxed values
>> of different widths.
>>
>> Certainly converting between a float and a non-float will require an
>> instruction on some architectures, since they use different register sets.
>>
>> Re (2) I have no idea.  You'll need to get more information... pprTrace or
>> something.
>>
>> Simon
>>
>> |  -----Original Message-----
>> |  From: ghc-devs [mailto:ghc-devs-bounces at haskell.org] On Behalf Of Ömer
>> |  Sinan Agacan
>> |  Sent: 06 December 2015 18:25
>> |  To: ghc-devs <ghc-devs at haskell.org>
>> |  Subject: question about coercions between primitive types in STG level
>> |
>> |  Hi all,
>> |
>> |  In my compiler pass(D1559, see ElimUbxSums.hs) I'm doing some unsafe
>> |  coercions at the STG level. It works fine for lifted types, but for
>> |  unlifted ones I'm having some problems. What I'm trying to do is given
>> |  a number of primitive types I'm finding the one with biggest size, and
>> |  then generating a constructor that takes this biggest primitive type
>> |  as argument.
>> |
>> |  The problem is that this is not working very well - GHC is generating
>> |  illegal instructions that try to load a F32 value to a register
>> |  allocated for I64, using movss instruction.
>> |
>> |  CoreLint is catching this error and printing this:
>> |
>> |      Cmm lint error:
>> |        in basic block c1hF
>> |          in assignment:
>> |            _g16W::I64 = 4.5 :: W32;   // CmmAssign
>> |            Reg ty: I64
>> |            Rhs ty: F32
>> |
>> |  So I have two questions about this:
>> |
>> |  1. Is there a way to safely do this? What are my options here? What
>> |  I'm trying
>> |     to do is to use a single data constructor field for different
>> |  primitive
>> |     types.  The field is guaranteed to be as big as necessary.
>> |
>> |  2. In the Cmm code shown above, the type annotation is showing `W32`
>> |  but in the
>> |     error message it says `F32`. I'm confused about this, is this error
>> |  message
>> |     given because the sizes don't match? (64bits vs 32bits) Why the
>> |  type
>> |     annotation says W32 while the value has type F32?
>> |
>> |  Thanks..
>> |  _______________________________________________
>> |  ghc-devs mailing list
>> |  ghc-devs at haskell.org
>> |  https://na01.safelinks.protection.outlook.com/?url=http%3a%2f%2fmail.h
>> |  askell.org%2fcgi-bin%2fmailman%2flistinfo%2fghc-
>> |  devs&data=01%7c01%7csimonpj%40064d.mgd.microsoft.com%7ced6a1fbfa6254e5
>> |  2a7d808d2fe6a9a63%7c72f988bf86f141af91ab2d7cd011db47%7c1&sdata=7j3fQs4
>> |  ox67SZbA4jv4uPVVdvp5X5yUUuMaqp4sh%2fpg%3d
>> _______________________________________________
>> ghc-devs mailing list
>> ghc-devs at haskell.org
>> http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
>>
>


More information about the ghc-devs mailing list