Making paths required on `#hal.executable.object`.
This makes it possible to switch on the object type lower down in the
pipeline when data is attached.
diff --git a/compiler/src/iree/compiler/Dialect/HAL/IR/HALBase.td b/compiler/src/iree/compiler/Dialect/HAL/IR/HALBase.td
index 57c3b73..f178cb0 100644
--- a/compiler/src/iree/compiler/Dialect/HAL/IR/HALBase.td
+++ b/compiler/src/iree/compiler/Dialect/HAL/IR/HALBase.td
@@ -752,9 +752,12 @@
   let mnemonic = "executable.object";
   let summary = [{object file reference}];
   let description = [{
-    WIP; defines an object file that can be linked into executables.
+    Defines an object file that can be linked into executables.
     Today this is only supported for external file references with paths the
     compiler can successfully resolve from its current working directory.
+    Inlined data can optionally be provided to avoid the need for file system
+    access and ensure the data source is attached to the IR as it makes its way
+    through multiple compiler stages or reproducers.
 
     Future revisions may change this to an interface that allows both internal
     and external resources to define the object contents. Linking needs to be
@@ -770,12 +773,15 @@
     Example:
     ```mlir
     #hal.executable.object<{path = "some/file.obj"}>
-    #hal.executable.object<{data = dense<[...]> : vector<2048xi8>}>
+    #hal.executable.object<{
+      path = "some/embedded/file.obj",
+      data = dense<[...]> : vector<2048xi8>
+    }>
     ```
   }];
 
   let parameters = (ins
-    OptionalParameter<"StringAttr", "">:$path,
+    AttrParameter<"StringAttr", "">:$path,
     OptionalParameter<"DenseIntElementsAttr", "">:$data
   );
 
diff --git a/compiler/src/iree/compiler/Dialect/HAL/IR/HALTypes.cpp b/compiler/src/iree/compiler/Dialect/HAL/IR/HALTypes.cpp
index d706d16..d0a5e8b 100644
--- a/compiler/src/iree/compiler/Dialect/HAL/IR/HALTypes.cpp
+++ b/compiler/src/iree/compiler/Dialect/HAL/IR/HALTypes.cpp
@@ -464,8 +464,9 @@
   if (auto pathAttr = getPath()) {
     os << "path = ";
     p.printAttribute(getPath());
-  } else if (auto dataAttr = getData()) {
-    os << "data = ";
+  }
+  if (auto dataAttr = getData()) {
+    os << ", data = ";
     p.printAttribute(getData());
   }
   os << "}>";
diff --git a/compiler/src/iree/compiler/Dialect/HAL/IR/test/attributes.mlir b/compiler/src/iree/compiler/Dialect/HAL/IR/test/attributes.mlir
index 525c1a2..fd70f70 100644
--- a/compiler/src/iree/compiler/Dialect/HAL/IR/test/attributes.mlir
+++ b/compiler/src/iree/compiler/Dialect/HAL/IR/test/attributes.mlir
@@ -32,8 +32,8 @@
 // -----
 
 "executable.objects"() {
-  // CHECK: data = #hal.executable.object<{data = dense<[4, 5, 6, 7]> : vector<4xi8>}>
-  data = #hal.executable.object<{data = dense<[4, 5, 6, 7]> : vector<4xi8>}>,
+  // CHECK: data = #hal.executable.object<{path = "bar", data = dense<[4, 5, 6, 7]> : vector<4xi8>}>
+  data = #hal.executable.object<{path = "bar", data = dense<[4, 5, 6, 7]> : vector<4xi8>}>,
   // CHECK: path = #hal.executable.object<{path = "foo"}>
   path = #hal.executable.object<{path = "foo"}>
 } : () -> ()
