diff --git a/loopy/target/opencl.py b/loopy/target/opencl.py
index 39e4844116f10e7527f35ea34b3aaa5027a20e93..1e558e99b0fd8c73dd8b2ac34b2de8711cb2108c 100644
--- a/loopy/target/opencl.py
+++ b/loopy/target/opencl.py
@@ -189,51 +189,53 @@ class OpenCLCallable(ScalarCallable):
     def with_types(self, arg_id_to_dtype, callables_table):
         name = self.name
 
-        # unary functions
-        if name in ["fabs", "acos", "asin", "atan", "cos", "cosh", "sin", "sinh",
-                    "tan", "tanh", "exp", "log", "log10", "sqrt", "ceil", "floor",
-                    "erf", "erfc"]:
-
+        # {{{ unary functions
+        if name == "abs":
             for id in arg_id_to_dtype:
                 if not -1 <= id <= 0:
                     raise LoopyError(f"'{name}' can take only one argument.")
 
             if 0 not in arg_id_to_dtype or arg_id_to_dtype[0] is None:
-                # the types provided aren't mature enough to specialize the
-                # callable
                 return (
                         self.copy(arg_id_to_dtype=arg_id_to_dtype),
                         callables_table)
 
-            dtype = arg_id_to_dtype[0]
-            dtype = dtype.numpy_dtype
+            dtype = arg_id_to_dtype[0].numpy_dtype
 
             if dtype.kind in ("u", "i"):
-                # ints and unsigned casted to float32
-                dtype = np.float32
-            elif dtype.kind == "c":
-                raise LoopyTypeError(f"{name} does not support type {dtype}")
+                # OpenCL C 2.2, Section 6.13.3: abs returns *u*gentype
+                from loopy.types import to_unsigned_dtype
+                return (self.copy(name_in_target=name,
+                            arg_id_to_dtype={
+                                0: NumpyType(dtype),
+                                -1: NumpyType(to_unsigned_dtype(dtype))}),
+                        callables_table)
+            elif dtype.kind == "f":
+                name = "fabs"
+            else:
+                raise LoopyTypeError(f"'{name}' does not support type {dtype}")
+
+        # deliberately not elif: abs branch above may end up taking this.
+        if name in ["fabs", "acos", "asin", "atan", "cos", "cosh", "sin", "sinh",
+                    "tan", "tanh", "exp", "log", "log10", "sqrt", "ceil", "floor",
+                    "erf", "erfc"]:
 
-            return (
-                    self.copy(name_in_target=name,
-                        arg_id_to_dtype={0: NumpyType(dtype), -1:
-                            NumpyType(dtype)}),
-                    callables_table)
-        elif name == "abs":
             for id in arg_id_to_dtype:
                 if not -1 <= id <= 0:
                     raise LoopyError(f"'{name}' can take only one argument.")
 
             if 0 not in arg_id_to_dtype or arg_id_to_dtype[0] is None:
-                # the types provided aren't mature enough to specialize the
-                # callable
                 return (
                         self.copy(arg_id_to_dtype=arg_id_to_dtype),
                         callables_table)
 
-            dtype = arg_id_to_dtype[0].numpy_dtype
+            dtype = arg_id_to_dtype[0]
+            dtype = dtype.numpy_dtype
 
-            if dtype.kind not in ("u", "i"):
+            if dtype.kind in ("u", "i"):
+                # ints and unsigned casted to float32
+                dtype = np.float32
+            elif dtype.kind == "c":
                 raise LoopyTypeError(f"{name} does not support type {dtype}")
 
             return (
@@ -241,6 +243,9 @@ class OpenCLCallable(ScalarCallable):
                         arg_id_to_dtype={0: NumpyType(dtype), -1:
                             NumpyType(dtype)}),
                     callables_table)
+
+        # }}}
+
         # binary functions
         elif name in ["fmax", "fmin", "atan2", "copysign"]:
 
@@ -253,8 +258,6 @@ class OpenCLCallable(ScalarCallable):
 
             if 0 not in arg_id_to_dtype or 1 not in arg_id_to_dtype or (
                     arg_id_to_dtype[0] is None or arg_id_to_dtype[1] is None):
-                # the types provided aren't mature enough to specialize the
-                # callable
                 return (
                         self.copy(arg_id_to_dtype=arg_id_to_dtype),
                         callables_table)
diff --git a/loopy/types.py b/loopy/types.py
index e7504862acc7944fa65fbdebb6cfd851f07ac812..14bf89fa197bf1aacbf1488ca53b8cfeebe9a174 100644
--- a/loopy/types.py
+++ b/loopy/types.py
@@ -20,6 +20,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.
 """
 
+from typing import Any
 from warnings import warn
 import numpy as np
 
@@ -245,4 +246,22 @@ def to_loopy_type(dtype, allow_auto=False, allow_none=False, for_atomic=False,
         raise TypeError("dtype must be a LoopyType, or convertible to one, "
                 "found '%s' instead" % type(dtype))
 
+
+_TO_UNSIGNED_MAPPING = {
+        np.int8: np.uint8,
+        np.int16: np.uint16,
+        np.int32: np.uint32,
+        np.int64: np.uint64,
+        }
+
+
+def to_unsigned_dtype(dtype: "np.dtype[Any]") -> "np.dtype[Any]":
+    if dtype.kind == "u":
+        return dtype
+    if dtype.kind != "i":
+        raise ValueError("can only convert integer types to unsigned")
+
+    return _TO_UNSIGNED_MAPPING[dtype.type]
+
+
 # vim: foldmethod=marker