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
+100
View File
@@ -0,0 +1,100 @@
load("@rules_python//python:proto.bzl", "py_proto_library")
load("//tensorflow:tensorflow.bzl", "tf_cc_test")
load(
"//tensorflow/core/platform:build_config.bzl",
"tf_proto_library",
)
load("//tensorflow/core/platform:rules_cc.bzl", "cc_library")
package(
# copybara:uncomment default_applicable_licenses = ["//tensorflow:LICENSE"],
default_visibility = [
"//tensorflow:__pkg__",
"//tensorflow/compiler/mlir/lite:__subpackages__",
],
licenses = ["notice"],
)
cc_library(
name = "error_collector",
srcs = ["error_collector.cc"],
hdrs = ["error_collector.h"],
deps = [
":converter_error_data_proto_cc",
":types_util",
"@com_google_absl//absl/strings",
],
)
cc_library(
name = "error_collector_inst",
srcs = ["error_collector_inst.cc"],
hdrs = ["error_collector_inst.h"],
deps = [
":converter_error_data_proto_cc",
":error_collector",
":types_util",
"@com_google_absl//absl/strings",
"@llvm-project//mlir:IR",
"@llvm-project//mlir:Pass",
"@llvm-project//mlir:Support",
],
)
tf_cc_test(
name = "error_collector_inst_test",
srcs = ["error_collector_inst_test.cc"],
data = [
"testdata/strided_slice.mlir",
],
deps = [
":converter_error_data_proto_cc",
":error_collector",
":error_collector_inst",
":types_util",
"//tensorflow/compiler/mlir/tensorflow",
"//tensorflow/core:test",
"//tensorflow/core/platform:errors",
"//tensorflow/core/platform:resource_loader",
"@com_google_absl//absl/status",
"@com_google_absl//absl/status:statusor",
"@com_google_googletest//:gtest_main",
"@llvm-project//llvm:Support",
"@llvm-project//mlir:FuncDialect",
"@llvm-project//mlir:IR",
"@llvm-project//mlir:Parser",
"@llvm-project//mlir:Pass",
"@llvm-project//mlir:Support",
"@xla//xla/tsl/platform:statusor",
],
)
cc_library(
name = "types_util",
srcs = ["types_util.cc"],
hdrs = ["types_util.h"],
deps = [
":converter_error_data_proto_cc",
"@llvm-project//llvm:Support",
"@llvm-project//mlir:IR",
"@llvm-project//mlir:Support",
],
)
tf_proto_library(
name = "converter_error_data_proto",
srcs = ["converter_error_data.proto"],
visibility = [
"//visibility:public",
],
)
# copybara:uncomment_begin(google-only)
# py_proto_library(
# name = "converter_error_data_proto_py",
# visibility = [
# "//visibility:public",
# ],
# deps = [":converter_error_data_proto"],
# )
# copybara:uncomment_end
@@ -0,0 +1,94 @@
// 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.
// This schema defines the converter error format to communicate between C++
// and python.
syntax = "proto2";
package tflite.metrics;
message ConverterErrorData {
// Error code for popular errors.
enum ErrorCode {
UNKNOWN = 0;
ERROR_NEEDS_FLEX_OPS = 1;
ERROR_NEEDS_CUSTOM_OPS = 2;
ERROR_UNSUPPORTED_CONTROL_FLOW_V1 = 3;
ERROR_STATEFUL_PARTITIONED_CALL_IN_FINAL_IR = 4;
// 200- 209 error codes are reserved for backend(delegate) compatibility.
// Backend compatibility is checked at MlirToFlatBufferTranslateFunction()
// with the converted flatbuffer model. If some nodes are incompatibile with
// the given backends in TocoFlags.supported_backends, the error will be
// raised.
ERROR_GPU_NOT_COMPATIBLE = 200;
}
// Information about the op where the error occurs.
message Operator {
// The op name has "<dialect>.<name>" format, Ex: "tf.Abs".
optional string name = 1;
}
// Represents the type of location.
enum LocationType {
// No location information available.
UNKNOWNLOC = 0;
// The location is the nodename;
NAMELOC = 1;
// The location is a stacktrace.
CALLSITELOC = 2;
// The location is a fused location, usually represents the list of output
// tensor locations of that node.
FUSEDLOC = 3;
}
// Represents a source location with file name, line and column number.
message FileLoc {
optional string filename = 1;
optional uint32 line = 2;
optional uint32 column = 3;
}
// Represents the node name and its source location.
message SourceLoc {
optional string name = 1;
optional FileLoc source = 2;
}
// Represents the location information of current node.
message Location {
optional LocationType type = 1;
// For each location type, this field is different. If type is:
// - UNKNOWNLOC: call is empty.
// - NAMELOC: call has a single element representing the current node.
// - CALLSITELOC: call is a chain of source locations representing a
// stacktrace.
// - FUSEDLOC: call is a list, represents the list of output tensor
// locations.
repeated SourceLoc call = 2;
}
// The name of the component from which the error was originally thrown.
optional string component = 1;
// The name of the subcomponent from which the error was originally thrown. In
// MLIR, this field contains the pass name.
optional string subcomponent = 2;
optional ErrorCode error_code = 3;
optional string error_message = 4;
optional Operator operator = 5;
optional Location location = 6;
}
@@ -0,0 +1,30 @@
/* 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/lite/metrics/error_collector.h"
namespace mlir {
namespace TFL {
ErrorCollector* ErrorCollector::error_collector_instance_ = nullptr;
ErrorCollector* ErrorCollector::GetErrorCollector() {
if (error_collector_instance_ == nullptr) {
error_collector_instance_ = new ErrorCollector();
}
return error_collector_instance_;
}
} // namespace TFL
} // namespace mlir
@@ -0,0 +1,58 @@
/* 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_LITE_METRICS_ERROR_COLLECTOR_H_
#define TENSORFLOW_COMPILER_MLIR_LITE_METRICS_ERROR_COLLECTOR_H_
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include "tensorflow/compiler/mlir/lite/metrics/converter_error_data.pb.h"
#include "tensorflow/compiler/mlir/lite/metrics/types_util.h"
namespace mlir {
namespace TFL {
// A singleton to store errors collected by the instrumentation.
class ErrorCollector {
using ConverterErrorData = tflite::metrics::ConverterErrorData;
using ConverterErrorDataSet =
std::unordered_set<ConverterErrorData, ConverterErrorDataHash,
ConverterErrorDataComparison>;
public:
const ConverterErrorDataSet &CollectedErrors() { return collected_errors_; }
void ReportError(const ConverterErrorData &error) {
collected_errors_.insert(error);
}
// Clear the set of collected errors.
void Clear() { collected_errors_.clear(); }
// Returns the global instance of ErrorCollector.
static ErrorCollector* GetErrorCollector();
private:
ErrorCollector() = default;
ConverterErrorDataSet collected_errors_;
static ErrorCollector* error_collector_instance_;
};
} // namespace TFL
} // namespace mlir
#endif // TENSORFLOW_COMPILER_MLIR_LITE_METRICS_ERROR_COLLECTOR_H_
@@ -0,0 +1,147 @@
/* 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/lite/metrics/error_collector_inst.h"
#include <memory>
#include <string>
#include <vector>
#include "absl/strings/match.h"
#include "absl/strings/str_split.h"
#include "mlir/IR/Diagnostics.h" // from @llvm-project
#include "mlir/IR/Location.h" // from @llvm-project
#include "mlir/Pass/Pass.h" // from @llvm-project
#include "mlir/Support/LogicalResult.h" // from @llvm-project
#include "tensorflow/compiler/mlir/lite/metrics/error_collector.h"
#include "tensorflow/compiler/mlir/lite/metrics/types_util.h"
namespace mlir {
namespace TFL {
namespace {
// The signature contains namespaces (Ex: mlir::TFL::(anonymous namespace)::).
// So only extract the function name as the pass name.
inline std::string extract_pass_name(const std::string &signature) {
const std::vector<std::string> &v = absl::StrSplit(signature, "::");
return v.back();
}
// Errors raised by emitOpError start with "'<dialect>.<op>' op". Returns an
// empty string if the pattern is not found or the operator is not in tf or tfl
// dialect.
inline std::string extract_op_name_from_error_message(
const std::string &error_message) {
int end_pos = error_message.find("' op");
if ((absl::StartsWith(error_message, "'tf.") ||
absl::StartsWith(error_message, "'tfl.")) &&
end_pos != std::string::npos) {
return error_message.substr(1, end_pos - 1);
}
return "";
}
// Only notes with character count smaller than kMaxAcceptedNoteSize will be
// appended to the error message.
const int kMaxAcceptedNoteSize = 1024;
} // namespace
ErrorCollectorInstrumentation::ErrorCollectorInstrumentation(
MLIRContext *context)
: error_collector_(ErrorCollector::GetErrorCollector()) {
handler_ = std::make_unique<ScopedDiagnosticHandler>(
context, [this](Diagnostic &diag) {
if (diag.getSeverity() == DiagnosticSeverity::Error) {
Location loc = diag.getLocation();
std::string error_message = diag.str();
std::string op_name, error_code;
if (loc_to_name_.count(loc)) {
op_name = loc_to_name_[loc];
} else {
op_name = extract_op_name_from_error_message(diag.str());
}
for (const auto &note : diag.getNotes()) {
const std::string note_str = note.str();
if (absl::StartsWith(note_str, kErrorCodePrefix)) {
error_code = note_str.substr(sizeof(kErrorCodePrefix) - 1);
}
error_message += "\n";
if (note_str.size() <= kMaxAcceptedNoteSize) {
error_message += note_str;
} else {
error_message += note_str.substr(0, kMaxAcceptedNoteSize);
error_message += "...";
}
}
ErrorCode error_code_enum = ConverterErrorData::UNKNOWN;
bool has_valid_error_code =
ConverterErrorData::ErrorCode_Parse(error_code, &error_code_enum);
if (!op_name.empty() || has_valid_error_code) {
error_collector_->ReportError(NewConverterErrorData(
pass_name_, error_message, error_code_enum, op_name, loc));
} else {
common_error_message_ += diag.str();
common_error_message_ += "\n";
}
}
return failure();
});
}
void ErrorCollectorInstrumentation::runBeforePass(Pass *pass,
Operation *module) {
// Find the op names with tf or tfl dialect prefix, Ex: "tf.Abs" or "tfl.Abs".
auto collectOps = [this](Operation *op) {
const auto &op_name = op->getName().getStringRef().str();
if (absl::StartsWith(op_name, "tf.") || absl::StartsWith(op_name, "tfl.")) {
loc_to_name_.emplace(op->getLoc(), op_name);
}
};
for (auto &region : module->getRegions()) {
region.walk(collectOps);
}
pass_name_ = extract_pass_name(pass->getName().str());
error_collector_->Clear();
}
void ErrorCollectorInstrumentation::runAfterPass(Pass *pass,
Operation *module) {
loc_to_name_.clear();
pass_name_.clear();
common_error_message_.clear();
error_collector_->Clear();
}
void ErrorCollectorInstrumentation::runAfterPassFailed(Pass *pass,
Operation *module) {
// Create a new error if no errors collected yet.
if (error_collector_->CollectedErrors().empty() &&
!common_error_message_.empty()) {
error_collector_->ReportError(NewConverterErrorData(
pass_name_, common_error_message_, ConverterErrorData::UNKNOWN,
/*op_name=*/"", module->getLoc()));
}
loc_to_name_.clear();
pass_name_.clear();
common_error_message_.clear();
}
} // namespace TFL
} // namespace mlir
@@ -0,0 +1,78 @@
/* 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_LITE_METRICS_ERROR_COLLECTOR_INST_H_
#define TENSORFLOW_COMPILER_MLIR_LITE_METRICS_ERROR_COLLECTOR_INST_H_
#include <memory>
#include <string>
#include <unordered_map>
#include <utility>
#include "mlir/IR/Diagnostics.h" // from @llvm-project
#include "mlir/IR/Location.h" // from @llvm-project
#include "mlir/IR/MLIRContext.h" // from @llvm-project
#include "mlir/IR/Operation.h" // from @llvm-project
#include "mlir/Pass/PassInstrumentation.h" // from @llvm-project
#include "tensorflow/compiler/mlir/lite/metrics/converter_error_data.pb.h"
#include "tensorflow/compiler/mlir/lite/metrics/error_collector.h"
#include "tensorflow/compiler/mlir/lite/metrics/types_util.h"
namespace mlir {
namespace TFL {
// Collects errors when running the pass manager.
class ErrorCollectorInstrumentation : public PassInstrumentation {
using ConverterErrorData = tflite::metrics::ConverterErrorData;
using ErrorCode = ConverterErrorData::ErrorCode;
public:
explicit ErrorCollectorInstrumentation(MLIRContext *context);
private:
// Instrumentation hooks. These hooks don't need to be thread-safe. The pass
// manager runs each pass for the entire module, then it walks through
// each op in the module and runs the pass on them, may be in async mode.
void runBeforePass(Pass *pass, Operation *module) override;
void runAfterPass(Pass *pass, Operation *module) override;
void runAfterPassFailed(Pass *pass, Operation *module) override;
// The handler to capture error messages.
std::unique_ptr<ScopedDiagnosticHandler> handler_;
// A map from location to op name.
std::unordered_map<Location, std::string, LocationHash> loc_to_name_;
// Stores the error message for errors without op name and error code.
std::string common_error_message_;
// Name of the running pass.
std::string pass_name_;
// Pointer to the global ErrorCollector instance.
ErrorCollector *error_collector_;
};
// Prefix when adding error code as a note in Diagnostic.
constexpr char kErrorCodePrefix[] = "Error code: ";
// Adds error code to a newly created InFlightDiagnostic.
inline InFlightDiagnostic AttachErrorCode(InFlightDiagnostic &&diag,
int error_code) {
using tflite::metrics::ConverterErrorData;
diag.attachNote() << kErrorCodePrefix
<< ConverterErrorData::ErrorCode_Name(error_code);
return std::move(diag);
}
} // namespace TFL
} // namespace mlir
#endif // TENSORFLOW_COMPILER_MLIR_LITE_METRICS_ERROR_COLLECTOR_INST_H_
@@ -0,0 +1,214 @@
/* 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/lite/metrics/error_collector_inst.h"
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "llvm/Support/SMLoc.h"
#include "llvm/Support/SourceMgr.h"
#include "mlir/Dialect/Func/IR/FuncOps.h" // from @llvm-project
#include "mlir/IR/BuiltinAttributes.h" // from @llvm-project
#include "mlir/IR/BuiltinOps.h" // from @llvm-project
#include "mlir/IR/DialectRegistry.h" // from @llvm-project
#include "mlir/IR/Location.h" // from @llvm-project
#include "mlir/IR/Operation.h" // from @llvm-project
#include "mlir/IR/OwningOpRef.h" // from @llvm-project
#include "mlir/Parser/Parser.h" // from @llvm-project
#include "mlir/Pass/Pass.h" // from @llvm-project
#include "mlir/Pass/PassManager.h" // from @llvm-project
#include "mlir/Support/FileUtilities.h" // from @llvm-project
#include "mlir/Support/LogicalResult.h" // from @llvm-project
#include "mlir/Support/TypeID.h" // from @llvm-project
#include "tensorflow/compiler/mlir/lite/metrics/converter_error_data.pb.h"
#include "tensorflow/compiler/mlir/lite/metrics/error_collector.h"
#include "tensorflow/compiler/mlir/lite/metrics/types_util.h"
#include "tensorflow/compiler/mlir/tensorflow/ir/tf_dialect.h"
#include "xla/tsl/platform/statusor.h"
#include "tensorflow/core/platform/errors.h"
#include "tensorflow/core/platform/resource_loader.h"
#include "tensorflow/core/platform/test.h"
namespace mlir {
namespace TFL {
namespace {
using tsl::StatusOr;
// MockSuccessPass reports errors but doesn't fail.
class MockSuccessPass
: public PassWrapper<MockSuccessPass, OperationPass<ModuleOp>> {
void getDependentDialects(DialectRegistry& registry) const override {
registry.insert<TF::TensorFlowDialect>();
}
public:
MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(MockSuccessPass)
explicit MockSuccessPass() = default;
private:
void runOnOperation() override {
getOperation().walk([](Operation* nestedOp) {
nestedOp->emitError()
<< "Error at " << nestedOp->getName().getStringRef().str() << " op";
});
};
};
// MockFailurePass reports errors and fails.
class MockFailurePass
: public PassWrapper<MockFailurePass, OperationPass<ModuleOp>> {
void getDependentDialects(DialectRegistry& registry) const override {
registry.insert<TF::TensorFlowDialect>();
}
public:
MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(MockFailurePass)
explicit MockFailurePass() = default;
private:
void runOnOperation() override {
getOperation().walk([](Operation* nestedOp) {
if (nestedOp->getName().getStringRef().str().rfind("tf.") != -1) {
AttachErrorCode(
nestedOp->emitError()
<< "Failed at " << nestedOp->getName().getStringRef().str()
<< " op",
tflite::metrics::ConverterErrorData::ERROR_NEEDS_FLEX_OPS);
}
});
signalPassFailure();
};
};
absl::StatusOr<OwningOpRef<mlir::ModuleOp>> LoadModule(
MLIRContext* context, const std::string& file_name) {
std::string error_message;
auto file = openInputFile(file_name, &error_message);
if (!file) {
return absl::InvalidArgumentError("fail to open input file");
}
llvm::SourceMgr source_mgr;
source_mgr.AddNewSourceBuffer(std::move(file), llvm::SMLoc());
return OwningOpRef<mlir::ModuleOp>(
parseSourceFile<mlir::ModuleOp>(source_mgr, context));
}
TEST(ErrorCollectorTest, TessSuccessPass) {
std::string input_file = tensorflow::GetDataDependencyFilepath(
"tensorflow/compiler/mlir/lite/metrics/testdata/strided_slice.mlir");
MLIRContext context;
context.getOrLoadDialect<mlir::func::FuncDialect>();
context.getOrLoadDialect<TF::TensorFlowDialect>();
context.enableMultithreading();
auto module = LoadModule(&context, input_file);
EXPECT_EQ(module.ok(), true);
PassManager pm(module.value().get()->getName(),
OpPassManager::Nesting::Implicit);
pm.addPass(std::make_unique<MockSuccessPass>());
pm.addInstrumentation(
std::make_unique<ErrorCollectorInstrumentation>(&context));
EXPECT_EQ(succeeded(pm.run(module.value().get())), true);
auto collected_errors =
ErrorCollector::GetErrorCollector()->CollectedErrors();
EXPECT_EQ(collected_errors.size(), 0);
}
TEST(ErrorCollectorTest, TessFailurePass) {
using tflite::metrics::ConverterErrorData;
MLIRContext context;
context.getOrLoadDialect<mlir::func::FuncDialect>();
context.getOrLoadDialect<TF::TensorFlowDialect>();
const std::string input_file =
"tensorflow/compiler/mlir/lite/metrics/testdata/strided_slice.mlir";
auto input_file_id = StringAttr::get(&context, input_file);
context.enableMultithreading();
auto module =
LoadModule(&context, tensorflow::GetDataDependencyFilepath(input_file));
EXPECT_EQ(module.ok(), true);
PassManager pm(module.value().get()->getName(),
OpPassManager::Nesting::Implicit);
pm.addPass(std::make_unique<MockSuccessPass>());
pm.addPass(std::make_unique<MockFailurePass>());
pm.addInstrumentation(
std::make_unique<ErrorCollectorInstrumentation>(&context));
EXPECT_EQ(succeeded(pm.run(module.value().get())), false);
auto collected_errors =
ErrorCollector::GetErrorCollector()->CollectedErrors();
EXPECT_EQ(collected_errors.size(), 3);
EXPECT_EQ(collected_errors.count(NewConverterErrorData(
"MockFailurePass",
"Failed at tf.Const op\nsee current operation: %0 = "
"\"tf.Const\"() <{value = dense<1> : tensor<4xi32>}> : () -> "
"tensor<4xi32>\nError code: ERROR_NEEDS_FLEX_OPS",
ConverterErrorData::ERROR_NEEDS_FLEX_OPS, "tf.Const",
mlir::FileLineColLoc::get(input_file_id, 17, 9))),
1);
EXPECT_EQ(collected_errors.count(NewConverterErrorData(
"MockFailurePass",
"Failed at tf.Const op\nsee current operation: %1 = "
"\"tf.Const\"() <{value = dense<0> : tensor<4xi32>}> : () -> "
"tensor<4xi32>\nError code: ERROR_NEEDS_FLEX_OPS",
ConverterErrorData::ERROR_NEEDS_FLEX_OPS, "tf.Const",
mlir::FileLineColLoc::get(input_file_id, 18, 9))),
1);
EXPECT_EQ(
collected_errors.count(NewConverterErrorData(
"MockFailurePass",
"Failed at tf.StridedSlice op\nsee current operation: %2 = "
"\"tf.StridedSlice\"(%arg0, %1, %1, %0) <{begin_mask = 11 : "
"i64, ellipsis_mask = 0 : i64, end_mask = 11 : i64, new_axis_mask = "
"4 : i64, shrink_axis_mask = 0 : i64}> {device = \"\"} : "
"(tensor<*xf32>, tensor<4xi32>, tensor<4xi32>, tensor<4xi32>) "
"-> tensor<*xf32>\nError code: ERROR_NEEDS_FLEX_OPS",
ConverterErrorData::ERROR_NEEDS_FLEX_OPS, "tf.StridedSlice",
mlir::FileLineColLoc::get(input_file_id, 19, 10))),
1);
// Check the location information.
std::vector<std::string> locations;
for (const auto& error : collected_errors) {
EXPECT_TRUE(error.has_location());
locations.push_back(error.location().DebugString());
}
EXPECT_THAT(locations, Each(testing::HasSubstr("CALLSITELOC")));
EXPECT_THAT(locations, Each(testing::HasSubstr(input_file)));
EXPECT_THAT(locations, Contains(testing::HasSubstr("line: 17")));
EXPECT_THAT(locations, Contains(testing::HasSubstr("column: 9")));
EXPECT_THAT(locations, Contains(testing::HasSubstr("line: 19")));
EXPECT_THAT(locations, Contains(testing::HasSubstr("column: 10")));
}
} // namespace
} // namespace TFL
} // namespace mlir
@@ -0,0 +1,21 @@
// 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.
// ==============================================================================
func.func @strided_slice(%arg0 : tensor<*xf32>) -> tensor<*xf32> {
%18 = "tf.Const"() {value = dense<1> : tensor<4xi32>} : () -> tensor<4xi32>
%57 = "tf.Const"() {value = dense<0> : tensor<4xi32>} : () -> tensor<4xi32>
%534 = "tf.StridedSlice"(%arg0, %57, %57, %18) {begin_mask = 11 : i64, device = "", ellipsis_mask = 0 : i64, end_mask = 11 : i64, new_axis_mask = 4 : i64, shrink_axis_mask = 0 : i64} : (tensor<*xf32>, tensor<4xi32>, tensor<4xi32>, tensor<4xi32>) -> tensor<*xf32>
"func.return"(%534) : (tensor<*xf32>) -> ()
}
@@ -0,0 +1,133 @@
/* 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/lite/metrics/types_util.h"
#include <cstddef>
#include <string>
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/TypeSwitch.h"
#include "mlir/IR/BuiltinAttributes.h" // from @llvm-project
#include "mlir/IR/Location.h" // from @llvm-project
#include "mlir/Support/LLVM.h" // from @llvm-project
#include "tensorflow/compiler/mlir/lite/metrics/converter_error_data.pb.h"
namespace mlir {
namespace TFL {
namespace {
// Extracts information from mlir::FileLineColLoc to the proto message
// tflite::metrics::ConverterErrorData::FileLoc.
void ExtractFileLine(const FileLineColLoc& loc,
tflite::metrics::ConverterErrorData::FileLoc* fileline) {
fileline->set_filename(loc.getFilename().str());
fileline->set_line(loc.getLine());
fileline->set_column(loc.getColumn());
}
// Defines a child class of Location to access its protected members.
class LocationExtractor : public Location {
public:
explicit LocationExtractor(const Location& loc) : Location(loc) {}
void Extract(tflite::metrics::ConverterErrorData* error_data) {
using tflite::metrics::ConverterErrorData;
auto mutable_location = error_data->mutable_location();
llvm::TypeSwitch<LocationAttr>(impl)
.Case<OpaqueLoc>([&](OpaqueLoc loc) {
LocationExtractor(loc.getFallbackLocation()).Extract(error_data);
})
.Case<UnknownLoc>([&](UnknownLoc loc) {
mutable_location->set_type(ConverterErrorData::UNKNOWNLOC);
})
.Case<FileLineColLoc>([&](FileLineColLoc loc) {
if (!mutable_location->has_type()) {
mutable_location->set_type(ConverterErrorData::CALLSITELOC);
}
auto new_call = mutable_location->mutable_call()->Add();
ExtractFileLine(loc, new_call->mutable_source());
})
.Case<NameLoc>([&](NameLoc loc) {
if (!mutable_location->has_type()) {
mutable_location->set_type(ConverterErrorData::NAMELOC);
}
auto new_call = mutable_location->mutable_call()->Add();
new_call->set_name(loc.getName().str());
// Add child as the source location.
auto child_loc = loc.getChildLoc();
if (mlir::isa<FileLineColLoc>(child_loc)) {
auto typed_child_loc = mlir::dyn_cast<FileLineColLoc>(child_loc);
ExtractFileLine(typed_child_loc, new_call->mutable_source());
}
})
.Case<CallSiteLoc>([&](CallSiteLoc loc) {
mutable_location->set_type(ConverterErrorData::CALLSITELOC);
LocationExtractor(loc.getCallee()).Extract(error_data);
LocationExtractor(loc.getCaller()).Extract(error_data);
})
.Case<FusedLoc>([&](FusedLoc loc) {
auto locations = loc.getLocations();
size_t num_locs = locations.size();
// Skip the first location if it stores information for propagating
// op_type metadata.
if (num_locs > 0) {
if (auto name_loc = mlir::dyn_cast<mlir::NameLoc>(locations[0])) {
if (name_loc.getName().strref().ends_with(":")) {
if (num_locs == 2) {
return LocationExtractor(locations[1]).Extract(error_data);
} else if (num_locs > 2) {
locations = {locations.begin() + 1, locations.end()};
}
}
}
}
mutable_location->set_type(ConverterErrorData::FUSEDLOC);
llvm::interleave(
locations,
[&](Location l) { LocationExtractor(l).Extract(error_data); },
[&]() {});
});
}
};
} // namespace
tflite::metrics::ConverterErrorData NewConverterErrorData(
const std ::string& pass_name, const std::string& error_message,
tflite::metrics::ConverterErrorData::ErrorCode error_code,
const std::string& op_name, const Location& location) {
using tflite::metrics::ConverterErrorData;
ConverterErrorData error;
if (!pass_name.empty()) {
error.set_subcomponent(pass_name);
}
if (!error_message.empty()) {
error.set_error_message(error_message);
}
if (!op_name.empty()) {
error.mutable_operator_()->set_name(op_name);
}
error.set_error_code(error_code);
LocationExtractor(location).Extract(&error);
return error;
}
} // namespace TFL
} // namespace mlir
@@ -0,0 +1,71 @@
/* 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_LITE_METRICS_TYPES_UTIL_H_
#define TENSORFLOW_COMPILER_MLIR_LITE_METRICS_TYPES_UTIL_H_
#include <cstddef>
#include <functional>
#include <string>
#include "mlir/IR/Location.h" // from @llvm-project
#include "tensorflow/compiler/mlir/lite/metrics/converter_error_data.pb.h"
namespace mlir {
namespace TFL {
// The hash function for mlir::Location.
struct LocationHash {
std::size_t operator()(const Location& v) const noexcept {
return hash_value(v);
}
};
// The hash function for ConverterErrorData.
struct ConverterErrorDataHash {
std::size_t operator()(
const tflite::metrics::ConverterErrorData& v) const noexcept {
std::size_t hash_result = std::hash<std::string>{}(v.error_message());
if (v.has_subcomponent()) {
hash_result ^= std::hash<std::string>{}(v.subcomponent()) << 1;
}
if (v.has_error_code()) {
hash_result ^= std::hash<int>{}(v.error_code()) << 2;
}
if (v.has_operator_() && v.operator_().has_name()) {
hash_result ^= std::hash<std::string>{}(v.operator_().name()) << 3;
}
return hash_result;
}
};
// The comparison function for ConverterErrorData.
struct ConverterErrorDataComparison {
std::size_t operator()(
const tflite::metrics::ConverterErrorData& a,
const tflite::metrics::ConverterErrorData& b) const noexcept {
return ConverterErrorDataHash()(a) == ConverterErrorDataHash()(b);
}
};
// Helper function to create a new ConverterErrorData.
tflite::metrics::ConverterErrorData NewConverterErrorData(
const std ::string& pass_name, const std::string& error_message,
tflite::metrics::ConverterErrorData::ErrorCode error_code,
const std::string& op_name, const Location& location);
} // namespace TFL
} // namespace mlir
#endif // TENSORFLOW_COMPILER_MLIR_LITE_METRICS_TYPES_UTIL_H_