{-# LANGUAGE OverloadedStrings #-}
module LLVM.Test.DataLayout where

import Test.Tasty
import Test.Tasty.HUnit

import LLVM.Test.Support

import Control.Monad.IO.Class
import Data.Maybe
import Data.Monoid
import qualified Data.Set as Set
import qualified Data.Map as Map

import LLVM.Context
import LLVM.Module
import LLVM.AST
import LLVM.AST.DataLayout
import LLVM.AST.AddrSpace
import qualified LLVM.AST.Global as G
import LLVM.Internal.Coding
import LLVM.Internal.DataLayout
import LLVM.Internal.EncodeAST
import LLVM.Internal.FFI.DataLayout (getTypeAllocSize)

m s = "; ModuleID = '<string>'\nsource_filename = \"<string>\"\n" <> s
t s = "target datalayout = \"" <> s <> "\"\n"
ddl = defaultDataLayout BigEndian

tests = testGroup "DataLayout" $
  testCase "getTypeAllocSize" (withContext $ \ctx -> runEncodeAST ctx $ do
    ty <- encodeM (IntegerType 8)
    liftIO $ do
      size <-
        withFFIDataLayout
          (ddl { typeLayouts = Map.singleton (IntegerAlign, 8) (AlignmentInfo 8 8) })
          (\dl -> getTypeAllocSize dl ty)
      size @?= 1
      size <-
        withFFIDataLayout
          (ddl { typeLayouts = Map.singleton (IntegerAlign, 8) (AlignmentInfo 32 32) })
          (\dl -> getTypeAllocSize dl ty)
      size @?= 4)
  :
  [
  testCase name $ strCheckC (Module "<string>" "<string>" mdl Nothing []) (m sdl) (m sdlc)
  | (name, mdl, sdl, sdlc) <- [
   ("none", Nothing, "", "")
  ] ++ [
   (name, Just mdl, t sdl, t (fromMaybe sdl msdlc))
   | (name, mdl, sdl, msdlc) <- [
    ("little-endian", defaultDataLayout LittleEndian, "e", Nothing),
    ("big-endian", defaultDataLayout BigEndian, "E", Nothing),
    ("native", ddl { nativeSizes = Just (Set.fromList [8,32]) }, "E-n8:32", Nothing),
    (
     "no pref",
     ddl {
       pointerLayouts = 
         Map.singleton
         (AddrSpace 0) 
         (
          8,
          AlignmentInfo 64 64
         )
     },
     "E-p:8:64",
     Nothing
    ), (
     "no pref",
     ddl {
       pointerLayouts = 
         Map.insert (AddrSpace 1) (8, AlignmentInfo 32 64) (pointerLayouts ddl)
     },
     "E-p1:8:32:64",
     Nothing
    ), (
     "big",
     ddl {
       endianness = LittleEndian,
       mangling = Just ELFMangling,
       stackAlignment = Just 128,
       pointerLayouts = Map.fromList [
         (AddrSpace 0, (8, AlignmentInfo 8 16))
        ],
       typeLayouts = Map.fromList [
         ((IntegerAlign, 1), AlignmentInfo 8 256),
         ((IntegerAlign, 8), AlignmentInfo 8 256),
         ((IntegerAlign, 16), AlignmentInfo 16 256),
         ((IntegerAlign, 32), AlignmentInfo 32 256),
         ((IntegerAlign, 64), AlignmentInfo 64 256),
         ((VectorAlign, 64), AlignmentInfo 64 256),
         ((VectorAlign, 128), AlignmentInfo 128 256),
         ((FloatAlign, 32), AlignmentInfo 32 256),
         ((FloatAlign, 64), AlignmentInfo 64 256),
         ((FloatAlign, 80), AlignmentInfo 128 256)
        ] `Map.union` typeLayouts ddl, 
       aggregateLayout = AlignmentInfo 0 256,
       nativeSizes = Just (Set.fromList [8,16,32,64])
     },
     "e-m:e-p:8:8:16-i1:8:256-i8:8:256-i16:16:256-i32:32:256-i64:64:256-v64:64:256-v128:128:256-f32:32:256-f64:64:256-f80:128:256-a:0:256-n8:16:32:64-S128",
     Nothing
    )
   ]
  ]
 ]