1 /* Copyright 2021 The TensorFlow Authors. All Rights Reserved.
2 
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5 You may obtain a copy of the License at
6 
7     http://www.apache.org/licenses/LICENSE-2.0
8 
9 Unless required by applicable law or agreed to in writing, software
10 distributed under the License is distributed on an "AS IS" BASIS,
11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 See the License for the specific language governing permissions and
13 limitations under the License.
14 ==============================================================================*/
15 #ifndef TENSORFLOW_LITE_MICRO_MICRO_MUTABLE_OP_RESOLVER_H_
16 #define TENSORFLOW_LITE_MICRO_MICRO_MUTABLE_OP_RESOLVER_H_
17 
18 #include <cstdio>
19 #include <cstring>
20 
21 #include "tensorflow/lite/c/common.h"
22 #include "tensorflow/lite/core/api/error_reporter.h"
23 #include "tensorflow/lite/core/api/flatbuffer_conversions.h"
24 #include "tensorflow/lite/kernels/internal/compatibility.h"
25 #include "tensorflow/lite/kernels/op_macros.h"
26 #include "tensorflow/lite/micro/compatibility.h"
27 #include "tensorflow/lite/micro/kernels/conv.h"
28 #include "tensorflow/lite/micro/kernels/ethosu.h"
29 #include "tensorflow/lite/micro/kernels/fully_connected.h"
30 #include "tensorflow/lite/micro/kernels/micro_ops.h"
31 #include "tensorflow/lite/micro/kernels/softmax.h"
32 #include "tensorflow/lite/micro/micro_op_resolver.h"
33 #include "tensorflow/lite/schema/schema_generated.h"
34 
35 namespace tflite {
36 TfLiteRegistration* Register_DETECTION_POSTPROCESS();
37 
38 template <unsigned int tOpCount>
39 class MicroMutableOpResolver : public MicroOpResolver {
40  public:
41   TF_LITE_REMOVE_VIRTUAL_DELETE
42 
43   explicit MicroMutableOpResolver(ErrorReporter* error_reporter = nullptr)
error_reporter_(error_reporter)44       : error_reporter_(error_reporter) {}
45 
FindOp(tflite::BuiltinOperator op)46   const TfLiteRegistration* FindOp(tflite::BuiltinOperator op) const override {
47     if (op == BuiltinOperator_CUSTOM) return nullptr;
48 
49     for (unsigned int i = 0; i < registrations_len_; ++i) {
50       const TfLiteRegistration& registration = registrations_[i];
51       if (registration.builtin_code == op) {
52         return &registration;
53       }
54     }
55     return nullptr;
56   }
57 
FindOp(const char * op)58   const TfLiteRegistration* FindOp(const char* op) const override {
59     for (unsigned int i = 0; i < registrations_len_; ++i) {
60       const TfLiteRegistration& registration = registrations_[i];
61       if ((registration.builtin_code == BuiltinOperator_CUSTOM) &&
62           (strcmp(registration.custom_name, op) == 0)) {
63         return &registration;
64       }
65     }
66     return nullptr;
67   }
68 
GetOpDataParser(BuiltinOperator op)69   MicroOpResolver::BuiltinParseFunction GetOpDataParser(
70       BuiltinOperator op) const override {
71     TFLITE_DCHECK(num_buitin_ops_ <= tOpCount);
72     for (unsigned int i = 0; i < num_buitin_ops_; ++i) {
73       if (builtin_codes_[i] == op) return builtin_parsers_[i];
74     }
75     return nullptr;
76   }
77 
78   // Registers a Custom Operator with the MicroOpResolver.
79   //
80   // Only the first call for a given name will be successful. i.e. if this
81   // function is called again for a previously added Custom Operator, the
82   // MicroOpResolver will be unchanged and this function will return
83   // kTfLiteError.
AddCustom(const char * name,TfLiteRegistration * registration)84   TfLiteStatus AddCustom(const char* name, TfLiteRegistration* registration) {
85     if (registrations_len_ >= tOpCount) {
86       if (error_reporter_) {
87         TF_LITE_REPORT_ERROR(
88             error_reporter_,
89             "Couldn't register custom op '%s', resolver size is too small (%d)",
90             name, tOpCount);
91       }
92       return kTfLiteError;
93     }
94 
95     if (FindOp(name) != nullptr) {
96       if (error_reporter_ != nullptr) {
97         TF_LITE_REPORT_ERROR(error_reporter_,
98                              "Calling AddCustom for the same op more than once "
99                              "is not supported (Op: %s).",
100                              name);
101       }
102       return kTfLiteError;
103     }
104 
105     TfLiteRegistration* new_registration = &registrations_[registrations_len_];
106     registrations_len_ += 1;
107 
108     *new_registration = *registration;
109     new_registration->builtin_code = BuiltinOperator_CUSTOM;
110     new_registration->custom_name = name;
111     return kTfLiteOk;
112   }
113 
114   // The Add* functions below add the various Builtin operators to the
115   // MicroMutableOpResolver object.
116 
AddAbs()117   TfLiteStatus AddAbs() {
118     return AddBuiltin(BuiltinOperator_ABS, tflite::ops::micro::Register_ABS(),
119                       ParseAbs);
120   }
121 
AddAdd()122   TfLiteStatus AddAdd() {
123     return AddBuiltin(BuiltinOperator_ADD, tflite::ops::micro::Register_ADD(),
124                       ParseAdd);
125   }
126 
AddAddN()127   TfLiteStatus AddAddN() {
128     return AddBuiltin(BuiltinOperator_ADD_N, tflite::Register_ADD_N(),
129                       ParseAddN);
130   }
131 
AddArgMax()132   TfLiteStatus AddArgMax() {
133     return AddBuiltin(BuiltinOperator_ARG_MAX,
134                       tflite::ops::micro::Register_ARG_MAX(), ParseArgMax);
135   }
136 
AddArgMin()137   TfLiteStatus AddArgMin() {
138     return AddBuiltin(BuiltinOperator_ARG_MIN,
139                       tflite::ops::micro::Register_ARG_MIN(), ParseArgMin);
140   }
141 
AddAveragePool2D()142   TfLiteStatus AddAveragePool2D() {
143     return AddBuiltin(BuiltinOperator_AVERAGE_POOL_2D,
144                       tflite::Register_AVERAGE_POOL_2D(), ParsePool);
145   }
146 
AddBatchToSpaceNd()147   TfLiteStatus AddBatchToSpaceNd() {
148     return AddBuiltin(BuiltinOperator_BATCH_TO_SPACE_ND,
149                       Register_BATCH_TO_SPACE_ND(), ParseBatchToSpaceNd);
150   }
151 
AddCast()152   TfLiteStatus AddCast() {
153     return AddBuiltin(BuiltinOperator_CAST, Register_CAST(), ParseCast);
154   }
155 
AddCeil()156   TfLiteStatus AddCeil() {
157     return AddBuiltin(BuiltinOperator_CEIL, tflite::ops::micro::Register_CEIL(),
158                       ParseCeil);
159   }
160 
AddCircularBuffer()161   TfLiteStatus AddCircularBuffer() {
162     return AddCustom("CIRCULAR_BUFFER",
163                      tflite::ops::micro::Register_CIRCULAR_BUFFER());
164   }
165 
AddConcatenation()166   TfLiteStatus AddConcatenation() {
167     return AddBuiltin(BuiltinOperator_CONCATENATION,
168                       tflite::ops::micro::Register_CONCATENATION(),
169                       ParseConcatenation);
170   }
171 
172   TfLiteStatus AddConv2D(
173       const TfLiteRegistration& registration = Register_CONV_2D()) {
174     return AddBuiltin(BuiltinOperator_CONV_2D, registration, ParseConv2D);
175   }
176 
AddCos()177   TfLiteStatus AddCos() {
178     return AddBuiltin(BuiltinOperator_COS, tflite::ops::micro::Register_COS(),
179                       ParseCos);
180   }
181 
AddCumSum()182   TfLiteStatus AddCumSum() {
183     return AddBuiltin(BuiltinOperator_CUMSUM, tflite::Register_CUMSUM(),
184                       ParseCumsum);
185   }
186 
AddDepthToSpace()187   TfLiteStatus AddDepthToSpace() {
188     return AddBuiltin(BuiltinOperator_DEPTH_TO_SPACE,
189                       tflite::Register_DEPTH_TO_SPACE(), ParseDepthToSpace);
190   }
191 
AddDepthwiseConv2D()192   TfLiteStatus AddDepthwiseConv2D() {
193     return AddBuiltin(BuiltinOperator_DEPTHWISE_CONV_2D,
194                       Register_DEPTHWISE_CONV_2D(), ParseDepthwiseConv2D);
195   }
196 
AddDequantize()197   TfLiteStatus AddDequantize() {
198     return AddBuiltin(BuiltinOperator_DEQUANTIZE,
199                       tflite::ops::micro::Register_DEQUANTIZE(),
200                       ParseDequantize);
201   }
202 
AddDetectionPostprocess()203   TfLiteStatus AddDetectionPostprocess() {
204     return AddCustom("TFLite_Detection_PostProcess",
205                      tflite::Register_DETECTION_POSTPROCESS());
206   }
207 
AddElu()208   TfLiteStatus AddElu() {
209     return AddBuiltin(BuiltinOperator_ELU, tflite::Register_ELU(), ParseElu);
210   }
211 
AddEqual()212   TfLiteStatus AddEqual() {
213     return AddBuiltin(BuiltinOperator_EQUAL,
214                       tflite::ops::micro::Register_EQUAL(), ParseEqual);
215   }
216 
AddEthosU()217   TfLiteStatus AddEthosU() {
218     TfLiteRegistration* registration = tflite::Register_ETHOSU();
219     if (registration) {
220       return AddCustom(tflite::GetString_ETHOSU(), registration);
221     }
222     return kTfLiteOk;
223   }
224 
AddExp()225   TfLiteStatus AddExp() {
226     return AddBuiltin(BuiltinOperator_EXP, Register_EXP(), ParseExp);
227   }
228 
AddExpandDims()229   TfLiteStatus AddExpandDims() {
230     return AddBuiltin(BuiltinOperator_EXPAND_DIMS, Register_EXPAND_DIMS(),
231                       ParseExpandDims);
232   }
233 
AddFill()234   TfLiteStatus AddFill() {
235     return AddBuiltin(BuiltinOperator_FILL, tflite::Register_FILL(), ParseFill);
236   }
237 
AddFloor()238   TfLiteStatus AddFloor() {
239     return AddBuiltin(BuiltinOperator_FLOOR,
240                       tflite::ops::micro::Register_FLOOR(), ParseFloor);
241   }
242 
AddFloorDiv()243   TfLiteStatus AddFloorDiv() {
244     return AddBuiltin(BuiltinOperator_FLOOR_DIV, tflite::Register_FLOOR_DIV(),
245                       ParseFloorDiv);
246   }
247 
AddFloorMod()248   TfLiteStatus AddFloorMod() {
249     return AddBuiltin(BuiltinOperator_FLOOR_MOD, tflite::Register_FLOOR_MOD(),
250                       ParseFloorMod);
251   }
252 
253   TfLiteStatus AddFullyConnected(
254       const TfLiteRegistration& registration = Register_FULLY_CONNECTED()) {
255     return AddBuiltin(BuiltinOperator_FULLY_CONNECTED, registration,
256                       ParseFullyConnected);
257   }
258 
AddGather()259   TfLiteStatus AddGather() {
260     return AddBuiltin(BuiltinOperator_GATHER, tflite::Register_GATHER(),
261                       ParseGather);
262   }
263 
AddGatherNd()264   TfLiteStatus AddGatherNd() {
265     return AddBuiltin(BuiltinOperator_GATHER_ND, tflite::Register_GATHER_ND(),
266                       ParseGatherNd);
267   }
268 
AddGreater()269   TfLiteStatus AddGreater() {
270     return AddBuiltin(BuiltinOperator_GREATER,
271                       tflite::ops::micro::Register_GREATER(), ParseGreater);
272   }
273 
AddGreaterEqual()274   TfLiteStatus AddGreaterEqual() {
275     return AddBuiltin(BuiltinOperator_GREATER_EQUAL,
276                       tflite::ops::micro::Register_GREATER_EQUAL(),
277                       ParseGreaterEqual);
278   }
279 
AddHardSwish()280   TfLiteStatus AddHardSwish() {
281     return AddBuiltin(BuiltinOperator_HARD_SWISH, tflite::Register_HARD_SWISH(),
282                       ParseHardSwish);
283   }
284 
AddIf()285   TfLiteStatus AddIf() {
286     return AddBuiltin(BuiltinOperator_IF, tflite::Register_IF(), ParseIf);
287   }
288 
AddL2Normalization()289   TfLiteStatus AddL2Normalization() {
290     return AddBuiltin(BuiltinOperator_L2_NORMALIZATION,
291                       tflite::ops::micro::Register_L2_NORMALIZATION(),
292                       ParseL2Normalization);
293   }
294 
AddL2Pool2D()295   TfLiteStatus AddL2Pool2D() {
296     return AddBuiltin(BuiltinOperator_L2_POOL_2D, tflite::Register_L2_POOL_2D(),
297                       ParsePool);
298   }
299 
AddLeakyRelu()300   TfLiteStatus AddLeakyRelu() {
301     return AddBuiltin(BuiltinOperator_LEAKY_RELU, tflite::Register_LEAKY_RELU(),
302                       ParseLeakyRelu);
303   }
304 
AddLess()305   TfLiteStatus AddLess() {
306     return AddBuiltin(BuiltinOperator_LESS, tflite::ops::micro::Register_LESS(),
307                       ParseLess);
308   }
309 
AddLessEqual()310   TfLiteStatus AddLessEqual() {
311     return AddBuiltin(BuiltinOperator_LESS_EQUAL,
312                       tflite::ops::micro::Register_LESS_EQUAL(),
313                       ParseLessEqual);
314   }
315 
AddLog()316   TfLiteStatus AddLog() {
317     return AddBuiltin(BuiltinOperator_LOG, tflite::ops::micro::Register_LOG(),
318                       ParseLog);
319   }
320 
AddLogicalAnd()321   TfLiteStatus AddLogicalAnd() {
322     return AddBuiltin(BuiltinOperator_LOGICAL_AND,
323                       tflite::Register_LOGICAL_AND(), ParseLogicalAnd);
324   }
325 
AddLogicalNot()326   TfLiteStatus AddLogicalNot() {
327     return AddBuiltin(BuiltinOperator_LOGICAL_NOT,
328                       tflite::ops::micro::Register_LOGICAL_NOT(),
329                       ParseLogicalNot);
330   }
331 
AddLogicalOr()332   TfLiteStatus AddLogicalOr() {
333     return AddBuiltin(BuiltinOperator_LOGICAL_OR, tflite::Register_LOGICAL_OR(),
334                       ParseLogicalOr);
335   }
336 
AddLogistic()337   TfLiteStatus AddLogistic() {
338     return AddBuiltin(BuiltinOperator_LOGISTIC, tflite::Register_LOGISTIC(),
339                       ParseLogistic);
340   }
341 
AddMaximum()342   TfLiteStatus AddMaximum() {
343     return AddBuiltin(BuiltinOperator_MAXIMUM,
344                       tflite::ops::micro::Register_MAXIMUM(), ParseMaximum);
345   }
346 
AddMaxPool2D()347   TfLiteStatus AddMaxPool2D() {
348     return AddBuiltin(BuiltinOperator_MAX_POOL_2D,
349                       tflite::Register_MAX_POOL_2D(), ParsePool);
350   }
351 
AddMean()352   TfLiteStatus AddMean() {
353     return AddBuiltin(BuiltinOperator_MEAN, tflite::ops::micro::Register_MEAN(),
354                       ParseReducer);
355   }
356 
AddMinimum()357   TfLiteStatus AddMinimum() {
358     return AddBuiltin(BuiltinOperator_MINIMUM,
359                       tflite::ops::micro::Register_MINIMUM(), ParseMinimum);
360   }
361 
AddMul()362   TfLiteStatus AddMul() {
363     return AddBuiltin(BuiltinOperator_MUL, tflite::ops::micro::Register_MUL(),
364                       ParseMul);
365   }
366 
AddNeg()367   TfLiteStatus AddNeg() {
368     return AddBuiltin(BuiltinOperator_NEG, tflite::ops::micro::Register_NEG(),
369                       ParseNeg);
370   }
371 
AddNotEqual()372   TfLiteStatus AddNotEqual() {
373     return AddBuiltin(BuiltinOperator_NOT_EQUAL,
374                       tflite::ops::micro::Register_NOT_EQUAL(), ParseNotEqual);
375   }
376 
AddPack()377   TfLiteStatus AddPack() {
378     return AddBuiltin(BuiltinOperator_PACK, tflite::ops::micro::Register_PACK(),
379                       ParsePack);
380   }
381 
AddPad()382   TfLiteStatus AddPad() {
383     return AddBuiltin(BuiltinOperator_PAD, tflite::ops::micro::Register_PAD(),
384                       ParsePad);
385   }
386 
AddPadV2()387   TfLiteStatus AddPadV2() {
388     return AddBuiltin(BuiltinOperator_PADV2,
389                       tflite::ops::micro::Register_PADV2(), ParsePadV2);
390   }
391 
AddPrelu()392   TfLiteStatus AddPrelu() {
393     return AddBuiltin(BuiltinOperator_PRELU,
394                       tflite::ops::micro::Register_PRELU(), ParsePrelu);
395   }
396 
AddQuantize()397   TfLiteStatus AddQuantize() {
398     return AddBuiltin(BuiltinOperator_QUANTIZE, Register_QUANTIZE(),
399                       ParseQuantize);
400   }
401 
AddReduceMax()402   TfLiteStatus AddReduceMax() {
403     return AddBuiltin(BuiltinOperator_REDUCE_MAX,
404                       tflite::ops::micro::Register_REDUCE_MAX(), ParseReducer);
405   }
406 
AddRelu()407   TfLiteStatus AddRelu() {
408     return AddBuiltin(BuiltinOperator_RELU, tflite::Register_RELU(), ParseRelu);
409   }
410 
AddRelu6()411   TfLiteStatus AddRelu6() {
412     return AddBuiltin(BuiltinOperator_RELU6, tflite::Register_RELU6(),
413                       ParseRelu6);
414   }
415 
AddReshape()416   TfLiteStatus AddReshape() {
417     return AddBuiltin(BuiltinOperator_RESHAPE,
418                       tflite::ops::micro::Register_RESHAPE(), ParseReshape);
419   }
420 
AddResizeBilinear()421   TfLiteStatus AddResizeBilinear() {
422     return AddBuiltin(BuiltinOperator_RESIZE_BILINEAR,
423                       Register_RESIZE_BILINEAR(), ParseResizeBilinear);
424   }
425 
AddResizeNearestNeighbor()426   TfLiteStatus AddResizeNearestNeighbor() {
427     return AddBuiltin(BuiltinOperator_RESIZE_NEAREST_NEIGHBOR,
428                       tflite::ops::micro::Register_RESIZE_NEAREST_NEIGHBOR(),
429                       ParseResizeNearestNeighbor);
430   }
431 
AddRound()432   TfLiteStatus AddRound() {
433     return AddBuiltin(BuiltinOperator_ROUND,
434                       tflite::ops::micro::Register_ROUND(), ParseRound);
435   }
436 
AddRsqrt()437   TfLiteStatus AddRsqrt() {
438     return AddBuiltin(BuiltinOperator_RSQRT,
439                       tflite::ops::micro::Register_RSQRT(), ParseRsqrt);
440   }
441 
AddShape()442   TfLiteStatus AddShape() {
443     return AddBuiltin(BuiltinOperator_SHAPE, Register_SHAPE(), ParseShape);
444   }
445 
AddSin()446   TfLiteStatus AddSin() {
447     return AddBuiltin(BuiltinOperator_SIN, tflite::ops::micro::Register_SIN(),
448                       ParseSin);
449   }
450 
451   TfLiteStatus AddSoftmax(
452       const TfLiteRegistration& registration = Register_SOFTMAX()) {
453     return AddBuiltin(BuiltinOperator_SOFTMAX, registration, ParseSoftmax);
454   }
455 
AddSpaceToBatchNd()456   TfLiteStatus AddSpaceToBatchNd() {
457     return AddBuiltin(BuiltinOperator_SPACE_TO_BATCH_ND,
458                       Register_SPACE_TO_BATCH_ND(), ParseSpaceToBatchNd);
459   }
460 
AddSpaceToDepth()461   TfLiteStatus AddSpaceToDepth() {
462     return AddBuiltin(BuiltinOperator_SPACE_TO_DEPTH, Register_SPACE_TO_DEPTH(),
463                       ParseSpaceToDepth);
464   }
465 
AddSplit()466   TfLiteStatus AddSplit() {
467     return AddBuiltin(BuiltinOperator_SPLIT,
468                       tflite::ops::micro::Register_SPLIT(), ParseSplit);
469   }
470 
AddSplitV()471   TfLiteStatus AddSplitV() {
472     return AddBuiltin(BuiltinOperator_SPLIT_V,
473                       tflite::ops::micro::Register_SPLIT_V(), ParseSplitV);
474   }
475 
AddSqueeze()476   TfLiteStatus AddSqueeze() {
477     return AddBuiltin(BuiltinOperator_SQUEEZE, Register_SQUEEZE(),
478                       ParseSqueeze);
479   }
480 
AddSqrt()481   TfLiteStatus AddSqrt() {
482     return AddBuiltin(BuiltinOperator_SQRT, tflite::ops::micro::Register_SQRT(),
483                       ParseSqrt);
484   }
485 
AddSquare()486   TfLiteStatus AddSquare() {
487     return AddBuiltin(BuiltinOperator_SQUARE,
488                       tflite::ops::micro::Register_SQUARE(), ParseSquare);
489   }
490 
AddStridedSlice()491   TfLiteStatus AddStridedSlice() {
492     return AddBuiltin(BuiltinOperator_STRIDED_SLICE,
493                       tflite::ops::micro::Register_STRIDED_SLICE(),
494                       ParseStridedSlice);
495   }
496 
AddSub()497   TfLiteStatus AddSub() {
498     return AddBuiltin(BuiltinOperator_SUB, tflite::ops::micro::Register_SUB(),
499                       ParseSub);
500   }
501 
AddSvdf()502   TfLiteStatus AddSvdf() {
503     return AddBuiltin(BuiltinOperator_SVDF, Register_SVDF(), ParseSvdf);
504   }
505 
AddTanh()506   TfLiteStatus AddTanh() {
507     return AddBuiltin(BuiltinOperator_TANH, tflite::ops::micro::Register_TANH(),
508                       ParseTanh);
509   }
510 
AddTransposeConv()511   TfLiteStatus AddTransposeConv() {
512     return AddBuiltin(BuiltinOperator_TRANSPOSE_CONV,
513                       tflite::Register_TRANSPOSE_CONV(), ParseTransposeConv);
514   }
515 
AddTranspose()516   TfLiteStatus AddTranspose() {
517     return AddBuiltin(BuiltinOperator_TRANSPOSE, Register_TRANSPOSE(),
518                       ParseTranspose);
519   }
520 
AddUnpack()521   TfLiteStatus AddUnpack() {
522     return AddBuiltin(BuiltinOperator_UNPACK,
523                       tflite::ops::micro::Register_UNPACK(), ParseUnpack);
524   }
525 
AddZerosLike()526   TfLiteStatus AddZerosLike() {
527     return AddBuiltin(BuiltinOperator_ZEROS_LIKE, Register_ZEROS_LIKE(),
528                       ParseZerosLike);
529   }
530 
GetRegistrationLength()531   unsigned int GetRegistrationLength() { return registrations_len_; }
532 
533  private:
AddBuiltin(tflite::BuiltinOperator op,const TfLiteRegistration & registration,MicroOpResolver::BuiltinParseFunction parser)534   TfLiteStatus AddBuiltin(tflite::BuiltinOperator op,
535                           const TfLiteRegistration& registration,
536                           MicroOpResolver::BuiltinParseFunction parser) {
537     if (op == BuiltinOperator_CUSTOM) {
538       if (error_reporter_ != nullptr) {
539         TF_LITE_REPORT_ERROR(error_reporter_,
540                              "Invalid parameter BuiltinOperator_CUSTOM to the "
541                              "AddBuiltin function.");
542       }
543       return kTfLiteError;
544     }
545 
546     if (FindOp(op) != nullptr) {
547       if (error_reporter_ != nullptr) {
548         TF_LITE_REPORT_ERROR(error_reporter_,
549                              "Calling AddBuiltin with the same op more than "
550                              "once is not supported (Op: #%d).",
551                              op);
552       }
553       return kTfLiteError;
554     }
555 
556     if (registrations_len_ >= tOpCount) {
557       if (error_reporter_) {
558         TF_LITE_REPORT_ERROR(error_reporter_,
559                              "Couldn't register builtin op #%d, resolver size "
560                              "is too small (%d).",
561                              op, tOpCount);
562       }
563       return kTfLiteError;
564     }
565 
566     registrations_[registrations_len_] = registration;
567     // Strictly speaking, the builtin_code is not necessary for TFLM but filling
568     // it in regardless.
569     registrations_[registrations_len_].builtin_code = op;
570     registrations_len_++;
571 
572     builtin_codes_[num_buitin_ops_] = op;
573     builtin_parsers_[num_buitin_ops_] = parser;
574     num_buitin_ops_++;
575 
576     return kTfLiteOk;
577   }
578 
579   TfLiteRegistration registrations_[tOpCount];
580   unsigned int registrations_len_ = 0;
581 
582   // Arrays (and counter) to store the builtin codes and their corresponding
583   // parse functions as these are registered with the Op Resolver.
584   BuiltinOperator builtin_codes_[tOpCount];
585   MicroOpResolver::BuiltinParseFunction builtin_parsers_[tOpCount];
586   unsigned int num_buitin_ops_ = 0;
587 
588   ErrorReporter* error_reporter_;
589 };
590 
591 };  // namespace tflite
592 
593 #endif  // TENSORFLOW_LITE_MICRO_MICRO_MUTABLE_OP_RESOLVER_H_
594