question about coercions between primitive types in STG level

Simon Marlow marlowsd at gmail.com
Thu Dec 17 17:15:34 UTC 2015


On 10/12/2015 02:45, Ömer Sinan Ağacan wrote:
> 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.

Sorry, I searched too but I couldn't find it.  I did find an 
implementation of the conversion in GHC (ByteCodeAsm.mkLitD).

> 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.

I'm not sure what you did to get to this point, but let me elaborate on 
what I think is needed:

- Add primops for the conversions
- Add appropriate MachOps for the conversions (F32 -> I32, F64 -> I64)
- Make sure the primops get compiled into the appropriate MachOps (see 
StgCmmPrim)
- Implement those MachOps in the native code generator (X86/CodeGen.hs). 
  For this part you'll need to figure out what the appropriate 
x86/x86_64 instructions to generate are; it may be that you need to go 
via memory, which would be unfortunate.

Cheers,
Simon

> 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