chore: import upstream snapshot with attribution
cffconvert / validate (push) Has been skipped
License Check / license-check (push) Failing after 2s

This commit is contained in:
wehub-resource-sync
2026-07-13 12:14:16 +08:00
commit 8a852e4b4e
36502 changed files with 9277225 additions and 0 deletions
@@ -0,0 +1,41 @@
// Copyright 2026 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.
// ==============================================================================
syntax = "proto3";
package mlir.tfrt;
message CompatibilityAnalysisReportProto {
bool unknown_dialect = 1;
bool ref_variable = 2;
bool incompatible_variable = 3;
bool incompatible_attribute = 4;
bool control_flow_v1 = 5;
string method_name = 6;
// TODO(chky): add more checks, eg. tensor datatypes.
}
message CompatibilityAnalysisProto {
CompatibilityAnalysisReportProto summary = 1;
message OpInfo {
int32 count = 1;
CompatibilityAnalysisReportProto report = 2;
}
map<string, OpInfo> ops = 2;
}
@@ -0,0 +1,235 @@
/* Copyright 2021 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 "tensorflow/compiler/mlir/tfrt/analysis/cost_analysis.h"
#include <algorithm>
#include <cassert>
#include <cstdint>
#include <string>
#include <utility>
#include "absl/container/flat_hash_map.h"
#include "absl/strings/string_view.h"
#include "llvm/Support/Casting.h"
#include "mlir/Dialect/Func/IR/FuncOps.h" // from @llvm-project
#include "mlir/IR/Block.h" // from @llvm-project
#include "mlir/IR/BuiltinAttributes.h" // from @llvm-project
#include "mlir/IR/BuiltinTypes.h" // from @llvm-project
#include "mlir/IR/Operation.h" // from @llvm-project
#include "mlir/Support/LLVM.h" // from @llvm-project
#include "tensorflow/compiler/mlir/tensorflow/ir/tf_dialect.h"
#include "tensorflow/compiler/mlir/tensorflow/ir/tf_ops.h"
#include "tensorflow/compiler/mlir/tensorflow/ir/tf_types.h"
#include "tensorflow/compiler/mlir/tfrt/constants.h"
#include "tensorflow/core/tfrt/fallback/cost_recorder.h"
#include "tfrt/compiler/opdefs/tfrt_op_interfaces.h" // from @tf_runtime
namespace tensorflow {
namespace tfrt_compiler {
namespace {
constexpr int64_t kDefaultCheapCost = 1;
int64_t GetRankedTensorSize(mlir::TensorType type) {
auto shape = type.getShape();
int64_t size = 1;
for (int64_t dim : shape) {
// For unknown dimensions, use 1 as the size because it is usually the batch
// dimension.
//
// TODO(chky): Find out a better default number for this case.
size *= std::max(kDefaultCheapCost, dim);
}
return size;
}
int64_t InferTensorSize(const CostContext& context, mlir::TensorType type) {
if (type.hasRank()) return GetRankedTensorSize(type);
return context.default_unranked_tensor_size;
}
// The cost function for tf.LookupTableFindV2.
int64_t InferLookupTableFindV2Cost(const CostContext& context,
mlir::TF::LookupTableFindV2Op op) {
// tf.LookupTableFindV2 ops are usually more costly than tf.AddV2 with the
// same input size, as it involves more operations like hashing, map lookup,
// etc.
constexpr int64_t kLookupTableFindCostScale = 8;
constexpr int64_t kLookupTableFindStringKeyCostScale = 16;
auto value_type = mlir::cast<mlir::TensorType>(op.getValues().getType());
auto key_type = mlir::cast<mlir::TensorType>(op.getKeys().getType());
int64_t output_size = InferTensorSize(context, value_type);
int64_t cost = kLookupTableFindCostScale * output_size;
if (mlir::isa<mlir::TF::StringType>(key_type.getElementType()))
cost *= kLookupTableFindStringKeyCostScale;
return cost;
}
// The cost function for tf.GatherV2.
int64_t InferGatherV2Cost(const CostContext& context, mlir::TF::GatherV2Op op) {
return InferTensorSize(
context, mlir::cast<mlir::TensorType>(op.getOutput().getType()));
}
// The cost function for tf.SparseSegmentSumOp.
template <typename OpType>
int64_t InferSparseSegmentOpCost(const CostContext& context, OpType op) {
return InferTensorSize(
context, mlir::cast<mlir::TensorType>(op.getOutput().getType()));
}
// CostFunctionRegistry is a map from op names to their cost functions.
using CostFunctionRegistry = absl::flat_hash_map<std::string, CostFunction>;
void RegisterCostFunction(CostFunctionRegistry& registry,
absl::string_view op_name,
CostFunction cost_function) {
auto r = registry.try_emplace(op_name, std::move(cost_function));
assert(r.second);
(void)r;
}
template <typename OpType, typename F>
void RegisterCostFunction(CostFunctionRegistry& registry, F f) {
RegisterCostFunction(
registry, OpType::getOperationName().str(),
[f = std::move(f)](const CostContext& context, mlir::Operation* op) {
return f(context, llvm::cast<OpType>(op));
});
}
CostFunctionRegistry& GetCostFunctionRegistry() {
static auto* const registry = []() {
auto* registry = new CostFunctionRegistry;
// TODO(chky): Find a more scalable way to register cost functions. One
// option is to incorporate it is TF MLIR ODS.
RegisterCostFunction<mlir::TF::GatherV2Op>(*registry, InferGatherV2Cost);
RegisterCostFunction<mlir::TF::SparseSegmentSumOp>(
*registry, InferSparseSegmentOpCost<mlir::TF::SparseSegmentSumOp>);
RegisterCostFunction<mlir::TF::SparseSegmentMeanOp>(
*registry, InferSparseSegmentOpCost<mlir::TF::SparseSegmentMeanOp>);
RegisterCostFunction<mlir::TF::SparseSegmentSqrtNOp>(
*registry, InferSparseSegmentOpCost<mlir::TF::SparseSegmentSqrtNOp>);
RegisterCostFunction<mlir::TF::LookupTableFindV2Op>(
*registry, InferLookupTableFindV2Cost);
return registry;
}();
return *registry;
}
} // namespace
void RegisterCostFunction(absl::string_view op_name,
CostFunction cost_function) {
RegisterCostFunction(GetCostFunctionRegistry(), op_name,
std::move(cost_function));
}
bool HasCostFunctionRegistered(absl::string_view op_name) {
return GetCostFunctionRegistry().contains(op_name);
}
int64_t CostAnalysis::GetCost(mlir::Operation* op) const {
assert(cost_map_.count(op) > 0);
return cost_map_.lookup(op);
}
void CostAnalysis::AnalyzeArguments(mlir::func::FuncOp func_op) {
// Use the max size among function inputs as the default size of dynamic
// shaped tensors in the function.
for (auto arg : func_op.getArguments()) {
if (!mlir::isa<mlir::TensorType>(arg.getType())) continue;
auto type = mlir::cast<mlir::TensorType>(arg.getType());
if (type.hasRank()) {
max_arg_size_ = std::max(max_arg_size_, GetRankedTensorSize(type));
}
}
}
void CostAnalysis::AnalyzeBlock(mlir::Block* block) {
for (auto& op : *block) {
EvaluateCost(&op);
}
}
void CostAnalysis::EvaluateCost(mlir::Operation* op) {
if (auto cost_function =
mlir::dyn_cast<tfrt::compiler::CostFunctionInterface>(op)) {
cost_map_[op] = cost_function.cost();
return;
}
if (!llvm::isa<mlir::TF::TensorFlowDialect>(op->getDialect())) {
cost_map_[op] = max_arg_size_;
return;
}
// Try to use its cost function if it is registered.
const auto& registry = GetCostFunctionRegistry();
absl::string_view op_name = op->getName().getStringRef();
auto iter = registry.find(op_name);
if (iter != registry.end()) {
CostContext context;
context.default_unranked_tensor_size = max_arg_size_;
cost_map_[op] = iter->second(context, op);
return;
}
// Try to use the recorded cost if any.
if (cost_recorder_ != nullptr) {
const auto op_key_attr =
op->getAttrOfType<mlir::IntegerAttr>(kOpKeyAttrName);
if (op_key_attr) {
cost_map_[op] = cost_recorder_->GetCost(op_key_attr.getInt());
return;
}
}
// These ops are cheap regardless of their input sizes.
//
// TODO(chky): Find a more scalable way to figure out cheap ops.
if (llvm::isa<mlir::TF::ShapeOp, mlir::TF::StridedSliceOp,
mlir::TF::ReshapeOp, mlir::TF::ExpandDimsOp>(op)) {
cost_map_[op] = kDefaultCheapCost;
return;
}
// For other ops, use the sum of input sizes as its cost.
int64_t cost = kDefaultCheapCost;
for (auto operand : op->getOperands()) {
auto type = mlir::cast<mlir::TensorType>(operand.getType());
if (type.hasRank()) {
cost += GetRankedTensorSize(type);
} else {
// For unranked tensors, use the max size among the input tensors. This is
// because the only dynamic information of the function should be the
// input, so the size of dynamic tensors should be usually capped by
// inputs' sizes.
cost += max_arg_size_;
}
}
cost_map_[op] = cost;
}
} // namespace tfrt_compiler
} // namespace tensorflow
@@ -0,0 +1,98 @@
/* Copyright 2021 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.
==============================================================================*/
#ifndef TENSORFLOW_COMPILER_MLIR_TFRT_ANALYSIS_COST_ANALYSIS_H_
#define TENSORFLOW_COMPILER_MLIR_TFRT_ANALYSIS_COST_ANALYSIS_H_
#include <cstdint>
#include <functional>
#include "absl/strings/string_view.h"
#include "llvm/ADT/DenseMap.h"
#include "mlir/Dialect/Func/IR/FuncOps.h" // from @llvm-project
#include "mlir/IR/Block.h" // from @llvm-project
#include "mlir/IR/BuiltinOps.h" // from @llvm-project
#include "mlir/IR/Operation.h" // from @llvm-project
#include "tensorflow/core/platform/status.h"
#include "tensorflow/core/tfrt/fallback/cost_recorder.h"
#include "tensorflow/core/tfrt/fallback/op_cost_map.pb.h"
namespace tensorflow {
namespace tfrt_compiler {
// Analyze costs for tensorflow operations.
//
// The current heuristic used is quite simple, which is to calculate the total
// size of input tensors. The exception is that ops whose cost is irrelevant to
// input sizes, such as tf.Shape and tf.Reshape, are whitelisted to have cheap
// cost. This cost analysis is expected to be used conservatively (eg. use a low
// threshold to decide whether a cost is cheap or expensive), as it might not be
// accurate in some cases.
//
class CostAnalysis {
public:
explicit CostAnalysis(
mlir::func::FuncOp func_op,
const tfrt_stub::CostRecorder* cost_recorder = nullptr) {
cost_recorder_ = cost_recorder;
AnalyzeArguments(func_op);
AnalyzeBlock(&func_op.front());
}
int64_t GetCost(mlir::Operation* op) const;
private:
void AnalyzeArguments(mlir::func::FuncOp func_op);
void AnalyzeBlock(mlir::Block* block);
void EvaluateCost(mlir::Operation* op);
int64_t max_arg_size_ = 1;
llvm::DenseMap<mlir::Operation*, int64_t> cost_map_;
const tfrt_stub::CostRecorder* cost_recorder_;
};
struct CostContext {
int64_t default_unranked_tensor_size;
};
using CostFunction =
std::function<int64_t(const CostContext&, mlir::Operation*)>;
void RegisterCostFunction(absl::string_view op_name,
CostFunction cost_function);
template <typename OpType, typename F>
void RegisterCostFunction(F f) {
RegisterCostFunction(
OpType::getOperationName().str(),
[f = std::move(f)](const CostContext& context, mlir::Operation* op) {
return f(context, llvm::cast<OpType>(op));
});
}
template <typename OpType>
struct CostFunctionRegistration {
explicit CostFunctionRegistration(
std::function<int64_t(const CostContext&, OpType)> cost_function) {
RegisterCostFunction<OpType>(std::move(cost_function));
}
};
bool HasCostFunctionRegistered(absl::string_view op_name);
} // namespace tfrt_compiler
} // namespace tensorflow
#endif // TENSORFLOW_COMPILER_MLIR_TFRT_ANALYSIS_COST_ANALYSIS_H_
@@ -0,0 +1,53 @@
/* Copyright 2021 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 "tensorflow/compiler/mlir/tfrt/analysis/tensor_array_side_effect_analysis.h"
#include "llvm/Support/Casting.h"
#include "mlir/Dialect/Func/IR/FuncOps.h" // from @llvm-project
#include "mlir/IR/BuiltinOps.h" // from @llvm-project
#include "mlir/IR/Operation.h" // from @llvm-project
#include "mlir/Interfaces/SideEffectInterfaces.h" // from @llvm-project
#include "tensorflow/compiler/mlir/tensorflow/ir/tf_ops.h"
namespace tensorflow {
namespace tfrt_compiler {
bool IsTensorArrayOp(mlir::Operation* op) {
return llvm::isa<mlir::TF::TensorArrayV3Op, mlir::TF::TensorArrayScatterV3Op,
mlir::TF::TensorArrayGatherV3Op,
mlir::TF::TensorArrayReadV3Op,
mlir::TF::TensorArrayWriteV3Op>(op);
}
static bool FunctionContainsOnlyNoSideEffectOpOrTensorArrayOp(
mlir::func::FuncOp func_op) {
for (mlir::Operation& op : func_op.front()) {
if (!mlir::isMemoryEffectFree(&op) && !IsTensorArrayOp(&op)) return false;
}
return true;
}
TensorArraySideEffectAnalysis::TensorArraySideEffectAnalysis(
mlir::ModuleOp module) {
for (auto func_op : module.getOps<mlir::func::FuncOp>()) {
if (FunctionContainsOnlyNoSideEffectOpOrTensorArrayOp(func_op)) {
set_.insert(func_op);
}
}
}
} // namespace tfrt_compiler
} // namespace tensorflow
@@ -0,0 +1,52 @@
/* Copyright 2021 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.
==============================================================================*/
#ifndef TENSORFLOW_COMPILER_MLIR_TFRT_ANALYSIS_TENSOR_ARRAY_SIDE_EFFECT_ANALYSIS_H_
#define TENSORFLOW_COMPILER_MLIR_TFRT_ANALYSIS_TENSOR_ARRAY_SIDE_EFFECT_ANALYSIS_H_
#include "llvm/ADT/DenseSet.h"
#include "mlir/Dialect/Func/IR/FuncOps.h" // from @llvm-project
#include "mlir/IR/BuiltinOps.h" // from @llvm-project
#include "mlir/IR/Operation.h" // from @llvm-project
namespace tensorflow {
namespace tfrt_compiler {
// Return true if it is a TensorArrayOp, eg. TensorArrayV3Op.
bool IsTensorArrayOp(mlir::Operation* op);
// This class provides utilities for analyzing side effects for TensorArray ops
// in the graph. mlir::TF::SideEffectAnalysis currently produces suboptimal
// side-effect analysis for TensorArray ops. On the other hand, control
// dependencies are already sorted out for TensorArray ops in the original TF
// graph. Each TensorArray op will take or produce a `flow` value and they are
// already properly chained in the origninal TF graph.
class TensorArraySideEffectAnalysis {
public:
explicit TensorArraySideEffectAnalysis(mlir::ModuleOp module);
// Return if the function contains only non-side-effecting ops or TensorArray
// ops.
bool HasAtMostTensorArrayEffect(mlir::func::FuncOp func_op) const {
return set_.count(func_op) > 0;
}
private:
llvm::DenseSet<mlir::func::FuncOp> set_;
};
} // namespace tfrt_compiler
} // namespace tensorflow
#endif // TENSORFLOW_COMPILER_MLIR_TFRT_ANALYSIS_TENSOR_ARRAY_SIDE_EFFECT_ANALYSIS_H_
@@ -0,0 +1,46 @@
/* Copyright 2021 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 "llvm/ADT/StringRef.h"
#include "mlir/Dialect/Func/IR/FuncOps.h" // from @llvm-project
#include "mlir/Pass/Pass.h" // from @llvm-project
#include "mlir/Pass/PassRegistry.h" // from @llvm-project
#include "tensorflow/compiler/mlir/tfrt/analysis/cost_analysis.h"
namespace tensorflow {
namespace tfrt_compiler {
class TestCostAnalysis
: public mlir::PassWrapper<TestCostAnalysis,
mlir::OperationPass<mlir::func::FuncOp>> {
llvm::StringRef getArgument() const final {
return "tfrt-test-cost-analysis";
}
llvm::StringRef getDescription() const final {
return "Add remarks based on cost analysis for testing purpose.";
}
void runOnOperation() override {
const auto& cost_analysis = getAnalysis<CostAnalysis>();
auto func_op = getOperation();
for (auto& op : func_op.front()) {
op.emitRemark() << "Cost: " << cost_analysis.GetCost(&op);
}
}
};
static mlir::PassRegistration<TestCostAnalysis> pass;
} // namespace tfrt_compiler
} // namespace tensorflow
@@ -0,0 +1,57 @@
/* Copyright 2021 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 "llvm/ADT/StringRef.h"
#include "mlir/Dialect/Func/IR/FuncOps.h" // from @llvm-project
#include "mlir/IR/BuiltinOps.h" // from @llvm-project
#include "mlir/Pass/Pass.h" // from @llvm-project
#include "mlir/Pass/PassRegistry.h" // from @llvm-project
#include "mlir/Support/TypeID.h" // from @llvm-project
#include "tensorflow/compiler/mlir/tfrt/analysis/tensor_array_side_effect_analysis.h"
namespace tensorflow {
namespace tfrt_compiler {
namespace {
class TestTensorArraySideEffectAnalysis
: public mlir::PassWrapper<TestTensorArraySideEffectAnalysis,
mlir::OperationPass<mlir::ModuleOp>> {
public:
MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(
TestTensorArraySideEffectAnalysis)
private:
llvm::StringRef getArgument() const final {
return "tfrt-test-tensor-array-effect";
}
llvm::StringRef getDescription() const final {
return "Test TensorArraySideEffectAnalysis";
}
void runOnOperation() override {
auto module = getOperation();
TensorArraySideEffectAnalysis tensor_array_side_effect_analysis(module);
for (auto func_op : module.getOps<mlir::func::FuncOp>()) {
func_op.emitRemark() << "HasAtMostTensorArrayEffect: "
<< tensor_array_side_effect_analysis
.HasAtMostTensorArrayEffect(func_op);
}
}
};
mlir::PassRegistration<TestTensorArraySideEffectAnalysis> pass;
} // namespace
} // namespace tfrt_compiler
} // namespace tensorflow