module LLVM.Util.Intrinsic ( min, max, abs, truncate, floor, maybeUAddSat, maybeSAddSat, maybeUSubSat, maybeSSubSat, call1, call2, ) where import qualified LLVM.Core.Proxy as LP import qualified LLVM.Core as LLVM import LLVM.Core (CodeGenFunction, Value, IsType, IsFirstClass, IsArithmetic, IsInteger, IsFloating) import qualified LLVM.FFI.Core as FFI import Data.Maybe.HT (toMaybe) import Prelude hiding (min, max, abs, truncate, floor) valueTypeName :: (IsType a) => Value a -> String valueTypeName = LLVM.intrinsicTypeName . ((\_ -> LP.Proxy) :: Value a -> LP.Proxy a) functionName :: (IsType a) => String -> Value a -> String functionName fn x = "llvm." ++ fn ++ "." ++ valueTypeName x call1 :: (IsFirstClass a) => String -> Value a -> CodeGenFunction r (Value a) call1 fn x = do op <- LLVM.externFunction $ functionName fn x LLVM.call op x call2 :: (IsFirstClass a) => String -> Value a -> Value a -> CodeGenFunction r (Value a) call2 fn x y = do op <- LLVM.externFunction $ functionName fn x LLVM.call op x y min, max :: (IsArithmetic a) => Value a -> Value a -> CodeGenFunction r (Value a) min = call2 "minnum" max = call2 "maxnum" abs :: (IsArithmetic a) => Value a -> CodeGenFunction r (Value a) abs = call1 "fabs" truncate, floor :: (IsFloating a) => Value a -> CodeGenFunction r (Value a) truncate = call1 "trunc" floor = call1 "floor" {- | Available since LLVM-8. -} maybeUAddSat, maybeSAddSat, maybeUSubSat, maybeSSubSat :: (IsInteger a) => Maybe (Value a -> Value a -> CodeGenFunction r (Value a)) maybeUAddSat = opsat "uadd" maybeSAddSat = opsat "sadd" maybeUSubSat = opsat "usub" maybeSSubSat = opsat "ssub" opsat :: (IsFirstClass a) => String -> Maybe (Value a -> Value a -> CodeGenFunction r (Value a)) opsat name = toMaybe (FFI.version >= 800) $ call2 (name++".sat")