Files
wehub-resource-sync 8a852e4b4e
cffconvert / validate (push) Has been skipped
License Check / license-check (push) Failing after 2s
chore: import upstream snapshot with attribution
2026-07-13 12:14:16 +08:00

142 lines
5.5 KiB
C++

/* Copyright 2017 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include <cstdint>
#include <vector>
#include "absl/algorithm/container.h"
#include "tensorflow/compiler/tf2xla/lib/broadcast.h"
#include "tensorflow/compiler/tf2xla/mlir_xla_op_kernel.h"
#include "tensorflow/compiler/tf2xla/xla_op_kernel.h"
#include "tensorflow/compiler/tf2xla/xla_op_registry.h"
#include "xla/hlo/builder/xla_builder.h"
#include "tensorflow/core/framework/op_kernel.h"
#include "tensorflow/core/framework/op_requires.h"
#include "tensorflow/core/framework/tensor_shape.h"
#include "tensorflow/core/platform/errors.h"
#include "tensorflow/core/util/bcast.h"
namespace tensorflow {
namespace {
class SelectOp : public XlaOpKernel {
public:
explicit SelectOp(OpKernelConstruction* ctx) : XlaOpKernel(ctx) {}
void Compile(XlaOpKernelContext* ctx) override {
const TensorShape cond_shape = ctx->InputShape(0);
const TensorShape then_shape = ctx->InputShape(1);
const TensorShape else_shape = ctx->InputShape(2);
OP_REQUIRES(
ctx, then_shape.IsSameSize(else_shape),
errors::InvalidArgument(
"'then' and 'else' must have the same size. but received: ",
then_shape.DebugString(), " vs. ", else_shape.DebugString()));
auto cond_handle = ctx->Input(0);
auto then_handle = ctx->Input(1);
auto else_handle = ctx->Input(2);
bool broadcasting = !cond_shape.IsSameSize(then_shape);
bool cond_is_scalar = TensorShapeUtils::IsScalar(cond_shape);
if (broadcasting && !cond_is_scalar) {
OP_REQUIRES(ctx, TensorShapeUtils::IsVector(cond_shape),
errors::InvalidArgument(
"'cond' must be a scalar or a vector, but saw shape: ",
cond_shape.DebugString()));
OP_REQUIRES(ctx, TensorShapeUtils::IsVectorOrHigher(then_shape),
errors::InvalidArgument(
"'then' must be at least a vector, but saw shape: ",
then_shape.DebugString()));
OP_REQUIRES(ctx, then_shape.dim_size(0) == cond_shape.num_elements(),
errors::InvalidArgument("Number of batches of 'then' must "
"match size of 'cond', but saw: ",
then_shape.dim_size(0), " vs. ",
cond_shape.num_elements()));
// Broadcast into the dimensions on the right.
std::vector<int64_t> broadcast_dimensions(cond_shape.dims());
absl::c_iota(broadcast_dimensions, 0);
cond_handle = xla::BroadcastInDim(cond_handle, then_shape.dim_sizes(),
broadcast_dimensions);
}
ctx->SetOutput(0, xla::Select(cond_handle, then_handle, else_handle));
}
private:
SelectOp(const SelectOp&) = delete;
void operator=(const SelectOp&) = delete;
};
REGISTER_XLA_OP(Name("Select"), MlirXlaOpKernel);
class SelectOpV2 : public XlaOpKernel {
public:
explicit SelectOpV2(OpKernelConstruction* ctx) : XlaOpKernel(ctx) {}
void Compile(XlaOpKernelContext* ctx) override {
const TensorShape cond_shape = ctx->InputShape(0);
const TensorShape then_shape = ctx->InputShape(1);
const TensorShape else_shape = ctx->InputShape(2);
// Compute the output shape from the broadcast of the two data inputs, with
// the broadcast of the conditional.
// Then Broadcast all three inputs to the output shape and emit a select.
BCast bcast_then_else(BCast::FromShape(then_shape),
BCast::FromShape(else_shape),
/*fewer_dims_optimization=*/false);
if (!bcast_then_else.IsValid()) {
ctx->SetStatus(errors::InvalidArgument(
"Incompatible shapes: ", then_shape.DebugString(), " vs. ",
else_shape.DebugString()));
return;
}
BCast bcast(bcast_then_else.output_shape(), BCast::FromShape(cond_shape),
/*fewer_dims_optimization=*/false);
if (!bcast.IsValid()) {
ctx->SetStatus(errors::InvalidArgument(
"Incompatible shapes: ",
BCast::ToShape(bcast_then_else.output_shape()).DebugString(), " vs. ",
cond_shape.DebugString()));
return;
}
auto bcasted_cond = BroadcastTo(ctx->Input(0), bcast.output_shape());
OP_REQUIRES_OK(ctx, bcasted_cond.status());
auto cond_handle = bcasted_cond.value();
auto bcasted_then = BroadcastTo(ctx->Input(1), bcast.output_shape());
OP_REQUIRES_OK(ctx, bcasted_then.status());
auto then_handle = bcasted_then.value();
auto bcasted_else = BroadcastTo(ctx->Input(2), bcast.output_shape());
OP_REQUIRES_OK(ctx, bcasted_else.status());
auto else_handle = bcasted_else.value();
ctx->SetOutput(0, xla::Select(cond_handle, then_handle, else_handle));
}
private:
SelectOpV2(const SelectOpV2&) = delete;
void operator=(const SelectOpV2&) = delete;
};
REGISTER_XLA_OP(Name("SelectV2"), SelectOpV2);
} // namespace
} // namespace tensorflow