blob: d6a95e10060f8d9f76146c611f6e38ebad83eed7 [file] [log] [blame]
Eric Kunzee5e26762020-10-13 16:11:07 -07001
Kevin Cheng3a478572021-01-22 17:21:02 -08002// Copyright (c) 2020-2021, 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#include "ewise_binary.h"
17#include "arith_util.h"
18#include "quant_util.h"
19#include "template_types.h"
20
21using namespace TosaReference;
22using namespace Eigen;
23using namespace tosa;
24
25template <int Rank, DType InDtype, DType OutDtype>
Kevin Chengacb550f2021-06-29 15:32:19 -070026BinaryNodeBase<Rank, InDtype, OutDtype>::BinaryNodeBase(SubgraphTraverser* sgt_,
27 const Op& op_,
28 TosaQuantInfoBase* qinfo_,
29 uint64_t id_)
30 : GraphNode(sgt_, op_, id_)
Eric Kunzee5e26762020-10-13 16:11:07 -070031{
32 setRequiredOperands(2, 1);
33 setRequiredRank(0, 6);
34
35 a_rank = b_rank = max_input_rank = -1;
36 a = b = nullptr;
37 a_rank0 = b_rank0 = nullptr;
38 result = nullptr;
39
40 fcn = [](InEigenType a, InEigenType b) -> OutEigenType { return OutEigenType(); };
41}
42
43template <int Rank, DType InDtype, DType OutDtype>
44BinaryNodeBase<Rank, InDtype, OutDtype>::~BinaryNodeBase()
45{}
46
47template <int Rank, DType InDtype, DType OutDtype>
48int BinaryNodeBase<Rank, InDtype, OutDtype>::checkTensorAttributes()
49{
50 if (validateRequiredOperands())
51 return 1;
52
53 if (validateRequiredRank(inputs[0]) || validateRequiredRank(inputs[1]) || validateRequiredRank(outputs[0]))
54 {
55 return 1;
56 }
57
58 a_rank = inputs[0]->getRank();
59 b_rank = inputs[1]->getRank();
60 if (a_rank != 0 && b_rank != 0 && a_rank != b_rank)
61 {
62 printNodeValidationError("Binary operator input ranks must match");
63 return 1;
64 }
65
66 max_input_rank = a_rank >= b_rank ? a_rank : b_rank;
67
68 // A & B must be the same types
69 if (inputs[0]->matchType(*inputs[1]))
70 {
71 printNodeValidationError("Binary operator input types must match");
72 return 1;
73 }
74
75 // Result's geometry must match, but the type may be wider
76 if (outputs[0]->getRank() != max_input_rank)
77 {
78 printNodeValidationError("Binary operator input and output genometry must match");
79 return 1;
80 }
81
82 if (a_rank == max_input_rank)
83 {
84 a = dynamic_cast<TosaReference::TensorTemplate<TIn>*>(inputs[0]);
85 }
86 else
87 {
88 a_rank0 = dynamic_cast<TosaReference::TensorTemplate<ETensor0<InEigenType>>*>(inputs[0]);
89 }
90
91 if (b_rank == max_input_rank)
92 {
93 b = dynamic_cast<TosaReference::TensorTemplate<TIn>*>(inputs[1]);
94 }
95 else
96 {
97 b_rank0 = dynamic_cast<TosaReference::TensorTemplate<ETensor0<InEigenType>>*>(inputs[1]);
98 }
99
100 result = dynamic_cast<TosaReference::TensorTemplate<TOut>*>(outputs[0]);
101
102 // either a or b can be rank0
103 // a_rank0 and b_rank0 can't be valid at the same time.
104 // if a and be are both rank0, they should be evaulated as 'a' and 'b', instead of 'a_rank0' and 'b_rank0'
105 ASSERT_MEM((a || a_rank0) && (b || b_rank0) && !(a_rank0 && b_rank0) && result);
106
107 return 0;
108}
109
110template <int Rank, DType InDtype, DType OutDtype>
111int BinaryNodeBase<Rank, InDtype, OutDtype>::broadcast()
112{
113 auto output_shape = result->getTensor().dimensions();
114
115 std::vector<int> a_shape, b_shape;
116
117 if (a_rank == max_input_rank)
118 {
119 a_shape = a->getShape();
120 }
121 else
122 {
123 a_shape.assign(max_input_rank, 1);
124 }
125
126 if (b_rank == max_input_rank)
127 {
128 b_shape = b->getShape();
129 }
130 else
131 {
132 b_shape.assign(max_input_rank, 1);
133 }
134
135 for (int i = 0; i < max_input_rank; i++)
136 {
137 if (a_shape[i] != output_shape[i] && a_shape[i] == 1)
138 {
139 bcast_a[i] = output_shape[i];
140 }
141 else
142 {
143 bcast_a[i] = 1;
144 }
145 if (b_shape[i] != output_shape[i] && b_shape[i] == 1)
146 {
147 bcast_b[i] = output_shape[i];
148 }
149 else
150 {
151 bcast_b[i] = 1;
152 }
153 }
154
155 return 0;
156}
157
158template <int Rank, DType InDtype, DType OutDtype>
159int BinaryNode<Rank, InDtype, OutDtype>::eval()
160{
161 this->broadcast();
162
163 Eigen::array<int, Rank> reshaper;
164 reshaper.fill(1);
165 TIn ia, ib;
166
167 if (this->a_rank == this->max_input_rank)
168 {
169 ia = this->a->getTensor().broadcast(this->bcast_a);
170 }
171 else
172 {
173 ia = this->a_rank0->getTensor().reshape(reshaper).broadcast(this->bcast_a);
174 }
175
176 if (this->b_rank == this->max_input_rank)
177 {
178 ib = this->b->getTensor().broadcast(this->bcast_b);
179 }
180 else
181 {
182 ib = this->b_rank0->getTensor().reshape(reshaper).broadcast(this->bcast_b);
183 }
184
185 this->result->getTensor() = ia.binaryExpr(ib, this->fcn);
186
187 return GraphNode::eval();
188}
189
190// still need to partial specialize this, or Eigen will throw static assertion
191template <DType InDtype, DType OutDtype>
192int BinaryNode<0, InDtype, OutDtype>::eval()
193{
194 this->result->getTensor() = this->a->getTensor().binaryExpr(this->b->getTensor(), this->fcn);
195
196 return GraphNode::eval();
197}
198
199template <int Rank, DType Dtype>
200int OpAdd<Rank, Dtype>::register_fcn()
201{
202 switch (InDtype)
203 {
204 case DType_FLOAT:
205 case DType_INT32:
206 this->fcn = [](InEigenType a, InEigenType b) -> OutEigenType { return a + b; };
207 break;
208 default:
Kevin Chengacb550f2021-06-29 15:32:19 -0700209 ERROR_IF(true, "unsupported DType %s", EnumNamesDType()[InDtype]);
Eric Kunzee5e26762020-10-13 16:11:07 -0700210 }
211
212 return 0;
213}
214
215template <int Rank, DType Dtype>
216int OpArithmeticRightShift<Rank, Dtype>::register_fcn()
217{
Kevin Chengaee1fac2020-11-11 13:54:06 -0800218 bool round = attribute->round();
Eric Kunzee5e26762020-10-13 16:11:07 -0700219 int32_t num_bits = 0;
220 switch (Dtype)
221 {
222 case DType_INT8:
223 num_bits = 8;
224 break;
225 case DType_INT16:
226 num_bits = 16;
227 break;
228 case DType_INT32:
229 num_bits = 32;
230 break;
231 default:
Kevin Chengacb550f2021-06-29 15:32:19 -0700232 ERROR_IF(true, "unsupported DType %s", EnumNamesDType()[Dtype]);
Eric Kunzee5e26762020-10-13 16:11:07 -0700233 }
234
Kevin Chengaee1fac2020-11-11 13:54:06 -0800235 this->fcn = [this, round, num_bits](InEigenType a, InEigenType b) -> OutEigenType {
Kevin Chengacb550f2021-06-29 15:32:19 -0700236 REQUIRE(b >= 0 && b < num_bits, "OpArithmeticRightShift: shift value %d is out of valid range [0, %d]",
237 (int32_t)b, num_bits);
Kevin Chengaee1fac2020-11-11 13:54:06 -0800238
239 InEigenType acc = a >> b;
240
241 if (round && b > 0 && (a >> (b - 1) & 1) != 0)
242 {
243 acc++;
244 }
245
246 return acc;
Eric Kunzee5e26762020-10-13 16:11:07 -0700247 };
248
249 return 0;
250}
251
252template <int Rank, DType Dtype>
253int OpBitwiseAnd<Rank, Dtype>::register_fcn()
254{
255 switch (Dtype)
256 {
Kevin Cheng3a478572021-01-22 17:21:02 -0800257 case DType_INT8:
Eric Kunzee5e26762020-10-13 16:11:07 -0700258 case DType_INT16:
259 case DType_INT32:
260 this->fcn = [](InEigenType a, InEigenType b) -> OutEigenType { return a & b; };
261 break;
262 default:
Kevin Chengacb550f2021-06-29 15:32:19 -0700263 ERROR_IF(true, "unsupported DType %s", EnumNamesDType()[Dtype]);
Eric Kunzee5e26762020-10-13 16:11:07 -0700264 }
265
266 return 0;
267}
268
269template <int Rank, DType Dtype>
270int OpBitwiseOr<Rank, Dtype>::register_fcn()
271{
272 switch (Dtype)
273 {
Kevin Cheng3a478572021-01-22 17:21:02 -0800274 case DType_INT8:
Eric Kunzee5e26762020-10-13 16:11:07 -0700275 case DType_INT16:
276 case DType_INT32:
277 this->fcn = [](InEigenType a, InEigenType b) -> OutEigenType { return a | b; };
278 break;
279 default:
Kevin Chengacb550f2021-06-29 15:32:19 -0700280 ERROR_IF(true, "unsupported DType %s", EnumNamesDType()[Dtype]);
Eric Kunzee5e26762020-10-13 16:11:07 -0700281 }
282
283 return 0;
284}
285
286template <int Rank, DType Dtype>
287int OpBitwiseXor<Rank, Dtype>::register_fcn()
288{
289 switch (Dtype)
290 {
Kevin Cheng3a478572021-01-22 17:21:02 -0800291 case DType_INT8:
Eric Kunzee5e26762020-10-13 16:11:07 -0700292 case DType_INT16:
293 case DType_INT32:
294 this->fcn = [](InEigenType a, InEigenType b) -> OutEigenType { return a ^ b; };
295 break;
296 default:
Kevin Chengacb550f2021-06-29 15:32:19 -0700297 ERROR_IF(true, "unsupported DType %s", EnumNamesDType()[Dtype]);
Eric Kunzee5e26762020-10-13 16:11:07 -0700298 }
299
300 return 0;
301}
302
303template <int Rank, DType Dtype>
Matthew Haddon459443c2021-08-23 16:43:13 +0100304int OpIntdiv<Rank, Dtype>::register_fcn()
Kevin Cheng14d7f7a2021-05-12 10:44:49 -0700305{
306 switch (InDtype)
307 {
308 case DType_INT32:
309 this->fcn = [this](InEigenType a, InEigenType b) -> OutEigenType {
Matthew Haddon459443c2021-08-23 16:43:13 +0100310 REQUIRE(b != 0, "OpIntDiv: divisor must be non-zero value");
Kevin Cheng14d7f7a2021-05-12 10:44:49 -0700311 int64_t res_in_64 = static_cast<int64_t>(a) / b;
312 int64_t i32_max_in_64 = static_cast<int64_t>(std::numeric_limits<InEigenType>::max());
Matthew Haddon459443c2021-08-23 16:43:13 +0100313 REQUIRE(a <= i32_max_in_64, "OpIntDiv: result not in i32 range");
Kevin Cheng14d7f7a2021-05-12 10:44:49 -0700314 return static_cast<InEigenType>(res_in_64);
315 };
316 break;
317 default:
Kevin Chengacb550f2021-06-29 15:32:19 -0700318 ERROR_IF(true, "unsupported DType %s", EnumNamesDType()[InDtype]);
Kevin Cheng14d7f7a2021-05-12 10:44:49 -0700319 }
320
321 return 0;
322}
323
324template <int Rank, DType Dtype>
Eric Kunzee5e26762020-10-13 16:11:07 -0700325int OpLogicalAnd<Rank, Dtype>::register_fcn()
326{
327 switch (Dtype)
328 {
329 case DType_BOOL:
330 this->fcn = [](InEigenType a, InEigenType b) -> OutEigenType { return a && b; };
331 break;
332 default:
Kevin Chengacb550f2021-06-29 15:32:19 -0700333 ERROR_IF(true, "unsupported DType %s", EnumNamesDType()[Dtype]);
Eric Kunzee5e26762020-10-13 16:11:07 -0700334 }
335
336 return 0;
337}
338
339template <int Rank, DType Dtype>
340int OpLogicalLeftShift<Rank, Dtype>::register_fcn()
341{
342 switch (Dtype)
343 {
344 case DType_INT8:
345 case DType_INT16:
346 case DType_INT32:
347 this->fcn = [](InEigenType a, InEigenType b) -> OutEigenType { return a << b; };
348 break;
349 default:
Kevin Chengacb550f2021-06-29 15:32:19 -0700350 ERROR_IF(true, "unsupported DType %s", EnumNamesDType()[Dtype]);
Eric Kunzee5e26762020-10-13 16:11:07 -0700351 }
352
353 return 0;
354}
355
356template <int Rank, DType Dtype>
357int OpLogicalRightShift<Rank, Dtype>::register_fcn()
358{
359 int32_t num_bits = 0;
360 switch (Dtype)
361 {
362 case DType_INT8:
363 num_bits = 8;
364 break;
365 case DType_INT16:
366 num_bits = 16;
367 break;
368 case DType_INT32:
369 num_bits = 32;
370 break;
371 default:
Kevin Chengacb550f2021-06-29 15:32:19 -0700372 ERROR_IF(true, "unsupported DType %s", EnumNamesDType()[Dtype]);
Eric Kunzee5e26762020-10-13 16:11:07 -0700373 }
374
375 this->fcn = [num_bits](InEigenType a, InEigenType b) -> OutEigenType {
376 uint32_t mask = ONES_MASK(num_bits) >> b;
377 return (a >> b) & mask;
378 };
379
380 return 0;
381}
382
383template <int Rank, DType Dtype>
384int OpLogicalOr<Rank, Dtype>::register_fcn()
385{
386 switch (Dtype)
387 {
388 case DType_BOOL:
389 this->fcn = [](InEigenType a, InEigenType b) -> OutEigenType { return a || b; };
390 break;
391 default:
Kevin Chengacb550f2021-06-29 15:32:19 -0700392 ERROR_IF(true, "unsupported DType %s", EnumNamesDType()[Dtype]);
Eric Kunzee5e26762020-10-13 16:11:07 -0700393 }
394
395 return 0;
396}
397
398template <int Rank, DType Dtype>
399int OpLogicalXor<Rank, Dtype>::register_fcn()
400{
401 switch (Dtype)
402 {
403 case DType_BOOL:
404 this->fcn = [](InEigenType a, InEigenType b) -> OutEigenType { return a ^ b; };
405 break;
406 default:
Kevin Chengacb550f2021-06-29 15:32:19 -0700407 ERROR_IF(true, "unsupported DType %s", EnumNamesDType()[Dtype]);
Eric Kunzee5e26762020-10-13 16:11:07 -0700408 }
409
410 return 0;
411}
412
413template <int Rank, DType Dtype>
414int OpMaximum<Rank, Dtype>::register_fcn()
415{
416 switch (Dtype)
417 {
418 case DType_FLOAT:
419 case DType_INT32:
420 this->fcn = [](InEigenType a, InEigenType b) -> OutEigenType { return a > b ? a : b; };
421 break;
422 default:
Kevin Chengacb550f2021-06-29 15:32:19 -0700423 ERROR_IF(true, "unsupported DType %s", EnumNamesDType()[Dtype]);
Eric Kunzee5e26762020-10-13 16:11:07 -0700424 }
425
426 return 0;
427}
428
429template <int Rank, DType Dtype>
430int OpMinimum<Rank, Dtype>::register_fcn()
431{
432 switch (Dtype)
433 {
434 case DType_FLOAT:
435 case DType_INT32:
436 this->fcn = [](InEigenType a, InEigenType b) -> OutEigenType { return a < b ? a : b; };
437 break;
438 default:
Kevin Chengacb550f2021-06-29 15:32:19 -0700439 ERROR_IF(true, "unsupported DType %s", EnumNamesDType()[Dtype]);
Eric Kunzee5e26762020-10-13 16:11:07 -0700440 }
441
442 return 0;
443}
444
445template <int Rank, DType InDtype, DType OutDtype>
446int OpMul<Rank, InDtype, OutDtype>::register_fcn()
447{
Kevin Chengaee1fac2020-11-11 13:54:06 -0800448 int32_t shift = attribute->shift();
Kevin Chengaee1fac2020-11-11 13:54:06 -0800449
Eric Kunzee5e26762020-10-13 16:11:07 -0700450 switch (InDtype)
451 {
452 case DType_FLOAT:
Kevin Chengaee1fac2020-11-11 13:54:06 -0800453 this->fcn = [shift](InEigenType a, InEigenType b) -> OutEigenType { return a * b; };
454 break;
Eric Kunzee5e26762020-10-13 16:11:07 -0700455 case DType_INT32:
Kevin Chengaee1fac2020-11-11 13:54:06 -0800456 this->fcn = [this, shift](InEigenType a, InEigenType b) -> OutEigenType {
457 int64_t result;
458 if (shift > 0)
459 {
460 int64_t round = 1L << (shift - 1);
Kevin Cheng9257fd52021-04-14 15:55:31 -0700461 result = static_cast<int64_t>(a) * static_cast<int64_t>(b) + round;
Kevin Chengaee1fac2020-11-11 13:54:06 -0800462 result = result >> shift;
463
Kevin Chengacb550f2021-06-29 15:32:19 -0700464 REQUIRE(result >= QMin && result <= QMax, "OpMul: result %ld exceeds valid range [%ld, %ld]",
465 result, QMin, QMax);
Kevin Chengaee1fac2020-11-11 13:54:06 -0800466 }
467 else
468 {
469 result = a * b;
470 }
471
472 return static_cast<OutEigenType>(result);
473 };
Eric Kunzee5e26762020-10-13 16:11:07 -0700474 break;
475 case DType_INT8:
476 case DType_INT16:
477 this->fcn = [this](InEigenType lhs, InEigenType rhs) -> OutEigenType {
478 OutEigenType raw_output = (OutEigenType)lhs * (OutEigenType)rhs;
479
480 OutEigenType clamped_output = std::min<OutEigenType>(QMax, std::max<OutEigenType>(raw_output, QMin));
481
482 return clamped_output;
483 };
484 break;
485 default:
Kevin Chengacb550f2021-06-29 15:32:19 -0700486 ERROR_IF(true, "unsupported DType %s", EnumNamesDType()[InDtype]);
Eric Kunzee5e26762020-10-13 16:11:07 -0700487 }
488
489 return 0;
490}
491
492template <int Rank, DType Dtype>
493int OpPow<Rank, Dtype>::register_fcn()
494{
495 switch (Dtype)
496 {
497 case DType_FLOAT:
498 this->fcn = [](InEigenType a, InEigenType b) -> OutEigenType { return powf(a, b); };
499 break;
500 default:
Kevin Chengacb550f2021-06-29 15:32:19 -0700501 ERROR_IF(true, "unsupported DType %s", EnumNamesDType()[Dtype]);
Eric Kunzee5e26762020-10-13 16:11:07 -0700502 }
503
504 return 0;
505}
506
507template <int Rank, DType Dtype>
508int OpSub<Rank, Dtype>::register_fcn()
509{
510 switch (InDtype)
511 {
512 case DType_FLOAT:
513 case DType_INT32:
514 this->fcn = [](InEigenType a, InEigenType b) -> OutEigenType { return a - b; };
515 break;
516 default:
Kevin Chengacb550f2021-06-29 15:32:19 -0700517 ERROR_IF(true, "unsupported DType %s", EnumNamesDType()[InDtype]);
Eric Kunzee5e26762020-10-13 16:11:07 -0700518 }
519
520 return 0;
521}
522
Kevin Cheng571f7182021-05-24 17:20:01 -0700523template <int Rank, DType InDtype>
Kevin Chengacb550f2021-06-29 15:32:19 -0700524OpTable<Rank, InDtype>::OpTable(SubgraphTraverser* sgt_,
525 TosaAttributeBase* attribute_,
526 TosaQuantInfoBase* qinfo_,
527 uint64_t id_)
528 : GraphNode(sgt_, Op_TABLE, id_)
Eric Kunzee5e26762020-10-13 16:11:07 -0700529{
530 setRequiredOperands(2, 1);
531 setRequiredRank(0, 6);
532}
533
Kevin Cheng571f7182021-05-24 17:20:01 -0700534template <int Rank, DType InDtype>
535OpTable<Rank, InDtype>::~OpTable()
Eric Kunzee5e26762020-10-13 16:11:07 -0700536{}
537
Kevin Cheng571f7182021-05-24 17:20:01 -0700538template <int Rank, DType InDtype>
539int OpTable<Rank, InDtype>::checkTensorAttributes()
Eric Kunzee5e26762020-10-13 16:11:07 -0700540{
541 if (validateRequiredOperands())
542 return 1;
543
544 if (validateRequiredRank(inputs[0]) || validateRequiredRank(outputs[0]))
545 {
546 return 1;
547 }
548
Kevin Cheng571f7182021-05-24 17:20:01 -0700549 if (inputs[1]->getRank() != 1)
Eric Kunzee5e26762020-10-13 16:11:07 -0700550 {
Kevin Cheng571f7182021-05-24 17:20:01 -0700551 printNodeValidationError("OpTable: Table must be rank 1 tensor");
Eric Kunzee5e26762020-10-13 16:11:07 -0700552 return 1;
553 }
554
Kevin Cheng571f7182021-05-24 17:20:01 -0700555 if (inputs[0]->getDtype() == DType_INT8)
556 {
557 if (inputs[1]->getElementCount() != 256 || inputs[1]->getDtype() != DType_INT8)
558 {
559 printNodeValidationError("OpTable: Table must be INT8[256] if input is INT8");
560 return 1;
561 }
562 }
563 else if (inputs[0]->getDtype() == DType_INT16)
564 {
565 if (inputs[1]->getElementCount() != 513 || inputs[1]->getDtype() != DType_INT16)
566 {
567 printNodeValidationError("OpTable: Table must be INT16[513] if input is INT16");
568 return 1;
569 }
570 }
571
Eric Kunzee5e26762020-10-13 16:11:07 -0700572 in = dynamic_cast<TosaReference::TensorTemplate<TIn>*>(inputs[0]);
573 table = dynamic_cast<TosaReference::TensorTemplate<TTable>*>(inputs[1]);
574 out = dynamic_cast<TosaReference::TensorTemplate<TOut>*>(outputs[0]);
575
576 ASSERT_MEM(in && table && out);
577
578 return 0;
579}
580
Kevin Cheng571f7182021-05-24 17:20:01 -0700581template <int Rank, DType InDtype>
582int OpTable<Rank, InDtype>::eval()
Eric Kunzee5e26762020-10-13 16:11:07 -0700583{
Kevin Cheng571f7182021-05-24 17:20:01 -0700584 switch (InDtype)
585 {
586 case DType_INT8:
587 this->out->getTensor() = this->in->getTensor().unaryExpr([this](InEigenType in) -> OutEigenType {
588 int32_t input_truncated = std::min<int32_t>(std::max<int32_t>(in, QInMin), QInMax);
589 int32_t index = input_truncated - QInMin;
590 int32_t value = this->table->getTensor()(index);
Eric Kunzee5e26762020-10-13 16:11:07 -0700591
Kevin Cheng571f7182021-05-24 17:20:01 -0700592 return value;
593 });
594 break;
595 case DType_INT16:
596 this->out->getTensor() = this->in->getTensor().unaryExpr([this](InEigenType in) -> OutEigenType {
597 // 1. make sure input is int16 range
598 int32_t input_truncated = std::min<int32_t>(std::max<int32_t>(in, QInMin), QInMax);
Eric Kunzee5e26762020-10-13 16:11:07 -0700599
Kevin Cheng571f7182021-05-24 17:20:01 -0700600 // 2. calculate index and interpolation fraction
601 int32_t index = (input_truncated >> FractionBits) + (1 << (IntegerBits - 1));
602 index = std::min<int32_t>(std::max<int32_t>(index, 0), NumTableEntries - 1); // 9-bit index
603 int32_t frac = (input_truncated)&0x7F; // 7-bit fraction
Eric Kunzee5e26762020-10-13 16:11:07 -0700604
Kevin Cheng571f7182021-05-24 17:20:01 -0700605 // 3. interpolate, generate 16.7 (23-bit) output
606 int32_t base = this->table->getTensor()(index);
607 int32_t next = this->table->getTensor()(index + 1);
608 int32_t value = (base << 7) + (next - base) * frac;
609
610 return value;
611 });
612 break;
613 default:
Kevin Chengacb550f2021-06-29 15:32:19 -0700614 ERROR_IF(true, "unsupported DType %s", EnumNamesDType()[InDtype]);
Kevin Cheng571f7182021-05-24 17:20:01 -0700615 }
Eric Kunzee5e26762020-10-13 16:11:07 -0700616
617 return GraphNode::eval();
618}
619
620// template explicit instantiation
621DEF_INSTANTIATE_RANK0_6_ONE_RANK_ONE_TYPE(OpAdd, FLOAT);
622DEF_INSTANTIATE_RANK0_6_ONE_RANK_ONE_TYPE(OpAdd, INT32);
623
624DEF_INSTANTIATE_RANK0_6_ONE_RANK_ONE_TYPE(OpArithmeticRightShift, INT8);
625DEF_INSTANTIATE_RANK0_6_ONE_RANK_ONE_TYPE(OpArithmeticRightShift, INT16);
626DEF_INSTANTIATE_RANK0_6_ONE_RANK_ONE_TYPE(OpArithmeticRightShift, INT32);
627
Kevin Cheng3a478572021-01-22 17:21:02 -0800628DEF_INSTANTIATE_RANK0_6_ONE_RANK_ONE_TYPE(OpBitwiseAnd, INT8);
Eric Kunzee5e26762020-10-13 16:11:07 -0700629DEF_INSTANTIATE_RANK0_6_ONE_RANK_ONE_TYPE(OpBitwiseAnd, INT16);
630DEF_INSTANTIATE_RANK0_6_ONE_RANK_ONE_TYPE(OpBitwiseAnd, INT32);
631
Kevin Cheng3a478572021-01-22 17:21:02 -0800632DEF_INSTANTIATE_RANK0_6_ONE_RANK_ONE_TYPE(OpBitwiseOr, INT8);
Eric Kunzee5e26762020-10-13 16:11:07 -0700633DEF_INSTANTIATE_RANK0_6_ONE_RANK_ONE_TYPE(OpBitwiseOr, INT16);
634DEF_INSTANTIATE_RANK0_6_ONE_RANK_ONE_TYPE(OpBitwiseOr, INT32);
635
Kevin Cheng3a478572021-01-22 17:21:02 -0800636DEF_INSTANTIATE_RANK0_6_ONE_RANK_ONE_TYPE(OpBitwiseXor, INT8);
Eric Kunzee5e26762020-10-13 16:11:07 -0700637DEF_INSTANTIATE_RANK0_6_ONE_RANK_ONE_TYPE(OpBitwiseXor, INT16);
638DEF_INSTANTIATE_RANK0_6_ONE_RANK_ONE_TYPE(OpBitwiseXor, INT32);
639
Matthew Haddon459443c2021-08-23 16:43:13 +0100640DEF_INSTANTIATE_RANK0_6_ONE_RANK_ONE_TYPE(OpIntdiv, INT32);
Kevin Cheng14d7f7a2021-05-12 10:44:49 -0700641
Eric Kunzee5e26762020-10-13 16:11:07 -0700642DEF_INSTANTIATE_RANK0_6_ONE_RANK_ONE_TYPE(OpLogicalAnd, BOOL);
643
644DEF_INSTANTIATE_RANK0_6_ONE_RANK_ONE_TYPE(OpLogicalLeftShift, INT8);
645DEF_INSTANTIATE_RANK0_6_ONE_RANK_ONE_TYPE(OpLogicalLeftShift, INT16);
646DEF_INSTANTIATE_RANK0_6_ONE_RANK_ONE_TYPE(OpLogicalLeftShift, INT32);
647
648DEF_INSTANTIATE_RANK0_6_ONE_RANK_ONE_TYPE(OpLogicalRightShift, INT8);
649DEF_INSTANTIATE_RANK0_6_ONE_RANK_ONE_TYPE(OpLogicalRightShift, INT16);
650DEF_INSTANTIATE_RANK0_6_ONE_RANK_ONE_TYPE(OpLogicalRightShift, INT32);
651
652DEF_INSTANTIATE_RANK0_6_ONE_RANK_ONE_TYPE(OpLogicalOr, BOOL);
653
654DEF_INSTANTIATE_RANK0_6_ONE_RANK_ONE_TYPE(OpLogicalXor, BOOL);
655
656DEF_INSTANTIATE_RANK0_6_ONE_RANK_ONE_TYPE(OpMaximum, FLOAT);
657DEF_INSTANTIATE_RANK0_6_ONE_RANK_ONE_TYPE(OpMaximum, INT32);
658
659DEF_INSTANTIATE_RANK0_6_ONE_RANK_ONE_TYPE(OpMinimum, FLOAT);
660DEF_INSTANTIATE_RANK0_6_ONE_RANK_ONE_TYPE(OpMinimum, INT32);
661
662DEF_INSTANTIATE_RANK0_6_ONE_RANK_TWO_TYPE(OpMul, FLOAT, FLOAT);
663DEF_INSTANTIATE_RANK0_6_ONE_RANK_TWO_TYPE(OpMul, INT8, INT32);
664DEF_INSTANTIATE_RANK0_6_ONE_RANK_TWO_TYPE(OpMul, INT16, INT32);
665DEF_INSTANTIATE_RANK0_6_ONE_RANK_TWO_TYPE(OpMul, INT32, INT32);
666
667DEF_INSTANTIATE_RANK0_6_ONE_RANK_ONE_TYPE(OpPow, FLOAT);
668
669DEF_INSTANTIATE_RANK0_6_ONE_RANK_ONE_TYPE(OpSub, FLOAT);
670DEF_INSTANTIATE_RANK0_6_ONE_RANK_ONE_TYPE(OpSub, INT32);
671
Kevin Cheng571f7182021-05-24 17:20:01 -0700672DEF_INSTANTIATE_RANK0_6_ONE_RANK_ONE_TYPE(OpTable, INT8);
673DEF_INSTANTIATE_RANK0_6_ONE_RANK_ONE_TYPE(OpTable, INT16);
Eric Kunzee5e26762020-10-13 16:11:07 -0700674
675DEF_INSTANTIATE_RANK0_6_ONE_RANK_TWO_TYPE(BinaryNode, FLOAT, BOOL);
676DEF_INSTANTIATE_RANK0_6_ONE_RANK_TWO_TYPE(BinaryNode, INT32, BOOL);