summaryrefslogtreecommitdiff
path: root/compiler/vectorise/Vectorise/Generic/PAMethods.hs
blob: 0d5d37c7d7af56c7b73d7c7e892abb0804336740 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584

-- | Generate methods for the PA class.
--
--   TODO: there is a large amount of redundancy here between the 
--   a, PData a, and PDatas a forms. See if we can factor some of this out.
--
module Vectorise.Generic.PAMethods
  ( buildPReprTyCon
  , buildPAScAndMethods 
  ) where

import Vectorise.Utils
import Vectorise.Monad
import Vectorise.Builtins
import Vectorise.Generic.Description
import CoreSyn
import CoreUtils
import FamInstEnv
import MkCore            ( mkWildCase, mkCoreLet )
import TyCon
import CoAxiom
import Type
import OccName
import Coercion
import MkId
import FamInst
import TysPrim( intPrimTy )

import DynFlags
import FastString
import MonadUtils
import Control.Monad
import Outputable


buildPReprTyCon :: TyCon -> TyCon -> SumRepr -> VM FamInst
buildPReprTyCon orig_tc vect_tc repr
 = do name      <- mkLocalisedName mkPReprTyConOcc (tyConName orig_tc)
      rhs_ty    <- sumReprType repr
      prepr_tc  <- builtin preprTyCon
      let axiom = mkSingleCoAxiom name tyvars prepr_tc instTys rhs_ty
      liftDs $ newFamInst SynFamilyInst axiom
  where
    tyvars = tyConTyVars vect_tc
    instTys = [mkTyConApp vect_tc . mkTyVarTys $ tyConTyVars vect_tc]

-- buildPAScAndMethods --------------------------------------------------------

-- | This says how to build the PR superclass and methods of PA
--   Recall the definition of the PA class:
--
--   @
--    class class PR (PRepr a) => PA a where
--      toPRepr       :: a                -> PRepr a
--      fromPRepr     :: PRepr a          -> a
--
--      toArrPRepr    :: PData a          -> PData (PRepr a)
--      fromArrPRepr  :: PData (PRepr a)  -> PData a
--
--      toArrPReprs   :: PDatas a         -> PDatas (PRepr a)
--      fromArrPReprs :: PDatas (PRepr a) -> PDatas a
--   @
--
type PAInstanceBuilder
        =  TyCon        -- ^ Vectorised TyCon 
        -> CoAxiom Unbranched
                        -- ^ Coercion to the representation TyCon
        -> TyCon        -- ^ 'PData'  TyCon
        -> TyCon        -- ^ 'PDatas' TyCon
        -> SumRepr      -- ^ Description of generic representation.
        -> VM CoreExpr  -- ^ Instance function.


buildPAScAndMethods :: VM [(String, PAInstanceBuilder)]
buildPAScAndMethods
 = return [ ("toPRepr",       buildToPRepr)
          , ("fromPRepr",     buildFromPRepr)
          , ("toArrPRepr",    buildToArrPRepr)
          , ("fromArrPRepr",  buildFromArrPRepr)
          , ("toArrPReprs",   buildToArrPReprs)
          , ("fromArrPReprs", buildFromArrPReprs)]


