content: {-# LANGUAGE ForeignFunctionInterface, TypeOperators, ScopedTypeVariables #-}
  module Struct (main) where
  
  import Data.Word
  import Data.TypeLevel(d0, d1, d2, D10)
  
  import LLVM.Core
  import LLVM.Util.File
  import LLVM.ExecutionEngine
  
  foreign import ccall structCheck :: Word32 -> Ptr S -> Int
  
  -- Watch out for double!  Alignment differs between platforms.
  -- struct S { uint32 x0; float x1; uint32 x2[10] };
  type S = Struct (Word32 :& Float :& Array D10 Word32 :& ())
  
  -- S *s = malloc(sizeof *s); s->x0 = a; s->x1 = 1.2; s->x2[5] = a+1; return s;
  mStruct :: CodeGenModule (Function (Word32 -> IO (Ptr S)))
  mStruct = do
      createFunction ExternalLinkage $ \ x -> do
        p  :: Value (Ptr S)
           <- malloc
        p0 <- getElementPtr0 p (d0 & ())
        store x (p0 :: Value (Ptr Word32))
        p1 <- getElementPtr0 p (d1 & ())
        store (valueOf 1.5) p1
        x' <- add x (1 :: Word32)
        p2 <- getElementPtr0 p (d2 & (5::Word32) & ())
        store x' p2
        ret p
  
  main :: IO ()
  main = do
      initializeNativeTarget
      writeCodeGenModule "Struct.bc" mStruct
      struct <- simpleFunction mStruct
      let a = 10
      p <- struct a
      putStrLn $ if structCheck a p /= 0 then "OK" else "failed"
      return ()
  