diff --git a/llvm-tf.cabal b/llvm-tf.cabal
--- a/llvm-tf.cabal
+++ b/llvm-tf.cabal
@@ -1,5 +1,5 @@
 Name:          llvm-tf
-Version:       12.2
+Version:       15.0
 License:       BSD3
 License-File:  LICENSE
 Synopsis:      Bindings to the LLVM compiler toolkit using type families.
@@ -37,7 +37,7 @@
   Location: http://code.haskell.org/~thielema/llvm-tf/
 
 Source-Repository this
-  Tag:      12.2
+  Tag:      15.0
   Type:     darcs
   Location: http://code.haskell.org/~thielema/llvm-tf/
 
@@ -53,7 +53,7 @@
 Library private
   Default-Language: Haskell98
   Build-Depends:
-    llvm-ffi >=9.1 && <15.0,
+    llvm-ffi >=15.0 && <16.0,
     tfp >=1.0 && <1.1,
     transformers >=0.3 && <0.7,
     storable-record >=0.0.2 && <0.1,
diff --git a/private/LLVM/Core/CodeGen.hs b/private/LLVM/Core/CodeGen.hs
--- a/private/LLVM/Core/CodeGen.hs
+++ b/private/LLVM/Core/CodeGen.hs
@@ -21,6 +21,7 @@
     FunctionArgs, FunctionCodeGen, FunctionResult,
     TFunction,
     CodeValue, CodeResult,
+    proxyFromFunction,
     -- * Global variable creation
     Global, newGlobal, newNamedGlobal,
     defineGlobal, createGlobal, createNamedGlobal, TGlobal,
diff --git a/private/LLVM/Core/Instructions.hs b/private/LLVM/Core/Instructions.hs
--- a/private/LLVM/Core/Instructions.hs
+++ b/private/LLVM/Core/Instructions.hs
@@ -81,7 +81,7 @@
 import qualified LLVM.Core.Proxy as LP
 import qualified LLVM.Core.CodeGen as CodeGen
 import LLVM.Core.Instructions.Private