-- buildToPRepr ---------------------------------------------------------------
-- | Build the 'toRepr' method of the PA class.
buildToPRepr :: PAInstanceBuilder
buildToPRepr vect_tc repr_ax _ _ repr
 = do let arg_ty = mkTyConApp vect_tc ty_args

      -- Get the representation type of the argument.
      res_ty <- mkPReprType arg_ty

      -- Var to bind the argument
      arg    <- newLocalVar (fsLit "x") arg_ty

      -- Build the expression to convert the argument to the generic representation.
      result <- to_sum (Var arg) arg_ty res_ty repr

      return $ Lam arg result
  where
    ty_args        = mkTyVarTys (tyConTyVars vect_tc)

    wrap_repr_inst = wrapTypeUnbranchedFamInstBody repr_ax ty_args

    -- CoreExp to convert the given argument to the generic representation.
    -- We start by doing a case branch on the possible data constructors.
    to_sum :: CoreExpr -> Type -> Type -> SumRepr -> VM CoreExpr
    to_sum _ _ _ EmptySum
     = do void <- builtin voidVar
          return $ wrap_repr_inst $ Var void

    to_sum arg arg_ty res_ty (UnarySum r)
     = do (pat, vars, body) <- con_alt r
          return $ mkWildCase arg arg_ty res_ty
                   [(pat, vars, wrap_repr_inst body)]

    to_sum arg arg_ty res_ty (Sum { repr_sum_tc  = sum_tc
                                  , repr_con_tys = tys
                                  , repr_cons    =  cons })
     = do alts <- mapM con_alt cons
          let alts' = [(pat, vars, wrap_repr_inst
                                   $ mkConApp sum_con (map Type tys ++ [body]))
                        | ((pat, vars, body), sum_con)
                            <- zip alts (tyConDataCons sum_tc)]
          return $ mkWildCase arg arg_ty res_ty alts'

    con_alt (ConRepr con r)
     = do (vars, body) <- to_prod r
          return (DataAlt con, vars, body)

    -- CoreExp to convert data constructor fields to the generic representation.
    to_prod :: ProdRepr -> VM ([Var], CoreExpr)
    to_prod EmptyProd
     = do void <- builtin voidVar
          return ([], Var void)

    to_prod (UnaryProd comp)
     = do var  <- newLocalVar (fsLit "x") (compOrigType comp)
          body <- to_comp (Var var) comp
          return ([var], body)

    to_prod (Prod { repr_tup_tc   = tup_tc
                  , repr_comp_tys = tys
                  , repr_comps    = comps })
     = do vars  <- newLocalVars (fsLit "x") (map compOrigType comps)
          exprs <- zipWithM to_comp (map Var vars) comps
          let [tup_con] = tyConDataCons tup_tc
          return (vars, mkConApp tup_con (map Type tys ++ exprs))

    -- CoreExp to convert a data constructor component to the generic representation.
    to_comp :: CoreExpr -> CompRepr -> VM CoreExpr
    to_comp expr (Keep _ _) = return expr
    to_comp expr (Wrap ty)  = wrapNewTypeBodyOfWrap expr ty


-- buildFromPRepr -------------------------------------------------------------

-- |Build the 'fromPRepr' method of the PA class.
--
buildFromPRepr :: PAInstanceBuilder
buildFromPRepr vect_tc repr_ax _ _ repr
  = do
      arg_ty <- mkPReprType res_ty
      arg <- newLocalVar (fsLit "x") arg_ty

      result <- from_sum (unwrapTypeUnbranchedFamInstScrut repr_ax ty_args (Var arg))
                         repr
      return $ Lam arg result
  where
    ty_args = mkTyVarTys (tyConTyVars vect_tc)
    res_ty  = mkTyConApp vect_tc ty_args

    from_sum _ EmptySum
     = do dummy <- builtin fromVoidVar
          return $ Var dummy `App` Type res_ty

    from_sum expr (UnarySum r) = from_con expr r
    from_sum expr (Sum { repr_sum_tc  = sum_tc
                       , repr_con_tys = tys
                       , repr_cons    = cons })
     = do vars  <- newLocalVars (fsLit "x") tys
          es    <- zipWithM from_con (map Var vars) cons
          return $ mkWildCase expr (exprType expr) res_ty
                   [(DataAlt con, [var], e)
                      | (con, var, e) <- zip3 (tyConDataCons sum_tc) vars es]

    from_con expr (ConRepr con r)
      = from_prod expr (mkConApp con $ map Type ty_args) r

    from_prod _ con EmptyProd = return con
    from_prod expr con (UnaryProd r)
     = do e <- from_comp expr r
          return $ con `App` e
     
    from_prod expr con (Prod { repr_tup_tc   = tup_tc
                             , repr_comp_tys = tys
                             , repr_comps    = comps
                             })
     = do vars <- newLocalVars (fsLit "y") tys
          es   <- zipWithM from_comp (map Var vars) comps
          let [tup_con] = tyConDataCons tup_tc
          return $ mkWildCase expr (exprType expr) res_ty
                   [(DataAlt tup_con, vars, con `mkApps` es)]

    from_comp expr (Keep _ _) = return expr
    from_comp expr (Wrap ty)  = unwrapNewTypeBodyOfWrap expr ty


