extractThreadAllocations :: Names -> [Stm InKernel]
                         -> Either String ([Stm InKernel], M.Map VName (SubExp, Space))
extractThreadAllocations bound_before_body bnds = do
  (allocs, bnds') <- mapAccumLM isAlloc M.empty bnds
  return (catMaybes bnds', allocs)
  where bound_here = bound_before_body `S.union` boundByStms bnds

        isAlloc _ (Let (Pattern [] [patElem]) _ (Op (Alloc (Var v) _)))
          | v `S.member` bound_here =
            throwError $ "Size " ++ pretty v ++
            " for block " ++ pretty patElem ++
            " is not lambda-invariant"

        isAlloc allocs (Let (Pattern [] [patElem]) _ (Op (Alloc size space))) =
          return (M.insert (patElemName patElem) (size, space) allocs,
                  Nothing)

        isAlloc allocs bnd =
          return (allocs, Just bnd)
extractThreadAllocations :: Names -> [Stm InKernel]
                         -> Either String ([Stm InKernel], M.Map VName (SubExp, Space))
extractThreadAllocations bound_before_body bnds = do
  (allocs, bnds') <- mapAccumLM isAlloc M.empty bnds
  return (catMaybes bnds', allocs)
  where bound_here = bound_before_body `S.union` boundByStms bnds

        isAlloc _ (Let (Pattern [] [patElem]) _ (Op (Alloc (Var v) _)))
          | v `S.member` bound_here =
            throwError $ "Size " ++ pretty v ++
            " for block " ++ pretty patElem ++
            " is not lambda-invariant"

        isAlloc allocs (Let (Pattern [] [patElem]) _ (Op (Alloc size space))) =
          return (M.insert (patElemName patElem) (size, space) allocs,
                  Nothing)

        isAlloc allocs bnd =
          return (allocs, Just bnd)
extractThreadAllocations bound_before_body bnds = do
  (allocs, bnds') <- mapAccumLM isAlloc M.empty bnds
  return (catMaybes bnds', allocs)
  where bound_here = bound_before_body `S.union` boundByStms bnds

        isAlloc _ (Let (Pattern [] [patElem]) _ (Op (Alloc (Var v) _)))
          | v `S.member` bound_here =
            throwError $ "Size " ++ pretty v ++
            " for block " ++ pretty patElem ++
            " is not lambda-invariant"

        isAlloc allocs (Let (Pattern [] [patElem]) _ (Op (Alloc size space))) =
          return (M.insert (patElemName patElem) (size, space) allocs,
                  Nothing)

        isAlloc allocs bnd =
          return (allocs, Just bnd)