diff --git a/hpvm/tools/py-approxhpvm/CMakeLists.txt b/hpvm/tools/py-approxhpvm/CMakeLists.txt
index 1e5eeb891d35fc028d1aa85c5e5e679902a4dad7..be796ab69aa0cd226963cf31939f74fc392a8822 100644
--- a/hpvm/tools/py-approxhpvm/CMakeLists.txt
+++ b/hpvm/tools/py-approxhpvm/CMakeLists.txt
@@ -22,16 +22,20 @@ set(DIRECT_LINK_LIBS ${OpenCL_LIBRARY} "$<TARGET_FILE:tensor_runtime>")
 # and does not export its file location.
 # Keep this in sync with hpvm/projects/hpvm-rt/CMakeLists.txt.
 set(HPVM_RT_PATH ${LLVM_BUILD_DIR}/tools/hpvm/projects/hpvm-rt/hpvm-rt.bc)
+# And this must be manually in sync with `hpvm/lib/Transforms/*`.
+# which is fine for because we don't have many passes for now.
 set(
     AVAILABLE_PASSES
     LLVMBuildDFG
-    LLVMInPlaceDFGAnalysis
+    LLVMClearDFG
     LLVMDFG2LLVM_CPU
     LLVMDFG2LLVM_CUDNN
+    LLVMDFG2LLVM_OpenCL
     LLVMDFG2LLVM_WrapperAPI
     LLVMFuseHPVMTensorNodes
-    LLVMClearDFG
     LLVMGenHPVM
+    LLVMInPlaceDFGAnalysis
+    LLVMLocalMem
 )
 
 # First resolve all `@symbol@` by configuring the file
diff --git a/hpvm/tools/py-approxhpvm/main.py.in b/hpvm/tools/py-approxhpvm/main.py.in
index 7b211911643c64d8bf2c34ef8a43e3ac98cdd88a..a0d2da10c2cf8e879dabd5b931e61c934436374c 100644
--- a/hpvm/tools/py-approxhpvm/main.py.in
+++ b/hpvm/tools/py-approxhpvm/main.py.in
@@ -24,18 +24,30 @@ COMPILE_FLAGS = ["fno-exceptions", "std=c++11", "O3"]
 def compile_hpvm_c(
     input_file: PathLike,
     output_file: PathLike,
-    codegen_target: str = "tensor",
+    tensor_target: Optional[str],
+    opencl: bool,
     include: List[PathLike] = None,
     working_dir: PathLike = None,
     conf_file: PathLike = None,
 ):
     from subprocess import check_output
 
-    codegen_functions = {
-        "tensor": lambda i, o: opt_codegen_tensor(i, o, conf_file),
-        "cudnn": opt_codegen_cudnn
-    }
-    codegen_f = codegen_functions[codegen_target]
+    passes = ["LLVMBuildDFG", "LLVMInPlaceDFGAnalysis"]
+    flags = ["buildDFG", "inplace"]
+    if tensor_target == "tensor":
+        if conf_file is None:
+            raise ValueError("conf_file must be defined when tensor_target=='tensor'.")
+        passes += ["LLVMFuseHPVMTensorNodes", "LLVMDFG2LLVM_WrapperAPI"]
+        flags += ["hpvm-fuse", "dfg2llvm-wrapperapi", f"configuration-inputs-filename={conf_file}"]
+    elif tensor_target == "cudnn":
+        passes += ["LLVMDFG2LLVM_CUDNN"]
+        flags += ["dfg2llvm-cudnn"]
+    if opencl:
+        passes += ["LLVMDFG2LLVM_OpenCL"]
+        flags += ["dfg2llvm-opencl"]
+    passes += ["LLVMDFG2LLVM_CPU", "LLVMClearDFG", "LLVMGenHPVM"]
+    flags += ["dfg2llvm-cpu", "clearDFG"]
+
     working_dir = Path(working_dir or ".")
     if not working_dir.is_dir():
         os.makedirs(working_dir)