-- buildToArrRepr -------------------------------------------------------------

-- |Build the 'toArrRepr' method of the PA class.
--
buildToArrPRepr :: PAInstanceBuilder
buildToArrPRepr vect_tc repr_co pdata_tc _ r
 = do arg_ty <- mkPDataType el_ty
      res_ty <- mkPDataType =<< mkPReprType el_ty
      arg    <- newLocalVar (fsLit "xs") arg_ty

      pdata_co <- mkBuiltinCo pdataTyCon
      let co           = mkAppCo pdata_co
                       . mkSymCo
                       $ mkUnbranchedAxInstCo Nominal repr_co ty_args

          scrut   = unwrapFamInstScrut pdata_tc ty_args (Var arg)

      (vars, result) <- to_sum r

      return . Lam arg
             $ mkWildCase scrut (mkTyConApp pdata_tc ty_args) res_ty
               [(DataAlt pdata_dc, vars, mkCast result co)]
  where
    ty_args    = mkTyVarTys $ tyConTyVars vect_tc
    el_ty      = mkTyConApp vect_tc ty_args
    [pdata_dc] = tyConDataCons pdata_tc

    to_sum ss
     = case ss of
        EmptySum    -> builtin pvoidVar >>= \pvoid -> return ([], Var pvoid) 
        UnarySum r  -> to_con r
        Sum{}
         -> do  let psum_tc     =  repr_psum_tc ss
                let [psum_con]  =  tyConDataCons psum_tc
                (vars, exprs)   <- mapAndUnzipM to_con (repr_cons ss)
                sel             <- newLocalVar (fsLit "sel") (repr_sel_ty ss)
                return ( sel : concat vars
                       , wrapFamInstBody psum_tc (repr_con_tys ss)
                         $ mkConApp psum_con 
                         $ map Type (repr_con_tys ss) ++ (Var sel : exprs))

    to_prod ss
     = case ss of
        EmptyProd    -> builtin pvoidVar >>= \pvoid -> return ([], Var pvoid)
        UnaryProd r
         -> do  pty  <- mkPDataType (compOrigType r)
                var  <- newLocalVar (fsLit "x") pty
                expr <- to_comp (Var var) r
                return ([var], expr)
        Prod{}
         -> do  let [ptup_con]  = tyConDataCons (repr_ptup_tc ss)
                ptys   <- mapM (mkPDataType . compOrigType) (repr_comps ss)
                vars   <- newLocalVars (fsLit "x") ptys
                exprs  <- zipWithM to_comp (map Var vars) (repr_comps ss)
                return ( vars
                       , wrapFamInstBody (repr_ptup_tc ss) (repr_comp_tys ss)
                         $ mkConApp ptup_con
                         $ map Type (repr_comp_tys ss) ++ exprs)

    to_con (ConRepr _ r)    = to_prod r

    to_comp expr (Keep _ _) = return expr
    to_comp expr (Wrap ty)  = wrapNewTypeBodyOfPDataWrap expr ty


-- buildFromArrPRepr ----------------------------------------------------------

