diff --git a/MEMO b/MEMO
index 9227c654b333d5f7fbf4a87381079630a49b340e..13d8e6afe025f4a5f8836f16e90f02742c943bb0 100644
--- a/MEMO
+++ b/MEMO
@@ -48,8 +48,6 @@ To-do
 
 - Kernel fusion
 
-- rename iname
-
 - when are link_inames, duplicate_inames safe?
 
 - ExpandingIdentityMapper
@@ -145,6 +143,8 @@ Future ideas
 Dealt with
 ^^^^^^^^^^
 
+- rename iname
+
 - delete unused inames
 
 - Expose iname-duplicate-and-rename as a primitive.
diff --git a/doc/reference.rst b/doc/reference.rst
index e066ba1df5ff27822f2052968850e6212e187b45..e3a59b97d89a2282ea4641025afd4eea17d3ce97 100644
--- a/doc/reference.rst
+++ b/doc/reference.rst
@@ -165,9 +165,9 @@ Wrangling inames
 
 .. autofunction:: link_inames
 
-.. autofunction:: rename_inames
+.. autofunction:: rename_iname
 
-.. autofunction:: delete_unused_inames
+.. autofunction:: remove_unused_inames
 
 Dealing with Substitution Rules
 -------------------------------
diff --git a/loopy/__init__.py b/loopy/__init__.py
index 6257e36b0c82e7a1ad03b5e0a123ecae031f20b6..9766aa37047111bddf15b61a1d14d628a6175d04 100644
--- a/loopy/__init__.py
+++ b/loopy/__init__.py
@@ -550,6 +550,23 @@ def duplicate_inames(knl, inames, within, new_inames=None, suffix=None,
 
 # }}}
 
+def rename_iname(knl, old_iname, new_iname, within):
+    """
+    :arg within: a stack match as understood by 
+        :func:`loopy.context_matching.parse_stack_match`.
+    """
+
+    var_name_gen = knl.get_var_name_generator()
+
+    if var_name_gen.is_name_conflicting(new_iname):
+        raise ValueError("iname '%s' conflicts with an existing identifier"
+                "--cannot rename" % new_iname)
+
+    knl = duplicate_inames([old_iname], within, [new_iname])
+    knl = remove_unused_inames(knl, [old_iname])
+
+    return knl
+
 # {{{ link inames
 
 def link_inames(knl, inames, new_iname, within=None, tag=None):
@@ -646,7 +663,7 @@ def link_inames(knl, inames, new_iname, within=None, tag=None):
 
     # }}}
 
-    knl = delete_unused_inames(knl, inames)
+    knl = remove_unused_inames(knl, inames)
 
     if tag is not None:
         knl = tag_inames(knl, {new_iname: tag})
@@ -655,9 +672,9 @@ def link_inames(knl, inames, new_iname, within=None, tag=None):
 
 # }}}
 
-# {{{ delete unused inames
+# {{{ remove unused inames
 
-def delete_unused_inames(knl, inames=None):
+def remove_unused_inames(knl, inames=None):
     """Delete those among *inames* that are unused, i.e. project them
     out of the domain. If these inames pose implicit restrictions on
     other inames, these restrictions will persist as existentially