blob: 2c3be7f6479270178390099ac215e16647b1655d [file] [log] [blame]
Eric Kunzee5e26762020-10-13 16:11:07 -07001
Tai Ly8690a082023-12-18 20:40:24 +00002// Copyright (c) 2020-2024, ARM Limited.
Eric Kunzee5e26762020-10-13 16:11:07 -07003//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16#ifndef TOSA_REFERENCE_TENSOR_H
17#define TOSA_REFERENCE_TENSOR_H
18
Grant Watson64285a12022-11-16 15:32:39 +000019#include "array_proxy.h"
Tai Lya4d748b2023-03-28 22:06:56 +000020#include "dtype.h"
Eric Kunzee5e26762020-10-13 16:11:07 -070021#include "model_common.h"
22#include "ops/template_types.h"
Eric Kunzee5e26762020-10-13 16:11:07 -070023#include "tosa_serialization_handler.h"
24#include <Eigen/CXX11/Tensor>
25#include <list>
26#include <vector>
27
28using namespace tosa;
29
30namespace TosaReference
31{
32class GraphNode;
33
34class Tensor
35{
36public:
Tai Lya4d748b2023-03-28 22:06:56 +000037 Tensor(const std::string tensorName_, const DType serializationDtype_, const std::vector<int> shape_);
Eric Kunzee5e26762020-10-13 16:11:07 -070038
39 virtual ~Tensor();
40
41 int setIsSubgraphInput();
42 int setIsSubgraphOutput();
Jerry Ge9e94af82022-10-27 09:57:00 -070043 int setIsParentGraphOutput();
44
Tai Lycf84bc92023-09-07 20:49:09 +000045 bool getIsParentGraphOutput() const
Jerry Ge9c9c8da2023-07-19 23:08:16 +000046 {
Jerry Ge9e94af82022-10-27 09:57:00 -070047 return isParentGraphOutput;
48 }
Tai Lycf84bc92023-09-07 20:49:09 +000049 int setIsVariable();
Eric Kunzee5e26762020-10-13 16:11:07 -070050
Tai Lycf84bc92023-09-07 20:49:09 +000051 bool getIsSubgraphInput() const
Eric Kunzee5e26762020-10-13 16:11:07 -070052 {
53 return isSubgraphInput;
54 }
55
Tai Lycf84bc92023-09-07 20:49:09 +000056 bool getIsSubgraphOutput() const
Eric Kunzee5e26762020-10-13 16:11:07 -070057 {
58 return isSubgraphOutput;
59 }
60
Tai Lycf84bc92023-09-07 20:49:09 +000061 bool getIsVariable() const
62 {
63 return isVariable;
64 }
65
Eric Kunzee5e26762020-10-13 16:11:07 -070066 int setProducer(GraphNode* node);
67 int addConsumer(GraphNode* node);
68
69 int setIsValid()
70 {
71 isValid = 1;
72 return 0;
73 }
74
75 int clearIsValid()
76 {
77 isValid = 0;
78 return 0;
79 }
80
81 int getIsValid() const
82 {
83 return isValid;
84 }
85
Eric Kunzee5e26762020-10-13 16:11:07 -070086 GraphNode* getProducer()
87 {
88 return producer;
89 }
90
91 std::vector<GraphNode*>& getConsumers()
92 {
93 return consumers;
94 }
95
96 const std::string& getName() const
97 {
98 return tensorName;
99 }
100
101 const std::vector<int>& getShape() const
102 {
103 return shape;
104 }
105
Jerry Ge264f7fa2023-04-21 22:49:57 +0000106 void setDimSize(size_t dim, uint32_t new_size)
107 {
108 this->shape[dim] = new_size;
109 return;
110 }
111
Eric Kunzee5e26762020-10-13 16:11:07 -0700112 std::string getShapeAsString() const
113 {
114 std::string shape_str("[");
115 for (auto& dim : shape)
116 {
117 shape_str += (std::to_string(dim) + ", ");
118 }
119 shape_str.append("]");
120 return shape_str;
121 }
122
Eric Kunzee5e26762020-10-13 16:11:07 -0700123 const uint32_t getElementCount() const
124 {
125 uint32_t elements = 1;
126 for (size_t i = 0; i < shape.size(); i++)
127 elements *= shape[i];
128
129 return elements;
130 }
131
132 // Comparison of rank and type with other tensors
133 const int matchRank(const Tensor& ref) const
134 {
135 return (ref.shape.size() == shape.size()) ? 0 : 1;
136 }
137
138 const int matchType(const Tensor& ref) const
139 {
140 return (ref.tensorDtype == tensorDtype) ? 0 : 1;
141 }
142
143 const int matchRankType(const Tensor& ref) const
144 {
145 return (matchType(ref) || matchRank(ref));
146 }
147
148 const int matchRankTypeShape(const Tensor& ref, const bool broadcastOk = false) const
149 {
150 if (matchRankType(ref))
151 return 1;
152
153 for (size_t i = 0; i < shape.size(); i++)
154 {
155 if (shape[i] != ref.shape[i])
156 {
157 if (!broadcastOk ||
Kevin Cheng2131a4d2021-11-11 19:35:30 +0000158 // For broadcasts, the order of *this and ref matters.
159 // *this should be the source tensor.
160 // ref should be the target tensor. In most of the case, ref is expected to be the output tensor.
161 // this->shape must have size 1 if they don't match
162 (broadcastOk && (shape[i] != 1)))
Eric Kunzee5e26762020-10-13 16:11:07 -0700163 {
164 return 1;
165 }
166 }
167 }
168
169 return 0;
170 }
171
Kevin Cheng1c3c8472021-11-08 11:19:10 -0800172 const int matchRankShape(const Tensor& ref, const bool broadcastOk = false) const
173 {
174 if (matchRank(ref))
175 return 1;
176
177 for (size_t i = 0; i < shape.size(); i++)
178 {
179 if (shape[i] != ref.shape[i])
180 {
181 if (!broadcastOk ||
Kevin Cheng2131a4d2021-11-11 19:35:30 +0000182 // For broadcasts, the order of *this and ref matters.
183 // *this should be the source tensor.
184 // ref should be the target tensor. In most of the case, ref is expected to be the output tensor.
185 // this->shape must have size 1 if they don't match
186 (broadcastOk && (shape[i] != 1)))
Kevin Cheng1c3c8472021-11-08 11:19:10 -0800187 {
188 return 1;
189 }
190 }
191 }
192
193 return 0;
194 }
195
Eric Kunzee5e26762020-10-13 16:11:07 -0700196 // Sometimes we might want to match several semi-compatible types,
197 // so just check rank and size here
198 const int matchRankSize(const Tensor& ref) const
199 {
200 if (matchRank(ref))
201 return 1;
202
203 for (size_t i = 0; i < shape.size(); i++)
204 {
205 if (shape[i] != ref.shape[i])
206 return 1;
207 }
208
209 return 0;
210 }
211
212 // Unary check to make sure rank matches
Jerry Ge0bd4ec82023-05-01 18:36:43 +0000213 const int checkRequiredRank(const int minRank) const
Eric Kunzee5e26762020-10-13 16:11:07 -0700214 {
Jerry Ge0bd4ec82023-05-01 18:36:43 +0000215 return (shape.size() >= (size_t)minRank) ? 0 : 1;
Eric Kunzee5e26762020-10-13 16:11:07 -0700216 }
217
218 const int checkRequiredRank(const int minRank, const int maxRank) const
219 {
220 return (shape.size() >= (size_t)minRank && shape.size() <= (size_t)maxRank) ? 0 : 1;
221 }
222
223 const int getRank() const
224 {
225 return shape.size();
226 }
227
Tai Lya4d748b2023-03-28 22:06:56 +0000228 const TOSA_REF_TYPE getDtype() const
Eric Kunzee5e26762020-10-13 16:11:07 -0700229 {
230 return tensorDtype;
231 }
232
Tai Lya4d748b2023-03-28 22:06:56 +0000233 const DType getSerializationDtype() const
234 {
235 return serializationDtype;
236 }
237
Eric Kunzee5e26762020-10-13 16:11:07 -0700238 virtual int dumpTensor(FILE* out) const = 0;
239 virtual int dumpTensorParams(FILE* out) const;
240 virtual int dumpTensorParams(std::ostream& out) const;
241
Tai Lya4d748b2023-03-28 22:06:56 +0000242 virtual int setTensorValueDouble(const size_t bufLen, const double* vals) = 0;
Eric Kunzee5e26762020-10-13 16:11:07 -0700243 virtual int setTensorValueFloat(const size_t bufLen, const float* vals) = 0;
Jerry Gec5291692024-01-02 22:29:08 +0000244 virtual int setTensorValueUInt8(const size_t bufLen, const uint8_t* vals) = 0;
245 virtual int setTensorValueInt8(const size_t bufLen, const int8_t* vals) = 0;
Georgios Pinitase9059772023-12-06 18:52:30 +0000246 virtual int setTensorValueInt16(const size_t bufLen, const int16_t* vals) = 0;
Eric Kunzee5e26762020-10-13 16:11:07 -0700247 virtual int setTensorValueInt32(const size_t bufLen, const int32_t* vals) = 0;
248 virtual int setTensorValueInt64(const size_t bufLen, const int64_t* vals) = 0;
249 virtual int setTensorValueBool(const size_t bufLen, const bool* vals) = 0;
Tai Lya4d748b2023-03-28 22:06:56 +0000250 virtual int getTensorValueDouble(const size_t bufLen, double* fbuf) const = 0;
Eric Kunzee5e26762020-10-13 16:11:07 -0700251 virtual int getTensorValueFloat(const size_t bufLen, float* fbuf) const = 0;
Jerry Gec5291692024-01-02 22:29:08 +0000252 virtual int getTensorValueUInt8(const size_t bufLen, uint8_t* ibuf) const = 0;
253 virtual int getTensorValueInt8(const size_t bufLen, int8_t* ibuf) const = 0;
Georgios Pinitase9059772023-12-06 18:52:30 +0000254 virtual int getTensorValueInt16(const size_t bufLen, int16_t* ibuf) const = 0;
Eric Kunzee5e26762020-10-13 16:11:07 -0700255 virtual int getTensorValueInt32(const size_t bufLen, int32_t* ibuf) const = 0;
256 virtual int getTensorValueInt64(const size_t bufLen, int64_t* ibuf) const = 0;
257 virtual int getTensorValueBool(const size_t bufLen, bool* ibuf) const = 0;
258
259 virtual int readFromNpyFile(const char* filename);
260 virtual int writeToNpyFile(const char* filename) const;
261 virtual int copyValueFrom(Tensor* tensor) = 0;
262
Tai Lya4d748b2023-03-28 22:06:56 +0000263 virtual int readfromVector(const ArrayProxy<double> vals);
Grant Watson64285a12022-11-16 15:32:39 +0000264 virtual int readfromVector(const ArrayProxy<float> vals);
265 virtual int readfromVector(const ArrayProxy<half_float::half> vals);
Jerry Gec5291692024-01-02 22:29:08 +0000266 virtual int readfromVector(const ArrayProxy<int8_t> vals);
Georgios Pinitase9059772023-12-06 18:52:30 +0000267 virtual int readfromVector(const ArrayProxy<int16_t> vals);
Grant Watson64285a12022-11-16 15:32:39 +0000268 virtual int readfromVector(const ArrayProxy<int32_t> vals);
269 virtual int readfromVector(const ArrayProxy<int64_t> vals);
270 virtual int readfromVector(const ArrayProxy<unsigned char> vals);
Matthew Sloyanba5fad32022-09-26 13:31:43 +0100271
Tai Lya4d748b2023-03-28 22:06:56 +0000272 virtual int writeToVector(ArrayProxy<double> vals);
Grant Watson64285a12022-11-16 15:32:39 +0000273 virtual int writeToVector(ArrayProxy<float> vals);
274 virtual int writeToVector(ArrayProxy<half_float::half> vals);
Jerry Gec5291692024-01-02 22:29:08 +0000275 virtual int writeToVector(ArrayProxy<int8_t> vals);
Georgios Pinitase9059772023-12-06 18:52:30 +0000276 virtual int writeToVector(ArrayProxy<int16_t> vals);
Grant Watson64285a12022-11-16 15:32:39 +0000277 virtual int writeToVector(ArrayProxy<int32_t> vals);
278 virtual int writeToVector(ArrayProxy<int64_t> vals);
279 virtual int writeToVector(ArrayProxy<unsigned char> vals);
Matthew Sloyanba5fad32022-09-26 13:31:43 +0100280
Eric Kunzee5e26762020-10-13 16:11:07 -0700281 const char* bool_to_str(bool in) const
282 {
283 static const char* true_str = "true";
284 static const char* false_str = "false";
285 return in ? true_str : false_str;
286 }
287
Tai Lycf84bc92023-09-07 20:49:09 +0000288 virtual int allocate() = 0;
289 virtual int deallocate() = 0;
290 virtual bool is_allocated() const = 0;
Eric Kunzee5e26762020-10-13 16:11:07 -0700291
292protected:
Tai Lya4d748b2023-03-28 22:06:56 +0000293 const std::string tensorName;
294 const DType serializationDtype;
Jerry Ge264f7fa2023-04-21 22:49:57 +0000295 std::vector<int> shape;
Tai Lya4d748b2023-03-28 22:06:56 +0000296 const TOSA_REF_TYPE tensorDtype;
Tai Lycf84bc92023-09-07 20:49:09 +0000297 bool isValid;
298 bool isSubgraphInput;
299 bool isSubgraphOutput;
300 bool isVariable;
Eric Kunzee5e26762020-10-13 16:11:07 -0700301 bool isAllocated;
302
Jerry Ge9e94af82022-10-27 09:57:00 -0700303 bool isParentGraphOutput;
304
Eric Kunzee5e26762020-10-13 16:11:07 -0700305 GraphNode* producer;
306 std::vector<GraphNode*> consumers;
307
308 // Note: the Eigen::Tensor is not declared in Tensor
309 // Instead, the TensorTemplate class keeps the templated tensor
310 // declaration so that the graph manipulation tools are isolated
311 // from the templated tensor type.
312 //
313 // Operators need to be aware of the TensorTemplate<EigenTensor<type, rank>> type
314 // so that they can operate on the right types.
315};
316
317template <class T>
318class TensorTemplate : public Tensor
319{
320public:
Tai Lya4d748b2023-03-28 22:06:56 +0000321 TensorTemplate(const std::string tensorName_, const DType dtype_, const std::vector<int> shape_)
322 : Tensor(tensorName_, dtype_, shape_)
Eric Kunzee5e26762020-10-13 16:11:07 -0700323 {
324 tensor = nullptr;
325 }
326
327 virtual ~TensorTemplate()
328 {
329 deallocate();
330 }
331
332 virtual int allocate()
333 {
334 tensor = new T();
335 if (tensor)
336 return 0;
337 else
338 return 1;
339 }
340
341 virtual int deallocate()
342 {
343 if (tensor)
344 {
Eric Kunze9a367552023-07-11 13:27:36 -0700345 DEBUG_INFO(GT, "Deallocating tensor %s", tensorName.c_str());
Eric Kunzee5e26762020-10-13 16:11:07 -0700346 delete tensor;
347 }
348 tensor = nullptr;
349 return 0;
350 }
351
Tai Lycf84bc92023-09-07 20:49:09 +0000352 virtual bool is_allocated() const
Eric Kunzee5e26762020-10-13 16:11:07 -0700353 {
354 if (tensor)
355 {
356 return true;
357 }
358 return false;
359 }
360
361 T& getTensor()
362 {
363 return *tensor;
364 }
365
366 virtual int dumpTensor(FILE* out) const;
367
Tai Lya4d748b2023-03-28 22:06:56 +0000368 virtual int setTensorValueDouble(const size_t bufLen, const double* vals);
Eric Kunzee5e26762020-10-13 16:11:07 -0700369 virtual int setTensorValueFloat(const size_t bufLen, const float* vals);
Jerry Gec5291692024-01-02 22:29:08 +0000370 virtual int setTensorValueUInt8(const size_t bufLen, const uint8_t* vals);
371 virtual int setTensorValueInt8(const size_t bufLen, const int8_t* vals);
Georgios Pinitase9059772023-12-06 18:52:30 +0000372 virtual int setTensorValueInt16(const size_t bufLen, const int16_t* vals);
Eric Kunzee5e26762020-10-13 16:11:07 -0700373 virtual int setTensorValueInt32(const size_t bufLen, const int32_t* vals);
374 virtual int setTensorValueInt64(const size_t bufLen, const int64_t* vals);
375 virtual int setTensorValueBool(const size_t bufLen, const bool* vals);
Tai Lya4d748b2023-03-28 22:06:56 +0000376
377 virtual int getTensorValueDouble(const size_t bufLen, double* fbuf) const;
Eric Kunzee5e26762020-10-13 16:11:07 -0700378 virtual int getTensorValueFloat(const size_t bufLen, float* fbuf) const;
Jerry Gec5291692024-01-02 22:29:08 +0000379 virtual int getTensorValueUInt8(const size_t bufLen, uint8_t* ibuf) const;
380 virtual int getTensorValueInt8(const size_t bufLen, int8_t* ibuf) const;
Georgios Pinitase9059772023-12-06 18:52:30 +0000381 virtual int getTensorValueInt16(const size_t bufLen, int16_t* ibuf) const;
Eric Kunzee5e26762020-10-13 16:11:07 -0700382 virtual int getTensorValueInt32(const size_t bufLen, int32_t* ibuf) const;
383 virtual int getTensorValueInt64(const size_t bufLen, int64_t* ibuf) const;
384 virtual int getTensorValueBool(const size_t bufLen, bool* bbuf) const;
385
386 virtual int copyValueFrom(Tensor* tensor);
387
388protected:
389 T* tensor;
390};
391
392// allocate() template specializations to allocate the different tensor sizes
393// Let the compiler know here before the factory uses them, but define them in the .cc file.
394template <>
395int Tensor0<float>::allocate();
396template <>
397int Tensor1<float>::allocate();
398template <>
399int Tensor2<float>::allocate();
400template <>
401int Tensor3<float>::allocate();
402template <>
403int Tensor4<float>::allocate();
404template <>
405int Tensor5<float>::allocate();
406template <>
407int Tensor6<float>::allocate();
408
409template <>
Tai Lya4d748b2023-03-28 22:06:56 +0000410int Tensor0<double>::allocate();
411template <>
412int Tensor1<double>::allocate();
413template <>
414int Tensor2<double>::allocate();
415template <>
416int Tensor3<double>::allocate();
417template <>
418int Tensor4<double>::allocate();
419template <>
420int Tensor5<double>::allocate();
421template <>
422int Tensor6<double>::allocate();
423
424template <>
Eric Kunzee5e26762020-10-13 16:11:07 -0700425int Tensor0<int32_t>::allocate();
426template <>
427int Tensor1<int32_t>::allocate();
428template <>
429int Tensor2<int32_t>::allocate();
430template <>
431int Tensor3<int32_t>::allocate();
432template <>
433int Tensor4<int32_t>::allocate();
434template <>
435int Tensor5<int32_t>::allocate();
436template <>
437int Tensor6<int32_t>::allocate();
438
439template <>
440int Tensor0<int64_t>::allocate();
441template <>
442int Tensor1<int64_t>::allocate();
443template <>
444int Tensor2<int64_t>::allocate();
445template <>
446int Tensor3<int64_t>::allocate();
447template <>
448int Tensor4<int64_t>::allocate();
449template <>
450int Tensor5<int64_t>::allocate();
451template <>
452int Tensor6<int64_t>::allocate();
453
454template <>
455int Tensor0<bool>::allocate();
456template <>
457int Tensor1<bool>::allocate();
458template <>
459int Tensor2<bool>::allocate();
460template <>
461int Tensor3<bool>::allocate();
462template <>
463int Tensor4<bool>::allocate();
464template <>
465int Tensor5<bool>::allocate();
466template <>
467int Tensor6<bool>::allocate();
468
469template <>
470int Tensor0<float>::copyValueFrom(Tensor* src);
471template <>
472int Tensor1<float>::copyValueFrom(Tensor* src);
473template <>
474int Tensor2<float>::copyValueFrom(Tensor* src);
475template <>
476int Tensor3<float>::copyValueFrom(Tensor* src);
477template <>
478int Tensor4<float>::copyValueFrom(Tensor* src);
479template <>
480int Tensor5<float>::copyValueFrom(Tensor* src);
481template <>
482int Tensor6<float>::copyValueFrom(Tensor* src);
483
484template <>
Tai Lya4d748b2023-03-28 22:06:56 +0000485int Tensor0<double>::copyValueFrom(Tensor* src);
486template <>
487int Tensor1<double>::copyValueFrom(Tensor* src);
488template <>
489int Tensor2<double>::copyValueFrom(Tensor* src);
490template <>
491int Tensor3<double>::copyValueFrom(Tensor* src);
492template <>
493int Tensor4<double>::copyValueFrom(Tensor* src);
494template <>
495int Tensor5<double>::copyValueFrom(Tensor* src);
496template <>
497int Tensor6<double>::copyValueFrom(Tensor* src);
498
499template <>
Eric Kunzee5e26762020-10-13 16:11:07 -0700500int Tensor0<int32_t>::copyValueFrom(Tensor* src);
501template <>
502int Tensor1<int32_t>::copyValueFrom(Tensor* src);
503template <>
504int Tensor2<int32_t>::copyValueFrom(Tensor* src);
505template <>
506int Tensor3<int32_t>::copyValueFrom(Tensor* src);
507template <>
508int Tensor4<int32_t>::copyValueFrom(Tensor* src);
509template <>
510int Tensor5<int32_t>::copyValueFrom(Tensor* src);
511template <>
512int Tensor6<int32_t>::copyValueFrom(Tensor* src);
513
514template <>
515int Tensor0<int64_t>::copyValueFrom(Tensor* src);
516template <>
517int Tensor1<int64_t>::copyValueFrom(Tensor* src);
518template <>
519int Tensor2<int64_t>::copyValueFrom(Tensor* src);
520template <>
521int Tensor3<int64_t>::copyValueFrom(Tensor* src);
522template <>
523int Tensor4<int64_t>::copyValueFrom(Tensor* src);
524template <>
525int Tensor5<int64_t>::copyValueFrom(Tensor* src);
526template <>
527int Tensor6<int64_t>::copyValueFrom(Tensor* src);
528
529template <>
530int Tensor0<bool>::copyValueFrom(Tensor* src);
531template <>
532int Tensor1<bool>::copyValueFrom(Tensor* src);
533template <>
534int Tensor2<bool>::copyValueFrom(Tensor* src);
535template <>
536int Tensor3<bool>::copyValueFrom(Tensor* src);
537template <>
538int Tensor4<bool>::copyValueFrom(Tensor* src);
539template <>
540int Tensor5<bool>::copyValueFrom(Tensor* src);
541template <>
542int Tensor6<bool>::copyValueFrom(Tensor* src);
543
544template <>
Jerry Gec5291692024-01-02 22:29:08 +0000545int Tensor0<int32_t>::setTensorValueUInt8(const size_t bufLen, const uint8_t* vals);
546template <>
547int Tensor1<int32_t>::setTensorValueUInt8(const size_t bufLen, const uint8_t* vals);
548template <>
549int Tensor2<int32_t>::setTensorValueUInt8(const size_t bufLen, const uint8_t* vals);
550template <>
551int Tensor3<int32_t>::setTensorValueUInt8(const size_t bufLen, const uint8_t* vals);
552template <>
553int Tensor4<int32_t>::setTensorValueUInt8(const size_t bufLen, const uint8_t* vals);
554template <>
555int Tensor5<int32_t>::setTensorValueUInt8(const size_t bufLen, const uint8_t* vals);
556template <>
557int Tensor6<int32_t>::setTensorValueUInt8(const size_t bufLen, const uint8_t* vals);
558
559template <>
560int Tensor0<int32_t>::setTensorValueInt8(const size_t bufLen, const int8_t* vals);
561template <>
562int Tensor1<int32_t>::setTensorValueInt8(const size_t bufLen, const int8_t* vals);
563template <>
564int Tensor2<int32_t>::setTensorValueInt8(const size_t bufLen, const int8_t* vals);
565template <>
566int Tensor3<int32_t>::setTensorValueInt8(const size_t bufLen, const int8_t* vals);
567template <>
568int Tensor4<int32_t>::setTensorValueInt8(const size_t bufLen, const int8_t* vals);
569template <>
570int Tensor5<int32_t>::setTensorValueInt8(const size_t bufLen, const int8_t* vals);
571template <>
572int Tensor6<int32_t>::setTensorValueInt8(const size_t bufLen, const int8_t* vals);
573
574template <>
Georgios Pinitase9059772023-12-06 18:52:30 +0000575int Tensor0<int32_t>::setTensorValueInt16(const size_t bufLen, const int16_t* vals);
576template <>
577int Tensor1<int32_t>::setTensorValueInt16(const size_t bufLen, const int16_t* vals);
578template <>
579int Tensor2<int32_t>::setTensorValueInt16(const size_t bufLen, const int16_t* vals);
580template <>
581int Tensor3<int32_t>::setTensorValueInt16(const size_t bufLen, const int16_t* vals);
582template <>
583int Tensor4<int32_t>::setTensorValueInt16(const size_t bufLen, const int16_t* vals);
584template <>
585int Tensor5<int32_t>::setTensorValueInt16(const size_t bufLen, const int16_t* vals);
586template <>
587int Tensor6<int32_t>::setTensorValueInt16(const size_t bufLen, const int16_t* vals);
588
589template <>
Eric Kunzee5e26762020-10-13 16:11:07 -0700590int Tensor0<int32_t>::setTensorValueInt32(const size_t bufLen, const int32_t* vals);
591template <>
592int Tensor1<int32_t>::setTensorValueInt32(const size_t bufLen, const int32_t* vals);
593template <>
594int Tensor2<int32_t>::setTensorValueInt32(const size_t bufLen, const int32_t* vals);
595template <>
596int Tensor3<int32_t>::setTensorValueInt32(const size_t bufLen, const int32_t* vals);
597template <>
598int Tensor4<int32_t>::setTensorValueInt32(const size_t bufLen, const int32_t* vals);
599template <>
600int Tensor5<int32_t>::setTensorValueInt32(const size_t bufLen, const int32_t* vals);
601template <>
602int Tensor6<int32_t>::setTensorValueInt32(const size_t bufLen, const int32_t* vals);
603
604template <>
Jerry Gec5291692024-01-02 22:29:08 +0000605int Tensor0<int32_t>::getTensorValueUInt8(const size_t bufLen, uint8_t* vals) const;
606template <>
607int Tensor1<int32_t>::getTensorValueUInt8(const size_t bufLen, uint8_t* vals) const;
608template <>
609int Tensor2<int32_t>::getTensorValueUInt8(const size_t bufLen, uint8_t* vals) const;
610template <>
611int Tensor3<int32_t>::getTensorValueUInt8(const size_t bufLen, uint8_t* vals) const;
612template <>
613int Tensor4<int32_t>::getTensorValueUInt8(const size_t bufLen, uint8_t* vals) const;
614template <>
615int Tensor5<int32_t>::getTensorValueUInt8(const size_t bufLen, uint8_t* vals) const;
616template <>
617int Tensor6<int32_t>::getTensorValueUInt8(const size_t bufLen, uint8_t* vals) const;
618
619template <>
620int Tensor0<int32_t>::getTensorValueInt8(const size_t bufLen, int8_t* vals) const;
621template <>
622int Tensor1<int32_t>::getTensorValueInt8(const size_t bufLen, int8_t* vals) const;
623template <>
624int Tensor2<int32_t>::getTensorValueInt8(const size_t bufLen, int8_t* vals) const;
625template <>
626int Tensor3<int32_t>::getTensorValueInt8(const size_t bufLen, int8_t* vals) const;
627template <>
628int Tensor4<int32_t>::getTensorValueInt8(const size_t bufLen, int8_t* vals) const;
629template <>
630int Tensor5<int32_t>::getTensorValueInt8(const size_t bufLen, int8_t* vals) const;
631template <>
632int Tensor6<int32_t>::getTensorValueInt8(const size_t bufLen, int8_t* vals) const;
633
634template <>
Georgios Pinitase9059772023-12-06 18:52:30 +0000635int Tensor0<int32_t>::getTensorValueInt16(const size_t bufLen, int16_t* vals) const;
636template <>
637int Tensor1<int32_t>::getTensorValueInt16(const size_t bufLen, int16_t* vals) const;
638template <>
639int Tensor2<int32_t>::getTensorValueInt16(const size_t bufLen, int16_t* vals) const;
640template <>
641int Tensor3<int32_t>::getTensorValueInt16(const size_t bufLen, int16_t* vals) const;
642template <>
643int Tensor4<int32_t>::getTensorValueInt16(const size_t bufLen, int16_t* vals) const;
644template <>
645int Tensor5<int32_t>::getTensorValueInt16(const size_t bufLen, int16_t* vals) const;
646template <>
647int Tensor6<int32_t>::getTensorValueInt16(const size_t bufLen, int16_t* vals) const;
648
649template <>
Eric Kunzee5e26762020-10-13 16:11:07 -0700650int Tensor0<int32_t>::getTensorValueInt32(const size_t bufLen, int32_t* vals) const;
651template <>
652int Tensor1<int32_t>::getTensorValueInt32(const size_t bufLen, int32_t* vals) const;
653template <>
654int Tensor2<int32_t>::getTensorValueInt32(const size_t bufLen, int32_t* vals) const;
655template <>
656int Tensor3<int32_t>::getTensorValueInt32(const size_t bufLen, int32_t* vals) const;
657template <>
658int Tensor4<int32_t>::getTensorValueInt32(const size_t bufLen, int32_t* vals) const;
659template <>
660int Tensor5<int32_t>::getTensorValueInt32(const size_t bufLen, int32_t* vals) const;
661template <>
662int Tensor6<int32_t>::getTensorValueInt32(const size_t bufLen, int32_t* vals) const;
663
664template <>
665int Tensor0<int64_t>::setTensorValueInt64(const size_t bufLen, const int64_t* vals);
666template <>
667int Tensor1<int64_t>::setTensorValueInt64(const size_t bufLen, const int64_t* vals);
668template <>
669int Tensor2<int64_t>::setTensorValueInt64(const size_t bufLen, const int64_t* vals);
670template <>
671int Tensor3<int64_t>::setTensorValueInt64(const size_t bufLen, const int64_t* vals);
672template <>
673int Tensor4<int64_t>::setTensorValueInt64(const size_t bufLen, const int64_t* vals);
674template <>
675int Tensor5<int64_t>::setTensorValueInt64(const size_t bufLen, const int64_t* vals);
676template <>
677int Tensor6<int64_t>::setTensorValueInt64(const size_t bufLen, const int64_t* vals);
678
679template <>
680int Tensor0<int64_t>::getTensorValueInt64(const size_t bufLen, int64_t* vals) const;
681template <>
682int Tensor1<int64_t>::getTensorValueInt64(const size_t bufLen, int64_t* vals) const;
683template <>
684int Tensor2<int64_t>::getTensorValueInt64(const size_t bufLen, int64_t* vals) const;
685template <>
686int Tensor3<int64_t>::getTensorValueInt64(const size_t bufLen, int64_t* vals) const;
687template <>
688int Tensor4<int64_t>::getTensorValueInt64(const size_t bufLen, int64_t* vals) const;
689template <>
690int Tensor5<int64_t>::getTensorValueInt64(const size_t bufLen, int64_t* vals) const;
691template <>
692int Tensor6<int64_t>::getTensorValueInt64(const size_t bufLen, int64_t* vals) const;
693
694template <>
695int Tensor0<float>::setTensorValueFloat(const size_t bufLen, const float* vals);
696template <>
697int Tensor1<float>::setTensorValueFloat(const size_t bufLen, const float* vals);
698template <>
699int Tensor2<float>::setTensorValueFloat(const size_t bufLen, const float* vals);
700template <>
701int Tensor3<float>::setTensorValueFloat(const size_t bufLen, const float* vals);
702template <>
703int Tensor4<float>::setTensorValueFloat(const size_t bufLen, const float* vals);
704template <>
705int Tensor5<float>::setTensorValueFloat(const size_t bufLen, const float* vals);
706template <>
707int Tensor6<float>::setTensorValueFloat(const size_t bufLen, const float* vals);
708
709template <>
710int Tensor0<float>::getTensorValueFloat(const size_t bufLen, float* vals) const;
711template <>
712int Tensor1<float>::getTensorValueFloat(const size_t bufLen, float* vals) const;
713template <>
714int Tensor2<float>::getTensorValueFloat(const size_t bufLen, float* vals) const;
715template <>
716int Tensor3<float>::getTensorValueFloat(const size_t bufLen, float* vals) const;
717template <>
718int Tensor4<float>::getTensorValueFloat(const size_t bufLen, float* vals) const;
719template <>
720int Tensor5<float>::getTensorValueFloat(const size_t bufLen, float* vals) const;
721template <>
722int Tensor6<float>::getTensorValueFloat(const size_t bufLen, float* vals) const;
723
724template <>
Tai Lya4d748b2023-03-28 22:06:56 +0000725int Tensor0<double>::setTensorValueDouble(const size_t bufLen, const double* vals);
726template <>
727int Tensor1<double>::setTensorValueDouble(const size_t bufLen, const double* vals);
728template <>
729int Tensor2<double>::setTensorValueDouble(const size_t bufLen, const double* vals);
730template <>
731int Tensor3<double>::setTensorValueDouble(const size_t bufLen, const double* vals);
732template <>
733int Tensor4<double>::setTensorValueDouble(const size_t bufLen, const double* vals);
734template <>
735int Tensor5<double>::setTensorValueDouble(const size_t bufLen, const double* vals);
736template <>
737int Tensor6<double>::setTensorValueDouble(const size_t bufLen, const double* vals);
738
739template <>
740int Tensor0<double>::getTensorValueDouble(const size_t bufLen, double* vals) const;
741template <>
742int Tensor1<double>::getTensorValueDouble(const size_t bufLen, double* vals) const;
743template <>
744int Tensor2<double>::getTensorValueDouble(const size_t bufLen, double* vals) const;
745template <>
746int Tensor3<double>::getTensorValueDouble(const size_t bufLen, double* vals) const;
747template <>
748int Tensor4<double>::getTensorValueDouble(const size_t bufLen, double* vals) const;
749template <>
750int Tensor5<double>::getTensorValueDouble(const size_t bufLen, double* vals) const;
751template <>
752int Tensor6<double>::getTensorValueDouble(const size_t bufLen, double* vals) const;
753
754template <>
Eric Kunzee5e26762020-10-13 16:11:07 -0700755int Tensor0<bool>::setTensorValueBool(const size_t bufLen, const bool* vals);
756template <>
757int Tensor1<bool>::setTensorValueBool(const size_t bufLen, const bool* vals);
758template <>
759int Tensor2<bool>::setTensorValueBool(const size_t bufLen, const bool* vals);
760template <>
761int Tensor3<bool>::setTensorValueBool(const size_t bufLen, const bool* vals);
762template <>
763int Tensor4<bool>::setTensorValueBool(const size_t bufLen, const bool* vals);
764template <>
765int Tensor5<bool>::setTensorValueBool(const size_t bufLen, const bool* vals);
766template <>
767int Tensor6<bool>::setTensorValueBool(const size_t bufLen, const bool* vals);
768
769template <>
770int Tensor0<bool>::getTensorValueBool(const size_t bufLen, bool* vals) const;
771template <>
772int Tensor1<bool>::getTensorValueBool(const size_t bufLen, bool* vals) const;
773template <>
774int Tensor2<bool>::getTensorValueBool(const size_t bufLen, bool* vals) const;
775template <>
776int Tensor3<bool>::getTensorValueBool(const size_t bufLen, bool* vals) const;
777template <>
778int Tensor4<bool>::getTensorValueBool(const size_t bufLen, bool* vals) const;
779template <>
780int Tensor5<bool>::getTensorValueBool(const size_t bufLen, bool* vals) const;
781template <>
782int Tensor6<bool>::getTensorValueBool(const size_t bufLen, bool* vals) const;
783
Eric Kunzee5e26762020-10-13 16:11:07 -0700784template <>
785int Tensor0<float>::dumpTensor(FILE* out) const;
786template <>
787int Tensor1<float>::dumpTensor(FILE* out) const;
788template <>
789int Tensor2<float>::dumpTensor(FILE* out) const;
790template <>
791int Tensor3<float>::dumpTensor(FILE* out) const;
792template <>
793int Tensor4<float>::dumpTensor(FILE* out) const;
794template <>
795int Tensor5<float>::dumpTensor(FILE* out) const;
796template <>
797int Tensor6<float>::dumpTensor(FILE* out) const;
798template <>
Tai Lya4d748b2023-03-28 22:06:56 +0000799int Tensor0<double>::dumpTensor(FILE* out) const;
800template <>
801int Tensor1<double>::dumpTensor(FILE* out) const;
802template <>
803int Tensor2<double>::dumpTensor(FILE* out) const;
804template <>
805int Tensor3<double>::dumpTensor(FILE* out) const;
806template <>
807int Tensor4<double>::dumpTensor(FILE* out) const;
808template <>
809int Tensor5<float>::dumpTensor(FILE* out) const;
810template <>
811int Tensor6<double>::dumpTensor(FILE* out) const;
812template <>
Eric Kunzee5e26762020-10-13 16:11:07 -0700813int Tensor0<int32_t>::dumpTensor(FILE* out) const;
814template <>
815int Tensor1<int32_t>::dumpTensor(FILE* out) const;
816template <>
817int Tensor2<int32_t>::dumpTensor(FILE* out) const;
818template <>
819int Tensor3<int32_t>::dumpTensor(FILE* out) const;
820template <>
821int Tensor4<int32_t>::dumpTensor(FILE* out) const;
822template <>
823int Tensor5<int32_t>::dumpTensor(FILE* out) const;
824template <>
825int Tensor6<int32_t>::dumpTensor(FILE* out) const;
826template <>
827int Tensor0<int64_t>::dumpTensor(FILE* out) const;
828template <>
829int Tensor1<int64_t>::dumpTensor(FILE* out) const;
830template <>
831int Tensor2<int64_t>::dumpTensor(FILE* out) const;
832template <>
833int Tensor3<int64_t>::dumpTensor(FILE* out) const;
834template <>
835int Tensor4<int64_t>::dumpTensor(FILE* out) const;
836template <>
837int Tensor5<int64_t>::dumpTensor(FILE* out) const;
838template <>
839int Tensor6<int64_t>::dumpTensor(FILE* out) const;
840template <>
841int Tensor0<bool>::dumpTensor(FILE* out) const;
842template <>
843int Tensor1<bool>::dumpTensor(FILE* out) const;
844template <>
845int Tensor2<bool>::dumpTensor(FILE* out) const;
846template <>
847int Tensor3<bool>::dumpTensor(FILE* out) const;
848template <>
849int Tensor4<bool>::dumpTensor(FILE* out) const;
850template <>
851int Tensor5<bool>::dumpTensor(FILE* out) const;
852template <>
853int Tensor6<bool>::dumpTensor(FILE* out) const;
854
855class TensorFactory
856{
857public:
Tai Lya4d748b2023-03-28 22:06:56 +0000858 static Tensor* newTensor(std::string tensorName_, DType dtype_, std::vector<int> shape_, const uint32_t rank)
Eric Kunzee5e26762020-10-13 16:11:07 -0700859 {
Tai Lya4d748b2023-03-28 22:06:56 +0000860 TOSA_REF_TYPE tensorDtype_ = ConvertDType(dtype_);
Eric Kunzee5e26762020-10-13 16:11:07 -0700861 switch (tensorDtype_)
862 {
Tai Lya4d748b2023-03-28 22:06:56 +0000863 case TOSA_REF_TYPE_FP32:
864 case TOSA_REF_TYPE_FP16:
865 case TOSA_REF_TYPE_BF16:
Eric Kunzee5e26762020-10-13 16:11:07 -0700866 switch (rank)
867 {
868 case 0:
Tai Lya4d748b2023-03-28 22:06:56 +0000869 return new Tensor0<float>(tensorName_, dtype_, shape_);
Eric Kunzee5e26762020-10-13 16:11:07 -0700870 case 1:
Tai Lya4d748b2023-03-28 22:06:56 +0000871 return new Tensor1<float>(tensorName_, dtype_, shape_);
Eric Kunzee5e26762020-10-13 16:11:07 -0700872 case 2:
Tai Lya4d748b2023-03-28 22:06:56 +0000873 return new Tensor2<float>(tensorName_, dtype_, shape_);
Eric Kunzee5e26762020-10-13 16:11:07 -0700874 case 3:
Tai Lya4d748b2023-03-28 22:06:56 +0000875 return new Tensor3<float>(tensorName_, dtype_, shape_);
Eric Kunzee5e26762020-10-13 16:11:07 -0700876 case 4:
Tai Lya4d748b2023-03-28 22:06:56 +0000877 return new Tensor4<float>(tensorName_, dtype_, shape_);
Eric Kunzee5e26762020-10-13 16:11:07 -0700878 case 5:
Tai Lya4d748b2023-03-28 22:06:56 +0000879 return new Tensor5<float>(tensorName_, dtype_, shape_);
Eric Kunzee5e26762020-10-13 16:11:07 -0700880 case 6:
Tai Lya4d748b2023-03-28 22:06:56 +0000881 return new Tensor6<float>(tensorName_, dtype_, shape_);
Eric Kunzee5e26762020-10-13 16:11:07 -0700882 }
Kevin Cheng989cb052021-04-28 16:29:44 -0700883 break;
Tai Lya4d748b2023-03-28 22:06:56 +0000884 case TOSA_REF_TYPE_INT32:
885 case TOSA_REF_TYPE_UINT8:
886 case TOSA_REF_TYPE_INT4:
887 case TOSA_REF_TYPE_INT8:
888 case TOSA_REF_TYPE_INT16:
889 case TOSA_REF_TYPE_UINT16:
Eric Kunzee5e26762020-10-13 16:11:07 -0700890 switch (rank)
891 {
892 case 0:
Tai Lya4d748b2023-03-28 22:06:56 +0000893 return new Tensor0<int32_t>(tensorName_, dtype_, shape_);
Eric Kunzee5e26762020-10-13 16:11:07 -0700894 case 1:
Tai Lya4d748b2023-03-28 22:06:56 +0000895 return new Tensor1<int32_t>(tensorName_, dtype_, shape_);
Eric Kunzee5e26762020-10-13 16:11:07 -0700896 case 2:
Tai Lya4d748b2023-03-28 22:06:56 +0000897 return new Tensor2<int32_t>(tensorName_, dtype_, shape_);
Eric Kunzee5e26762020-10-13 16:11:07 -0700898 case 3:
Tai Lya4d748b2023-03-28 22:06:56 +0000899 return new Tensor3<int32_t>(tensorName_, dtype_, shape_);
Eric Kunzee5e26762020-10-13 16:11:07 -0700900 case 4:
Tai Lya4d748b2023-03-28 22:06:56 +0000901 return new Tensor4<int32_t>(tensorName_, dtype_, shape_);
Eric Kunzee5e26762020-10-13 16:11:07 -0700902 case 5:
Tai Lya4d748b2023-03-28 22:06:56 +0000903 return new Tensor5<int32_t>(tensorName_, dtype_, shape_);
Eric Kunzee5e26762020-10-13 16:11:07 -0700904 case 6:
Tai Lya4d748b2023-03-28 22:06:56 +0000905 return new Tensor6<int32_t>(tensorName_, dtype_, shape_);
Eric Kunzee5e26762020-10-13 16:11:07 -0700906 }
Kevin Cheng989cb052021-04-28 16:29:44 -0700907 break;
Tai Lya4d748b2023-03-28 22:06:56 +0000908 case TOSA_REF_TYPE_INT48:
Eric Kunzee5e26762020-10-13 16:11:07 -0700909 switch (rank)
910 {
911 case 0:
Tai Lya4d748b2023-03-28 22:06:56 +0000912 return new Tensor0<int64_t>(tensorName_, dtype_, shape_);
Eric Kunzee5e26762020-10-13 16:11:07 -0700913 case 1:
Tai Lya4d748b2023-03-28 22:06:56 +0000914 return new Tensor1<int64_t>(tensorName_, dtype_, shape_);
Eric Kunzee5e26762020-10-13 16:11:07 -0700915 case 2:
Tai Lya4d748b2023-03-28 22:06:56 +0000916 return new Tensor2<int64_t>(tensorName_, dtype_, shape_);
Eric Kunzee5e26762020-10-13 16:11:07 -0700917 case 3:
Tai Lya4d748b2023-03-28 22:06:56 +0000918 return new Tensor3<int64_t>(tensorName_, dtype_, shape_);
Eric Kunzee5e26762020-10-13 16:11:07 -0700919 case 4:
Tai Lya4d748b2023-03-28 22:06:56 +0000920 return new Tensor4<int64_t>(tensorName_, dtype_, shape_);
Eric Kunzee5e26762020-10-13 16:11:07 -0700921 case 5:
Tai Lya4d748b2023-03-28 22:06:56 +0000922 return new Tensor5<int64_t>(tensorName_, dtype_, shape_);
Eric Kunzee5e26762020-10-13 16:11:07 -0700923 case 6:
Tai Lya4d748b2023-03-28 22:06:56 +0000924 return new Tensor6<int64_t>(tensorName_, dtype_, shape_);
Eric Kunzee5e26762020-10-13 16:11:07 -0700925 }
Kevin Cheng989cb052021-04-28 16:29:44 -0700926 break;
Won Jeona21b2e82023-08-10 10:33:01 +0000927 case TOSA_REF_TYPE_SHAPE:
Tai Ly8690a082023-12-18 20:40:24 +0000928 switch (rank)
929 {
930 case 0:
931 return new Tensor0<int64_t>(tensorName_, dtype_, shape_);
932 case 1:
933 return new Tensor1<int64_t>(tensorName_, dtype_, shape_);
934 default:
935 assert(0); // shape tensors must have rank of 0 or 1
936 }
937 break;
Tai Lya4d748b2023-03-28 22:06:56 +0000938 case TOSA_REF_TYPE_BOOL:
Eric Kunzee5e26762020-10-13 16:11:07 -0700939 switch (rank)
940 {
941 case 0:
Tai Lya4d748b2023-03-28 22:06:56 +0000942 return new Tensor0<bool>(tensorName_, dtype_, shape_);
Eric Kunzee5e26762020-10-13 16:11:07 -0700943 case 1:
Tai Lya4d748b2023-03-28 22:06:56 +0000944 return new Tensor1<bool>(tensorName_, dtype_, shape_);
Eric Kunzee5e26762020-10-13 16:11:07 -0700945 case 2:
Tai Lya4d748b2023-03-28 22:06:56 +0000946 return new Tensor2<bool>(tensorName_, dtype_, shape_);
Eric Kunzee5e26762020-10-13 16:11:07 -0700947 case 3:
Tai Lya4d748b2023-03-28 22:06:56 +0000948 return new Tensor3<bool>(tensorName_, dtype_, shape_);
Eric Kunzee5e26762020-10-13 16:11:07 -0700949 case 4:
Tai Lya4d748b2023-03-28 22:06:56 +0000950 return new Tensor4<bool>(tensorName_, dtype_, shape_);
Eric Kunzee5e26762020-10-13 16:11:07 -0700951 case 5:
Tai Lya4d748b2023-03-28 22:06:56 +0000952 return new Tensor5<bool>(tensorName_, dtype_, shape_);
Eric Kunzee5e26762020-10-13 16:11:07 -0700953 case 6:
Tai Lya4d748b2023-03-28 22:06:56 +0000954 return new Tensor6<bool>(tensorName_, dtype_, shape_);
Eric Kunzee5e26762020-10-13 16:11:07 -0700955 }
Kevin Cheng989cb052021-04-28 16:29:44 -0700956 break;
Tai Lya4d748b2023-03-28 22:06:56 +0000957 case TOSA_REF_TYPE_FP64:
958 switch (rank)
959 {
960 case 0:
961 return new Tensor0<double>(tensorName_, dtype_, shape_);
962 case 1:
963 return new Tensor1<double>(tensorName_, dtype_, shape_);
964 case 2:
965 return new Tensor2<double>(tensorName_, dtype_, shape_);
966 case 3:
967 return new Tensor3<double>(tensorName_, dtype_, shape_);
968 case 4:
969 return new Tensor4<double>(tensorName_, dtype_, shape_);
970 case 5:
971 return new Tensor5<double>(tensorName_, dtype_, shape_);
972 case 6:
973 return new Tensor6<double>(tensorName_, dtype_, shape_);
974 }
975 break;
976 case TOSA_REF_TYPE_UNKNOWN:
977 assert(0); // tensorDtype_ is uninitialized
Kevin Cheng989cb052021-04-28 16:29:44 -0700978 break;
Eric Kunzee5e26762020-10-13 16:11:07 -0700979 }
Kevin Cheng903763c2021-09-28 16:14:52 -0700980 return nullptr;
Eric Kunzee5e26762020-10-13 16:11:07 -0700981 }
Eric Kunzee5e26762020-10-13 16:11:07 -0700982};
983}; // namespace TosaReference
984
985#endif