diff --git a/ast.py b/ast.py
index 49f712a572301ed16d04355c3609a14dc4214271..8c8fc9f8bda28a52b3af77eef2d087f459863266 100644
--- a/ast.py
+++ b/ast.py
@@ -45,7 +45,7 @@ class KernelFunction(Node):
     class Argument:
         def __init__(self, name, dtype):
             self.name = name
-            self.dtype = dtype
+            self.dtype = dtype  # TODO ordentliche Klasse
             self.isFieldPtrArgument = False
             self.isFieldShapeArgument = False
             self.isFieldStrideArgument = False
diff --git a/backends/llvm.py b/backends/llvm.py
index 0d1eb1a86a3fde4636cf0ee901eb191d27ca0bb0..affc9987fdb2a8b753c3badfa1f45bd75c1ee11c 100644
--- a/backends/llvm.py
+++ b/backends/llvm.py
@@ -1,26 +1,19 @@
 import llvmlite.ir as ir
-import llvmlite.binding as llvm
-import logging.config
-
-from sympy.utilities.codegen import CCodePrinter
-from pystencils.ast import Node
 
 from sympy.printing.printer import Printer
 from sympy import S
 # S is numbers?
 
 
-def generateLLVM(astNode):
-    return None
-
-
 class LLVMPrinter(Printer):
     """Convert expressions to LLVM IR"""
-    def __init__(self, module, builder, fn, *args, **kwargs):
+    def __init__(self, module, builder, fn=None, *args, **kwargs):
         self.func_arg_map = kwargs.pop("func_arg_map", {})
         super(LLVMPrinter, self).__init__(*args, **kwargs)
         self.fp_type = ir.DoubleType()
-        #self.integer = ir.IntType(64)
+        self.fp_pointer = self.fp_type.as_pointer()
+        self.integer = ir.IntType(64)
+        self.void = ir.VoidType()
         self.module = module
         self.builder = builder
         self.fn = fn
@@ -81,9 +74,32 @@ class LLVMPrinter(Printer):
             e = self.builder.fadd(e, node)
         return e
 
+    def _print_KernelFunction(self, function):
+        return_type = self.void
+        # TODO argument in their own call?
+        parameter_type = []
+        for parameter in function.parameters:
+            # TODO what bout ptr shape and stride argument?
+            if parameter.isFieldArgument:
+                parameter_type.append(self.fp_pointer)
+            else:
+                parameter_type.append(self.fp_type)
+        # TODO need tuple()?
+        func_type = ir.FunctionType(return_type, tuple(parameter_type))
+        self.fn = ir.Function(self.module, func_type, function.functionName)
+
+        # func.attributes.add("inlinehint")
+        # func.attributes.add("argmemonly")
+        block = self.fn.append_basic_block(name="entry")
+        self.builder = ir.IRBuilder(block)
+        return self.fn
+
+
+
         # TODO - assumes all called functions take one double precision argument.
         #        Should have a list of math library functions to validate this.
 
+    # TODO delete this?
     def _print_Function(self, expr):
         name = expr.func.__name__
         e0 = self._print(expr.args[0])
@@ -99,71 +115,7 @@ class LLVMPrinter(Printer):
                         % type(expr))
 
 
