@@ -30,9 +30,12 @@ limitations under the License.
3030#include " xla/backends/cpu/runtime/convolution_lib.h"
3131#include " xla/backends/cpu/runtime/dot_lib.h"
3232#include " xla/backends/cpu/runtime/thunk.pb.h"
33+ #include " xla/layout_util.h"
3334#include " xla/service/cpu/executable.pb.h"
3435#include " xla/shape.h"
3536#include " xla/shape_util.h"
37+ #include " xla/status_macros.h"
38+ #include " xla/tsl/platform/statusor.h"
3639#include " xla/util.h"
3740#include " xla/xla_data.pb.h"
3841
@@ -43,7 +46,7 @@ namespace {
4346
4447std::string GetBufferAllocationString (
4548 const xla::buffer_assignment::BufferAllocationSliceProto& slice) {
46- return absl::StrCat (" reinterpret_cast<std::byte*>(buffer_table() [" ,
49+ return absl::StrCat (" reinterpret_cast<std::byte*>(buffer_table[" ,
4750 slice.buffer_allocation_index (), " ]) + " , slice.offset ());
4851}
4952
@@ -73,11 +76,6 @@ ThunkProtoExecutionDeserializer::ThunkSpecificRunImplFromThunkSequence(
7376 GetDotThunkRunImpl (thunk));
7477 break ;
7578 }
76- case xla::cpu::ThunkProto::kCopyThunk : {
77- TF_ASSIGN_OR_RETURN (thunk_run_impls.emplace_back (),
78- GetCopyThunkRunImpl (thunk));
79- break ;
80- }
8179 case xla::cpu::ThunkProto::kConditionalThunk : {
8280 TF_ASSIGN_OR_RETURN (thunk_run_impls.emplace_back (),
8381 GetConditionalThunkRunImpl (thunk));
@@ -103,6 +101,16 @@ ThunkProtoExecutionDeserializer::ThunkSpecificRunImplFromThunkSequence(
103101 GetCallThunkRunImpl (thunk));
104102 break ;
105103 }
104+ case xla::cpu::ThunkProto::kCopyThunk : {
105+ TF_ASSIGN_OR_RETURN (thunk_run_impls.emplace_back (),
106+ GetCopyThunkRunImpl (thunk));
107+ break ;
108+ }
109+ case xla::cpu::ThunkProto::kSortThunk : {
110+ TF_ASSIGN_OR_RETURN (thunk_run_impls.emplace_back (),
111+ GetSortThunkRunImpl (thunk));
112+ break ;
113+ }
106114 default : {
107115 return xla::Internal (" Unsupported thunk type: %s." , thunk.kind ());
108116 }
@@ -151,9 +159,9 @@ absl::StatusOr<std::string> ThunkProtoExecutionDeserializer::GetDotThunkRunImpl(
151159 absl::string_view dot_thunk_invocation_format = R"(
152160 // Dot Thunk
153161 {
154- if (run_options() ->intra_op_thread_pool() != nullptr) {
162+ if (run_options->intra_op_thread_pool() != nullptr) {
155163 {{MATMUL_FUNCTION}}(
156- run_options() , {{OUTPUT_PTR}}, {{LHS_PTR}}, {{RHS_PTR}},
164+ run_options, {{OUTPUT_PTR}}, {{LHS_PTR}}, {{RHS_PTR}},
157165 {{M}}, {{N}}, {{K}}, {{TRANSPOSE_LHS}}, {{TRANSPOSE_RHS}});
158166 } else {
159167 {{SINGLE_THREADED_MATMUL_FUNCTION}}(
@@ -302,9 +310,9 @@ ThunkProtoExecutionDeserializer::GetConvolution2DRunImpl(
302310 absl::string_view convolution_thunk_invocation_format = R"(
303311 // Convolution Thunk
304312 {
305- if (run_options() ->intra_op_thread_pool() != nullptr) {
313+ if (run_options->intra_op_thread_pool() != nullptr) {
306314 {{CONVOLUTION_FUNCTION}}(
307- run_options() ,
315+ run_options,
308316 {{OUTPUT_PTR}}, {{LHS_PTR}}, {{RHS_PTR}}, {{INPUT_BATCH}},
309317 {{INPUT_ROWS}}, {{INPUT_COLS}}, {{INPUT_CHANNELS}}, {{KERNEL_ROWS}},
310318 {{KERNEL_COLS}}, {{KERNEL_CHANNELS}}, {{KERNEL_FILTERS}},
@@ -417,7 +425,7 @@ ThunkProtoExecutionDeserializer::GetRngGetAndUpdateStateThunkRunImpl(
417425 absl::string_view rng_thunk_invocation_format = R"(
418426 // Rng Thunk
419427 {
420- rng_states_ [{{RNG_STATE_INDEX}}]. GetAndUpdateState({{RNG_STATE_PTR}});
428+ rng_states [{{RNG_STATE_INDEX}}]-> GetAndUpdateState({{RNG_STATE_PTR}});
421429 })" ;
422430
423431 if (rng_thunk.state_buffer ().size () != sizeof (absl::int128)) {
@@ -458,6 +466,137 @@ ThunkProtoExecutionDeserializer::GetCallThunkRunImpl(
458466 {{" {{CALL_THUNK_IMPL}}" , call_thunk_impl}});
459467}
460468
469+ absl::StatusOr<std::string>
470+ ThunkProtoExecutionDeserializer::GetCopyThunkRunImpl (
471+ const xla::cpu::ThunkProto& thunk) {
472+ // IMPORTANT(basioli): tfcompiled models should always emit llvm kernels for
473+ // copy thunks. Here we emit just a memcpy. This is done exclusively for copy
474+ // thunks that get created by the sort thunk.
475+ if (!thunk.has_copy_thunk ()) {
476+ return xla::Internal (
477+ " Copy thunk was expected when getting thunk run implementation." );
478+ }
479+
480+ const xla::cpu::CopyThunkProto& copy_thunk = thunk.copy_thunk ();
481+ TF_ASSIGN_OR_RETURN (
482+ auto input_shape,
483+ xla::Shape::FromProto (copy_thunk.src_buffer_shape ().shape ()));
484+ TF_ASSIGN_OR_RETURN (
485+ auto output_shape,
486+ xla::Shape::FromProto (copy_thunk.dst_buffer_shape ().shape ()));
487+
488+ if (input_shape != output_shape) {
489+ return xla::Internal (
490+ " Copy thunk has input shape %s and output shape %s that are not the "
491+ " same." ,
492+ input_shape.ToString (true ), output_shape.ToString (true ));
493+ }
494+
495+ absl::string_view copy_thunk_invocation_format = R"(
496+ // Copy Thunk
497+ {
498+ std::memcpy({{OUTPUT_PTR}}, {{INPUT_PTR}}, {{SIZE}});
499+ })" ;
500+
501+ return absl::StrReplaceAll (
502+ copy_thunk_invocation_format,
503+ {{" {{OUTPUT_PTR}}" ,
504+ absl::StrCat (
505+ " reinterpret_cast<char*>(" ,
506+ GetBufferAllocationString (copy_thunk.dst_buffer_shape ().slice ()),
507+ " )" )},
508+ {" {{INPUT_PTR}}" ,
509+ absl::StrCat (
510+ " reinterpret_cast<char*>(" ,
511+ GetBufferAllocationString (copy_thunk.src_buffer_shape ().slice ()),
512+ " )" )},
513+ {" {{SIZE}}" ,
514+ absl::StrCat (copy_thunk.src_buffer_shape ().slice ().size ())}});
515+ }
516+
517+ absl::StatusOr<std::string>
518+ ThunkProtoExecutionDeserializer::GetSortThunkRunImpl (
519+ const xla::cpu::ThunkProto& thunk) {
520+ if (!thunk.has_sort_thunk ()) {
521+ return xla::Internal (
522+ " Sort thunk was expected when getting thunk run implementation." );
523+ }
524+ const xla::cpu::SortThunkProto& sort_thunk = thunk.sort_thunk ();
525+
526+ std::vector<std::string> buffers_to_sort;
527+ buffers_to_sort.reserve (sort_thunk.inputs_shapes_size ());
528+
529+ std::vector<int32_t > values_primitive_type_size_in_bytes;
530+ values_primitive_type_size_in_bytes.reserve (sort_thunk.inputs_shapes_size ());
531+ for (const auto & buffer_proto : sort_thunk.inputs_shapes ()) {
532+ buffers_to_sort.push_back (
533+ absl::StrCat (" reinterpret_cast<char*>(" ,
534+ GetBufferAllocationString (buffer_proto.slice ()), " )" ));
535+ values_primitive_type_size_in_bytes.push_back (
536+ xla::ShapeUtil::ByteSizeOfPrimitiveType (
537+ buffer_proto.shape ().element_type ()));
538+ }
539+ absl::string_view sort_thunk_invocation_format = R"(
540+ // Sort Thunk
541+ {
542+ std::vector<char*> values = {
543+ {{BUFFERS_TO_SORT}}
544+ };
545+ std::vector<int32_t> values_primitive_type_size_in_bytes = {
546+ {{VALUES_PRIMITIVE_TYPE_SIZE_IN_BYTES}}
547+ };
548+
549+ __xla_cpu_runtime_KeyValueSort(
550+ {{HIGHER_DIMENSIONS}}, {{SORT_DIMENSION_ELEMENTS}}, {{LOWER_DIMENSIONS}},
551+ values.data(),
552+ int32_t(values.size()),
553+ values_primitive_type_size_in_bytes.data(),
554+ /*is_stable=*/{{IS_STABLE}},
555+ reinterpret_cast<char*>(run_options),
556+ /*prof_counters=*/nullptr,
557+ reinterpret_cast<void(*)(char*, char*, char**, char**, int64_t*)>({{SORT_FUNCTION_NAME}}));
558+ })" ;
559+
560+ TF_ASSIGN_OR_RETURN (
561+ auto keys_shape,
562+ xla::Shape::FromProto (sort_thunk.inputs_shapes (0 ).shape ()));
563+
564+ // Normalize the shape and the dimension to sort.
565+ xla::Shape normalized_keys_shape =
566+ xla::ShapeUtil::MakeShapeWithDescendingLayoutAndSamePhysicalLayout (
567+ keys_shape);
568+ auto logical_to_physical =
569+ xla::LayoutUtil::MakeLogicalToPhysical (keys_shape.layout ());
570+ TF_RET_CHECK (sort_thunk.dimension () < logical_to_physical.size ());
571+ int64_t physical_dimension_to_sort =
572+ logical_to_physical[sort_thunk.dimension ()];
573+
574+ int64_t sort_dimension_elements =
575+ normalized_keys_shape.dimensions (physical_dimension_to_sort);
576+ int64_t higher_dimensions = 1 ;
577+ for (int64_t i = 0 ; i < physical_dimension_to_sort; ++i) {
578+ higher_dimensions *= normalized_keys_shape.dimensions (i);
579+ }
580+ int64_t lower_dimensions = 1 ;
581+ for (int64_t i = normalized_keys_shape.dimensions ().size () - 1 ;
582+ i > physical_dimension_to_sort; --i) {
583+ lower_dimensions *= normalized_keys_shape.dimensions (i);
584+ }
585+ return absl::StrReplaceAll (
586+ sort_thunk_invocation_format,
587+ {
588+ {" {{HIGHER_DIMENSIONS}}" , absl::StrCat (higher_dimensions)},
589+ {" {{SORT_DIMENSION_ELEMENTS}}" ,
590+ absl::StrCat (sort_dimension_elements)},
591+ {" {{LOWER_DIMENSIONS}}" , absl::StrCat (lower_dimensions)},
592+ {" {{SORT_FUNCTION_NAME}}" , sort_thunk.comparator_name ()},
593+ {" {{BUFFERS_TO_SORT}}" , absl::StrJoin (buffers_to_sort, " , " )},
594+ {" {{VALUES_PRIMITIVE_TYPE_SIZE_IN_BYTES}}" ,
595+ absl::StrJoin (values_primitive_type_size_in_bytes, " , " )},
596+ {" {{IS_STABLE}}" , sort_thunk.is_stable () ? " true" : " false" },
597+ });
598+ }
599+
461600absl::StatusOr<std::string>
462601ThunkProtoExecutionDeserializer::GetKernelThunkRunImpl (
463602 const xla::cpu::ThunkProto& thunk) {
@@ -488,7 +627,7 @@ ThunkProtoExecutionDeserializer::GetKernelThunkRunImpl(
488627 // Kernel Thunk
489628 {
490629 std::array<XLA_CPU_KernelArg, {{NUM_ARGS}}> args = {{ARGS_INITIALIZER}};
491- XLA_CPU_KernelThreadDim kernel_thread_dims = {
630+ XLA_CPU_NumWorkGroups kernel_thread_dims = {
492631 {{THREAD_DIM_X}},
493632 {{THREAD_DIM_Y}},
494633 {{THREAD_DIM_Z}},
@@ -497,7 +636,7 @@ ThunkProtoExecutionDeserializer::GetKernelThunkRunImpl(
497636 for (uint64_t z = 0; z < {{THREAD_DIM_Z}}; ++z) {
498637 for (uint64_t y = 0; y < {{THREAD_DIM_Y}}; ++y) {
499638 for (uint64_t x = 0; x < {{THREAD_DIM_X}}; ++x) {
500- XLA_CPU_KernelThread kernel_thread = {x, y, z};
639+ XLA_CPU_WorkGroupId kernel_thread = {x, y, z};
501640
502641 XLA_CPU_KernelCallFrame call_frame = {
503642 &kernel_thread_dims, &kernel_thread, args.size(), args.data()};
@@ -528,46 +667,6 @@ ThunkProtoExecutionDeserializer::GetKernelThunkRunImpl(
528667 });
529668}
530669
531- absl::StatusOr<std::string>
532- ThunkProtoExecutionDeserializer::GetCopyThunkRunImpl (
533- const xla::cpu::ThunkProto& thunk) {
534- if (!thunk.has_copy_thunk ()) {
535- return xla::Internal (
536- " Copy thunk was expected when getting thunk run implementation." );
537- }
538- const xla::cpu::CopyThunkProto& copy_thunk = thunk.copy_thunk ();
539-
540- TF_ASSIGN_OR_RETURN (
541- xla::Shape src_buffer_shape,
542- xla::Shape::FromProto (copy_thunk.src_buffer_shape ().shape ()));
543- TF_ASSIGN_OR_RETURN (
544- xla::Shape dst_buffer_shape,
545- xla::Shape::FromProto (copy_thunk.dst_buffer_shape ().shape ()));
546- if (!xla::ShapeUtil::Equal (src_buffer_shape, dst_buffer_shape)) {
547- return xla::Internal (" Source and destination shapes must be equal." );
548- }
549-
550- absl::string_view copy_invocation_format = R"(
551- // Copy Thunk
552- {
553- std::memcpy({{DST_BUFFER}},
554- {{SRC_BUFFER}},
555- {{SRC_BUFFER_SIZE}});
556- }
557- )" ;
558-
559- return absl::StrReplaceAll (
560- copy_invocation_format,
561- {
562- {" {{DST_BUFFER}}" ,
563- GetBufferAllocationString (copy_thunk.dst_buffer_shape ().slice ())},
564- {" {{SRC_BUFFER}}" ,
565- GetBufferAllocationString (copy_thunk.src_buffer_shape ().slice ())},
566- {" {{SRC_BUFFER_SIZE}}" ,
567- absl::StrCat (copy_thunk.src_buffer_shape ().slice ().size ())},
568- });
569- }
570-
571670absl::StatusOr<std::string>
572671ThunkProtoExecutionDeserializer::GetConditionalThunkRunImpl (
573672 const xla::cpu::ThunkProto& thunk) {
0 commit comments