diff --git a/compiler/src/iree/compiler/Dialect/HAL/Target/LLVM/LLVMCPUTarget.cpp b/compiler/src/iree/compiler/Dialect/HAL/Target/LLVM/LLVMCPUTarget.cpp
index 01425cf..2466f53 100644
--- a/compiler/src/iree/compiler/Dialect/HAL/Target/LLVM/LLVMCPUTarget.cpp
+++ b/compiler/src/iree/compiler/Dialect/HAL/Target/LLVM/LLVMCPUTarget.cpp
@@ -477,7 +477,11 @@
     if (auto objectAttrs = variantOp.getObjects()) {
       for (auto [index, attr] : llvm::enumerate(objectAttrs.value())) {
         auto objectAttr = attr.cast<IREE::HAL::ExecutableObjectAttr>();
-        if (objectAttr.getPath()) {
+        if (auto dataAttr = objectAttr.getData()) {
+          objectFiles.push_back(Artifact::createTemporary(
+              objectFiles.front().path + "_object_" + std::to_string(index),
+              ".o"));
+        } else {
           auto absolutePath = objectAttr.getAbsolutePath();
           if (failed(absolutePath)) {
             llvm::errs()
@@ -488,10 +492,6 @@
             return failure();
           }
           objectFiles.push_back(Artifact::fromFile(*absolutePath));
-        } else if (auto dataAttr = objectAttr.getData()) {
-          objectFiles.push_back(Artifact::createTemporary(
-              objectFiles.front().path + "_object_" + std::to_string(index),
-              ".o"));
         }
       }
     }
diff --git a/compiler/src/iree/compiler/Dialect/HAL/Transforms/SubstituteExecutables.cpp b/compiler/src/iree/compiler/Dialect/HAL/Transforms/SubstituteExecutables.cpp
index 7381d29..12b2c8a 100644
--- a/compiler/src/iree/compiler/Dialect/HAL/Transforms/SubstituteExecutables.cpp
+++ b/compiler/src/iree/compiler/Dialect/HAL/Transforms/SubstituteExecutables.cpp
@@ -167,10 +167,11 @@
   // there may have been microkernel libraries or something referenced by the
   // existing module.
   auto dataObjectAttr = builder.getAttr<IREE::HAL::ExecutableObjectAttr>(
-      nullptr, DenseIntElementsAttr::get(
-                   VectorType::get({static_cast<int64_t>(fileContents->size())},
-                                   builder.getI8Type()),
-                   ArrayRef(fileContents->data(), fileContents->size())));
+      builder.getStringAttr(llvm::sys::path::filename(filePath)),
+      DenseIntElementsAttr::get(
+          VectorType::get({static_cast<int64_t>(fileContents->size())},
+                          builder.getI8Type()),
+          ArrayRef(fileContents->data(), fileContents->size())));
   variantOp.setObjectsAttr(builder.getArrayAttr({dataObjectAttr}));
 
   // Drop the inner module if present (may already be external).
diff --git a/compiler/src/iree/compiler/Dialect/HAL/Transforms/test/substitute_executables.mlir b/compiler/src/iree/compiler/Dialect/HAL/Transforms/test/substitute_executables.mlir
index 372dbcb..a2d3ffd 100644
--- a/compiler/src/iree/compiler/Dialect/HAL/Transforms/test/substitute_executables.mlir
+++ b/compiler/src/iree/compiler/Dialect/HAL/Transforms/test/substitute_executables.mlir
@@ -30,7 +30,9 @@
 // CHECK: hal.executable private @executable1
 hal.executable private @executable1 {
   // CHECK: hal.executable.variant public @variant
-  // CHECK-SAME: objects = [#hal.executable.object<{data = dense<[72, 69, 76, 76, 79, 33,
+  // CHECK-SAME: #hal.executable.object<{
+  // CHECK-SAME:   path = "substitute_executables_replacement.obj",
+  // CHECK-SAME:   data = dense<[72, 69, 76, 76, 79, 33,
   hal.executable.variant public @variant, target = <"cuda", "cuda-nvptx-fb"> {
     hal.executable.export public @dispatch1 ordinal(0) layout(#hal.pipeline.layout<push_constants = 0, sets = [<0, bindings = [<0, storage_buffer>]>]>) {
     ^bb0(%arg0: !hal.device, %arg1: index, %arg2: index):