-class Eval(object):
-    def __init__(self):
-        llvm.initialize()
-        llvm.initialize_all_targets()
-        llvm.initialize_native_target()
-        llvm.initialize_native_asmprinter()
-        self.target = llvm.Target.from_default_triple()
-
-    def compile(self, module):
-        logger.debug('=============Preparse')
-        logger.debug(str(module))
-        llvmmod = llvm.parse_assembly(str(module))
-        llvmmod.verify()
-        logger.debug('=============Function in IR')
-        logger.debug(str(llvmmod))
-        # TODO cpu, features, opt
-        cpu = llvm.get_host_cpu_name()
-        features = llvm.get_host_cpu_features()
-        logger.debug('=======Things')
-        logger.debug(cpu)
-        logger.debug(features.flatten())
-        target_machine = self.target.create_target_machine(cpu=cpu, features=features.flatten(), opt=2)
-
-        logger.debug('Machine = ' + str(target_machine.target_data))
-
-        with open('gen.ll', 'w') as f:
-            f.write(str(llvmmod))
-        optimize = True
-        if optimize:
-            pmb = llvm.create_pass_manager_builder()
-            pmb.opt_level = 2
-            pmb.disable_unit_at_a_time = False
-            pmb.loop_vectorize = True
-            pmb.slp_vectorize = True
-            # TODO possible to pass for functions
-            pm = llvm.create_module_pass_manager()
-            pm.add_instruction_combining_pass()
-            pm.add_function_attrs_pass()
-            pm.add_constant_merge_pass()
-            pm.add_licm_pass()
-            pmb.populate(pm)
-            pm.run(llvmmod)
-            logger.debug("==========Opt")
-            logger.debug(str(llvmmod))
-            with open('gen_opt.ll', 'w') as f:
-                f.write(str(llvmmod))
-
-        with llvm.create_mcjit_compiler(llvmmod, target_machine) as ee:
-            ee.finalize_object()
-
-            logger.debug('==========Machine code')
-            logger.debug(target_machine.emit_assembly(llvmmod))
-            with open('gen.S', 'w') as f:
-                f.write(target_machine.emit_assembly(llvmmod))
-            with open('gen.o', 'wb') as f:
-                f.write(target_machine.emit_object(llvmmod))
-
-            # fptr = CFUNCTYPE(c_double, c_double, c_double)(ee.get_function_address('add2'))
-            # result = fptr(2, 3)
-            # print(result)
-            return 0
-
-
-if __name__ == "__main__":
-    logger = logging.getLogger(__name__)
-else:
-    logger = logging.getLogger(__name__)
 