@@ -48,7 +60,7 @@ def compile_hpvm_c(
     commands = [
         hpvm_c_to_ll(input_file, ll_file, extra_includes=include),
         opt_codegen_hpvm(ll_file, hpvm_ll_file),
-        codegen_f(hpvm_ll_file, llvm_ll_file),
+        _run_opt(hpvm_ll_file, llvm_ll_file, passes, flags),
         link_hpvm_rt(llvm_ll_file, hpvm_rt_linked_file),
         link_binary(hpvm_rt_linked_file, output_file),
     ]
@@ -76,36 +88,6 @@ def opt_codegen_hpvm(src_file: PathLike, target_file: PathLike) -> List[str]:
     return _run_opt(src_file, target_file, ["LLVMGenHPVM"], ["genhpvm", "globaldce"])
 
 
-def opt_codegen_cudnn(src_file: PathLike, target_file: PathLike) -> List[str]:
-    passes = [
-        "LLVMBuildDFG", "LLVMInPlaceDFGAnalysis",
-        "LLVMDFG2LLVM_CUDNN", "LLVMDFG2LLVM_CPU",
-        "LLVMFuseHPVMTensorNodes", "LLVMClearDFG", "LLVMGenHPVM"
-    ]
-    flags = [
-        "buildDFG", "inplace", "hpvm-fuse",
-        "dfg2llvm-cudnn", "dfg2llvm-cpu", "clearDFG"
-    ]
-    return _run_opt(src_file, target_file, passes, flags)
-
-
-def opt_codegen_tensor(
-    src_file: PathLike, target_file: PathLike, conf_file: PathLike
-):
-    passes = [
-        "LLVMBuildDFG", "LLVMInPlaceDFGAnalysis",
-        "LLVMDFG2LLVM_WrapperAPI", "LLVMDFG2LLVM_CPU",
-        "LLVMFuseHPVMTensorNodes", "LLVMClearDFG", "LLVMGenHPVM"
-    ]
-    flags = [
-        "buildDFG", "inplace", "hpvm-fuse",
-        "dfg2llvm-wrapperapi",
-        f"configuration-inputs-filename={conf_file}",
-        "dfg2llvm-cpu", "clearDFG",
-    ]
-    return _run_opt(src_file, target_file, passes, flags)
-
-
 def link_hpvm_rt(src_file: PathLike, target_file: PathLike) -> List[str]:
     return [str(LLVM_BUILD_BIN / "llvm-link"), str(src_file), HPVM_RT_PATH, "-o", str(target_file)]
 
@@ -143,7 +125,7 @@ def _run_opt(
 ) -> List[str]:
     unavailable = set(pass_names) - set(AVAILABLE_PASSES)
     if unavailable:
-        raise ValueError(f"Passes {unavailable} are unavailable from CMake")
+        raise ValueError(f"Passes {unavailable} are unavailable for this compilation.")
     load_passes_strs = [s for pass_ in pass_names for s in ["-load", f"{pass_}.so"]]
     pass_flags_strs = [f"-{flag}" for flag in pass_flags]
     return [
@@ -158,18 +140,22 @@ def parse_args():
     parser.add_argument("output_file", type=Path, help="Path to generate binary to")
     parser.add_argument(
         "-t",
-        "--codegen-target",
+        "--tensor-target",
         type=str,
-        required=True,
         choices=["tensor", "cudnn"],
-        help="Backend to use",
+        help="Backend to use for tensor operators",
     )
     parser.add_argument(
-        "-d", "--working-dir", type=Path, help="Directory to generate temp files in"
+        "--conf-file", type=Path,
+        help="File to approximation configurations; required for tensor target 'tensor'"
     )
     parser.add_argument(
-        "--conf-file", type=Path,
-        help="File to approximation configurations; required for 'tensor' target"
+        "--opencl",
+        action="store_true",
+        help="Use OpenCL support. Requires HPVM built with OpenCL",
+    )
+    parser.add_argument(
+        "-d", "--working-dir", type=Path, help="Directory to generate temp files in"
     )
     parser.add_argument(
         "-I", "--include", type=Path, action="append",
@@ -177,9 +163,9 @@ def parse_args():
     )
 
     args = parser.parse_args()
-    if args.codegen_target == "tensor":
+    if args.tensor_target == "tensor":
         if args.conf_file is None:
-            parser.error('Codegen target "tensor" requires --conf-file argument')
+            parser.error('Tensor target "tensor" requires --conf-file argument')
     return args