transformExp :: Exp ExplicitMemory -> ExpandM ([Stm ExplicitMemory], Exp ExplicitMemory)

transformExp (Op (Inner (Kernel desc space ts kbody)))
  | Right (kbody', thread_allocs) <- extractKernelBodyAllocations bound_in_kernel kbody = do

      num_threads64 <- newVName "num_threads64"
      let num_threads64_pat = Pattern [] [PatElem num_threads64 BindVar $ MemPrim int64]
          num_threads64_bnd = Let num_threads64_pat (defAux ()) $ BasicOp $
                              ConvOp (SExt Int32 Int64) (spaceNumThreads space)

      (alloc_bnds, alloc_offsets) <-
        expandedAllocations
        (Var num_threads64, spaceNumGroups space, spaceGroupSize space)
        (spaceGlobalId space, spaceGroupId space, spaceLocalId space) thread_allocs
      let kbody'' = offsetMemoryInKernelBody alloc_offsets kbody'

      return (num_threads64_bnd : alloc_bnds,
              Op $ Inner $ Kernel desc space ts kbody'')

  where bound_in_kernel =
          S.fromList $ M.keys $ scopeOfKernelSpace space <>
          scopeOf (kernelBodyStms kbody)
transformExp :: Exp ExplicitMemory -> ExpandM ([Stm ExplicitMemory], Exp ExplicitMemory)
transformExp (Op (Inner (Kernel desc space ts kbody)))
  | Right (kbody', thread_allocs) <- extractKernelBodyAllocations bound_in_kernel kbody = do

      num_threads64 <- newVName "num_threads64"
      let num_threads64_pat = Pattern [] [PatElem num_threads64 BindVar $ MemPrim int64]
          num_threads64_bnd = Let num_threads64_pat (defAux ()) $ BasicOp $
                              ConvOp (SExt Int32 Int64) (spaceNumThreads space)

      (alloc_bnds, alloc_offsets) <-
        expandedAllocations
        (Var num_threads64, spaceNumGroups space, spaceGroupSize space)
        (spaceGlobalId space, spaceGroupId space, spaceLocalId space) thread_allocs
      let kbody'' = offsetMemoryInKernelBody alloc_offsets kbody'

      return (num_threads64_bnd : alloc_bnds,
              Op $ Inner $ Kernel desc space ts kbody'')

  where bound_in_kernel =
          S.fromList $ M.keys $ scopeOfKernelSpace space <>
          scopeOf (kernelBodyStms kbody)
transformExp (Op (Inner (Kernel desc space ts kbody)))
  | Right (kbody', thread_allocs) <- extractKernelBodyAllocations bound_in_kernel kbody = do

      num_threads64 <- newVName "num_threads64"
      let num_threads64_pat = Pattern [] [PatElem num_threads64 BindVar $ MemPrim int64]
          num_threads64_bnd = Let num_threads64_pat (defAux ()) $ BasicOp $
                              ConvOp (SExt Int32 Int64) (spaceNumThreads space)

      (alloc_bnds, alloc_offsets) <-
        expandedAllocations
        (Var num_threads64, spaceNumGroups space, spaceGroupSize space)
        (spaceGlobalId space, spaceGroupId space, spaceLocalId space) thread_allocs
      let kbody'' = offsetMemoryInKernelBody alloc_offsets kbody'

      return (num_threads64_bnd : alloc_bnds,
              Op $ Inner $ Kernel desc space ts kbody'')

  where bound_in_kernel =
          S.fromList $ M.keys $ scopeOfKernelSpace space <>
          scopeOf (kernelBodyStms kbody)