-- |Build the 'fromArrPRepr' method for the PA class.
--
buildFromArrPRepr :: PAInstanceBuilder
buildFromArrPRepr vect_tc repr_co pdata_tc _ r
 = do arg_ty <- mkPDataType =<< mkPReprType el_ty
      res_ty <- mkPDataType el_ty
      arg    <- newLocalVar (fsLit "xs") arg_ty

      pdata_co <- mkBuiltinCo pdataTyCon
      let co           = mkAppCo pdata_co
                       $ mkUnbranchedAxInstCo Nominal repr_co var_tys

      let scrut        = mkCast (Var arg) co

      let mk_result args
            = wrapFamInstBody pdata_tc var_tys
            $ mkConApp pdata_con
            $ map Type var_tys ++ args

      (expr, _) <- fixV $ \ ~(_, args) ->
                     from_sum res_ty (mk_result args) scrut r

      return $ Lam arg expr
 where
    var_tys     = mkTyVarTys $ tyConTyVars vect_tc
    el_ty       = mkTyConApp vect_tc var_tys
    [pdata_con] = tyConDataCons pdata_tc

    from_sum res_ty res expr ss
     = case ss of
        EmptySum    -> return (res, [])
        UnarySum r  -> from_con res_ty res expr r
        Sum {}
         -> do  let psum_tc    =  repr_psum_tc ss
                let [psum_con] =  tyConDataCons psum_tc
                sel            <- newLocalVar (fsLit "sel") (repr_sel_ty ss)
                ptys           <- mapM mkPDataType (repr_con_tys ss)
                vars           <- newLocalVars (fsLit "xs") ptys
                (res', args)   <- fold from_con res_ty res (map Var vars) (repr_cons ss)
                let scrut      =  unwrapFamInstScrut psum_tc (repr_con_tys ss) expr
                let body       =  mkWildCase scrut (exprType scrut) res_ty
                                    [(DataAlt psum_con, sel : vars, res')]
                return (body, Var sel : args)

    from_prod res_ty res expr ss
     = case ss of
        EmptyProd   -> return (res, [])
        UnaryProd r -> from_comp res_ty res expr r
        Prod {}
         -> do  let ptup_tc    =  repr_ptup_tc ss
                let [ptup_con] =  tyConDataCons ptup_tc
                ptys           <- mapM mkPDataType (repr_comp_tys ss)
                vars           <- newLocalVars (fsLit "ys") ptys
                (res', args)   <- fold from_comp res_ty res (map Var vars) (repr_comps ss)
                let scrut      =  unwrapFamInstScrut ptup_tc (repr_comp_tys ss) expr
                let body       =  mkWildCase scrut (exprType scrut) res_ty
                                    [(DataAlt ptup_con, vars, res')]
                return (body, args)      

    from_con res_ty res expr (ConRepr _ r) = from_prod res_ty res expr r

    from_comp _ res expr (Keep _ _) = return (res, [expr])
    from_comp _ res expr (Wrap ty)  = do { expr' <- unwrapNewTypeBodyOfPDataWrap expr ty
                                         ; return (res, [expr'])
                                         }

    fold f res_ty res exprs rs
      = foldrM f' (res, []) (zip exprs rs)
      where
        f' (expr, r) (res, args) 
         = do (res', args') <- f res_ty res expr r
              return (res', args' ++ args)


-- buildToArrPReprs -----------------------------------------------------------
-- | Build the 'toArrPReprs' instance for the PA class.
--   This converts a PData of elements into the generic representation.
buildToArrPReprs :: PAInstanceBuilder
buildToArrPReprs vect_tc repr_co _ pdatas_tc r
 = do
    -- The argument type of the instance.
    --  eg: 'PDatas (Tree a b)'
    arg_ty    <- mkPDatasType el_ty

    -- The result type. 
    --  eg: 'PDatas (PRepr (Tree a b))'
    res_ty    <- mkPDatasType =<< mkPReprType el_ty

    -- Variable to bind the argument to the instance
    -- eg: (xss :: PDatas (Tree a b))
    varg      <- newLocalVar (fsLit "xss") arg_ty

    -- Coersion to case between the (PRepr a) type and its instance.
    pdatas_co <- mkBuiltinCo pdatasTyCon
    let co           = mkAppCo pdatas_co
                     . mkSymCo
                     $ mkUnbranchedAxInstCo Nominal repr_co ty_args

    let scrut        = unwrapFamInstScrut pdatas_tc ty_args (Var varg)
    (vars, result)  <- to_sum r

    return  $ Lam varg
            $ mkWildCase scrut (mkTyConApp pdatas_tc ty_args) res_ty
                    [(DataAlt pdatas_dc, vars, mkCast result co)]

 where
    -- The element type of the argument.
    --  eg: 'Tree a b'.
    ty_args = mkTyVarTys $ tyConTyVars vect_tc
    el_ty   = mkTyConApp vect_tc ty_args
        
    -- PDatas data constructor
    [pdatas_dc] = tyConDataCons pdatas_tc
                  
    to_sum ss
     = case ss of
        -- We can't convert data types with no data.
        -- See Note: [Empty PDatas].
        EmptySum        -> do dflags <- getDynFlags
                              return ([], errorEmptyPDatas dflags el_ty)
        UnarySum r      -> do dflags <- getDynFlags
                              to_con (errorEmptyPDatas dflags el_ty) r

        Sum{}
         -> do  let psums_tc     = repr_psums_tc ss
                let [psums_con]  = tyConDataCons psums_tc
                sels             <- newLocalVar (fsLit "sels") (repr_sels_ty ss)

                -- Take the number of selectors to serve as the length of 
                -- and PDatas Void arrays in the product. See Note [Empty PDatas].
                let xSums        =  App (repr_selsLength_v ss) (Var sels)

                xSums_var <- newLocalVar (fsLit "xsum") intPrimTy

                (vars, exprs)    <- mapAndUnzipM (to_con xSums_var) (repr_cons ss)
                return ( sels : concat vars
                       , wrapFamInstBody psums_tc (repr_con_tys ss)
                         $ mkCoreLet (NonRec xSums_var xSums)
                                 -- mkCoreLet ensures that the let/app invariant holds
                         $ mkConApp psums_con 
                         $ map Type (repr_con_tys ss) ++ (Var sels : exprs))        

    to_prod xSums ss
     = case ss of
        EmptyProd    
         -> do  pvoids  <- builtin pvoidsVar
                return ([], App (Var pvoids) (Var xSums) )

        UnaryProd r
         -> do  pty  <- mkPDatasType (compOrigType r)
                var  <- newLocalVar (fsLit "x") pty
                expr <- to_comp (Var var) r
                return ([var], expr)

        Prod{}
         -> do  let [ptups_con]  = tyConDataCons (repr_ptups_tc ss)
                ptys   <- mapM (mkPDatasType . compOrigType) (repr_comps ss)
                vars   <- newLocalVars (fsLit "x") ptys
                exprs  <- zipWithM to_comp (map Var vars) (repr_comps ss)
                return ( vars
                       , wrapFamInstBody (repr_ptups_tc ss) (repr_comp_tys ss)
                         $ mkConApp ptups_con
                         $ map Type (repr_comp_tys ss) ++ exprs)

    to_con xSums (ConRepr _ r)
        = to_prod xSums r

    to_comp expr (Keep _ _) = return expr
    to_comp expr (Wrap ty)  = wrapNewTypeBodyOfPDatasWrap expr ty


-- buildFromArrPReprs ---------------------------------------------------------
buildFromArrPReprs :: PAInstanceBuilder
buildFromArrPReprs vect_tc repr_co _ pdatas_tc r
 = do   
    -- The argument type of the instance.
    --  eg: 'PDatas (PRepr (Tree a b))'
    arg_ty      <- mkPDatasType =<< mkPReprType el_ty

    -- The result type. 
    --  eg: 'PDatas (Tree a b)'
    res_ty      <- mkPDatasType el_ty
        
    -- Variable to bind the argument to the instance
    -- eg: (xss :: PDatas (PRepr (Tree a b)))
    varg        <- newLocalVar (fsLit "xss") arg_ty
        
    -- Build the coercion between PRepr and the instance type
    pdatas_co <- mkBuiltinCo pdatasTyCon
    let co           = mkAppCo pdatas_co
                     $ mkUnbranchedAxInstCo Nominal repr_co var_tys

    let scrut        = mkCast (Var varg) co

    let mk_result args
            = wrapFamInstBody pdatas_tc var_tys
            $ mkConApp pdatas_con
            $ map Type var_tys ++ args

    (expr, _) <- fixV $ \ ~(_, args) ->
                     from_sum res_ty (mk_result args) scrut r

    return $ Lam varg expr
 where
    -- The element type of the argument.
    --  eg: 'Tree a b'.
    ty_args      = mkTyVarTys $ tyConTyVars vect_tc
    el_ty        = mkTyConApp vect_tc ty_args

    var_tys      = mkTyVarTys $ tyConTyVars vect_tc
    [pdatas_con] = tyConDataCons pdatas_tc

    from_sum res_ty res expr ss
     = case ss of
        -- We can't convert data types with no data.
        -- See Note: [Empty PDatas].
        EmptySum        -> do dflags <- getDynFlags
                              return (res, errorEmptyPDatas dflags el_ty)
        UnarySum r      -> from_con res_ty res expr r

        Sum {}
         -> do  let psums_tc    =  repr_psums_tc ss
                let [psums_con] =  tyConDataCons psums_tc
                sel             <- newLocalVar (fsLit "sels") (repr_sels_ty ss)
                ptys            <- mapM mkPDatasType (repr_con_tys ss)
                vars            <- newLocalVars (fsLit "xs") ptys
                (res', args)    <- fold from_con res_ty res (map Var vars) (repr_cons ss)
                let scrut       =  unwrapFamInstScrut psums_tc (repr_con_tys ss) expr
                let body        =  mkWildCase scrut (exprType scrut) res_ty
                                    [(DataAlt psums_con, sel : vars, res')]
                return (body, Var sel : args)

    from_prod res_ty res expr ss
     = case ss of
        EmptyProd   -> return (res, [])
        UnaryProd r -> from_comp res_ty res expr r
        Prod {}
         -> do  let ptups_tc    =  repr_ptups_tc ss
                let [ptups_con] =  tyConDataCons ptups_tc
                ptys            <- mapM mkPDatasType (repr_comp_tys ss)
                vars            <- newLocalVars (fsLit "ys") ptys
                (res', args)    <- fold from_comp res_ty res (map Var vars) (repr_comps ss)
                let scrut       =  unwrapFamInstScrut ptups_tc (repr_comp_tys ss) expr
                let body        =  mkWildCase scrut (exprType scrut) res_ty
                                    [(DataAlt ptups_con, vars, res')]
                return (body, args)      

    from_con res_ty res expr (ConRepr _ r)
        = from_prod res_ty res expr r

    from_comp _ res expr (Keep _ _) = return (res, [expr])
    from_comp _ res expr (Wrap ty)  = do { expr' <- unwrapNewTypeBodyOfPDatasWrap expr ty
                                         ; return (res, [expr'])
                                         }

    fold f res_ty res exprs rs
      = foldrM f' (res, []) (zip exprs rs)
      where
        f' (expr, r) (res, args) 
         = do (res', args') <- f res_ty res expr r
              return (res', args' ++ args)


-- Notes ----------------------------------------------------------------------
{-
Note [Empty PDatas]
~~~~~~~~~~~~~~~~~~~
We don't support "empty" data types like the following:

  data Empty0
  data Empty1 = MkEmpty1
  data Empty2 = MkEmpty2 Empty0
  ...

There is no parallel data associcated with these types, so there is no where
to store the length of the PDatas array with our standard representation.

Enumerations like the following are ok:
  data Bool = True | False

The native and generic representations are:
  type instance (PDatas Bool)        = VPDs:Bool Sels2
  type instance (PDatas (Repr Bool)) = PSum2s Sels2 (PDatas Void) (PDatas Void)

To take the length of a (PDatas Bool) we take the length of the contained Sels2.
When converting a (PDatas Bool) to a (PDatas (Repr Bool)) we use this length to
initialise the two (PDatas Void) arrays.

However, with this:
  data Empty1 = MkEmpty1
 
The native and generic representations would be:
  type instance (PDatas Empty1)        = VPDs:Empty1
  type instance (PDatas (Repr Empty1)) = PVoids Int
 
The 'Int' argument of PVoids is supposed to store the length of the PDatas 
array. When converting the (PDatas Empty1) to a (PDatas (Repr Empty1)) we
need to come up with a value for it, but there isn't one.

To fix this we'd need to add an Int field to VPDs:Empty1 as well, but that's
too much hassle and there's no point running a parallel computation on no
data anyway.
-}
errorEmptyPDatas :: DynFlags -> Type -> a
errorEmptyPDatas dflags tc
    = cantVectorise dflags "Vectorise.PAMethods"
    $ vcat  [ text "Cannot vectorise data type with no parallel data " <> quotes (ppr tc)
            , text "Data types to be vectorised must contain at least one constructor"
            , text "with at least one field." ]