-            (ValueCons, unValue, convert, unop,
+            (ValueCons, unValue, convert, unop, binopValue, proxyFromValuePtr,
              FFIBinOp, FFIConstBinOp,
              GetField, FieldType, GetElementPtr, ElementPtrType,
              IsIndexArg, IsIndexType, getIxList, getArg,
@@ -92,6 +92,7 @@
 import LLVM.Core.CodeGenMonad
 import LLVM.Core.CodeGen
             (BasicBlock(BasicBlock), Function, withCurrentBuilder,
+             proxyFromFunction,
              ConstValue(ConstValue), zero,
              Value(Value), value, valueOf, UnValue, CodeResult)
 
@@ -383,22 +384,21 @@
 
 
 add, sub, mul ::
-    (ValueCons2 value0 value1, IsArithmetic a) =>
-    value0 a -> value1 a -> CodeGenFunction r (BinOpValue value0 value1 a)
+    (IsArithmetic a) => Value a -> Value a -> CodeGenFunction r (Value a)
 add =
     curry $ withArithmeticType $ \typ -> uncurry $ case typ of
-      IntegerType  -> binop FFI.constAdd  FFI.buildAdd
-      FloatingType -> binop FFI.constFAdd FFI.buildFAdd
+      IntegerType  -> binopValue FFI.buildAdd
+      FloatingType -> binopValue FFI.buildFAdd
 
 sub =
     curry $ withArithmeticType $ \typ -> uncurry $ case typ of
-      IntegerType  -> binop FFI.constSub  FFI.buildSub
-      FloatingType -> binop FFI.constFSub FFI.buildFSub
+      IntegerType  -> binopValue FFI.buildSub
+      FloatingType -> binopValue FFI.buildFSub
 
 mul =
     curry $ withArithmeticType $ \typ -> uncurry $ case typ of
-      IntegerType  -> binop FFI.constMul  FFI.buildMul
-      FloatingType -> binop FFI.constFMul FFI.buildFMul
+      IntegerType  -> binopValue FFI.buildMul
+      FloatingType -> binopValue FFI.buildFMul
 
 iadd, isub, imul ::
     (ValueCons2 value0 value1, IsInteger a) =>
@@ -418,45 +418,35 @@
     sbinop FFI.constNSWMul FFI.buildNSWMul FFI.constNUWMul FFI.buildNUWMul
 
 -- | signed or unsigned integer division depending on the type
-idiv ::
-    (ValueCons2 value0 value1, IsInteger a) =>
-    value0 a -> value1 a -> CodeGenFunction r (BinOpValue value0 value1 a)
-idiv = sbinop FFI.constSDiv FFI.buildSDiv FFI.constUDiv FFI.buildUDiv
+idiv :: (IsInteger a) => Value a -> Value a -> CodeGenFunction r (Value a)
+idiv = sbinopValue FFI.buildSDiv FFI.buildUDiv
 -- | signed or unsigned remainder depending on the type
-irem ::
-    (ValueCons2 value0 value1, IsInteger a) =>
-    value0 a -> value1 a -> CodeGenFunction r (BinOpValue value0 value1 a)
-irem = sbinop FFI.constSRem FFI.buildSRem FFI.constURem FFI.buildURem
+irem :: (IsInteger a) => Value a -> Value a -> CodeGenFunction r (Value a)
+irem = sbinopValue FFI.buildSRem FFI.buildURem
 
 {-# DEPRECATED udiv "use idiv instead" #-}
 {-# DEPRECATED sdiv "use idiv instead" #-}
 {-# DEPRECATED urem "use irem instead" #-}
 {-# DEPRECATED srem "use irem instead" #-}
 udiv, sdiv, urem, srem ::
-    (ValueCons2 value0 value1, IsInteger a) =>
-    value0 a -> value1 a -> CodeGenFunction r (BinOpValue value0 value1 a)
-udiv = binop FFI.constUDiv FFI.buildUDiv
-sdiv = binop FFI.constSDiv FFI.buildSDiv
-urem = binop FFI.constURem FFI.buildURem
-srem = binop FFI.constSRem FFI.buildSRem
+    (IsInteger a) => Value a -> Value a -> CodeGenFunction r (Value a)
+udiv = binopValue FFI.buildUDiv
+sdiv = binopValue FFI.buildSDiv
+urem = binopValue FFI.buildURem
+srem = binopValue FFI.buildSRem
 
 fadd, fsub, fmul ::
-    (ValueCons2 value0 value1, IsFloating a) =>
-    value0 a -> value1 a -> CodeGenFunction r (BinOpValue value0 value1 a)
-fadd = binop FFI.constFAdd FFI.buildFAdd
-fsub = binop FFI.constFSub FFI.buildFSub
-fmul = binop FFI.constFMul FFI.buildFMul
+    (IsFloating a) => Value a -> Value a -> CodeGenFunction r (Value a)
+fadd = binopValue FFI.buildFAdd
+fsub = binopValue FFI.buildFSub
+fmul = binopValue FFI.buildFMul
 
 -- | Floating point division.
-fdiv ::
-    (ValueCons2 value0 value1, IsFloating a) =>
-    value0 a -> value1 a -> CodeGenFunction r (BinOpValue value0 value1 a)
-fdiv = binop FFI.constFDiv FFI.buildFDiv
+fdiv :: (IsFloating a) => Value a -> Value a -> CodeGenFunction r (Value a)
+fdiv = binopValue FFI.buildFDiv
 -- | Floating point remainder.
-frem ::
-    (ValueCons2 value0 value1, IsFloating a) =>
-    value0 a -> value1 a -> CodeGenFunction r (BinOpValue value0 value1 a)
-frem = binop FFI.constFRem FFI.buildFRem
+frem :: (IsFloating a) => Value a -> Value a -> CodeGenFunction r (Value a)
+frem = binopValue FFI.buildFRem
 
 shl, lshr, ashr, and, or, xor ::
     (ValueCons2 value0 value1, IsInteger a) =>
@@ -473,6 +463,16 @@
     value0 a -> value1 a -> CodeGenFunction r (BinOpValue value0 value1 a)
 shr = sbinop FFI.constAShr FFI.buildAShr FFI.constLShr FFI.buildLShr
 
+sbinopValue ::
+    forall a b r.
+    (IsInteger a) =>
+    FFIBinOp -> FFIBinOp ->
+    Value a -> Value a -> CodeGenFunction r (Value b)
+sbinopValue sop uop =
+    if isSigned (LP.Proxy :: LP.Proxy a)
+        then binopValue sop
+        else binopValue uop
+
 sbinop ::
     forall value0 value1 a b r.
     (ValueCons2 value0 value1, IsInteger a) =>
@@ -894,19 +894,23 @@
 -}
 
 -- |Acceptable arguments to 'call'.
-class (r ~ CodeResult g, f ~ CalledFunction g, g ~ CallerFunction r f) =>
-         CallArgs r f g where
+class
+    (r ~ CodeResult g, f ~ CalledFunction g, g ~ CallerFunction r f,
+     IsFunction f) =>
+        CallArgs r f g where
     type CalledFunction g
     type CallerFunction r f
     doCall :: Call f -> g
 
-instance (Value a ~ a', CallArgs r b b') => CallArgs r (a -> b) (a' -> b') where
+instance
+    (IsFirstClass a, Value a ~ a', CallArgs r b b') =>
+        CallArgs r (a -> b) (a' -> b') where
     type CalledFunction (a' -> b') = UnValue a' -> CalledFunction b'
     type CallerFunction r (a -> b) = Value a -> CallerFunction r b
     doCall f a = doCall (applyCall f a)
 
 instance
-    (Value a ~ a', r ~ r') =>
+    (IsFirstClass a, Value a ~ a', r ~ r') =>
         CallArgs r (IO a) (CodeGenFunction r' a') where
     type CalledFunction (CodeGenFunction r' a') = IO (UnValue a')
     type CallerFunction r (IO a) = CodeGenFunction r (Value a)
@@ -924,9 +928,22 @@
 
 data Call a = Call Caller [FFI.ValueRef]
 
-callFromFunction :: Function a -> Call a
-callFromFunction (Value f) = Call (U.makeCall f) []
+typedCall ::
+    (IsFunction f) =>
+    Function f ->
+    (U.FunctionWithType -> FFI.BuilderRef ->
+        [FFI.ValueRef] -> IO FFI.ValueRef) ->
+    Call a
+typedCall func@(Value f) makeCall =
+    Call
+        (\bld args -> do
+            typ <- typeRef $ proxyFromFunction func
+            makeCall (typ, f) bld args)
+        []
 
+callFromFunction :: (IsFunction f) => Function f -> Call f
+callFromFunction func = typedCall func U.makeCall
+
 -- like Applicative.<*>
 infixl 4 `applyCall`
 
@@ -938,12 +955,13 @@
 
 
 invokeFromFunction ::
-          BasicBlock         -- ^Normal return point.
+          (IsFunction f)
+       => BasicBlock         -- ^Normal return point.
        -> BasicBlock         -- ^Exception return point.
        -> Function f         -- ^Function to call.
        -> Call f
-invokeFromFunction (BasicBlock norm) (BasicBlock expt) (Value f) =
-    Call (U.makeInvoke norm expt f) []
+invokeFromFunction (BasicBlock norm) (BasicBlock expt) func =
+    typedCall func $ U.makeInvoke norm expt
 
 -- | Call a function with exception handling.
 invoke :: (CallArgs r f g)
@@ -953,9 +971,9 @@
        -> g
 invoke norm expt f = doCall $ invokeFromFunction norm expt f
 
-callWithConvFromFunction :: FFI.CallingConvention -> Function f -> Call f
-callWithConvFromFunction cc (Value f) =
-    Call (U.makeCallWithCc cc f) []
+callWithConvFromFunction ::
+    (IsFunction f) => FFI.CallingConvention -> Function f -> Call f
+callWithConvFromFunction cc func = typedCall func $ U.makeCallWithCc cc
 
 -- | Call a function with the given arguments.  The 'call' instruction
 -- is variadic, i.e., the number of arguments it takes depends on the
@@ -968,13 +986,14 @@
 callWithConv cc f = doCall $ callWithConvFromFunction cc f
 
 invokeWithConvFromFunction ::
-          FFI.CallingConvention -- ^Calling convention
+          (IsFunction f)
+       => FFI.CallingConvention -- ^Calling convention
        -> BasicBlock         -- ^Normal return point.
        -> BasicBlock         -- ^Exception return point.
        -> Function f         -- ^Function to call.
        -> Call f
-invokeWithConvFromFunction cc (BasicBlock norm) (BasicBlock expt) (Value f) =
-    Call (U.makeInvokeWithCc cc norm expt f) []
+invokeWithConvFromFunction cc (BasicBlock norm) (BasicBlock expt) func =
+    typedCall func $ U.makeInvokeWithCc cc norm expt
 
 -- | Call a function with exception handling.
 -- This also sets the calling convention of the call to the function.
@@ -1154,17 +1173,22 @@
 
 
 -- | Load a value from memory.
-load :: Value (Ptr a)                   -- ^ Address to load from.
-     -> CodeGenFunction r (Value a)
-load (Value p) =
+load ::
+       (IsType a)
+    => Value (Ptr a)                   -- ^ Address to load from.
+    -> CodeGenFunction r (Value a)
+load ptr@(Value p) =
     liftM Value $
-    withCurrentBuilder $ \ bldPtr ->
-      U.withEmptyCString $ FFI.buildLoad bldPtr p
+    withCurrentBuilder $ \ bldPtr -> do
+        typ <- typeRef $ proxyFromValuePtr ptr
+        U.withEmptyCString $ FFI.buildLoad2 bldPtr typ p
 
 -- | Store a value in memory
-store :: Value a                        -- ^ Value to store.
-      -> Value (Ptr a)                  -- ^ Address to store to.
-      -> CodeGenFunction r ()
+store ::
+       (IsType a)
+    => Value a                        -- ^ Value to store.
+    -> Value (Ptr a)                  -- ^ Address to store to.
+    -> CodeGenFunction r ()
 store (Value v) (Value p) = do
     withCurrentBuilder_ $ \ bldPtr ->
       FFI.buildStore bldPtr v p
@@ -1172,37 +1196,39 @@
 
 -- | Address arithmetic.  See LLVM description.
 -- (The type isn't as accurate as it should be.)
-_getElementPtrDynamic :: (IsInteger i) =>
+_getElementPtrDynamic :: (IsType a, IsInteger i) =>
     Value (Ptr a) -> [Value i] -> CodeGenFunction r (Value (Ptr b))
-_getElementPtrDynamic (Value ptr) ixs =
+_getElementPtrDynamic ptr@(Value p) ixs =
     liftM Value $
-    withCurrentBuilder $ \ bldPtr ->
+    withCurrentBuilder $ \ bldPtr -> do
+      typ <- typeRef $ proxyFromValuePtr ptr
       U.withArrayLen [ v | Value v <- ixs ] $ \ idxLen idxPtr ->
         U.withEmptyCString $
-          FFI.buildGEP bldPtr ptr idxPtr (fromIntegral idxLen)
+          FFI.buildGEP2 bldPtr typ p idxPtr (fromIntegral idxLen)
 
 -- | Address arithmetic.  See LLVM description.
 -- The index is a nested tuple of the form @(i1,(i2,( ... ())))@.
 -- (This is without a doubt the most confusing LLVM instruction, but the types help.)
-getElementPtr :: forall a o i r . (GetElementPtr o i, IsIndexArg a) =>
+getElementPtr :: forall a o i r . (GetElementPtr o i, IsType o, IsIndexArg a) =>
                  Value (Ptr o) -> (a, i) -> CodeGenFunction r (Value (Ptr (ElementPtrType o i)))
-getElementPtr (Value ptr) (a, ixs) =
+getElementPtr ptr@(Value p) (a, ixs) =
     let ixl = getArg a : getIxList (LP.Proxy :: LP.Proxy o) ixs in
     liftM Value $
-    withCurrentBuilder $ \ bldPtr ->
+    withCurrentBuilder $ \ bldPtr -> do
+      typ <- typeRef $ proxyFromValuePtr ptr
       U.withArrayLen ixl $ \ idxLen idxPtr ->
         U.withEmptyCString $
-          FFI.buildGEP bldPtr ptr idxPtr (fromIntegral idxLen)
+          FFI.buildGEP2 bldPtr typ p idxPtr (fromIntegral idxLen)
 
 -- | Like getElementPtr, but with an initial index that is 0.
 -- This is useful since any pointer first need to be indexed off the pointer, and then into
 -- its actual value.  This first indexing is often with 0.
-getElementPtr0 :: (GetElementPtr o i) =>
+getElementPtr0 :: (GetElementPtr o i, IsType o) =>
                   Value (Ptr o) -> i -> CodeGenFunction r (Value (Ptr (ElementPtrType o i)))
 getElementPtr0 p i = getElementPtr p (0::Word32, i)
 
 _getElementPtr :: forall value o i i0 r.
-    (ValueCons value, GetElementPtr o i, IsIndexType i0) =>
+    (ValueCons value, IsType o, GetElementPtr o i, IsIndexType i0) =>
     value (Ptr o) -> (value i0, i) ->
     CodeGenFunction r (value (Ptr (ElementPtrType o i)))
 _getElementPtr vptr (a, ixs) =
@@ -1212,10 +1238,13 @@
             \ idxLen idxPtr ->
                 act idxPtr (fromIntegral idxLen)
     in  unop
-            (\ptr -> withArgs $ FFI.constGEP ptr)
-            (\bldPtr ptr cstr ->
+            (\ptr -> do
+                typ <- typeRef $ proxyFromValuePtr vptr
+                withArgs $ FFI.constGEP2 typ ptr)
+            (\bldPtr ptr cstr -> do
+                typ <- typeRef $ proxyFromValuePtr vptr
                 withArgs $ \idxPtr idxLen ->
-                    FFI.buildGEP bldPtr ptr idxPtr idxLen cstr)
+                    FFI.buildGEP2 bldPtr typ ptr idxPtr idxLen cstr)
             vptr
 
 --------------------------------------
diff --git a/private/LLVM/Core/Instructions/Guided.hs b/private/LLVM/Core/Instructions/Guided.hs
--- a/private/LLVM/Core/Instructions/Guided.hs
+++ b/private/LLVM/Core/Instructions/Guided.hs
@@ -50,7 +50,7 @@
 import qualified LLVM.Core.Type as Type
 import qualified LLVM.Core.Util as U
 import qualified LLVM.Core.Proxy as LP
-import LLVM.Core.Instructions.Private (ValueCons)
+import LLVM.Core.Instructions.Private (ValueCons, proxyFromValuePtr)
 import LLVM.Core.CodeGenMonad (CodeGenFunction)
 import LLVM.Core.CodeGen (ConstValue, zero)
 import LLVM.Core.Data (Ptr)
@@ -58,7 +58,7 @@
          (IsArithmetic, IsInteger, IsIntegerOrPointer, IsFloating,
           IsFirstClass, IsPrimitive,
           Signed, Positive, IsType, IsSized, SizeOf,
-          isFloating, sizeOf, typeDesc)
+          isFloating, sizeOf, typeDesc, typeRef)
 
 import qualified LLVM.FFI.Core as FFI
 
@@ -88,7 +88,7 @@
 type VT value shape a = value (Type shape a)
 
 getElementPtr ::
-    (ValueCons value, Priv.GetElementPtr o i, Priv.IsIndexType i0) =>
+    (ValueCons value, IsType o, Priv.GetElementPtr o i, Priv.IsIndexType i0) =>
     Guide shape (Ptr o, i0) ->
     VT value shape (Ptr o) ->
     (VT value shape i0, i) ->
@@ -97,7 +97,7 @@
     getElementPtrGen (fmap fst guide) vptr (Priv.unValue a, ixs)
 
 getElementPtr0 ::
-    (ValueCons value, Priv.GetElementPtr o i) =>
+    (ValueCons value, IsType o, Priv.GetElementPtr o i) =>
     Guide shape (Ptr o) ->
     VT value shape (Ptr o) -> i ->
     CodeGenFunction r (VT value shape (Ptr (Priv.ElementPtrType o i)))
@@ -106,7 +106,7 @@
         (Priv.unConst (zero :: ConstValue Word32), ixs)
 
 getElementPtrGen ::
-    (ValueCons value, Priv.GetElementPtr o i) =>
+    (ValueCons value, IsType o, Priv.GetElementPtr o i) =>
     Guide shape (Ptr o) ->
     VT value shape (Ptr o) -> (FFI.ValueRef, i) ->
     CodeGenFunction r (VT value shape (Ptr (Priv.ElementPtrType o i)))
@@ -117,10 +117,13 @@
             \ idxLen idxPtr ->
                 act idxPtr (fromIntegral idxLen)
     in  Priv.unop
-            (\ptr -> withArgs $ FFI.constGEP ptr)
-            (\bldPtr ptr cstr ->
+            (\ptr -> do
+                typ <- typeRef $ proxyFromValuePtr guide
+                withArgs $ FFI.constGEP2 typ ptr)
+            (\bldPtr ptr cstr -> do
+                typ <- typeRef $ proxyFromValuePtr guide
                 withArgs $ \idxPtr idxLen ->
-                    FFI.buildGEP bldPtr ptr idxPtr idxLen cstr)
+                    FFI.buildGEP2 bldPtr typ ptr idxPtr idxLen cstr)
             vptr
 
 
diff --git a/private/LLVM/Core/Instructions/Private.hs b/private/LLVM/Core/Instructions/Private.hs
--- a/private/LLVM/Core/Instructions/Private.hs
+++ b/private/LLVM/Core/Instructions/Private.hs
@@ -10,7 +10,7 @@
 import qualified LLVM.Core.Util as U
 import qualified LLVM.Core.Proxy as LP
 import LLVM.Core.Type (IsType, IsPrimitive, typeRef)
-import LLVM.Core.Data (Vector, Array, Struct, PackedStruct)
+import LLVM.Core.Data (Vector, Array, Struct, PackedStruct, Ptr)
 import LLVM.Core.CodeGenMonad (CodeGenFunction)
 import LLVM.Core.CodeGen
             (ConstValue(ConstValue), constOf, Value(Value), withCurrentBuilder)
@@ -51,6 +51,10 @@
         U.CString -> IO FFI.ValueRef
 
 
+proxyFromValuePtr :: value (Ptr a) -> LP.Proxy a
+proxyFromValuePtr _ = LP.Proxy
+
+
 class ValueCons value where
     switchValueCons :: f ConstValue -> f Value -> f value
 
@@ -122,10 +126,15 @@
     switchValueCons
         (BinOp $ \(ConstValue a) (ConstValue b) ->
             liftIO $ fmap ConstValue $ cop a b)
-        (BinOp $ \(Value a) (Value b) ->
-            liftM Value $
-            withCurrentBuilder $ \ bld ->
-                U.withEmptyCString $ op bld a b)
+        (BinOp $ binopValue op)
+
+binopValue ::
+    FFIBinOp ->
+    Value a -> Value b -> CodeGenFunction r (Value c)
+binopValue op (Value a) (Value b) =
+    liftM Value $
+    withCurrentBuilder $ \ bld ->
+        U.withEmptyCString $ op bld a b
 
 newtype TrinOp a b c d r value =
     TrinOp {
diff --git a/private/LLVM/Core/Util.hs b/private/LLVM/Core/Util.hs
--- a/private/LLVM/Core/Util.hs
+++ b/private/LLVM/Core/Util.hs
@@ -15,6 +15,7 @@
     appendBasicBlock, getBasicBlocks,
     -- * Functions
     Function,
+    FunctionWithType,
     addFunction, getParam, getParams,
     -- * Structs
     structType,
@@ -226,6 +227,7 @@
 --------------------------------------
 
 type Function = FFI.ValueRef
+type FunctionWithType = (FFI.TypeRef, FFI.ValueRef)
 
 addFunction :: Module -> FFI.Linkage -> String -> Type -> IO Function
 addFunction modul linkage name typ =
@@ -275,11 +277,13 @@
 withBasicBlock :: FFI.BasicBlockRef -> (FFI.BasicBlockRef -> IO a) -> IO a
 withBasicBlock v f = f v
 
-makeCall :: Function -> FFI.BuilderRef -> [Value] -> IO Value
+makeCall :: FunctionWithType -> FFI.BuilderRef -> [Value] -> IO Value
 makeCall = makeCallWithCc FFI.C
 
-makeCallWithCc :: FFI.CallingConvention -> Function -> FFI.BuilderRef -> [Value] -> IO Value
-makeCallWithCc cc func bldPtr args = do
+makeCallWithCc ::
+    FFI.CallingConvention -> FunctionWithType -> FFI.BuilderRef ->
+    [Value] -> IO Value
+makeCallWithCc cc (funcType, func) bldPtr args = do
 {-
       print "makeCall"
       FFI.dumpValue func
@@ -288,21 +292,23 @@
 -}
       withArrayLen args $ \ argLen argPtr ->
         withEmptyCString $ \cstr -> do
-          i <- FFI.buildCall bldPtr func argPtr
+          i <- FFI.buildCall2 bldPtr funcType func argPtr
                              (fromIntegral argLen) cstr
           FFI.setInstructionCallConv i (FFI.fromCallingConvention cc)
           return i
 
-makeInvoke :: BasicBlock -> BasicBlock -> Function -> FFI.BuilderRef ->
+makeInvoke :: BasicBlock -> BasicBlock -> FunctionWithType -> FFI.BuilderRef ->
               [Value] -> IO Value
 makeInvoke = makeInvokeWithCc FFI.C
 
-makeInvokeWithCc :: FFI.CallingConvention -> BasicBlock -> BasicBlock -> Function -> FFI.BuilderRef ->
-              [Value] -> IO Value
-makeInvokeWithCc cc norm expt func bldPtr args =
+makeInvokeWithCc ::
+    FFI.CallingConvention -> BasicBlock -> BasicBlock ->
+    FunctionWithType -> FFI.BuilderRef -> [Value] -> IO Value
+makeInvokeWithCc cc norm expt (funcType, func) bldPtr args =
       withArrayLen args $ \ argLen argPtr ->
         withEmptyCString $ \cstr -> do
-          i <- FFI.buildInvoke bldPtr func argPtr (fromIntegral argLen) norm expt cstr
+          i <- FFI.buildInvoke2 bldPtr funcType
+                    func argPtr (fromIntegral argLen) norm expt cstr
           FFI.setInstructionCallConv i (FFI.fromCallingConvention cc)
           return i
 
diff --git a/src/LLVM/Util/Arithmetic.hs b/src/LLVM/Util/Arithmetic.hs
--- a/src/LLVM/Util/Arithmetic.hs
+++ b/src/LLVM/Util/Arithmetic.hs
@@ -231,19 +231,22 @@
 
 
 class
-    (TFunB r a ~ b, TFunA b ~ a, CodeResult b ~ r) =>
+    (TFunB r a ~ b, TFunA b ~ a, CodeResult b ~ r, IsFunction a) =>
         ToArithFunction r a b where
     type TFunA b
     type TFunB r a
     toArithFunction' :: CodeGenFunction r (Call a) -> b
 
-instance (Value a ~ b) => ToArithFunction r (IO a) (CodeGenFunction r b) where
+instance
+    (Value a ~ b, IsFirstClass a) =>
+        ToArithFunction r (IO a) (CodeGenFunction r b) where
     type TFunA (CodeGenFunction r b) = IO (UnValue b)
     type TFunB r (IO a) = TValue r a
     toArithFunction' cl = runCall =<< cl
 
 instance
-    (ToArithFunction r b0 b1, CodeGenFunction r (Value a0) ~ a1) =>
+    (ToArithFunction r b0 b1, CodeGenFunction r (Value a0) ~ a1,
+     IsFirstClass a0) =>
         ToArithFunction r (a0 -> b0) (a1 -> b1) where
     type TFunA (a1 -> b1) = UnValue (CodeValue a1) -> TFunA b1
     type TFunB r (a0 -> b0) = TValue r a0 -> TFunB r b0
@@ -252,6 +255,7 @@
 
 
 _toArithFunction2 ::
+    (IsFirstClass a, IsFirstClass b, IsFirstClass c) =>
     Function (a -> b -> IO c) -> TValue r a -> TValue r b -> TValue r c
 _toArithFunction2 f tx ty = do
     x <- tx
