packages feed

hhlo-0.10.0.0: examples/CustomCallPlugin.hs

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeApplications #-}

-- | Example: using a custom-call plugin from HHLO.
--
-- Before running this example you must compile the CUDA kernel:
--
-- @
--   cd examples/cbits && bash build.sh
-- @
--
-- Then run with the GPU plugin:
--
-- @
--   cabal run example-custom-call --flag=examples
-- @
module Main where

import qualified Data.Text as T
import HHLO.Core.Types
import HHLO.EDSL.Ops
import HHLO.IR.AST
import HHLO.IR.Builder
import HHLO.IR.Pretty
import HHLO.Runtime.CustomCall (registerGpuCustomCall)
import HHLO.Session

main :: IO ()
main = withGPU $ \sess -> do
    -- 1. Register the GPU custom-call target with the PJRT CUDA plugin.
    --    This MUST happen before 'compile'.
    registerGpuCustomCall (sessionApi sess)
        "examples/cbits/libvector_add.so" "vector_add"

    -- 2. Build a StableHLO module that uses the custom call.
    let modu = moduleFromBuilder @'[4] @'F32 "main"
            [ FuncArg "a" (TensorType [4] F32)
            , FuncArg "b" (TensorType [4] F32)
            ]
            $ do
                a <- arg @'[4] @'F32
                b <- arg @'[4] @'F32
                c <- customCall1 "vector_add" [a, b] "" False
                return c

    putStrLn "=== Emitted MLIR ==="
    putStrLn (T.unpack (render modu))

    -- 3. Compile and execute via PJRT.
    compiled <- compile sess modu
    let aVals = hostFromList @'[4] @'F32 [1.0, 2.0, 3.0, 4.0]
        bVals = hostFromList @'[4] @'F32 [10.0, 20.0, 30.0, 40.0]
    result <- run sess compiled (aVals, bVals) :: IO (HostTensor '[4] 'F32)

    putStrLn "=== Result ==="
    print (hostToList result)