Fixing CUDA graph recording and allowing for re-recording. (#8005)

diff --git a/iree/hal/cuda/graph_command_buffer.c b/iree/hal/cuda/graph_command_buffer.c
index 592cbd9..093bbcb 100644
--- a/iree/hal/cuda/graph_command_buffer.c
+++ b/iree/hal/cuda/graph_command_buffer.c
@@ -67,9 +67,6 @@
   IREE_ASSERT_ARGUMENT(out_command_buffer);
   IREE_TRACE_ZONE_BEGIN(z0);
 
-  CUgraph graph = NULL;
-  CUDA_RETURN_IF_ERROR(context->syms, cuGraphCreate(&graph, /*flags=*/0),
-                       "cuGraphCreate");
   iree_hal_cuda_graph_command_buffer_t* command_buffer = NULL;
   size_t total_size = sizeof(*command_buffer) +
                       IREE_HAL_CUDA_MAX_KERNEL_ARG * sizeof(void*) +
@@ -82,7 +79,7 @@
         &iree_hal_cuda_graph_command_buffer_vtable, &command_buffer->base);
     command_buffer->context = context;
     command_buffer->block_pool = block_pool;
-    command_buffer->graph = graph;
+    command_buffer->graph = NULL;
     command_buffer->exec = NULL;
     command_buffer->last_node = NULL;
 
@@ -100,27 +97,38 @@
   if (iree_status_is_ok(status)) {
     *out_command_buffer = &command_buffer->base;
   } else {
-    context->syms->cuGraphDestroy(graph);
+    iree_hal_command_buffer_release(&command_buffer->base);
   }
-
   IREE_TRACE_ZONE_END(z0);
   return status;
 }
 
+static void iree_hal_cuda_graph_command_buffer_reset(
+    iree_hal_cuda_graph_command_buffer_t* command_buffer) {
+  if (command_buffer->graph != NULL) {
+    CUDA_IGNORE_ERROR(command_buffer->context->syms,
+                      cuGraphDestroy(command_buffer->graph));
+    command_buffer->graph = NULL;
+  }
+
+  if (command_buffer->exec != NULL) {
+    CUDA_IGNORE_ERROR(command_buffer->context->syms,
+                      cuGraphExecDestroy(command_buffer->exec));
+    command_buffer->exec = NULL;
+  }
+
+  command_buffer->last_node = NULL;
+
+  iree_hal_resource_set_reset(command_buffer->resource_set);
+}
+
 static void iree_hal_cuda_graph_command_buffer_destroy(
     iree_hal_command_buffer_t* base_command_buffer) {
   iree_hal_cuda_graph_command_buffer_t* command_buffer =
       iree_hal_cuda_graph_command_buffer_cast(base_command_buffer);
   IREE_TRACE_ZONE_BEGIN(z0);
 
-  if (command_buffer->graph != NULL) {
-    CUDA_IGNORE_ERROR(command_buffer->context->syms,
-                      cuGraphDestroy(command_buffer->graph));
-  }
-  if (command_buffer->exec != NULL) {
-    CUDA_IGNORE_ERROR(command_buffer->context->syms,
-                      cuGraphExecDestroy(command_buffer->exec));
-  }
+  iree_hal_cuda_graph_command_buffer_reset(command_buffer);
   iree_hal_resource_set_free(command_buffer->resource_set);
   iree_allocator_free(command_buffer->context->host_allocator, command_buffer);
 
@@ -153,13 +161,15 @@
     iree_hal_command_buffer_t* base_command_buffer) {
   iree_hal_cuda_graph_command_buffer_t* command_buffer =
       iree_hal_cuda_graph_command_buffer_cast(base_command_buffer);
-  // TODO(thomasroux): reset existing state, if present. Right now this leaks.
-  if (command_buffer->graph) {
-    return iree_make_status(
-        IREE_STATUS_UNIMPLEMENTED,
-        "rerecording of command buffers not yet supported with CUDA graphs");
-  }
-  iree_hal_resource_set_reset(command_buffer->resource_set);
+
+  // Reset any prior recorded commands.
+  iree_hal_cuda_graph_command_buffer_reset(command_buffer);
+
+  // Create a new empty graph to record into.
+  CUDA_RETURN_IF_ERROR(command_buffer->context->syms,
+                       cuGraphCreate(&command_buffer->graph, /*flags=*/0),
+                       "cuGraphCreate");
+
   return iree_ok_status();
 }
 
@@ -168,23 +178,24 @@
   iree_hal_cuda_graph_command_buffer_t* command_buffer =
       iree_hal_cuda_graph_command_buffer_cast(base_command_buffer);
 
-  size_t num_nodes;
-  CUDA_RETURN_IF_ERROR(command_buffer->context->syms,
-                       cuGraphGetNodes(command_buffer->graph, NULL, &num_nodes),
-                       "cuGraphGetNodes");
+  // Reset state used during recording.
+  command_buffer->last_node = NULL;
 
-  CUgraphNode error_node;
+  // Compile the graph.
+  CUgraphNode error_node = NULL;
   iree_status_t status =
       CU_RESULT_TO_STATUS(command_buffer->context->syms,
                           cuGraphInstantiate(&command_buffer->exec,
                                              command_buffer->graph, &error_node,
                                              /*logBuffer=*/NULL,
-                                             /* bufferSize=*/0));
+                                             /*bufferSize=*/0));
   if (iree_status_is_ok(status)) {
+    // No longer need the source graph used for construction.
     CUDA_IGNORE_ERROR(command_buffer->context->syms,
                       cuGraphDestroy(command_buffer->graph));
+    command_buffer->graph = NULL;
   }
-  command_buffer->graph = NULL;
+
   return iree_ok_status();
 }