[lite] Add shim for builtin_op_kernels.h; also ensure that
tflite::MutableOpResolver::AddBuiltin returns immediately if passed a
null TfLiteRegistration* pointer.

PiperOrigin-RevId: 367657532
Change-Id: I98c9a4296e3b19470db742cd49390fcbc36919db
diff --git a/tensorflow/lite/core/shims/BUILD b/tensorflow/lite/core/shims/BUILD
index 320666f..733fe02 100644
--- a/tensorflow/lite/core/shims/BUILD
+++ b/tensorflow/lite/core/shims/BUILD
@@ -97,7 +97,10 @@
 cc_library(
     name = "builtin_ops",
     hdrs = [
+        "cc/kernels/builtin_op_kernels.h",
         "cc/kernels/register.h",
+        # TODO(b/161243354): remove the line below when clients no
+        # longer depend on it.
         "//tensorflow/lite/kernels:builtin_op_kernels.h",
         "//tensorflow/lite/kernels:fully_connected.h",
     ],
@@ -106,6 +109,7 @@
         "@org_tensorflow_lite_support//tensorflow_lite_support:__subpackages__",
     ],
     deps = [
+        ":builtin_ops_list",
         "//tensorflow/lite:cc_api",
         "//tensorflow/lite/c:common",
         "//tensorflow/lite/kernels:builtin_ops",
@@ -218,6 +222,17 @@
     ],
 )
 
+cc_library(
+    name = "builtin_ops_list",
+    textual_hdrs = ["builtin_ops_list.inc"],
+    visibility = ["//tensorflow/lite:__subpackages__"],
+)
+
+exports_files(
+    srcs = ["builtin_ops_list.inc"],
+    visibility = ["//tensorflow/lite:__subpackages__"],
+)
+
 #------------------------------------------------------------------------------
 # Testing infrastructure
 
