Add HAL CTS tests using executables. (#7982)

Fixes https://github.com/google/iree/issues/5678 (for `executable_cache_test`, tests issuing dispatches can follow on later)

Tests are filtered based on the HAL driver and compiler target being enabled as well as the presence of a new `COMPILER_TARGET_BACKEND` parameter to the `iree_hal_cts_test_suite()` function.

If all of those conditions are met, executable testdata is generated using the new `-iree-mlir-to-hal-executable` translation mode and relevant tests in the suite get to load and reference the generated data.

---

Rough edges:

* ~~`iree_file_toc_t` definition copy/paste from `generate_embed_data` (since leaf binaries provide their own implementations)~~
* Specifying executable formats in CMake is hacky (`"\"embedded-elf-\" IREE_ARCH"`)
* We may also want to test the system loader as well as the embedded loader, which is possible with another `iree_hal_cts_test_suite()` call

I was also expecting the CMake to be a bit gnarly, and it is. Could maybe refactor into some helper functions or golf on the logic a bit. The interface to each HAL implementation is pretty nice, but the new implicit dependency on `iree-translate` makes it harder to use with out-of-tree runtime HAL drivers + compiler targets. Could pass `TRANSLATE_TOOL` as well 🤔 
diff --git a/build_tools/cmake/iree_bytecode_module.cmake b/build_tools/cmake/iree_bytecode_module.cmake
index 6d9bc26..f918702 100644
--- a/build_tools/cmake/iree_bytecode_module.cmake
+++ b/build_tools/cmake/iree_bytecode_module.cmake
@@ -25,8 +25,8 @@
 #    -DIREE_BUILD_TESTS=ON to CMake.
 #
 # Note:
-# By default, iree_bytecode_module will create a library named ${NAME}_cc,
-# and alias target iree::${NAME}_cc. The iree:: form should always be used.
+# By default, iree_bytecode_module will create a library named ${NAME}_c,
+# and alias target iree::${NAME}_c. The iree:: form should always be used.
 # This is to reduce namespace pollution.
 function(iree_bytecode_module)
   cmake_parse_arguments(
diff --git a/build_tools/cmake/iree_c_embed_data.cmake b/build_tools/cmake/iree_c_embed_data.cmake
index ec13693..659e256 100644
--- a/build_tools/cmake/iree_c_embed_data.cmake
+++ b/build_tools/cmake/iree_c_embed_data.cmake
@@ -49,7 +49,7 @@
   list(APPEND _ARGS "--output_header=${_RULE_H_FILE_OUTPUT}")
   list(APPEND _ARGS "--output_impl=${_RULE_C_FILE_OUTPUT}")
   list(APPEND _ARGS "--identifier=${_IDENTIFIER}")
-  if(DEFINED _RULE_STRIP_PREFIX})
+  if(DEFINED _RULE_STRIP_PREFIX)
     list(APPEND _ARGS "--strip_prefix=${_RULE_STRIP_PREFIX}")
   endif()
   if(${_RULE_FLATTEN})
diff --git a/build_tools/cmake/iree_hal_cts_test_suite.cmake b/build_tools/cmake/iree_hal_cts_test_suite.cmake
index 68f166b..3c60e30 100644
--- a/build_tools/cmake/iree_hal_cts_test_suite.cmake
+++ b/build_tools/cmake/iree_hal_cts_test_suite.cmake
@@ -16,6 +16,15 @@
 #       for `iree_hal_driver_registry_try_create_by_name()` within test code.
 #   DRIVER_REGISTRATION_HDR: The C #include path for `DRIVER_REGISTRATION_FN`.
 #   DRIVER_REGISTRATION_FN: The C function which registers `DRIVER_NAME`.
+#   COMPILER_TARGET_BACKEND: Optional target backend name to pass to the
+#       `-iree-hal-target-backends` option of `iree-translate` to use for
+#       executable generation. If this is omitted, or the associated compiler
+#       target is not enabled, tests which use executables will be disabled.
+#   EXECUTABLE_FORMAT: Executable format identifier. Will be interpreted
+#       literally in C++ and may include macros like IREE_ARCH as needed.
+#       Examples:
+#           "\"vmvx-bytecode-fb\"" -> "vmvx-bytecode-fb"
+#           "\"embedded-elf-\" IREE_ARCH" -> "embedded-elf-x86_64"
 #   DEPS: List of other libraries to link in to the binary targets (typically
 #       the dependency for `DRIVER_REGISTRATION_HDR`).
 #   EXCLUDED_TESTS: List of test names from `IREE_ALL_CTS_TESTS` to
@@ -30,18 +39,117 @@
   cmake_parse_arguments(
     _RULE
     ""
-    "DRIVER_NAME;DRIVER_REGISTRATION_HDR;DRIVER_REGISTRATION_FN"
+    "DRIVER_NAME;DRIVER_REGISTRATION_HDR;DRIVER_REGISTRATION_FN;COMPILER_TARGET_BACKEND;EXECUTABLE_FORMAT"
     "DEPS;EXCLUDED_TESTS;LABELS"
     ${ARGN}
   )
 
+  # Omit tests for which the specified driver is not enabled.
+  string(TOUPPER ${_RULE_DRIVER_NAME} _UPPERCASE_DRIVER)
+  string(REPLACE "-" "_" _NORMALIZED_DRIVER ${_UPPERCASE_DRIVER})
+  if(NOT DEFINED IREE_HAL_DRIVER_${_NORMALIZED_DRIVER})
+    message(SEND_ERROR "Unknown driver '${_RULE_DRIVER_NAME}'. Check IREE_HAL_DRIVER_* options.")
+  endif()
+  if(NOT IREE_HAL_DRIVER_${_NORMALIZED_DRIVER})
+    return()
+  endif()
+
   list(APPEND _RULE_LABELS "driver=${_RULE_DRIVER_NAME}")
 
+  # Enable executable tests if a compiler target backend capable of producing
+  # executables compatible with the driver is provided and enabled.
+  set(_ENABLE_EXECUTABLE_TESTS OFF)
+  if(DEFINED _RULE_COMPILER_TARGET_BACKEND)
+    string(TOUPPER ${_RULE_COMPILER_TARGET_BACKEND} _UPPERCASE_TARGET_BACKEND)
+    string(REPLACE "-" "_" _NORMALIZED_TARGET_BACKEND ${_UPPERCASE_TARGET_BACKEND})
+    if(NOT DEFINED IREE_TARGET_BACKEND_${_NORMALIZED_TARGET_BACKEND})
+      message(SEND_ERROR "Unknown backend '${_RULE_COMPILER_TARGET_BACKEND}'. Check IREE_TARGET_BACKEND_* options.")
+    endif()
+    if(DEFINED IREE_HOST_BINARY_ROOT)
+      # If we're not building the host tools from source under this configuration,
+      # such as when cross compiling, then we can't easily check for which
+      # compiler target backends are enabled. Just assume all are enabled and only
+      # rely on the runtime HAL driver check above for filtering.
+      set(_ENABLE_EXECUTABLE_TESTS ON)
+    else()
+      # We are building the host tools, so check enabled compiler target backends.
+      if(IREE_TARGET_BACKEND_${_NORMALIZED_TARGET_BACKEND})
+        set(_ENABLE_EXECUTABLE_TESTS ON)
+      endif()
+    endif()
+  endif()
+
+  # Generate testdata if executable tests are enabled.
+  if(_ENABLE_EXECUTABLE_TESTS)
+
+    set(_EXECUTABLES_TESTDATA_NAME "${_RULE_COMPILER_TARGET_BACKEND}_executables")
+
+    set(_TRANSLATE_FLAGS
+      "-iree-mlir-to-hal-executable"
+      "-iree-hal-target-backends=${_RULE_COMPILER_TARGET_BACKEND}"
+    )
+    if(ANDROID)
+      set(_TARGET_TRIPLE "aarch64-none-linux-android${ANDROID_PLATFORM_LEVEL}")
+      list(APPEND _TRANSLATE_FLAGS "--iree-llvm-target-triple=${_TARGET_TRIPLE}")
+    endif()
+
+    # Skip if already created (multiple suites using the same compiler setting).
+    iree_package_name(_PACKAGE_NAME)
+    if(NOT TARGET ${_PACKAGE_NAME}_${_EXECUTABLES_TESTDATA_NAME}_c)
+      set(_EMBED_DATA_SOURCES "")
+      foreach(_FILE_NAME ${IREE_ALL_CTS_EXECUTABLE_SOURCES})
+        # Note: this is an abuse of naming. We are not building a bytecode
+        # module, but this CMake rule already wraps iree-translate.
+        # We should add a new function like `iree_hal_executable()`.
+        iree_bytecode_module(
+          NAME
+            ${_RULE_COMPILER_TARGET_BACKEND}_${_FILE_NAME}
+          MODULE_FILE_NAME
+            "${_RULE_COMPILER_TARGET_BACKEND}_${_FILE_NAME}.bin"
+          SRC
+            "${IREE_ROOT_DIR}/iree/hal/cts/testdata/${_FILE_NAME}.mlir"
+          FLAGS
+            ${_TRANSLATE_FLAGS}
+          PUBLIC
+          TESTONLY
+        )
+        list(APPEND _EMBED_DATA_SOURCES "${_RULE_COMPILER_TARGET_BACKEND}_${_FILE_NAME}.bin")
+      endforeach()
+
+      iree_c_embed_data(
+        NAME
+          ${_EXECUTABLES_TESTDATA_NAME}_c
+        GENERATED_SRCS
+          ${_EMBED_DATA_SOURCES}
+        C_FILE_OUTPUT
+          "${_EXECUTABLES_TESTDATA_NAME}_c.c"
+        H_FILE_OUTPUT
+          "${_EXECUTABLES_TESTDATA_NAME}_c.h"
+        IDENTIFIER
+          "iree_cts_testdata_executables"
+        STRIP_PREFIX
+          "${_RULE_COMPILER_TARGET_BACKEND}_"
+        FLATTEN
+        PUBLIC
+        TESTONLY
+      )
+
+    endif()
+
+    list(APPEND _RULE_DEPS
+      ::${_EXECUTABLES_TESTDATA_NAME}_c
+    )
+  endif()
+
   foreach(_TEST_NAME ${IREE_ALL_CTS_TESTS})
     if("${_TEST_NAME}" IN_LIST _RULE_EXCLUDED_TESTS)
       continue()
     endif()
 
+    if("${_TEST_NAME}" IN_LIST IREE_EXECUTABLE_CTS_TESTS AND NOT _ENABLE_EXECUTABLE_TESTS)
+      continue()
+    endif()
+
     # Note: driver names may contain dashes and other special characters. We
     # could sanitize for file and target names, but passing through directly
     # may be more intuitive.
@@ -55,6 +163,11 @@
     set(IREE_CTS_DRIVER_REGISTRATION_FN "${_RULE_DRIVER_REGISTRATION_FN}")
     set(IREE_CTS_TEST_CLASS_NAME "${_TEST_NAME}_test")
     set(IREE_CTS_DRIVER_NAME "${_RULE_DRIVER_NAME}")
+    set(IREE_CTS_EXECUTABLE_FORMAT "${_RULE_EXECUTABLE_FORMAT}")
+    if(_ENABLE_EXECUTABLE_TESTS)
+      set(IREE_CTS_EXECUTABLES_TESTDATA_HDR "${_EXECUTABLES_TESTDATA_NAME}_c.h")
+    endif()
+
     configure_file(
       "${IREE_ROOT_DIR}/iree/hal/cts/cts_test_template.cc.in"
       ${_TEST_SOURCE_NAME}
diff --git a/experimental/rocm/cts/CMakeLists.txt b/experimental/rocm/cts/CMakeLists.txt
index 0f65682..e5d7d07 100644
--- a/experimental/rocm/cts/CMakeLists.txt
+++ b/experimental/rocm/cts/CMakeLists.txt
@@ -6,11 +6,15 @@
 
 iree_hal_cts_test_suite(
   DRIVER_NAME
-    vulkan
+    rocm
   DRIVER_REGISTRATION_HDR
     "experimental/rocm/registration/driver_module.h"
   DRIVER_REGISTRATION_FN
     "iree_hal_rocm_driver_module_register"
+  COMPILER_TARGET_BACKEND
+    "rocm"
+  EXECUTABLE_FORMAT
+    "\"PTXE\""
   DEPS
     experimental::rocm::registration
 )
diff --git a/iree/hal/cts/CMakeLists.txt b/iree/hal/cts/CMakeLists.txt
index 9e10a2e..dea7cfd 100644
--- a/iree/hal/cts/CMakeLists.txt
+++ b/iree/hal/cts/CMakeLists.txt
@@ -12,12 +12,27 @@
   "descriptor_set"
   "driver"
   "event"
+  "executable_cache"
   "executable_layout"
   "semaphore_submission"
   "semaphore"
   PARENT_SCOPE
 )
 
+# These tests use executables produced by the iree-translate compiler tool.
+# If the compiler is disabled or a HAL driver implementation is not yet
+# connected to a functional compiler target, these tests can be skipped.
+set(IREE_EXECUTABLE_CTS_TESTS
+  "executable_cache"
+  PARENT_SCOPE
+)
+
+# List of testdata/{name}.mlir source files.
+set(IREE_ALL_CTS_EXECUTABLE_SOURCES
+  "executable_cache_test"
+  PARENT_SCOPE
+)
+
 iree_cc_library(
   NAME
     cts_test_base
@@ -129,6 +144,18 @@
 
 iree_cc_library(
   NAME
+    executable_cache_test_library
+  HDRS
+    "executable_cache_test.h"
+  DEPS
+    ::cts_test_base
+    iree::base
+    iree::hal
+    iree::testing::gtest
+)
+
+iree_cc_library(
+  NAME
     semaphore_test_library
   HDRS
     "semaphore_test.h"
diff --git a/iree/hal/cts/cts_test_base.h b/iree/hal/cts/cts_test_base.h
index 611926d..7f3599a 100644
--- a/iree/hal/cts/cts_test_base.h
+++ b/iree/hal/cts/cts_test_base.h
@@ -11,6 +11,7 @@
 #include <string>
 
 #include "iree/base/api.h"
+#include "iree/base/string_view.h"
 #include "iree/hal/api.h"
 #include "iree/testing/gtest.h"
 #include "iree/testing/status_matchers.h"
@@ -19,12 +20,18 @@
 namespace hal {
 namespace cts {
 
-// Leaf test binaries must implement this function, registering the driver
-// that will be used with INSTANTIATE_TEST_SUITE_P.
-// Multiple drivers _may_ be registered and used with parameterized test suite
-// construction, but the expected use is 1 driver : 1 test suite.
+// Registers the driver that will be used with INSTANTIATE_TEST_SUITE_P.
+// Leaf test binaries must implement this function.
 iree_status_t register_test_driver(iree_hal_driver_registry_t* registry);
 
+// Returns the executable format for the driver under test.
+// Leaf test binaries must implement this function.
+const char* get_test_executable_format();
+
+// Returns a file's executable data for the driver under test.
+// Leaf test binaries must implement this function.
+iree_const_byte_span_t get_test_executable_data(iree_string_view_t file_name);
+
 // Common setup for tests parameterized on driver names.
 class CtsTestBase : public ::testing::TestWithParam<std::string> {
  protected:
diff --git a/iree/hal/cts/cts_test_template.cc.in b/iree/hal/cts/cts_test_template.cc.in
index 73dd0f2..be02a15 100644
--- a/iree/hal/cts/cts_test_template.cc.in
+++ b/iree/hal/cts/cts_test_template.cc.in
@@ -10,6 +10,8 @@
 #cmakedefine IREE_CTS_DRIVER_REGISTRATION_FN @IREE_CTS_DRIVER_REGISTRATION_FN@
 #cmakedefine IREE_CTS_TEST_CLASS_NAME @IREE_CTS_TEST_CLASS_NAME@
 #cmakedefine IREE_CTS_DRIVER_NAME "@IREE_CTS_DRIVER_NAME@"
+#cmakedefine IREE_CTS_EXECUTABLE_FORMAT @IREE_CTS_EXECUTABLE_FORMAT@
+#cmakedefine IREE_CTS_EXECUTABLES_TESTDATA_HDR "@IREE_CTS_EXECUTABLES_TESTDATA_HDR@"
 // clang-format on
 
 #include IREE_CTS_TEST_FILE_PATH
@@ -18,6 +20,10 @@
 #include "iree/hal/cts/cts_test_base.h"
 #include "iree/testing/gtest.h"
 
+#ifdef IREE_CTS_EXECUTABLES_TESTDATA_HDR
+#include IREE_CTS_EXECUTABLES_TESTDATA_HDR
+#endif
+
 namespace iree {
 namespace hal {
 namespace cts {
@@ -26,6 +32,28 @@
   return IREE_CTS_DRIVER_REGISTRATION_FN(registry);
 }
 
+const char* get_test_executable_format() {
+#ifdef IREE_CTS_EXECUTABLE_FORMAT
+  return IREE_CTS_EXECUTABLE_FORMAT;
+#else
+  return "UNDEFINED";
+#endif
+}
+
+iree_const_byte_span_t get_test_executable_data(iree_string_view_t file_name) {
+#ifdef IREE_CTS_EXECUTABLES_TESTDATA_HDR
+  const struct iree_file_toc_t* toc = iree_cts_testdata_executables_create();
+  for (size_t i = 0; i < iree_cts_testdata_executables_size(); ++i) {
+    const auto& file = toc[i];
+    if (iree_string_view_equal(file_name, iree_make_cstring_view(file.name))) {
+      return iree_make_const_byte_span(file.data, file.size);
+    }
+  }
+  // TODO(scotttodd): error handling / reporting? This a sharp edge.
+#endif
+  return {NULL, 0};
+}
+
 INSTANTIATE_TEST_SUITE_P(CTS, IREE_CTS_TEST_CLASS_NAME,
                          ::testing::Values(IREE_CTS_DRIVER_NAME),
                          GenerateTestName());
diff --git a/iree/hal/cts/executable_cache_test.h b/iree/hal/cts/executable_cache_test.h
new file mode 100644
index 0000000..3801f2e
--- /dev/null
+++ b/iree/hal/cts/executable_cache_test.h
@@ -0,0 +1,86 @@
+// Copyright 2021 The IREE Authors
+//
+// Licensed under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#ifndef IREE_HAL_CTS_EXECUTABLE_CACHE_TEST_H_
+#define IREE_HAL_CTS_EXECUTABLE_CACHE_TEST_H_
+
+#include "iree/base/api.h"
+#include "iree/base/string_view.h"
+#include "iree/hal/api.h"
+#include "iree/hal/cts/cts_test_base.h"
+#include "iree/testing/gtest.h"
+#include "iree/testing/status_matchers.h"
+
+namespace iree {
+namespace hal {
+namespace cts {
+
+class executable_cache_test : public CtsTestBase {};
+
+TEST_P(executable_cache_test, Create) {
+  iree_hal_executable_cache_t* executable_cache;
+  IREE_ASSERT_OK(iree_hal_executable_cache_create(
+      device_, iree_make_cstring_view("default"), &executable_cache));
+
+  iree_hal_executable_cache_release(executable_cache);
+}
+
+TEST_P(executable_cache_test, CantPrepareUnknownFormat) {
+  iree_hal_executable_cache_t* executable_cache;
+  IREE_ASSERT_OK(iree_hal_executable_cache_create(
+      device_, iree_make_cstring_view("default"), &executable_cache));
+
+  EXPECT_FALSE(iree_hal_executable_cache_can_prepare_format(
+      executable_cache, /*caching_mode=*/0, iree_make_cstring_view("FOO?")));
+
+  iree_hal_executable_cache_release(executable_cache);
+}
+
+TEST_P(executable_cache_test, PrepareExecutable) {
+  iree_hal_executable_cache_t* executable_cache;
+  IREE_ASSERT_OK(iree_hal_executable_cache_create(
+      device_, iree_make_cstring_view("default"), &executable_cache));
+
+  // Note: this layout must match the testdata executable.
+  iree_hal_descriptor_set_layout_t* descriptor_set_layout;
+  iree_hal_descriptor_set_layout_binding_t descriptor_set_layout_bindings[] = {
+      {0, IREE_HAL_DESCRIPTOR_TYPE_STORAGE_BUFFER},
+      {1, IREE_HAL_DESCRIPTOR_TYPE_STORAGE_BUFFER},
+  };
+  IREE_ASSERT_OK(iree_hal_descriptor_set_layout_create(
+      device_, IREE_HAL_DESCRIPTOR_SET_LAYOUT_USAGE_TYPE_IMMUTABLE,
+      IREE_ARRAYSIZE(descriptor_set_layout_bindings),
+      descriptor_set_layout_bindings, &descriptor_set_layout));
+  iree_hal_executable_layout_t* executable_layout;
+  IREE_ASSERT_OK(iree_hal_executable_layout_create(
+      device_, /*push_constants=*/0, /*set_layout_count=*/1,
+      &descriptor_set_layout, &executable_layout));
+
+  iree_hal_executable_spec_t executable_spec;
+  executable_spec.caching_mode =
+      IREE_HAL_EXECUTABLE_CACHING_MODE_ALIAS_PROVIDED_DATA;
+  executable_spec.executable_format =
+      iree_make_cstring_view(get_test_executable_format());
+  executable_spec.executable_data = get_test_executable_data(
+      iree_make_cstring_view("executable_cache_test.bin"));
+  executable_spec.executable_layout_count = 1;
+  executable_spec.executable_layouts = &executable_layout;
+
+  iree_hal_executable_t* executable;
+  IREE_ASSERT_OK(iree_hal_executable_cache_prepare_executable(
+      executable_cache, &executable_spec, &executable));
+
+  iree_hal_executable_release(executable);
+  iree_hal_executable_layout_release(executable_layout);
+  iree_hal_descriptor_set_layout_release(descriptor_set_layout);
+  iree_hal_executable_cache_release(executable_cache);
+}
+
+}  // namespace cts
+}  // namespace hal
+}  // namespace iree
+
+#endif  // IREE_HAL_CTS_EXECUTABLE_CACHE_TEST_H_
diff --git a/iree/hal/cts/testdata/executable_cache_test.mlir b/iree/hal/cts/testdata/executable_cache_test.mlir
new file mode 100644
index 0000000..0e0e73e
--- /dev/null
+++ b/iree/hal/cts/testdata/executable_cache_test.mlir
@@ -0,0 +1,37 @@
+// Bootstrapped from this source IR:
+//
+// func @abs(%input : tensor<f32>) -> (tensor<f32>) {
+//   %result = math.abs %input : tensor<f32>
+//   return %result : tensor<f32>
+// }
+
+#executable_layout = #hal.executable.layout<push_constants = 0, sets = [
+  #hal.descriptor_set.layout<0, bindings = [
+    #hal.descriptor_set.binding<0, storage_buffer>,
+    #hal.descriptor_set.binding<1, storage_buffer>
+  ]>
+]>
+
+hal.executable.source public @executable {
+  hal.executable.entry_point public @abs layout(#executable_layout)
+
+  builtin.module {
+    func @abs() {
+      %c0 = arith.constant 0 : index
+
+      %0 = hal.interface.binding.subspan set(0) binding(0) type(storage_buffer) offset(%c0) alignment(32) : !flow.dispatch.tensor<readonly:f32>
+      %1 = hal.interface.binding.subspan set(0) binding(1) type(storage_buffer) offset(%c0) alignment(32) : !flow.dispatch.tensor<writeonly:f32>
+
+      %2 = flow.dispatch.tensor.load %0, offsets = [], sizes = [], strides = [] : !flow.dispatch.tensor<readonly:f32> -> tensor<f32>
+      %3 = linalg.init_tensor [] : tensor<f32>
+      %4 = linalg.generic {indexing_maps = [affine_map<() -> ()>, affine_map<() -> ()>], iterator_types = []} ins(%2 : tensor<f32>) outs(%3 : tensor<f32>) {
+      ^bb0(%arg0: f32, %arg1: f32):
+        %5 = math.abs %arg0 : f32
+        linalg.yield %5 : f32
+      } -> tensor<f32>
+      flow.dispatch.tensor.store %4, %1, offsets = [], sizes = [], strides = [] : tensor<f32> -> !flow.dispatch.tensor<writeonly:f32>
+
+      return
+    }
+  }
+}
diff --git a/iree/hal/cuda/cts/CMakeLists.txt b/iree/hal/cuda/cts/CMakeLists.txt
index d0c6f59..520cd96 100644
--- a/iree/hal/cuda/cts/CMakeLists.txt
+++ b/iree/hal/cuda/cts/CMakeLists.txt
@@ -11,6 +11,10 @@
     "iree/hal/cuda/registration/driver_module.h"
   DRIVER_REGISTRATION_FN
     "iree_hal_cuda_driver_module_register"
+  COMPILER_TARGET_BACKEND
+    "cuda"
+  EXECUTABLE_FORMAT
+    "\"PTXE\""
   DEPS
     iree::hal::cuda::registration
   EXCLUDED_TESTS
diff --git a/iree/hal/dylib/cts/CMakeLists.txt b/iree/hal/dylib/cts/CMakeLists.txt
index 61c8efe..eb7337b 100644
--- a/iree/hal/dylib/cts/CMakeLists.txt
+++ b/iree/hal/dylib/cts/CMakeLists.txt
@@ -4,8 +4,6 @@
 # See https://llvm.org/LICENSE.txt for license information.
 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 
-if(${IREE_HAL_DRIVER_DYLIB})
-
 iree_hal_cts_test_suite(
   DRIVER_NAME
     dylib
@@ -13,14 +11,14 @@
     "iree/hal/dylib/registration/driver_module.h"
   DRIVER_REGISTRATION_FN
     "iree_hal_dylib_driver_module_register"
+  COMPILER_TARGET_BACKEND
+    "dylib-llvm-aot"
+  EXECUTABLE_FORMAT
+    "\"embedded-elf-\" IREE_ARCH"
   DEPS
     iree::hal::dylib::registration
 )
 
-endif()
-
-if(${IREE_HAL_DRIVER_DYLIB_SYNC})
-
 iree_hal_cts_test_suite(
   DRIVER_NAME
     dylib-sync
@@ -28,6 +26,10 @@
     "iree/hal/dylib/registration/driver_module_sync.h"
   DRIVER_REGISTRATION_FN
     "iree_hal_dylib_sync_driver_module_register"
+  COMPILER_TARGET_BACKEND
+    "dylib-llvm-aot"
+  EXECUTABLE_FORMAT
+    "\"embedded-elf-\" IREE_ARCH"
   DEPS
     iree::hal::dylib::registration::sync
   EXCLUDED_TESTS
@@ -36,5 +38,3 @@
     "event"
     "semaphore_submission"
 )
-
-endif()
diff --git a/iree/hal/vmvx/cts/CMakeLists.txt b/iree/hal/vmvx/cts/CMakeLists.txt
index 7bc5db1..f85ae45 100644
--- a/iree/hal/vmvx/cts/CMakeLists.txt
+++ b/iree/hal/vmvx/cts/CMakeLists.txt
@@ -4,8 +4,6 @@
 # See https://llvm.org/LICENSE.txt for license information.
 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 
-if(${IREE_HAL_DRIVER_VMVX})
-
 iree_hal_cts_test_suite(
   DRIVER_NAME
     vmvx
@@ -13,14 +11,14 @@
     "iree/hal/vmvx/registration/driver_module.h"
   DRIVER_REGISTRATION_FN
     "iree_hal_vmvx_driver_module_register"
+  COMPILER_TARGET_BACKEND
+    "vmvx"
+  EXECUTABLE_FORMAT
+    "\"vmvx-bytecode-fb\""
   DEPS
     iree::hal::vmvx::registration
 )
 
-endif()
-
-if(${IREE_HAL_DRIVER_VMVX_SYNC})
-
 iree_hal_cts_test_suite(
   DRIVER_NAME
     vmvx-sync
@@ -28,6 +26,10 @@
     "iree/hal/vmvx/registration/driver_module_sync.h"
   DRIVER_REGISTRATION_FN
     "iree_hal_vmvx_sync_driver_module_register"
+  COMPILER_TARGET_BACKEND
+    "vmvx"
+  EXECUTABLE_FORMAT
+    "\"vmvx-bytecode-fb\""
   DEPS
     iree::hal::vmvx::registration::sync
   EXCLUDED_TESTS
@@ -36,5 +38,3 @@
     "event"
     "semaphore_submission"
 )
-
-endif()
diff --git a/iree/hal/vulkan/cts/CMakeLists.txt b/iree/hal/vulkan/cts/CMakeLists.txt
index 7385754..0ca8b65 100644
--- a/iree/hal/vulkan/cts/CMakeLists.txt
+++ b/iree/hal/vulkan/cts/CMakeLists.txt
@@ -11,6 +11,10 @@
     "iree/hal/vulkan/registration/driver_module.h"
   DRIVER_REGISTRATION_FN
     "iree_hal_vulkan_driver_module_register"
+  COMPILER_TARGET_BACKEND
+    "vulkan-spirv"
+  EXECUTABLE_FORMAT
+    "\"SPVE\""
   DEPS
     iree::hal::vulkan::registration
 )