+
+def generateLLVM(astNode):
+    return None
diff --git a/llvm/jit.py b/llvm/jit.py
new file mode 100644
index 0000000000000000000000000000000000000000..8e6fdb56f947ce6a98ba93aad5f8bb2ef9006014
--- /dev/null
+++ b/llvm/jit.py
@@ -0,0 +1,71 @@
+import llvmlite.binding as llvm
+import logging.config
+
+
+class Eval(object):
+    def __init__(self):
+        llvm.initialize()
+        llvm.initialize_all_targets()
+        llvm.initialize_native_target()
+        llvm.initialize_native_asmprinter()
+        self.target = llvm.Target.from_default_triple()
+
+    def compile(self, module):
+        logger.debug('=============Preparse')
+        logger.debug(str(module))
+        llvmmod = llvm.parse_assembly(str(module))
+        llvmmod.verify()
+        logger.debug('=============Function in IR')
+        logger.debug(str(llvmmod))
+        # TODO cpu, features, opt
+        cpu = llvm.get_host_cpu_name()
+        features = llvm.get_host_cpu_features()
+        logger.debug('=======Things')
+        logger.debug(cpu)
+        logger.debug(features.flatten())
+        target_machine = self.target.create_target_machine(cpu=cpu, features=features.flatten(), opt=2)
+
+        logger.debug('Machine = ' + str(target_machine.target_data))
+
+        with open('gen.ll', 'w') as f:
+            f.write(str(llvmmod))
+        optimize = True
+        if optimize:
+            pmb = llvm.create_pass_manager_builder()
+            pmb.opt_level = 2
+            pmb.disable_unit_at_a_time = False
+            pmb.loop_vectorize = True
+            pmb.slp_vectorize = True
+            # TODO possible to pass for functions
+            pm = llvm.create_module_pass_manager()
+            pm.add_instruction_combining_pass()
+            pm.add_function_attrs_pass()
+            pm.add_constant_merge_pass()
+            pm.add_licm_pass()
+            pmb.populate(pm)
+            pm.run(llvmmod)
+            logger.debug("==========Opt")
+            logger.debug(str(llvmmod))
+            with open('gen_opt.ll', 'w') as f:
+                f.write(str(llvmmod))
+
+        with llvm.create_mcjit_compiler(llvmmod, target_machine) as ee:
+            ee.finalize_object()
+
+            logger.debug('==========Machine code')
+            logger.debug(target_machine.emit_assembly(llvmmod))
+            with open('gen.S', 'w') as f:
+                f.write(target_machine.emit_assembly(llvmmod))
+            with open('gen.o', 'wb') as f:
+                f.write(target_machine.emit_object(llvmmod))
+
+            # fptr = CFUNCTYPE(c_double, c_double, c_double)(ee.get_function_address('add2'))
+            # result = fptr(2, 3)
+            # print(result)
+            return 0
+
+
+if __name__ == "__main__":
+    logger = logging.getLogger(__name__)
+else:
+    logger = logging.getLogger(__name__)
diff --git a/llvm/kernelcreation.py b/llvm/kernelcreation.py
deleted file mode 100644
index 89eca80b86f18f9fdf4a3be208e0f32885539af2..0000000000000000000000000000000000000000
--- a/llvm/kernelcreation.py
+++ /dev/null
@@ -1,65 +0,0 @@
-import sympy as sp
-from pystencils.transformations import resolveFieldAccesses, makeLoopOverDomain, typingFromSympyInspection, \
-    typeAllEquations, getOptimalLoopOrdering, parseBasePointerInfo, moveConstantsBeforeLoop, splitInnerLoop
-from pystencils.typedsymbol import TypedSymbol
-from pystencils.field import Field
-import pystencils.ast as ast
-
-
-def createKernel(listOfEquations, functionName="kernel", typeForSymbol=None, splitGroups=(),
-                 iterationSlice=None, ghostLayers=None):
-    """
-    Creates an abstract syntax tree for a kernel function, by taking a list of update rules.
-
-    Loops are created according to the field accesses in the equations.
-
-    :param listOfEquations: list of sympy equations, containing accesses to :class:`pystencils.field.Field`.
-           Defining the update rules of the kernel
-    :param functionName: name of the generated function - only important if generated code is written out
-    :param typeForSymbol: a map from symbol name to a C type specifier. If not specified all symbols are assumed to
-           be of type 'double' except symbols which occur on the left hand side of equations where the
-           right hand side is a sympy Boolean which are assumed to be 'bool' .
-    :param splitGroups: Specification on how to split up inner loop into multiple loops. For details see
-           transformation :func:`pystencils.transformation.splitInnerLoop`
-    :param iterationSlice: if not None, iteration is done only over this slice of the field
-    :param ghostLayers: a sequence of pairs for each coordinate with lower and upper nr of ghost layers
-                        if None, the number of ghost layers is determined automatically and assumed to be equal for a
-                        all dimensions
-
-    :return: :class:`pystencils.ast.KernelFunction` node
-    """
-    if not typeForSymbol:
-        typeForSymbol = typingFromSympyInspection(listOfEquations, "double")
-
-    def typeSymbol(term):
-        if isinstance(term, Field.Access) or isinstance(term, TypedSymbol):
-            return term
-        elif isinstance(term, sp.Symbol):
-            return TypedSymbol(term.name, typeForSymbol[term.name])
-        else:
-            raise ValueError("Term has to be field access or symbol")
-
-    fieldsRead, fieldsWritten, assignments = typeAllEquations(listOfEquations, typeForSymbol)
-    allFields = fieldsRead.union(fieldsWritten)
-
-    for field in allFields:
-        field.setReadOnly(False)
-    for field in fieldsRead - fieldsWritten:
-        field.setReadOnly()
-
-    body = ast.Block(assignments)
-    code = makeLoopOverDomain(body, functionName, iterationSlice=iterationSlice, ghostLayers=ghostLayers)
-
-    if splitGroups:
-        typedSplitGroups = [[typeSymbol(s) for s in splitGroup] for splitGroup in splitGroups]
-        splitInnerLoop(code, typedSplitGroups)
-
-    loopOrder = getOptimalLoopOrdering(allFields)
-
-    basePointerInfo = [['spatialInner0'], ['spatialInner1']]
-    basePointerInfos = {field.name: parseBasePointerInfo(basePointerInfo, loopOrder, field) for field in allFields}
-
-    resolveFieldAccesses(code, fieldToBasePointerInfo=basePointerInfos)
-    moveConstantsBeforeLoop(code)
-
-    return code
\ No newline at end of file