diff --git a/loopy/__init__.py b/loopy/__init__.py
index b374041f78cc4dfd4e0db511b36b9486b2a7a132..5ae1a1291a956841f3ad7683757135b052e77ade 100644
--- a/loopy/__init__.py
+++ b/loopy/__init__.py
@@ -41,14 +41,16 @@ from loopy.symbolic import ExpandingIdentityMapper, ExpandingSubstitutionMapper
 
 # {{{ imported user interface
 
-from loopy.kernel.data import (
-        ValueArg, GlobalArg, ConstantArg, ImageArg,
-
+from loopy.library.function import (
         default_function_mangler, single_arg_function_mangler,
-        opencl_function_mangler,
+        opencl_function_mangler)
 
-        default_preamble_generator,
+from loopy.library.preamble import default_preamble_generator
 
+from loopy.library.symbol import opencl_symbol_mangler
+
+from loopy.kernel.data import (
+        ValueArg, GlobalArg, ConstantArg, ImageArg,
         Instruction)
 
 from loopy.kernel import LoopKernel
@@ -56,7 +58,7 @@ from loopy.kernel.tools import (
         get_dot_dependency_graph, add_argument_dtypes,
         add_and_infer_argument_dtypes)
 from loopy.kernel.creation import make_kernel
-from loopy.reduction import register_reduction_parser
+from loopy.library.reduction import register_reduction_parser
 from loopy.subst import extract_subst, expand_subst
 from loopy.precompute import precompute
 from loopy.padding import (split_arg_axis, find_padding_multiple,
diff --git a/loopy/kernel/__init__.py b/loopy/kernel/__init__.py
index b2baf97e74e14db92040573dd927c9498f08b267..314da630aa1360b215a520252ff6d103a0d25003 100644
--- a/loopy/kernel/__init__.py
+++ b/loopy/kernel/__init__.py
@@ -33,15 +33,13 @@ import re
 
 from pytools import UniqueNameGenerator, generate_unique_possibilities
 
-from loopy.kernel.data import (
+from loopy.library.function import (
         default_function_mangler,
         opencl_function_mangler,
-        single_arg_function_mangler,
+        single_arg_function_mangler)
 
-        opencl_symbol_mangler,
-
-        default_preamble_generator,
-        )
+from loopy.library.symbol import opencl_symbol_mangler
+from loopy.library.preamble import default_preamble_generator
 
 
 class CannotBranchDomainTree(RuntimeError):
diff --git a/loopy/kernel/data.py b/loopy/kernel/data.py
index 6a4ac40382d7cfa89eff30d994d4738f28c00c45..9de7f133edc7a96b7cc91186b7bbd48f25464eef 100644
--- a/loopy/kernel/data.py
+++ b/loopy/kernel/data.py
@@ -446,142 +446,4 @@ class Instruction(Record):
 
 # }}}
 
-
-# {{{ function manglers / dtype getters
-
-def default_function_mangler(name, arg_dtypes):
-    from loopy.reduction import reduction_function_mangler
-
-    manglers = [reduction_function_mangler]
-    for mangler in manglers:
-        result = mangler(name, arg_dtypes)
-        if result is not None:
-            return result
-
-    return None
-
-
-def opencl_function_mangler(name, arg_dtypes):
-    if name in ["max", "min"] and len(arg_dtypes) == 2:
-        dtype = np.find_common_type([], arg_dtypes)
-
-        if dtype.kind == "c":
-            raise RuntimeError("min/max do not support complex numbers")
-
-        if dtype.kind == "f":
-            name = "f" + name
-
-        return dtype, name
-
-    if name in "atan2" and len(arg_dtypes) == 2:
-        return arg_dtypes[0], name
-
-    if len(arg_dtypes) == 1:
-        arg_dtype, = arg_dtypes
-
-        if arg_dtype.kind == "c":
-            if arg_dtype == np.complex64:
-                tpname = "cfloat"
-            elif arg_dtype == np.complex128:
-                tpname = "cdouble"
-            else:
-                raise RuntimeError("unexpected complex type '%s'" % arg_dtype)
-
-            if name in ["sqrt", "exp", "log",
-                    "sin", "cos", "tan",
-                    "sinh", "cosh", "tanh",
-                    "conj"]:
-                return arg_dtype, "%s_%s" % (tpname, name)
-
-            if name in ["real", "imag", "abs"]:
-                return np.dtype(arg_dtype.type(0).real), "%s_%s" % (tpname, name)
-
-    if name == "dot":
-        scalar_dtype, offset, field_name = arg_dtypes[0].fields["s0"]
-        return scalar_dtype, name
-
-    return None
-
-
-def single_arg_function_mangler(name, arg_dtypes):
-    if len(arg_dtypes) == 1:
-        dtype, = arg_dtypes
-        return dtype, name
-
-    return None
-
-
-def opencl_symbol_mangler(name):
-    # FIXME: should be more picky about exact names
-    if name.startswith("FLT_"):
-        return np.dtype(np.float32), name
-    elif name.startswith("DBL_"):
-        return np.dtype(np.float64), name
-    elif name.startswith("M_"):
-        if name.endswith("_F"):
-            return np.dtype(np.float32), name
-        else:
-            return np.dtype(np.float64), name
-    elif name == "INFINITY":
-        return np.dtype(np.float32), name
-    else:
-        return None
-
-# }}}
-
-
-# {{{ preamble generators
-
-def default_preamble_generator(seen_dtypes, seen_functions):
-    from loopy.reduction import reduction_preamble_generator
-
-    for result in reduction_preamble_generator(seen_dtypes, seen_functions):
-        yield result
-
-    has_double = False
-    has_complex = False
-
-    for dtype in seen_dtypes:
-        if dtype in [np.float64, np.complex128]:
-            has_double = True
-        if dtype.kind == "c":
-            has_complex = True
-
-    if has_double:
-        yield ("00_enable_double", """
-            #pragma OPENCL EXTENSION cl_khr_fp64: enable
-            """)
-
-    if has_complex:
-        if has_double:
-            yield ("10_include_complex_header", """
-                #define PYOPENCL_DEFINE_CDOUBLE
-
-                #include <pyopencl-complex.h>
-                """)
-        else:
-            yield ("10_include_complex_header", """
-                #include <pyopencl-complex.h>
-                """)
-
-    c_funcs = set(c_name for name, c_name, arg_dtypes in seen_functions)
-    if "int_floor_div" in c_funcs:
-        yield ("05_int_floor_div", """
-            #define int_floor_div(a,b) \
-              (( (a) - \
-                 ( ( (a)<0 ) != ( (b)<0 )) \
-                  *( (b) + ( (b)<0 ) - ( (b)>=0 ) )) \
-               / (b) )
-            """)
-
-    if "int_floor_div_pos_b" in c_funcs:
-        yield ("05_int_floor_div_pos_b", """
-            #define int_floor_div_pos_b(a,b) ( \
-                ( (a) - ( ((a)<0) ? ((b)-1) : 0 )  ) / (b) \
-                )
-            """)
-
-
-# }}}
-
 # vim: foldmethod=marker
diff --git a/loopy/library/__init__.py b/loopy/library/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/loopy/library/function.py b/loopy/library/function.py
new file mode 100644
index 0000000000000000000000000000000000000000..fcae07b6b599761e4081c40f1eaad54ca9bcb2c6
--- /dev/null
+++ b/loopy/library/function.py
@@ -0,0 +1,91 @@
+from __future__ import division
+
+__copyright__ = "Copyright (C) 2012 Andreas Kloeckner"
+
+__license__ = """
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+"""
+
+
+import numpy as np
+
+
+def default_function_mangler(name, arg_dtypes):
+    from loopy.library.reduction import reduction_function_mangler
+
+    manglers = [reduction_function_mangler]
+    for mangler in manglers:
+        result = mangler(name, arg_dtypes)
+        if result is not None:
+            return result
+
+    return None
+
+
+def opencl_function_mangler(name, arg_dtypes):
+    if name in ["max", "min"] and len(arg_dtypes) == 2:
+        dtype = np.find_common_type([], arg_dtypes)
+
+        if dtype.kind == "c":
+            raise RuntimeError("min/max do not support complex numbers")
+
+        if dtype.kind == "f":
+            name = "f" + name
+
+        return dtype, name
+
+    if name in "atan2" and len(arg_dtypes) == 2:
+        return arg_dtypes[0], name
+
+    if len(arg_dtypes) == 1:
+        arg_dtype, = arg_dtypes
+
+        if arg_dtype.kind == "c":
+            if arg_dtype == np.complex64:
+                tpname = "cfloat"
+            elif arg_dtype == np.complex128:
+                tpname = "cdouble"
+            else:
+                raise RuntimeError("unexpected complex type '%s'" % arg_dtype)
+
+            if name in ["sqrt", "exp", "log",
+                    "sin", "cos", "tan",
+                    "sinh", "cosh", "tanh",
+                    "conj"]:
+                return arg_dtype, "%s_%s" % (tpname, name)
+
+            if name in ["real", "imag", "abs"]:
+                return np.dtype(arg_dtype.type(0).real), "%s_%s" % (tpname, name)
+
+    if name == "dot":
+        scalar_dtype, offset, field_name = arg_dtypes[0].fields["s0"]
+        return scalar_dtype, name
+
+    return None
+
+
+def single_arg_function_mangler(name, arg_dtypes):
+    if len(arg_dtypes) == 1:
+        dtype, = arg_dtypes
+        return dtype, name
+
+    return None
+
+
+# vim: foldmethod=marker
diff --git a/loopy/library/preamble.py b/loopy/library/preamble.py
new file mode 100644
index 0000000000000000000000000000000000000000..590320b058622bc89f188e98f92e891efcda8a4d
--- /dev/null
+++ b/loopy/library/preamble.py
@@ -0,0 +1,78 @@
+from __future__ import division
+
+__copyright__ = "Copyright (C) 2012 Andreas Kloeckner"
+
+__license__ = """
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+"""
+
+
+import numpy as np
+
+
+def default_preamble_generator(seen_dtypes, seen_functions):
+    from loopy.library.reduction import reduction_preamble_generator
+
+    for result in reduction_preamble_generator(seen_dtypes, seen_functions):
+        yield result
+
+    has_double = False
+    has_complex = False
+
+    for dtype in seen_dtypes:
+        if dtype in [np.float64, np.complex128]:
+            has_double = True
+        if dtype.kind == "c":
+            has_complex = True
+
+    if has_double:
+        yield ("00_enable_double", """
+            #pragma OPENCL EXTENSION cl_khr_fp64: enable
+            """)
+
+    if has_complex:
+        if has_double:
+            yield ("10_include_complex_header", """
+                #define PYOPENCL_DEFINE_CDOUBLE
+
+                #include <pyopencl-complex.h>
+                """)
+        else:
+            yield ("10_include_complex_header", """
+                #include <pyopencl-complex.h>
+                """)
+
+    c_funcs = set(c_name for name, c_name, arg_dtypes in seen_functions)
+    if "int_floor_div" in c_funcs:
+        yield ("05_int_floor_div", """
+            #define int_floor_div(a,b) \
+              (( (a) - \
+                 ( ( (a)<0 ) != ( (b)<0 )) \
+                  *( (b) + ( (b)<0 ) - ( (b)>=0 ) )) \
+               / (b) )
+            """)
+
+    if "int_floor_div_pos_b" in c_funcs:
+        yield ("05_int_floor_div_pos_b", """
+            #define int_floor_div_pos_b(a,b) ( \
+                ( (a) - ( ((a)<0) ? ((b)-1) : 0 )  ) / (b) \
+                )
+            """)
+
+# vim: foldmethod=marker
diff --git a/loopy/reduction.py b/loopy/library/reduction.py
similarity index 100%
rename from loopy/reduction.py
rename to loopy/library/reduction.py
diff --git a/loopy/library/symbol.py b/loopy/library/symbol.py
new file mode 100644
index 0000000000000000000000000000000000000000..4ad22d58cebcff297a21509d43ba226eb4b1da8e
--- /dev/null
+++ b/loopy/library/symbol.py
@@ -0,0 +1,45 @@
+from __future__ import division
+
+__copyright__ = "Copyright (C) 2012 Andreas Kloeckner"
+
+__license__ = """
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+"""
+
+
+import numpy as np
+
+
+def opencl_symbol_mangler(name):
+    # FIXME: should be more picky about exact names
+    if name.startswith("FLT_"):
+        return np.dtype(np.float32), name
+    elif name.startswith("DBL_"):
+        return np.dtype(np.float64), name
+    elif name.startswith("M_"):
+        if name.endswith("_F"):
+            return np.dtype(np.float32), name
+        else:
+            return np.dtype(np.float64), name
+    elif name == "INFINITY":
+        return np.dtype(np.float32), name
+    else:
+        return None
+
+# vim: foldmethod=marker
diff --git a/loopy/symbolic.py b/loopy/symbolic.py
index 950dcafb58cf51e52aa993de154986a078ab0bdb..2352269d4c86dbdb0ffc761051ac2bb2b78c79ff 100644
--- a/loopy/symbolic.py
+++ b/loopy/symbolic.py
@@ -103,7 +103,7 @@ class Reduction(AlgebraicLeaf):
         assert isinstance(inames, tuple)
 
         if isinstance(operation, str):
-            from loopy.reduction import parse_reduction_op
+            from loopy.library.reduction import parse_reduction_op
             operation = parse_reduction_op(operation)
 
         self.operation = operation
@@ -613,7 +613,7 @@ class FunctionToPrimitiveMapper(IdentityMapper):
         else:
             # see if 'name' is an existing reduction op
 
-            from loopy.reduction import parse_reduction_op
+            from loopy.library.reduction import parse_reduction_op
             if parse_reduction_op(name):
                 if len(expr.parameters) != 2:
                     raise RuntimeError("invalid invocation of "
diff --git a/setup.py b/setup.py
index 65a5f37e3efcfbf7a6d7d227e07dde98b4237996..795af07236b100ca3e613a8cd431e3efd58f543c 100644
--- a/setup.py
+++ b/setup.py
@@ -53,6 +53,7 @@ setup(name="loo.py",
           "loopy",
           "loopy.codegen",
           "loopy.kernel",
+          "loopy.library",
           ],
 
       # 2to3 invocation