diff --git a/tensorflow/lite/core/shims/builtin_ops_list.inc b/tensorflow/lite/core/shims/builtin_ops_list.inc
new file mode 100644
index 0000000..38ef776
--- /dev/null
+++ b/tensorflow/lite/core/shims/builtin_ops_list.inc
@@ -0,0 +1,155 @@
+
+/* 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.
+==============================================================================*/
+
+// DO NOT EDIT MANUALLY: This file is automatically generated by
+// `tensorflow/lite/schema/builtin_ops_list/generator.cc`.
+
+TFLITE_OP(Register_ADD)
+TFLITE_OP(Register_AVERAGE_POOL_2D)
+TFLITE_OP(Register_CONCATENATION)
+TFLITE_OP(Register_CONV_2D)
+TFLITE_OP(Register_DEPTHWISE_CONV_2D)
+TFLITE_OP(Register_DEPTH_TO_SPACE)
+TFLITE_OP(Register_DEQUANTIZE)
+TFLITE_OP(Register_EMBEDDING_LOOKUP)
+TFLITE_OP(Register_FLOOR)
+TFLITE_OP(Register_FULLY_CONNECTED)
+TFLITE_OP(Register_HASHTABLE_LOOKUP)
+TFLITE_OP(Register_L2_NORMALIZATION)
+TFLITE_OP(Register_L2_POOL_2D)
+TFLITE_OP(Register_LOCAL_RESPONSE_NORMALIZATION)
+TFLITE_OP(Register_LOGISTIC)
+TFLITE_OP(Register_LSH_PROJECTION)
+TFLITE_OP(Register_LSTM)
+TFLITE_OP(Register_MAX_POOL_2D)
+TFLITE_OP(Register_MUL)
+TFLITE_OP(Register_RELU)
+TFLITE_OP(Register_RELU_N1_TO_1)
+TFLITE_OP(Register_RELU6)
+TFLITE_OP(Register_RESHAPE)
+TFLITE_OP(Register_RESIZE_BILINEAR)
+TFLITE_OP(Register_RNN)
+TFLITE_OP(Register_SOFTMAX)
+TFLITE_OP(Register_SPACE_TO_DEPTH)
+TFLITE_OP(Register_SVDF)
+TFLITE_OP(Register_TANH)
+TFLITE_OP(Register_SKIP_GRAM)
+TFLITE_OP(Register_EMBEDDING_LOOKUP_SPARSE)
+TFLITE_OP(Register_PAD)
+TFLITE_OP(Register_UNIDIRECTIONAL_SEQUENCE_RNN)
+TFLITE_OP(Register_GATHER)
+TFLITE_OP(Register_BATCH_TO_SPACE_ND)
+TFLITE_OP(Register_SPACE_TO_BATCH_ND)
+TFLITE_OP(Register_TRANSPOSE)
+TFLITE_OP(Register_MEAN)
+TFLITE_OP(Register_SUB)
+TFLITE_OP(Register_DIV)
+TFLITE_OP(Register_SQUEEZE)
+TFLITE_OP(Register_UNIDIRECTIONAL_SEQUENCE_LSTM)
+TFLITE_OP(Register_STRIDED_SLICE)
+TFLITE_OP(Register_BIDIRECTIONAL_SEQUENCE_RNN)
+TFLITE_OP(Register_EXP)
+TFLITE_OP(Register_TOPK_V2)
+TFLITE_OP(Register_SPLIT)
+TFLITE_OP(Register_LOG_SOFTMAX)
+TFLITE_OP(Register_BIDIRECTIONAL_SEQUENCE_LSTM)
+TFLITE_OP(Register_CAST)
+TFLITE_OP(Register_PRELU)
+TFLITE_OP(Register_MAXIMUM)
+TFLITE_OP(Register_ARG_MAX)
+TFLITE_OP(Register_MINIMUM)
+TFLITE_OP(Register_LESS)
+TFLITE_OP(Register_NEG)
+TFLITE_OP(Register_PADV2)
+TFLITE_OP(Register_GREATER)
+TFLITE_OP(Register_GREATER_EQUAL)
+TFLITE_OP(Register_LESS_EQUAL)
+TFLITE_OP(Register_SELECT)
+TFLITE_OP(Register_SLICE)
+TFLITE_OP(Register_SIN)
+TFLITE_OP(Register_TRANSPOSE_CONV)
+TFLITE_OP(Register_SPARSE_TO_DENSE)
+TFLITE_OP(Register_TILE)
+TFLITE_OP(Register_EXPAND_DIMS)
+TFLITE_OP(Register_EQUAL)
+TFLITE_OP(Register_NOT_EQUAL)
+TFLITE_OP(Register_LOG)
+TFLITE_OP(Register_SUM)
+TFLITE_OP(Register_SQRT)
+TFLITE_OP(Register_RSQRT)
+TFLITE_OP(Register_SHAPE)
+TFLITE_OP(Register_POW)
+TFLITE_OP(Register_ARG_MIN)
+TFLITE_OP(Register_FAKE_QUANT)
+TFLITE_OP(Register_REDUCE_PROD)
+TFLITE_OP(Register_REDUCE_MAX)
+TFLITE_OP(Register_PACK)
+TFLITE_OP(Register_LOGICAL_OR)
+TFLITE_OP(Register_ONE_HOT)
+TFLITE_OP(Register_LOGICAL_AND)
+TFLITE_OP(Register_LOGICAL_NOT)
+TFLITE_OP(Register_UNPACK)
+TFLITE_OP(Register_REDUCE_MIN)
+TFLITE_OP(Register_FLOOR_DIV)
+TFLITE_OP(Register_REDUCE_ANY)
+TFLITE_OP(Register_SQUARE)
+TFLITE_OP(Register_ZEROS_LIKE)
+TFLITE_OP(Register_FILL)
+TFLITE_OP(Register_FLOOR_MOD)
+TFLITE_OP(Register_RANGE)
+TFLITE_OP(Register_RESIZE_NEAREST_NEIGHBOR)
+TFLITE_OP(Register_LEAKY_RELU)
+TFLITE_OP(Register_SQUARED_DIFFERENCE)
+TFLITE_OP(Register_MIRROR_PAD)
+TFLITE_OP(Register_ABS)
+TFLITE_OP(Register_SPLIT_V)
+TFLITE_OP(Register_UNIQUE)
+TFLITE_OP(Register_CEIL)
+TFLITE_OP(Register_REVERSE_V2)
+TFLITE_OP(Register_ADD_N)
+TFLITE_OP(Register_GATHER_ND)
+TFLITE_OP(Register_COS)
+TFLITE_OP(Register_WHERE)
+TFLITE_OP(Register_RANK)
+TFLITE_OP(Register_ELU)
+TFLITE_OP(Register_REVERSE_SEQUENCE)
+TFLITE_OP(Register_MATRIX_DIAG)
+TFLITE_OP(Register_QUANTIZE)
+TFLITE_OP(Register_MATRIX_SET_DIAG)
+TFLITE_OP(Register_ROUND)
+TFLITE_OP(Register_HARD_SWISH)
+TFLITE_OP(Register_IF)
+TFLITE_OP(Register_WHILE)
+TFLITE_OP(Register_NON_MAX_SUPPRESSION_V4)
+TFLITE_OP(Register_NON_MAX_SUPPRESSION_V5)
+TFLITE_OP(Register_SCATTER_ND)
+TFLITE_OP(Register_SELECT_V2)
+TFLITE_OP(Register_DENSIFY)
+TFLITE_OP(Register_SEGMENT_SUM)
+TFLITE_OP(Register_BATCH_MATMUL)
+TFLITE_OP(Register_CUMSUM)
+TFLITE_OP(Register_CALL_ONCE)
+TFLITE_OP(Register_BROADCAST_TO)
+TFLITE_OP(Register_RFFT2D)
+TFLITE_OP(Register_CONV_3D)
+TFLITE_OP(Register_IMAG)
+TFLITE_OP(Register_REAL)
+TFLITE_OP(Register_COMPLEX_ABS)
+TFLITE_OP(Register_HASHTABLE)
+TFLITE_OP(Register_HASHTABLE_FIND)
+TFLITE_OP(Register_HASHTABLE_IMPORT)
+TFLITE_OP(Register_HASHTABLE_SIZE)
+TFLITE_OP(Register_REDUCE_ALL)
diff --git a/tensorflow/lite/core/shims/cc/kernels/builtin_op_kernels.h b/tensorflow/lite/core/shims/cc/kernels/builtin_op_kernels.h
new file mode 100644
index 0000000..da671f6
--- /dev/null
+++ b/tensorflow/lite/core/shims/cc/kernels/builtin_op_kernels.h
@@ -0,0 +1,35 @@
+/* Copyright 2020 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_LITE_CORE_SHIMS_CC_KERNELS_BUILTIN_OP_KERNELS_H_
+#define TENSORFLOW_LITE_CORE_SHIMS_CC_KERNELS_BUILTIN_OP_KERNELS_H_
+
+#include "tensorflow/lite/kernels/builtin_op_kernels.h"
+
+namespace tflite_shims {
+namespace ops {
+namespace builtin {
+
+#define TFLITE_OP(NAME) \
+    using ::tflite::ops::builtin::NAME;
+
+#include "tensorflow/lite/core/shims/builtin_ops_list.inc"
+
+#undef TFLITE_OP
+
+}  // namespace builtin
+}  // namespace ops
+}  // namespace tflite_shims
+
+#endif  // TENSORFLOW_LITE_CORE_SHIMS_CC_KERNELS_BUILTIN_OP_KERNELS_H_
diff --git a/tensorflow/lite/kernels/builtin_op_kernels.h b/tensorflow/lite/kernels/builtin_op_kernels.h
index b52663e..93e4f3c 100644
--- a/tensorflow/lite/kernels/builtin_op_kernels.h
+++ b/tensorflow/lite/kernels/builtin_op_kernels.h
@@ -28,6 +28,9 @@
 // needed. In such cases, the client can selectively add only the registrations
 // their model requires, using a custom `OpResolver` or `MutableOpResolver`.
 // Selective registration in turn allows the linker to strip unused kernels.
+//
+// TODO(b/184734878): auto-generate this header file from the BuiltinOperator
+// enum in the FlatBuffer schema.
 
 TfLiteRegistration* Register_ABS();
 TfLiteRegistration* Register_ADD();
diff --git a/tensorflow/lite/mutable_op_resolver.cc b/tensorflow/lite/mutable_op_resolver.cc
index a21cb84..eba154b 100644
--- a/tensorflow/lite/mutable_op_resolver.cc
+++ b/tensorflow/lite/mutable_op_resolver.cc
@@ -57,6 +57,12 @@
 void MutableOpResolver::AddBuiltin(tflite::BuiltinOperator op,
                                    const TfLiteRegistration* registration,
                                    int version) {
+  if (registration == nullptr) {
+    // Under certain conditions, builtin TfLiteRegistration factory methods may
+    // return null in the client library. This is generally benign, and we
+    // silently suppress resulting AddBuiltin calls here.
+    return;
+  }
   TfLiteRegistration new_registration = *registration;
   new_registration.custom_name = nullptr;
   new_registration.builtin_code = op;
diff --git a/tensorflow/lite/schema/builtin_ops_header/README.md b/tensorflow/lite/schema/builtin_ops_header/README.md
index e34a30b..b5e902b 100644
--- a/tensorflow/lite/schema/builtin_ops_header/README.md
+++ b/tensorflow/lite/schema/builtin_ops_header/README.md
@@ -8,5 +8,8 @@
 ```sh
 bazel run \
   //tensorflow/lite/schema/builtin_ops_header:generate > \
-  tensorflow/lite/builtin_ops.h
+  tensorflow/lite/builtin_ops.h &&
+bazel run \
+  //tensorflow/lite/schema/builtin_ops_list:generate > \
+  tensorflow/lite/core/shims/builtin_ops_list.inc
 ```
diff --git a/tensorflow/lite/schema/builtin_ops_list/BUILD b/tensorflow/lite/schema/builtin_ops_list/BUILD
new file mode 100644
index 0000000..a8a6f15
--- /dev/null
+++ b/tensorflow/lite/schema/builtin_ops_list/BUILD
@@ -0,0 +1,53 @@
+# This package contains code to auto-generate the contents of the file
+#   tensorflow/lite/core/shims:builtin_ops_list.inc
+# from the BuiltinOperator enum in the FlatBuffer schema,
+# and a test to verify that the checked-in copy remains up-to-date.
+
+# TODO(b/184934065): consider merging the code in this directory with
+# the code in ../builtin_ops_header/, i.e. have a single tool generate
+# both the builtin_ops.h header and the builtin_ops_list.inc file?
+
+package(
+    default_visibility = [
+        "//visibility:public",
+    ],
+    licenses = ["notice"],
+)
+
+cc_library(
+    name = "generator",
+    srcs = ["generator.cc"],
+    hdrs = ["generator.h"],
+    deps = [
+        "//tensorflow/lite/schema:schema_fbs",
+    ],
+)
+
+cc_binary(
+    name = "generate",
+    srcs = ["generate.cc"],
+    deps = [
+        ":generator",
+    ],
+)
+
+cc_test(
+    name = "generator_test",
+    srcs = ["generator_test.cc"],
+    deps = [
+        ":generator",
+        "@com_google_googletest//:gtest",
+    ],
+)
+
+cc_test(
+    name = "consistency_test",
+    srcs = ["consistency_test.cc"],
+    data = [
+        "//tensorflow/lite/core/shims:builtin_ops_list.inc",
+    ],
+    deps = [
+        ":generator",
+        "@com_google_googletest//:gtest",
+    ],
+)
diff --git a/tensorflow/lite/schema/builtin_ops_list/README.md b/tensorflow/lite/schema/builtin_ops_list/README.md
new file mode 100644
index 0000000..dd9a753
--- /dev/null
+++ b/tensorflow/lite/schema/builtin_ops_list/README.md
@@ -0,0 +1,15 @@
+# Builtin Ops List Generator.
+
+This directory contains a code generator to generate a pure C header for
+builtin ops lists.
+
+Whenever you add a new builtin op, please execute:
+
+```sh
+bazel run \
+  //tensorflow/lite/schema/builtin_ops_header:generate > \
+  tensorflow/lite/builtin_ops.h &&
+bazel run \
+  //tensorflow/lite/schema/builtin_ops_list:generate > \
+  tensorflow/lite/core/shims/builtin_ops_list.inc
+```
diff --git a/tensorflow/lite/schema/builtin_ops_list/consistency_test.cc b/tensorflow/lite/schema/builtin_ops_list/consistency_test.cc
new file mode 100644
index 0000000..f82ac12
--- /dev/null
+++ b/tensorflow/lite/schema/builtin_ops_list/consistency_test.cc
@@ -0,0 +1,48 @@
+/* Copyright 2018 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 <fstream>
+
+#include <gtest/gtest.h>
+#include "tensorflow/lite/schema/builtin_ops_list/generator.h"
+
+namespace {
+
+const char* kHeaderFileName =
+    "tensorflow/lite/core/shims/builtin_ops_list.inc";
+
+// The test ensures that `builtin_ops_list.inc` header is consistent with the
+// FlatBuffer schema definition. When the schema is modified, it's required to
+// run the generator to re-generate the header.
+// Please see README.md for more details.
+TEST(BuiltinOpsHeaderTest, TestConsistency) {
+  std::ifstream input_stream(kHeaderFileName, std::ios::binary);
+  ASSERT_TRUE(input_stream);
+  std::string file_content((std::istreambuf_iterator<char>(input_stream)),
+                           std::istreambuf_iterator<char>());
+
+  std::ostringstream output_stream;
+  tflite::builtin_ops_list::GenerateHeader(output_stream);
+  std::string generated_content = output_stream.str();
+
+  EXPECT_EQ(file_content, generated_content);
+}
+
+}  // anonymous namespace
+
+int main(int argc, char** argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/tensorflow/lite/schema/builtin_ops_list/generate.cc b/tensorflow/lite/schema/builtin_ops_list/generate.cc
new file mode 100644
index 0000000..bcc2206
--- /dev/null
+++ b/tensorflow/lite/schema/builtin_ops_list/generate.cc
@@ -0,0 +1,26 @@
+/* Copyright 2018 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 <iostream>
+
+#include "tensorflow/lite/schema/builtin_ops_list/generator.h"
+
+// This executable is used to generate builtin_ops.h in TensorFlow Lite.
+// Please see README.md for more details.
+int main() {
+  if (!tflite::builtin_ops_list::GenerateHeader(std::cout)) {
+    std::cerr << "Failed to generate the header file.\n";
+  }
+  return 0;
+}
diff --git a/tensorflow/lite/schema/builtin_ops_list/generator.cc b/tensorflow/lite/schema/builtin_ops_list/generator.cc
new file mode 100644
index 0000000..40549ce
--- /dev/null
+++ b/tensorflow/lite/schema/builtin_ops_list/generator.cc
@@ -0,0 +1,104 @@
+/* Copyright 2018 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/lite/schema/builtin_ops_list/generator.h"
+
+#include <iostream>
+
+#include "tensorflow/lite/schema/schema_generated.h"
+
+namespace tflite {
+namespace builtin_ops_list {
+
+const char kFileHeader[] = R"(
+/* 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.
+==============================================================================*/
+
+// DO NOT EDIT MANUALLY: This file is automatically generated by
+// `tensorflow/lite/schema/builtin_ops_list/generator.cc`.
+
+)";
+
+bool IsValidInputEnumName(const std::string& name) {
+  const char* begin = name.c_str();
+  const char* ch = begin;
+  while (*ch != '\0') {
+    // If it's not the first character, expect an underscore.
+    if (ch != begin) {
+      if (*ch != '_') {
+        return false;
+      }
+      ++ch;
+    }
+
+    // Expecting a word with upper case letters or digits, like "CONV",
+    // "CONV2D", "2D"...etc.
+    bool empty = true;
+    while (isupper(*ch) || isdigit(*ch)) {
+      // It's not empty if at least one character is consumed.
+      empty = false;
+      ++ch;
+    }
+    if (empty) {
+      return false;
+    }
+  }
+  return true;
+}
+
+bool GenerateHeader(std::ostream& os) {
+  auto enum_names = tflite::EnumNamesBuiltinOperator();
+
+  os << kFileHeader;
+
+  // Check if all the input enum names are valid.
+  for (auto enum_value : EnumValuesBuiltinOperator()) {
+    std::string enum_name = enum_names[enum_value];
+    if (!IsValidInputEnumName(enum_name)) {
+      std::cerr << "Invalid input enum name: " << enum_name << std::endl;
+      return false;
+    }
+  }
+
+  for (auto enum_value : EnumValuesBuiltinOperator()) {
+    std::string enum_name = enum_names[enum_value];
+    // Skip pseudo-opcodes that aren't real ops.
+    if (enum_name == "CUSTOM" ||
+        enum_name == "PLACEHOLDER_FOR_GREATER_OP_CODES" ||
+        enum_name == "DELEGATE") {
+      continue;
+    }
+    // Skip ops that aren't declared in builtin_op_kernels.h.
+    if (enum_name == "CALL" || enum_name == "CONCAT_EMBEDDINGS") {
+      continue;
+    }
+    os << "TFLITE_OP(Register_" << enum_name << ")\n";
+  }
+  return true;
+}
+
+}  // namespace builtin_ops_list
+}  // namespace tflite
diff --git a/tensorflow/lite/schema/builtin_ops_list/generator.h b/tensorflow/lite/schema/builtin_ops_list/generator.h
new file mode 100644
index 0000000..9bd1c49
--- /dev/null
+++ b/tensorflow/lite/schema/builtin_ops_list/generator.h
@@ -0,0 +1,35 @@
+/* Copyright 2018 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.
+==============================================================================*/
+// An utility library to generate pure C header for builtin ops definition.
+#ifndef TENSORFLOW_LITE_SCHEMA_BUILTIN_OPS_LIST_GENERATOR_H_
+#define TENSORFLOW_LITE_SCHEMA_BUILTIN_OPS_LIST_GENERATOR_H_
+
+#include <iostream>
+#include <string>
+
+namespace tflite {
+namespace builtin_ops_list {
+
+// Check if the input enum name (from the Flatbuffer definition) is valid.
+bool IsValidInputEnumName(const std::string& name);
+
+// The function generates a pure C header for builtin ops definition, and write
+// it to the output stream.
+bool GenerateHeader(std::ostream& os);
+
+}  // namespace builtin_ops_list
+}  // namespace tflite
+
+#endif  // TENSORFLOW_LITE_SCHEMA_BUILTIN_OPS_LIST_GENERATOR_H_
diff --git a/tensorflow/lite/schema/builtin_ops_list/generator_test.cc b/tensorflow/lite/schema/builtin_ops_list/generator_test.cc
new file mode 100644
index 0000000..548218b
--- /dev/null
+++ b/tensorflow/lite/schema/builtin_ops_list/generator_test.cc
@@ -0,0 +1,58 @@
+
+/* Copyright 2018 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/lite/schema/builtin_ops_list/generator.h"
+
+#include <fstream>
+
+#include <gtest/gtest.h>
+
+namespace {
+
+using tflite::builtin_ops_list::IsValidInputEnumName;
+
+TEST(TestIsValidInputEnumName, TestWithValidInputNames) {
+  EXPECT_TRUE(IsValidInputEnumName("ADD"));
+  EXPECT_TRUE(IsValidInputEnumName("CONV_2D"));
+  EXPECT_TRUE(IsValidInputEnumName("L2_POOL_2D"));
+}
+
+TEST(TestIsValidInputEnumName, TestWithLeadingUnderscore) {
+  EXPECT_FALSE(IsValidInputEnumName("_ADD"));
+  EXPECT_FALSE(IsValidInputEnumName("_CONV_2D"));
+}
+
+TEST(TestIsValidInputEnumName, TestWithLowerCase) {
+  EXPECT_FALSE(IsValidInputEnumName("_AdD"));
+  EXPECT_FALSE(IsValidInputEnumName("_COnV_2D"));
+}
+
+TEST(TestIsValidInputEnumName, TestWithOtherCharacters) {
+  EXPECT_FALSE(IsValidInputEnumName("_AdD!2D"));
+  EXPECT_FALSE(IsValidInputEnumName("_COnV?2D"));
+}
+
+TEST(TestIsValidInputEnumName, TestWithDoubleUnderscores) {
+  EXPECT_FALSE(IsValidInputEnumName("ADD__2D"));
+  EXPECT_FALSE(IsValidInputEnumName("CONV__2D"));
+}
+
+}  // anonymous namespace
+
+int main(int argc, char** argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/tensorflow/opensource_only.files b/tensorflow/opensource_only.files
index 064bcac..2c98709 100644
--- a/tensorflow/opensource_only.files
+++ b/tensorflow/opensource_only.files
@@ -16,6 +16,7 @@
 tensorflow/lite/core/shims/cc/experimental/acceleration/configuration/delegate_registry.h
 tensorflow/lite/core/shims/cc/interpreter.h
 tensorflow/lite/core/shims/cc/interpreter_builder.h
+tensorflow/lite/core/shims/cc/kernels/builtin_op_kernels.h
 tensorflow/lite/core/shims/cc/kernels/register.h
 tensorflow/lite/core/shims/cc/model.h
 tensorflow/lite/core/shims/cc/model_builder.h