|
2 | 2 | #include "xla/service/service.h"
|
3 | 3 | #undef protected
|
4 | 4 |
|
| 5 | +// Needed to access CompileXlaRuntimeCpuExecutable/etc |
| 6 | +#define private public |
| 7 | +#include "xla/service/cpu/cpu_compiler.h" |
| 8 | +#undef private |
| 9 | + |
| 10 | +#include "xla/service/compiler.h" |
5 | 11 | #include "xla/service/cpu/cpu_executable.h"
|
| 12 | +#include "xla/service/hlo_module_util.h" |
| 13 | +#include "xla/service/hlo_proto_util.h" |
6 | 14 | #include "xla/service/local_service_utils.h"
|
7 | 15 |
|
8 | 16 | #include "absl/status/statusor.h"
|
|
27 | 35 | #include "xla/translate/mhlo_to_hlo/mlir_hlo_to_hlo.h"
|
28 | 36 | #include "xla/translate/mhlo_to_hlo/type_to_shape.h"
|
29 | 37 |
|
| 38 | +#include "xla/statusor.h" |
| 39 | + |
30 | 40 | #include "pybind11/pybind11.h"
|
31 | 41 |
|
32 | 42 | #include "compile_with_xla.h"
|
@@ -161,6 +171,80 @@ run_pass_pipeline(const std::vector<std::string> &oldsym_vec,
|
161 | 171 | return std::make_pair(entryfn.str(), ss.str());
|
162 | 172 | }
|
163 | 173 |
|
| 174 | +absl::StatusOr<std::unique_ptr<xla::Executable>> |
| 175 | +RunBackend(xla::cpu::CpuCompiler *self, std::unique_ptr<xla::HloModule> module, |
| 176 | + [[maybe_unused]] xla::se::StreamExecutor *stream_exec, |
| 177 | + const xla::Compiler::CompileOptions &options, bool xla_runtime) { |
| 178 | + |
| 179 | + std::unique_ptr<xla::cpu::CpuExecutable> cpu_executable; |
| 180 | + if (xla_runtime) { |
| 181 | + TF_ASSIGN_OR_RETURN(cpu_executable, |
| 182 | + self->CompileXlaRuntimeCpuExecutable(std::move(module), |
| 183 | + options.registry)); |
| 184 | + } else { |
| 185 | + TF_ASSIGN_OR_RETURN(cpu_executable, |
| 186 | + self->CompileLegacyCpuExecutable(std::move(module))); |
| 187 | + } |
| 188 | + |
| 189 | + return std::unique_ptr<xla::Executable>(std::move(cpu_executable)); |
| 190 | +} |
| 191 | + |
| 192 | +absl::StatusOr<std::unique_ptr<xla::Executable>> |
| 193 | +BuildExecutable(xla::Service *self, const xla::HloModuleProto &module_proto, |
| 194 | + std::unique_ptr<xla::HloModuleConfig> module_config, |
| 195 | + xla::Backend *backend, xla::se::StreamExecutor *executor, |
| 196 | + const xla::Compiler::CompileOptions &options, |
| 197 | + bool run_backend_only, bool xla_runtime) { |
| 198 | + |
| 199 | + TF_ASSIGN_OR_RETURN(std::unique_ptr<xla::HloModule> module, |
| 200 | + xla::CreateModuleFromProto(module_proto, *module_config, |
| 201 | + run_backend_only)); |
| 202 | + xla::UpdateEntryComputationLayout( |
| 203 | + module.get(), std::bind(&xla::Compiler::DefaultDeviceShapeRepresentation, |
| 204 | + backend->compiler(), std::placeholders::_1)); |
| 205 | + // xla::DumpHloModuleIfEnabled(*module, xla::kBeforeOptimizationsDumpName); |
| 206 | + |
| 207 | + std::unique_ptr<xla::HloProto> hlo_proto_before_opt; |
| 208 | + if (!run_backend_only) { |
| 209 | + // Save proto state before optimizations if we want a snapshot. |
| 210 | + // When run_backend_only is enabled the post-optimization HLO will be the |
| 211 | + // same as the pre-optimization HLO. |
| 212 | + // if (xla::DumpingEnabledForHloModule(*module)) { |
| 213 | + // hlo_proto_before_opt = |
| 214 | + // std::make_unique<xla::HloProto>(MakeHloProto(*module)); |
| 215 | + // } |
| 216 | + TF_ASSIGN_OR_RETURN(module, backend->compiler()->RunHloPasses( |
| 217 | + std::move(module), executor, options)); |
| 218 | + } |
| 219 | + |
| 220 | + /* |
| 221 | + TF_ASSIGN_OR_RETURN( |
| 222 | + std::unique_ptr<xla::Executable> executable, |
| 223 | + backend->compiler()->RunBackend(std::move(module), executor, options)); |
| 224 | + */ |
| 225 | + TF_ASSIGN_OR_RETURN(std::unique_ptr<xla::Executable> executable, |
| 226 | + RunBackend((xla::cpu::CpuCompiler *)backend->compiler(), |
| 227 | + std::move(module), executor, options, |
| 228 | + xla_runtime)); |
| 229 | + |
| 230 | + const xla::BufferAssignmentProto *buffer_assignment_proto_after_opt = |
| 231 | + executable->buffer_assignment_proto(); |
| 232 | + |
| 233 | + // If dumping is enabled RunBackend(...) will emit a hlo_proto in the |
| 234 | + // executable. This contains the buffer_assignment that is only available |
| 235 | + // after RunBackend(). If hlo_proto_before_opt is not null, then we replace |
| 236 | + // its buffer_assignment with the one from after_opt and then store it into |
| 237 | + // the executable. |
| 238 | + if (hlo_proto_before_opt != nullptr && |
| 239 | + buffer_assignment_proto_after_opt != nullptr) { |
| 240 | + // CHECK(xla::DumpingEnabledForHloModule(executable->module())); |
| 241 | + *hlo_proto_before_opt->mutable_buffer_assignment() = |
| 242 | + std::move(*buffer_assignment_proto_after_opt); |
| 243 | + executable->set_hlo_proto(std::move(hlo_proto_before_opt)); |
| 244 | + } |
| 245 | + return std::move(executable); |
| 246 | +} |
| 247 | + |
164 | 248 | // Compile an MHLO module given as a string to LLVM IR using XLA.
|
165 | 249 | std::unique_ptr<xla::LocalExecutable>
|
166 | 250 | compile_mhlo_to_llvm_with_xla(llvm::StringRef mhlo_text, std::string &output,
|
@@ -288,10 +372,11 @@ compile_mhlo_to_llvm_with_xla(llvm::StringRef mhlo_text, std::string &output,
|
288 | 372 | build_options.device_allocator(), build_options.compile_thread_pool(),
|
289 | 373 | build_options.layout_canonicalization_callback()};
|
290 | 374 | opts.registry = ®istry;
|
291 |
| - auto executable = local_client->local_service()->BuildExecutable( |
292 |
| - xla_computation.proto(), std::move(module_config_or_error.value()), |
293 |
| - local_client->mutable_backend(), executor.value(), opts, |
294 |
| - build_options.run_backend_only()); |
| 375 | + auto executable = |
| 376 | + BuildExecutable(local_client->local_service(), xla_computation.proto(), |
| 377 | + std::move(module_config_or_error.value()), |
| 378 | + local_client->mutable_backend(), executor.value(), opts, |
| 379 | + build_options.run_backend_only(), xla_runtime); |
295 | 380 | if (!executable.ok()) {
|
296 | 381 | throw pybind11::value_error(executable.status().ToString());
|
297 | 382 | }
|
|
0 commit comments