Bug Summary

File:nnc/ccv_nnc_micro_core.c
Warning:line 587, column 40
Potential memory leak

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name ccv_nnc_micro_core.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -target-feature +sse2 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/home/liu/actions-runner/_work/ccv/ccv/lib/nnc -fcoverage-compilation-dir=/home/liu/actions-runner/_work/ccv/ccv/lib/nnc -resource-dir /usr/local/lib/clang/19 -I ../ -I /usr/local/cuda/include -D HAVE_CBLAS -D HAVE_LIBPNG -D HAVE_LIBJPEG -D HAVE_FFTW3 -D HAVE_PTHREAD -D HAVE_LIBLINEAR -D HAVE_TESSERACT -D HAVE_AVCODEC -D HAVE_AVFORMAT -D HAVE_AVUTIL -D HAVE_SWSCALE -D HAVE_SSE2 -D HAVE_GSL -D HAVE_CUDA -D HAVE_CUDNN -D HAVE_NCCL -D USE_SYSTEM_CUB -I /usr/local/include -internal-isystem /usr/local/lib/clang/19/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/12/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O3 -ferror-limit 19 -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -vectorize-loops -vectorize-slp -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/liu/actions-runner/_work/ccv/ccv/_analyze/2024-11-11-003326-289375-1 -x c ccv_nnc_micro_core.c

ccv_nnc_micro_core.c

1#include "ccv_nnc.h"
2#include "ccv_nnc_easy.h"
3#include "ccv_nnc_internal.h"
4#include "ccv_internal.h"
5#include "_ccv_nnc_micro.h"
6#include "3rdparty/khash/khash.h"
7
8// MARK - Level-1 API
9
10const ccv_nnc_micro_io_vtab_t ccv_nnc_micro_io_input_isa = {};
11
12#define GRAD(_id)(2 * (var_count) - 1 - (_id)) (2 * (var_count) - 1 - (_id))
13
14ccv_nnc_micro_io_t ccv_nnc_micro_input(const int dimensions)
15{
16 assert(dimensions <= CCV_NNC_MAX_DIM_ALLOC)((void) sizeof ((dimensions <= (12)) ? 1 : 0), __extension__
({ if (dimensions <= (12)) ; else __assert_fail ("dimensions <= CCV_NNC_MAX_DIM_ALLOC"
, "ccv_nnc_micro_core.c", 16, __extension__ __PRETTY_FUNCTION__
); }))
;
17 ccv_nnc_micro_io_t input = cccalloccalloc(1, sizeof(struct ccv_nnc_micro_io_s));
18 input->isa = &ccv_nnc_micro_io_input_isa;
19 input->dimensions = dimensions;
20 input->id = 0;
21 return input;
22}
23struct ccv_nnc_micro_io_grad_s {
24 struct ccv_nnc_micro_io_s super;
25 ccv_nnc_micro_io_t x;
26};
27
28static void _ccv_nnc_micro_grad_numbering(const ccv_nnc_micro_io_t super, const int id, const int var_count)
29{
30 struct ccv_nnc_micro_io_grad_s* const self = (struct ccv_nnc_micro_io_grad_s*)super;
31 const int sid = self->x->id;
32 self->super.id = GRAD(sid)(2 * (var_count) - 1 - (sid));
33}
34
35const ccv_nnc_micro_io_vtab_t ccv_nnc_micro_io_grad_isa = {
36 .numbering = _ccv_nnc_micro_grad_numbering
37};
38
39ccv_nnc_micro_io_t ccv_nnc_micro_grad(const ccv_nnc_micro_io_t x)
40{
41 struct ccv_nnc_micro_io_grad_s* const grad = cccalloccalloc(1, sizeof(struct ccv_nnc_micro_io_grad_s));
42 grad->super.isa = &ccv_nnc_micro_io_grad_isa;
43 grad->super.dimensions = x->dimensions;
44 grad->super.id = 0;
45 grad->x = x;
46 return (ccv_nnc_micro_io_t)grad;
47}
48
49// A simple recursive descent parser. Omitted tokenisation step.
50static int _accept(const char** const pos, int* const remain_size, const char* symbol, int size)
51{
52 if (*remain_size < size)
53 return 0;
54 if (memcmp(*pos, symbol, size) == 0)
55 {
56 *remain_size -= size;
57 *pos += size;
58 return 1;
59 }
60 return 0;
61}
62
63static int _expect(const char** const pos, int* const remain_size, const char* symbol, int size)
64{
65 if (_accept(pos, remain_size, symbol, size))
66 return 1;
67 assert(0 && "unexpected symbol")((void) sizeof ((0 && "unexpected symbol") ? 1 : 0), __extension__
({ if (0 && "unexpected symbol") ; else __assert_fail
("0 && \"unexpected symbol\"", "ccv_nnc_micro_core.c"
, 67, __extension__ __PRETTY_FUNCTION__); }))
;
68 return 0;
69}
70
71static int _constant(const char** const pos, int* const remain_size, int* const id)
72{
73 int size = 0;
74 *id = 0;
75 while (*remain_size - size > 0 && pos[0][size] >= '0' && pos[0][size] <= '9')
76 {
77 *id *= 10;
78 *id += (pos[0][size] - '0');
79 ++size;
80 }
81 *remain_size -= size;
82 *pos += size;
83 return size > 0;
84}
85
86static int _index(const char** const pos, int* const remain_size, int* const id)
87{
88 if (!(*remain_size > 0 && pos[0][0] == 'i'))
89 return 0;
90 int size = 1;
91 *id = 0;
92 while (*remain_size - size > 0 && pos[0][size] >= '0' && pos[0][size] <= '9')
93 {
94 *id *= 10;
95 *id += (pos[0][size] - '0');
96 ++size;
97 }
98 if (size > 1)
99 {
100 *remain_size -= size;
101 *pos += size;
102 return 1;
103 }
104 return 0;
105}
106
107static int _dim(const char** const pos, int* const remain_size, int* const id, int* const d, ccv_array_t* const equal_assertions)
108{
109 if (!(*remain_size > 1 && pos[0][0] == 'd'))
110 return 0;
111 if (!(pos[0][1] >= 'A' && pos[0][1] <= 'Z'))
112 return 0;
113 *id = pos[0][1] - 'A';
114 int size = 2;
115 *d = 0;
116 while (*remain_size - size > 0 && pos[0][size] >= '0' && pos[0][size] <= '9')
117 {
118 *d *= 10;
119 *d += (pos[0][size] - '0');
120 ++size;
121 }
122 if (size > 1)
123 {
124 *remain_size -= size;
125 *pos += size;
126 while (_accept(pos, remain_size, " ", 1)) {}
127 if (_accept(pos, remain_size, "[", 1))
128 {
129 while (_accept(pos, remain_size, " ", 1)) {}
130 _expect(pos, remain_size, "=", 1);
131 while (_accept(pos, remain_size, " ", 1)) {}
132 int next_id;
133 int next_d;
134 if (!_dim(pos, remain_size, &next_id, &next_d, equal_assertions))
135 { assert(0 && "unexpected symbol")((void) sizeof ((0 && "unexpected symbol") ? 1 : 0), __extension__
({ if (0 && "unexpected symbol") ; else __assert_fail
("0 && \"unexpected symbol\"", "ccv_nnc_micro_core.c"
, 135, __extension__ __PRETTY_FUNCTION__); }))
; }
136 const ccv_nnc_micro_id_equal_assertion_t equal_assertion = {
137 .left = {
138 .type = CCV_NNC_MICRO_AXIS_SIZE_ID,
139 .id = -(*id + 1),
140 .d = *d
141 },
142 .right = {
143 .type = CCV_NNC_MICRO_AXIS_SIZE_ID,
144 .id = -(next_id + 1),
145 .d = next_d
146 }
147 };
148 ccv_array_push(equal_assertions, &equal_assertion);
149 while (_accept(pos, remain_size, " ", 1)) {}
150 _expect(pos, remain_size, "]", 1);
151 }
152 return 1;
153 }
154 return 0;
155}
156
157static int _var(const char** const pos, int* const remain_size, char** name)
158{
159 if (!(*remain_size > 0 && pos[0][0] == '$'))
160 return 0;
161 int size = 1;
162 while (*remain_size - size > 0 &&
163 ((pos[0][size] >= '0' && pos[0][size] <= '9') ||
164 (pos[0][size] >= 'a' && pos[0][size] <= 'z') ||
165 (pos[0][size] >= 'A' && pos[0][size] <= 'Z') ||
166 pos[0][size] == '_'))
167 ++size;
168 if (size > 1)
169 {
170 *name = ccmallocmalloc(size + 1);
171 memcpy(*name, *pos, size);
172 name[0][size] = 0;
173 *remain_size -= size;
174 *pos += size;
175 return 1;
176 }
177 return 0;
178}
179
180static CCV_WARN_UNUSED(ccv_nnc_micro_loop_index_term_t)ccv_nnc_micro_loop_index_term_t __attribute__((warn_unused_result
))
_expression(const char** const pos, int* const remain_size, ccv_array_t* const equal_assertions);
181
182static ccv_nnc_micro_loop_index_term_t _factor(const char** const pos, int* const remain_size, ccv_array_t* const equal_assertions)
183{
184 ccv_nnc_micro_loop_index_term_t term;
185 while (_accept(pos, remain_size, " ", 1)) {}
186 int id, d;
187 char* name;
188 if (_constant(pos, remain_size, &id)) {
189 term.type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_VAL;
190 term.immediate_value = id;
191 } else if (_index(pos, remain_size, &id)) {
192 term.type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID;
193 term.id.type = CCV_NNC_MICRO_LOOP_ID;
194 term.id.id = id;
195 } else if (_dim(pos, remain_size, &id, &d, equal_assertions)) {
196 term.type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID;
197 term.id.type = CCV_NNC_MICRO_AXIS_SIZE_ID;
198 term.id.d = d;
199 term.id.id = -(id + 1);
200 } else if (_var(pos, remain_size, &name)) {
201 term.type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_UNBOUND_SCALAR;
202 term.name = name;
203 } else if (_accept(pos, remain_size, "(", 1)) {
204 term = _expression(pos, remain_size, equal_assertions);
205 _expect(pos, remain_size, ")", 1);
206 } else {
207 assert(0 && "factor: syntax error")((void) sizeof ((0 && "factor: syntax error") ? 1 : 0
), __extension__ ({ if (0 && "factor: syntax error") ;
else __assert_fail ("0 && \"factor: syntax error\"",
"ccv_nnc_micro_core.c", 207, __extension__ __PRETTY_FUNCTION__
); }))
;
208 }
209 while (_accept(pos, remain_size, " ", 1)) {}
210 return term;
211}
212
213static ccv_nnc_micro_loop_index_term_t _term(const char** const pos, int* const remain_size, ccv_array_t* const equal_assertions)
214{
215 while (_accept(pos, remain_size, " ", 1)) {}
216 ccv_nnc_micro_loop_index_term_t term = _factor(pos, remain_size, equal_assertions);
217 while (*remain_size > 0 && (pos[0][0] == '*' || pos[0][0] == '/'))
218 {
219 const int op = pos[0][0] == '*' ? CCV_NNC_MICRO_BINARY_OP_MUL : CCV_NNC_MICRO_BINARY_OP_DIV;
220 *remain_size -= 1;
221 *pos += 1;
222 const ccv_nnc_micro_loop_index_term_t left = term;
223 const ccv_nnc_micro_loop_index_term_t right = _factor(pos, remain_size, equal_assertions);
224 term.type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_BINARY;
225 term.binary = (ccv_nnc_micro_loop_index_binary_t*)ccmallocmalloc(sizeof(ccv_nnc_micro_loop_index_binary_t));
226 term.binary->op = op;
227 term.binary->left = left;
228 term.binary->right = right;
229 }
230 while (_accept(pos, remain_size, " ", 1)) {}
231 return term;
232}
233
234static ccv_nnc_micro_loop_index_term_t _expression(const char** const pos, int* const remain_size, ccv_array_t* const equal_assertions)
235{
236 while (_accept(pos, remain_size, " ", 1)) {}
237 int prefix_op = -1;
238 if (*remain_size > 0 && (pos[0][0] == '+' || pos[0][0] == '-'))
239 {
240 prefix_op = pos[0][0] == '+' ? CCV_NNC_MICRO_BINARY_OP_PLUS : CCV_NNC_MICRO_BINARY_OP_MINUS;
241 *remain_size -= 1;
242 *pos += 1;
243 }
244 ccv_nnc_micro_loop_index_term_t node = _term(pos, remain_size, equal_assertions);
245 while (*remain_size > 0 && (pos[0][0] == '+' || pos[0][0] == '-'))
246 {
247 const int op = pos[0][0] == '+' ? CCV_NNC_MICRO_BINARY_OP_PLUS : CCV_NNC_MICRO_BINARY_OP_MINUS;
248 *remain_size -= 1;
249 *pos += 1;
250 const ccv_nnc_micro_loop_index_term_t left = node;
251 const ccv_nnc_micro_loop_index_term_t right = _term(pos, remain_size, equal_assertions);
252 node.type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_BINARY;
253 node.binary = (ccv_nnc_micro_loop_index_binary_t*)ccmallocmalloc(sizeof(ccv_nnc_micro_loop_index_binary_t));
254 node.binary->op = op;
255 node.binary->left = left;
256 node.binary->right = right;
257 }
258 while (_accept(pos, remain_size, " ", 1)) {}
259 if (prefix_op >= 0)
260 {
261 ccv_nnc_micro_loop_index_binary_t* const expr = (ccv_nnc_micro_loop_index_binary_t*)ccmallocmalloc(sizeof(ccv_nnc_micro_loop_index_binary_t));
262 expr->op = prefix_op;
263 expr->left = node;
264 expr->right.type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_NONE;
265 node.type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_BINARY;
266 node.binary = expr;
267 }
268 return node;
269}
270
271static void _no_index(const ccv_nnc_micro_loop_index_term_t term)
272{
273 switch (term.type) {
274 case CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID:
275 // Can only be axis size id. No loop index.
276 assert(term.id.type == CCV_NNC_MICRO_AXIS_SIZE_ID)((void) sizeof ((term.id.type == CCV_NNC_MICRO_AXIS_SIZE_ID) ?
1 : 0), __extension__ ({ if (term.id.type == CCV_NNC_MICRO_AXIS_SIZE_ID
) ; else __assert_fail ("term.id.type == CCV_NNC_MICRO_AXIS_SIZE_ID"
, "ccv_nnc_micro_core.c", 276, __extension__ __PRETTY_FUNCTION__
); }))
;
277 break;
278 case CCV_NNC_MICRO_LOOP_INDEX_TYPE_BINARY:
279 _no_index(term.binary->left);
280 _no_index(term.binary->right);
281 break;
282 }
283}
284
285static void _sid_to_axis_size_term(ccv_nnc_micro_loop_index_term_t* const term, const int* const sids, const int sid_count)
286{
287 switch (term->type) {
288 case CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID:
289 // Can only be axis size id. No loop index.
290 if (term->id.type == CCV_NNC_MICRO_AXIS_SIZE_ID && term->id.id < 0)
291 {
292 const int id = -(term->id.id + 1);
293 assert(id >= 0 && id < sid_count)((void) sizeof ((id >= 0 && id < sid_count) ? 1
: 0), __extension__ ({ if (id >= 0 && id < sid_count
) ; else __assert_fail ("id >= 0 && id < sid_count"
, "ccv_nnc_micro_core.c", 293, __extension__ __PRETTY_FUNCTION__
); }))
;
294 term->id.id = sids[id];
295 }
296 break;
297 case CCV_NNC_MICRO_LOOP_INDEX_TYPE_BINARY:
298 _sid_to_axis_size_term(&term->binary->left, sids, sid_count);
299 _sid_to_axis_size_term(&term->binary->right, sids, sid_count);
300 break;
301 }
302}
303
304struct ccv_nnc_micro_io_reindex_s {
305 struct ccv_nnc_micro_io_s super;
306 int s_count;
307 ccv_nnc_micro_io_t x;
308 ccv_nnc_micro_loop_index_term_t* shape;
309 ccv_nnc_micro_loop_index_term_t* reindex;
310 ccv_nnc_micro_io_t* ss;
311 ccv_array_t* equal_assertions;
312};
313
314static void _ccv_nnc_micro_reindex_numbering(const ccv_nnc_micro_io_t super, const int id, const int var_count)
315{
316 struct ccv_nnc_micro_io_reindex_s* const self = (struct ccv_nnc_micro_io_reindex_s*)super;
317 self->super.id = id;
318 // No need to update axis size.
319 if (self->s_count == 0)
320 return;
321 int sids[self->s_count];
322 int i;
323 for (i = 0; i < self->s_count; i++)
324 sids[i] = self->ss[i]->id;
325 for (i = 0; i < self->super.dimensions; i++)
326 _sid_to_axis_size_term(&self->shape[i], sids, self->s_count);
327 for (i = 0; i < self->x->dimensions; i++)
328 _sid_to_axis_size_term(&self->reindex[i], sids, self->s_count);
329 for (i = 0; i < self->equal_assertions->rnum; i++)
330 {
331 ccv_nnc_micro_id_equal_assertion_t* const equal_assertion = (ccv_nnc_micro_id_equal_assertion_t*)ccv_array_get(self->equal_assertions, i)((void*)(((char*)((self->equal_assertions)->data)) + (size_t
)(self->equal_assertions)->rsize * (size_t)(i)))
;
332 if (equal_assertion->left.type == CCV_NNC_MICRO_AXIS_SIZE_ID && equal_assertion->left.id < 0)
333 {
334 const int id = -(equal_assertion->left.id + 1);
335 assert(id >= 0 && id < self->s_count)((void) sizeof ((id >= 0 && id < self->s_count
) ? 1 : 0), __extension__ ({ if (id >= 0 && id <
self->s_count) ; else __assert_fail ("id >= 0 && id < self->s_count"
, "ccv_nnc_micro_core.c", 335, __extension__ __PRETTY_FUNCTION__
); }))
;
336 equal_assertion->left.id = sids[id];
337 }
338 if (equal_assertion->right.type == CCV_NNC_MICRO_AXIS_SIZE_ID && equal_assertion->right.id < 0)
339 {
340 const int id = -(equal_assertion->right.id + 1);
341 assert(id >= 0 && id < self->s_count)((void) sizeof ((id >= 0 && id < self->s_count
) ? 1 : 0), __extension__ ({ if (id >= 0 && id <
self->s_count) ; else __assert_fail ("id >= 0 && id < self->s_count"
, "ccv_nnc_micro_core.c", 341, __extension__ __PRETTY_FUNCTION__
); }))
;
342 equal_assertion->right.id = sids[id];
343 }
344 }
345}
346
347static void _ccv_nnc_micro_reindex_equal_assertions(const ccv_nnc_micro_io_t super, ccv_array_t* const equal_assertions)
348{
349 struct ccv_nnc_micro_io_reindex_s* const self = (struct ccv_nnc_micro_io_reindex_s*)super;
350 int i;
351 for (i = 0; i < self->equal_assertions->rnum; i++)
352 {
353 ccv_nnc_micro_id_equal_assertion_t* const equal_assertion = (ccv_nnc_micro_id_equal_assertion_t*)ccv_array_get(self->equal_assertions, i)((void*)(((char*)((self->equal_assertions)->data)) + (size_t
)(self->equal_assertions)->rsize * (size_t)(i)))
;
354 ccv_array_push(equal_assertions, equal_assertion);
355 }
356}
357
358static void _ccv_nnc_bind_scalars_in_term(ccv_nnc_micro_loop_index_term_t* const term, ccv_nnc_micro_scalar_lookup_f lookup, const void* const context)
359{
360 switch (term->type)
361 {
362 case CCV_NNC_MICRO_LOOP_INDEX_TYPE_BINARY:
363 _ccv_nnc_bind_scalars_in_term(&term->binary->left, lookup, context);
364 _ccv_nnc_bind_scalars_in_term(&term->binary->right, lookup, context);
365 break;
366 case CCV_NNC_MICRO_LOOP_INDEX_TYPE_UNBOUND_SCALAR: {
367 char* const name = term->name;
368 term->id.id = lookup(context, name);
369 ccfreefree(name);
370 term->id.d = 0;
371 term->id.type = CCV_NNC_MICRO_SCALAR_ID;
372 term->type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID;
373 break;
374 }
375 }
376}
377
378static void _ccv_nnc_micro_reindex_bind_scalars(const ccv_nnc_micro_io_t super, ccv_nnc_micro_scalar_lookup_f lookup, const void* const context)
379{
380 struct ccv_nnc_micro_io_reindex_s* const self = (struct ccv_nnc_micro_io_reindex_s*)super;
381 int i;
382 for (i = 0; i < self->super.dimensions; i++)
383 _ccv_nnc_bind_scalars_in_term(&self->shape[i], lookup, context);
384 for (i = 0; i < self->x->dimensions; i++)
385 _ccv_nnc_bind_scalars_in_term(&self->reindex[i], lookup, context);
386}
387
388ccv_nnc_micro_loop_index_term_t ccv_nnc_micro_loop_index_deep_copy(const ccv_nnc_micro_loop_index_term_t* const term)
389{
390 switch (term->type)
391 {
392 case CCV_NNC_MICRO_LOOP_INDEX_TYPE_BINARY: {
393 ccv_nnc_micro_loop_index_term_t copy = *term;
394 copy.binary = (ccv_nnc_micro_loop_index_binary_t*)ccmallocmalloc(sizeof(ccv_nnc_micro_loop_index_binary_t));
395 *copy.binary = *term->binary;
396 copy.binary->left = ccv_nnc_micro_loop_index_deep_copy(&term->binary->left);
397 copy.binary->right = ccv_nnc_micro_loop_index_deep_copy(&term->binary->right);
398 return copy;
399 }
400 case CCV_NNC_MICRO_LOOP_INDEX_TYPE_NONE:
401 case CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID:
402 case CCV_NNC_MICRO_LOOP_INDEX_TYPE_VAL:
403 case CCV_NNC_MICRO_LOOP_INDEX_TYPE_UNBOUND_SCALAR:
404 return *term;
405 }
406 return *term;
407}
408
409static CCV_WARN_UNUSED(ccv_nnc_micro_function_t)ccv_nnc_micro_function_t __attribute__((warn_unused_result)) _ccv_nnc_micro_reindex_emit(const ccv_nnc_micro_io_t super)
410{
411 struct ccv_nnc_micro_io_reindex_s* const self = (struct ccv_nnc_micro_io_reindex_s*)super;
412 const int loop_count = self->super.dimensions;
413 assert(loop_count <= CCV_NNC_MAX_DIM_ALLOC)((void) sizeof ((loop_count <= (12)) ? 1 : 0), __extension__
({ if (loop_count <= (12)) ; else __assert_fail ("loop_count <= CCV_NNC_MAX_DIM_ALLOC"
, "ccv_nnc_micro_core.c", 413, __extension__ __PRETTY_FUNCTION__
); }))
;
414 ccv_nnc_micro_loop_t* const loops = (ccv_nnc_micro_loop_t*)ccmallocmalloc(sizeof(ccv_nnc_micro_loop_t) * loop_count);
415 int i;
416 for (i = 0; i < loop_count; i++)
417 loops[i] = ccv_nnc_micro_for_in(ccv_nnc_micro_index_of_value(0), ccv_nnc_micro_index_of_axis_size(self->super.id, i), i);
418 const ccv_nnc_micro_loop_statement_t statement = ccv_nnc_micro_loop_assignment(
419 ccv_nnc_micro_loop_variable_of_tensor(self->super.id, loop_count, ccv_nnc_micro_index_of_loops(loops, loop_count)(ccv_nnc_micro_loop_index_term_t [(12)]){ { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 0 ? loops[0].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 1 ? loops[1].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 2 ? loops[2].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 3 ? loops[3].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 4 ? loops[4].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 5 ? loops[5].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 6 ? loops[6].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 7 ? loops[7].id : (ccv_nnc_micro_id_t){} } }
),
420 ccv_nnc_micro_loop_expression_of_variable(ccv_nnc_micro_loop_variable_of_tensor(self->x->id, self->x->dimensions, self->reindex))
421 );
422 for (i = 0; i < self->x->dimensions; i++)
423 self->reindex[i] = ccv_nnc_micro_loop_index_deep_copy(&self->reindex[i]);
424 loops[loop_count - 1].statement_count = 1;
425 loops[loop_count - 1].statements = (ccv_nnc_micro_loop_statement_t*)ccmallocmalloc(sizeof(ccv_nnc_micro_loop_statement_t));
426 loops[loop_count - 1].statements[0] = statement;
427 return (ccv_nnc_micro_function_t){
428 .block_count = 1,
429 .one_block = {
430 .loop_count = loop_count,
431 .loops = loops
432 }
433 };
434}
435
436static CCV_WARN_UNUSED(ccv_nnc_micro_function_t)ccv_nnc_micro_function_t __attribute__((warn_unused_result)) _ccv_nnc_micro_reindex_emit_grad(const ccv_nnc_micro_io_t super, const int var_count)
437{
438 // The grad is var_count + original id.
439 struct ccv_nnc_micro_io_reindex_s* const self = (struct ccv_nnc_micro_io_reindex_s*)super;
440 const int reset_loop_count = self->x->dimensions;
441 ccv_nnc_micro_loop_t* const reset_loops = (ccv_nnc_micro_loop_t*)ccmallocmalloc(sizeof(ccv_nnc_micro_loop_t) * reset_loop_count);
442 // This loop reset grad to 0.
443 int i;
444 for (i = 0; i < reset_loop_count; i++)
445 reset_loops[i] = ccv_nnc_micro_for_in(ccv_nnc_micro_index_of_value(0), ccv_nnc_micro_index_of_axis_size(GRAD(self->x->id)(2 * (var_count) - 1 - (self->x->id)), i), i);
446 const ccv_nnc_micro_loop_statement_t reset_statement = ccv_nnc_micro_loop_assignment(
447 ccv_nnc_micro_loop_variable_of_tensor(GRAD(self->x->id)(2 * (var_count) - 1 - (self->x->id)), reset_loop_count, ccv_nnc_micro_index_of_loops(reset_loops, reset_loop_count)(ccv_nnc_micro_loop_index_term_t [(12)]){ { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = reset_loop_count > 0 ? reset_loops[0].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = reset_loop_count
> 1 ? reset_loops[1].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = reset_loop_count >
2 ? reset_loops[2].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = reset_loop_count > 3 ? reset_loops[3].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = reset_loop_count
> 4 ? reset_loops[4].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = reset_loop_count >
5 ? reset_loops[5].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = reset_loop_count > 6 ? reset_loops[6].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = reset_loop_count
> 7 ? reset_loops[7].id : (ccv_nnc_micro_id_t){} } }
),
448 ccv_nnc_micro_loop_expression_of_value(0)
449 );
450 reset_loops[reset_loop_count - 1].statement_count = 1;
451 reset_loops[reset_loop_count - 1].statements = (ccv_nnc_micro_loop_statement_t*)ccmallocmalloc(sizeof(ccv_nnc_micro_loop_statement_t));
452 reset_loops[reset_loop_count - 1].statements[0] = reset_statement;
453 const int loop_count = self->super.dimensions;
454 ccv_nnc_micro_loop_t* const loops = (ccv_nnc_micro_loop_t*)ccmallocmalloc(sizeof(ccv_nnc_micro_loop_t) * loop_count);
455 for (i = 0; i < loop_count; i++)
456 loops[i] = ccv_nnc_micro_for_in(ccv_nnc_micro_index_of_value(0), ccv_nnc_micro_index_of_axis_size(GRAD(self->super.id)(2 * (var_count) - 1 - (self->super.id)), i), i);
457 const ccv_nnc_micro_loop_statement_t statement = ccv_nnc_micro_loop_compound_assignment_of_tensor(
458 ccv_nnc_micro_loop_variable_of_tensor(GRAD(self->x->id)(2 * (var_count) - 1 - (self->x->id)), self->x->dimensions, self->reindex),
459 ccv_nnc_micro_loop_expression_of_variable(ccv_nnc_micro_loop_variable_of_tensor(GRAD(self->super.id)(2 * (var_count) - 1 - (self->super.id)), loop_count, ccv_nnc_micro_index_of_loops(loops, loop_count)(ccv_nnc_micro_loop_index_term_t [(12)]){ { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 0 ? loops[0].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 1 ? loops[1].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 2 ? loops[2].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 3 ? loops[3].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 4 ? loops[4].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 5 ? loops[5].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 6 ? loops[6].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 7 ? loops[7].id : (ccv_nnc_micro_id_t){} } }
))
460 );
461 for (i = 0; i < self->x->dimensions; i++)
462 self->reindex[i] = ccv_nnc_micro_loop_index_deep_copy(&self->reindex[i]);
463 loops[loop_count - 1].statement_count = 1;
464 loops[loop_count - 1].statements = (ccv_nnc_micro_loop_statement_t*)ccmallocmalloc(sizeof(ccv_nnc_micro_loop_statement_t));
465 loops[loop_count - 1].statements[0] = statement;
466 ccv_nnc_micro_loop_block_t* const blocks = (ccv_nnc_micro_loop_block_t*)ccmallocmalloc(sizeof(ccv_nnc_micro_loop_block_t) * 2);
467 blocks[0] = (ccv_nnc_micro_loop_block_t){
468 .loop_count = reset_loop_count,
469 .loops = reset_loops
470 };
471 blocks[1] = (ccv_nnc_micro_loop_block_t){
472 .loop_count = loop_count,
473 .loops = loops
474 };
475 return (ccv_nnc_micro_function_t){
476 .block_count = 2,
477 .blocks = blocks
478 };
479}
480
481static ccv_nnc_micro_tensor_t _ccv_nnc_micro_reindex_return_shape(const ccv_nnc_micro_io_t super)
482{
483 struct ccv_nnc_micro_io_reindex_s* const self = (struct ccv_nnc_micro_io_reindex_s*)super;
484 ccv_nnc_micro_tensor_t var = {};
485 var.dimensions = self->super.dimensions;
486 var.sibling = -1;
487 var.input = self->x->id;
488 var.shape = (ccv_nnc_micro_loop_index_term_t*)ccmallocmalloc(sizeof(ccv_nnc_micro_loop_index_term_t) * self->super.dimensions);
489 memcpy(var.shape, self->shape, sizeof(ccv_nnc_micro_loop_index_term_t) * self->super.dimensions);
490 return var;
491}
492
493static void _ccv_nnc_micro_reindex_deinit(const ccv_nnc_micro_io_t super)
494{
495 struct ccv_nnc_micro_io_reindex_s* const self = (struct ccv_nnc_micro_io_reindex_s*)super;
496 int i;
497 for (i = 0; i < self->x->dimensions; i++)
498 ccv_nnc_micro_loop_index_free(&self->reindex[i]);
499 ccv_array_free(self->equal_assertions);
500}
501
502static const ccv_nnc_micro_io_vtab_t ccv_nnc_micro_io_reindex_isa = {
503 .numbering = _ccv_nnc_micro_reindex_numbering,
504 .equal_assertions = _ccv_nnc_micro_reindex_equal_assertions,
505 .bind_scalars = _ccv_nnc_micro_reindex_bind_scalars,
506 .emit = _ccv_nnc_micro_reindex_emit,
507 .emit_grad = _ccv_nnc_micro_reindex_emit_grad,
508 .return_shape = _ccv_nnc_micro_reindex_return_shape,
509 .deinit = _ccv_nnc_micro_reindex_deinit
510};
511
512ccv_nnc_micro_io_t ccv_nnc_micro_reindex(const char* const* const shape, const int shape_count, const ccv_nnc_micro_io_t* const ss, const int s_count, const char* const* const reindex, const int reindex_count, const ccv_nnc_micro_io_t x)
513{
514 assert(shape_count <= CCV_NNC_MAX_DIM_ALLOC)((void) sizeof ((shape_count <= (12)) ? 1 : 0), __extension__
({ if (shape_count <= (12)) ; else __assert_fail ("shape_count <= CCV_NNC_MAX_DIM_ALLOC"
, "ccv_nnc_micro_core.c", 514, __extension__ __PRETTY_FUNCTION__
); }))
;
515 assert(reindex_count <= CCV_NNC_MAX_DIM_ALLOC)((void) sizeof ((reindex_count <= (12)) ? 1 : 0), __extension__
({ if (reindex_count <= (12)) ; else __assert_fail ("reindex_count <= CCV_NNC_MAX_DIM_ALLOC"
, "ccv_nnc_micro_core.c", 515, __extension__ __PRETTY_FUNCTION__
); }))
;
516 assert(reindex_count == x->dimensions)((void) sizeof ((reindex_count == x->dimensions) ? 1 : 0),
__extension__ ({ if (reindex_count == x->dimensions) ; else
__assert_fail ("reindex_count == x->dimensions", "ccv_nnc_micro_core.c"
, 516, __extension__ __PRETTY_FUNCTION__); }))
;
517 int i;
518 struct ccv_nnc_micro_io_reindex_s* const self = (struct ccv_nnc_micro_io_reindex_s*)cccalloccalloc(1, sizeof(struct ccv_nnc_micro_io_reindex_s) + sizeof(ccv_nnc_micro_loop_index_term_t) * (shape_count + reindex_count) + sizeof(ccv_nnc_micro_io_t) * (s_count + 1));
519 self->super.isa = &ccv_nnc_micro_io_reindex_isa;
520 self->super.dimensions = shape_count;
521 self->super.id = 0;
522 self->x = x;
523 self->shape = (ccv_nnc_micro_loop_index_term_t*)(self + 1);
524 self->reindex = self->shape + shape_count;
525 self->ss = (ccv_nnc_micro_io_t*)(self->reindex + reindex_count);
526 self->s_count = s_count;
527 self->ss[s_count] = x;
528 self->super.inputs = self->ss;
529 self->super.input_size = s_count + 1;
530 if (s_count > 0)
531 memcpy(self->ss, ss, sizeof(ccv_nnc_micro_io_t) * s_count);
532 ccv_array_t* const equal_assertions = self->equal_assertions = ccv_array_new(sizeof(ccv_nnc_micro_id_equal_assertion_t), 0, 0);
533 // Parse shape into expressions and validate the grammar. Do this upfront so we don't fail on parsing
534 // later, which can be confusing.
535 // CFG:
536 // VAR -> $[a-zA-Z0-9]+
537 // DIM -> d[A-Z]{1}[0-9]+
538 // INDEX -> i[0-9]+
539 // CONST -> [0-9]+
540 // FACTOR -> VAR | DIM | CONST | INDEX
541 // TERM -> FACTOR { ("*" | "/") FACTOR }
542 // EXPRESSION -> ["+" | "-"] TERM { ("+" | "-") TERM }
543 // Also, we choose to reuse the index expression structure even some information (such as id of tensors
544 // and the binding variables) not available. In this way, there is no need to reallocate index expression
545 // later, we just need to simply "patch" it in ccv_nnc_micro_combine_t.
546 for (i = 0; i < shape_count; i++)
547 {
548 int remain_size = strlen(shape[i]);
549 const char* pos = shape[i];
550 ccv_nnc_micro_loop_index_term_t term = _expression(&pos, &remain_size, equal_assertions);
551 _no_index(term); // Make sure this is not index, no loop index.
552 self->shape[i] = term;
553 }
554 // Parse reindex.
555 for (i = 0; i < reindex_count; i++)
556 {
557 int remain_size = strlen(reindex[i]);
558 const char* pos = reindex[i];
559 self->reindex[i] = _expression(&pos, &remain_size, equal_assertions);
560 }
561 return (ccv_nnc_micro_io_t)self;
562}
563
564struct ccv_nnc_micro_io_unary_s {
565 struct ccv_nnc_micro_io_s super;
566 uint32_t unary_op;
567 ccv_nnc_micro_io_t x;
568};
569
570static CCV_WARN_UNUSED(ccv_nnc_micro_function_t)ccv_nnc_micro_function_t __attribute__((warn_unused_result)) _ccv_nnc_micro_unary_emit(const ccv_nnc_micro_io_t super)
571{
572 struct ccv_nnc_micro_io_unary_s* const self = (struct ccv_nnc_micro_io_unary_s*)super;
573 const int loop_count = self->super.dimensions;
574 assert(self->x->dimensions == loop_count)((void) sizeof ((self->x->dimensions == loop_count) ? 1
: 0), __extension__ ({ if (self->x->dimensions == loop_count
) ; else __assert_fail ("self->x->dimensions == loop_count"
, "ccv_nnc_micro_core.c", 574, __extension__ __PRETTY_FUNCTION__
); }))
;
1
Assuming 'loop_count' is equal to field 'dimensions'
2
Taking true branch
575 assert(loop_count <= CCV_NNC_MAX_DIM_ALLOC)((void) sizeof ((loop_count <= (12)) ? 1 : 0), __extension__
({ if (loop_count <= (12)) ; else __assert_fail ("loop_count <= CCV_NNC_MAX_DIM_ALLOC"
, "ccv_nnc_micro_core.c", 575, __extension__ __PRETTY_FUNCTION__
); }))
;
3
Assuming 'loop_count' is <= 12
4
Taking true branch
576 ccv_nnc_micro_loop_t* const loops = (ccv_nnc_micro_loop_t*)ccmallocmalloc(sizeof(ccv_nnc_micro_loop_t) * loop_count);
577 int i;
578 for (i = 0; i < loop_count; i++)
5
Assuming 'i' is >= 'loop_count'
6
Loop condition is false. Execution continues on line 580
579 loops[i] = ccv_nnc_micro_for_in(ccv_nnc_micro_index_of_value(0), ccv_nnc_micro_index_of_axis_size(self->super.id, i), i);
580 const ccv_nnc_micro_loop_statement_t statement = ccv_nnc_micro_loop_assignment(
581 ccv_nnc_micro_loop_variable_of_tensor(self->super.id, loop_count, ccv_nnc_micro_index_of_loops(loops, loop_count)(ccv_nnc_micro_loop_index_term_t [(12)]){ { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 0 ? loops[0].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 1 ? loops[1].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 2 ? loops[2].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 3 ? loops[3].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 4 ? loops[4].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 5 ? loops[5].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 6 ? loops[6].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 7 ? loops[7].id : (ccv_nnc_micro_id_t){} } }
),
7
'?' condition is false
8
'?' condition is false
9
'?' condition is false
10
'?' condition is false
11
'?' condition is false
12
'?' condition is false
13
'?' condition is false
14
'?' condition is false
582 ccv_nnc_micro_loop_expression_of_unary(
23
Calling 'ccv_nnc_micro_loop_expression_of_unary'
25
Returned allocated memory
583 self->unary_op,
584 ccv_nnc_micro_loop_expression_of_variable(ccv_nnc_micro_loop_variable_of_tensor(self->x->id, loop_count, ccv_nnc_micro_index_of_loops(loops, loop_count)(ccv_nnc_micro_loop_index_term_t [(12)]){ { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 0 ? loops[0].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 1 ? loops[1].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 2 ? loops[2].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 3 ? loops[3].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 4 ? loops[4].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 5 ? loops[5].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 6 ? loops[6].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 7 ? loops[7].id : (ccv_nnc_micro_id_t){} } }
))
15
'?' condition is false
16
'?' condition is false
17
'?' condition is false
18
'?' condition is false
19
'?' condition is false
20
'?' condition is false
21
'?' condition is false
22
'?' condition is false
585 )
586 );
587 loops[loop_count - 1].statement_count = 1;
26
Potential memory leak
588 loops[loop_count - 1].statements = (ccv_nnc_micro_loop_statement_t*)ccmallocmalloc(sizeof(ccv_nnc_micro_loop_statement_t));
589 loops[loop_count - 1].statements[0] = statement;
590 return (ccv_nnc_micro_function_t){
591 .block_count = 1,
592 .one_block = {
593 .loop_count = loop_count,
594 .loops = loops
595 }
596 };
597}
598
599static CCV_WARN_UNUSED(ccv_nnc_micro_function_t)ccv_nnc_micro_function_t __attribute__((warn_unused_result)) _ccv_nnc_micro_unary_emit_grad(const ccv_nnc_micro_io_t super, const int var_count)
600{
601 struct ccv_nnc_micro_io_unary_s* const self = (struct ccv_nnc_micro_io_unary_s*)super;
602 const int loop_count = self->super.dimensions;
603 assert(self->x->dimensions == loop_count)((void) sizeof ((self->x->dimensions == loop_count) ? 1
: 0), __extension__ ({ if (self->x->dimensions == loop_count
) ; else __assert_fail ("self->x->dimensions == loop_count"
, "ccv_nnc_micro_core.c", 603, __extension__ __PRETTY_FUNCTION__
); }))
;
604 assert(loop_count <= CCV_NNC_MAX_DIM_ALLOC)((void) sizeof ((loop_count <= (12)) ? 1 : 0), __extension__
({ if (loop_count <= (12)) ; else __assert_fail ("loop_count <= CCV_NNC_MAX_DIM_ALLOC"
, "ccv_nnc_micro_core.c", 604, __extension__ __PRETTY_FUNCTION__
); }))
;
605 ccv_nnc_micro_loop_t* const loops = (ccv_nnc_micro_loop_t*)ccmallocmalloc(sizeof(ccv_nnc_micro_loop_t) * loop_count);
606 int i;
607 for (i = 0; i < loop_count; i++)
608 loops[i] = ccv_nnc_micro_for_in(ccv_nnc_micro_index_of_value(0), ccv_nnc_micro_index_of_axis_size(GRAD(self->super.id)(2 * (var_count) - 1 - (self->super.id)), i), i);
609 ccv_nnc_micro_loop_statement_t statement;
610 switch (self->unary_op)
611 {
612 case CCV_NNC_MICRO_UNARY_OP_NEG:
613 statement = ccv_nnc_micro_loop_assignment(
614 ccv_nnc_micro_loop_variable_of_tensor(GRAD(self->x->id)(2 * (var_count) - 1 - (self->x->id)), loop_count, ccv_nnc_micro_index_of_loops(loops, loop_count)(ccv_nnc_micro_loop_index_term_t [(12)]){ { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 0 ? loops[0].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 1 ? loops[1].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 2 ? loops[2].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 3 ? loops[3].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 4 ? loops[4].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 5 ? loops[5].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 6 ? loops[6].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 7 ? loops[7].id : (ccv_nnc_micro_id_t){} } }
),
615 ccv_nnc_micro_loop_expression_of_unary(
616 CCV_NNC_MICRO_UNARY_OP_NEG,
617 ccv_nnc_micro_loop_expression_of_variable(ccv_nnc_micro_loop_variable_of_tensor(GRAD(self->super.id)(2 * (var_count) - 1 - (self->super.id)), loop_count, ccv_nnc_micro_index_of_loops(loops, loop_count)(ccv_nnc_micro_loop_index_term_t [(12)]){ { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 0 ? loops[0].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 1 ? loops[1].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 2 ? loops[2].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 3 ? loops[3].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 4 ? loops[4].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 5 ? loops[5].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 6 ? loops[6].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 7 ? loops[7].id : (ccv_nnc_micro_id_t){} } }
))
618 )
619 );
620 break;
621 case CCV_NNC_MICRO_UNARY_OP_EXP:
622 statement = ccv_nnc_micro_loop_assignment(
623 ccv_nnc_micro_loop_variable_of_tensor(GRAD(self->x->id)(2 * (var_count) - 1 - (self->x->id)), loop_count, ccv_nnc_micro_index_of_loops(loops, loop_count)(ccv_nnc_micro_loop_index_term_t [(12)]){ { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 0 ? loops[0].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 1 ? loops[1].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 2 ? loops[2].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 3 ? loops[3].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 4 ? loops[4].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 5 ? loops[5].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 6 ? loops[6].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 7 ? loops[7].id : (ccv_nnc_micro_id_t){} } }
),
624 ccv_nnc_micro_loop_expression_of_binary(
625 CCV_NNC_MICRO_BINARY_OP_MUL,
626 ccv_nnc_micro_loop_expression_of_variable(ccv_nnc_micro_loop_variable_of_tensor(self->super.id, loop_count, ccv_nnc_micro_index_of_loops(loops, loop_count)(ccv_nnc_micro_loop_index_term_t [(12)]){ { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 0 ? loops[0].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 1 ? loops[1].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 2 ? loops[2].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 3 ? loops[3].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 4 ? loops[4].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 5 ? loops[5].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 6 ? loops[6].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 7 ? loops[7].id : (ccv_nnc_micro_id_t){} } }
)),
627 ccv_nnc_micro_loop_expression_of_variable(ccv_nnc_micro_loop_variable_of_tensor(GRAD(self->super.id)(2 * (var_count) - 1 - (self->super.id)), loop_count, ccv_nnc_micro_index_of_loops(loops, loop_count)(ccv_nnc_micro_loop_index_term_t [(12)]){ { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 0 ? loops[0].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 1 ? loops[1].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 2 ? loops[2].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 3 ? loops[3].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 4 ? loops[4].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 5 ? loops[5].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 6 ? loops[6].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 7 ? loops[7].id : (ccv_nnc_micro_id_t){} } }
))
628 )
629 );
630 break;
631 case CCV_NNC_MICRO_UNARY_OP_LOG:
632 statement = ccv_nnc_micro_loop_assignment(
633 ccv_nnc_micro_loop_variable_of_tensor(GRAD(self->x->id)(2 * (var_count) - 1 - (self->x->id)), loop_count, ccv_nnc_micro_index_of_loops(loops, loop_count)(ccv_nnc_micro_loop_index_term_t [(12)]){ { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 0 ? loops[0].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 1 ? loops[1].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 2 ? loops[2].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 3 ? loops[3].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 4 ? loops[4].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 5 ? loops[5].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 6 ? loops[6].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 7 ? loops[7].id : (ccv_nnc_micro_id_t){} } }
),
634 ccv_nnc_micro_loop_expression_of_binary(
635 CCV_NNC_MICRO_BINARY_OP_DIV,
636 ccv_nnc_micro_loop_expression_of_variable(ccv_nnc_micro_loop_variable_of_tensor(GRAD(self->super.id)(2 * (var_count) - 1 - (self->super.id)), loop_count, ccv_nnc_micro_index_of_loops(loops, loop_count)(ccv_nnc_micro_loop_index_term_t [(12)]){ { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 0 ? loops[0].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 1 ? loops[1].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 2 ? loops[2].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 3 ? loops[3].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 4 ? loops[4].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 5 ? loops[5].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 6 ? loops[6].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 7 ? loops[7].id : (ccv_nnc_micro_id_t){} } }
)),
637 ccv_nnc_micro_loop_expression_of_variable(ccv_nnc_micro_loop_variable_of_tensor(self->x->id, loop_count, ccv_nnc_micro_index_of_loops(loops, loop_count)(ccv_nnc_micro_loop_index_term_t [(12)]){ { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 0 ? loops[0].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 1 ? loops[1].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 2 ? loops[2].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 3 ? loops[3].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 4 ? loops[4].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 5 ? loops[5].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 6 ? loops[6].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 7 ? loops[7].id : (ccv_nnc_micro_id_t){} } }
))
638 )
639 );
640 break;
641 }
642 loops[loop_count - 1].statement_count = 1;
643 loops[loop_count - 1].statements = (ccv_nnc_micro_loop_statement_t*)ccmallocmalloc(sizeof(ccv_nnc_micro_loop_statement_t));
644 loops[loop_count - 1].statements[0] = statement;
645 return (ccv_nnc_micro_function_t){
646 .block_count = 1,
647 .one_block = {
648 .loop_count = loop_count,
649 .loops = loops
650 }
651 };
652}
653
654static ccv_nnc_micro_tensor_t _ccv_nnc_micro_unary_return_shape(const ccv_nnc_micro_io_t super)
655{
656 struct ccv_nnc_micro_io_unary_s* const self = (struct ccv_nnc_micro_io_unary_s*)super;
657 ccv_nnc_micro_tensor_t var = {};
658 var.dimensions = self->super.dimensions;
659 var.input = self->x->id;
660 var.sibling = -1;
661 return var;
662}
663
664static const ccv_nnc_micro_io_vtab_t ccv_nnc_micro_io_unary_isa = {
665 .emit = _ccv_nnc_micro_unary_emit,
666 .emit_grad = _ccv_nnc_micro_unary_emit_grad,
667 .return_shape = _ccv_nnc_micro_unary_return_shape
668};
669
670ccv_nnc_micro_io_t ccv_nnc_micro_unary(const uint32_t op, const ccv_nnc_micro_io_t x)
671{
672 struct ccv_nnc_micro_io_unary_s* const self = (struct ccv_nnc_micro_io_unary_s*)cccalloccalloc(1, sizeof(struct ccv_nnc_micro_io_unary_s));
673 self->super.isa = &ccv_nnc_micro_io_unary_isa;
674 self->super.dimensions = x->dimensions;
675 self->super.id = 0;
676 self->super.inputs = &self->x;
677 self->super.input_size = 1;
678 self->unary_op = op;
679 self->x = x;
680 return (ccv_nnc_micro_io_t)self;
681}
682
683struct ccv_nnc_micro_io_binary_s {
684 struct ccv_nnc_micro_io_s super;
685 uint32_t binary_op;
686 ccv_nnc_micro_io_t left;
687 ccv_nnc_micro_io_t right;
688};
689
690static CCV_WARN_UNUSED(ccv_nnc_micro_function_t)ccv_nnc_micro_function_t __attribute__((warn_unused_result)) _ccv_nnc_micro_binary_emit(const ccv_nnc_micro_io_t super)
691{
692 struct ccv_nnc_micro_io_binary_s* const self = (struct ccv_nnc_micro_io_binary_s*)super;
693 const int loop_count = self->super.dimensions;
694 assert(self->left->dimensions == loop_count)((void) sizeof ((self->left->dimensions == loop_count) ?
1 : 0), __extension__ ({ if (self->left->dimensions ==
loop_count) ; else __assert_fail ("self->left->dimensions == loop_count"
, "ccv_nnc_micro_core.c", 694, __extension__ __PRETTY_FUNCTION__
); }))
;
695 assert(self->right->dimensions == loop_count)((void) sizeof ((self->right->dimensions == loop_count)
? 1 : 0), __extension__ ({ if (self->right->dimensions
== loop_count) ; else __assert_fail ("self->right->dimensions == loop_count"
, "ccv_nnc_micro_core.c", 695, __extension__ __PRETTY_FUNCTION__
); }))
;
696 assert(loop_count <= CCV_NNC_MAX_DIM_ALLOC)((void) sizeof ((loop_count <= (12)) ? 1 : 0), __extension__
({ if (loop_count <= (12)) ; else __assert_fail ("loop_count <= CCV_NNC_MAX_DIM_ALLOC"
, "ccv_nnc_micro_core.c", 696, __extension__ __PRETTY_FUNCTION__
); }))
;
697 ccv_nnc_micro_loop_t* const loops = (ccv_nnc_micro_loop_t*)ccmallocmalloc(sizeof(ccv_nnc_micro_loop_t) * loop_count);
698 int i;
699 for (i = 0; i < loop_count; i++)
700 loops[i] = ccv_nnc_micro_for_in(ccv_nnc_micro_index_of_value(0), ccv_nnc_micro_index_of_axis_size(self->super.id, i), i);
701 const ccv_nnc_micro_loop_statement_t statement = ccv_nnc_micro_loop_assignment(
702 ccv_nnc_micro_loop_variable_of_tensor(self->super.id, loop_count, ccv_nnc_micro_index_of_loops(loops, loop_count)(ccv_nnc_micro_loop_index_term_t [(12)]){ { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 0 ? loops[0].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 1 ? loops[1].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 2 ? loops[2].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 3 ? loops[3].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 4 ? loops[4].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 5 ? loops[5].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 6 ? loops[6].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 7 ? loops[7].id : (ccv_nnc_micro_id_t){} } }
),
703 ccv_nnc_micro_loop_expression_of_binary(
704 self->binary_op,
705 ccv_nnc_micro_loop_expression_of_variable(ccv_nnc_micro_loop_variable_of_tensor(self->left->id, loop_count, ccv_nnc_micro_index_of_loops(loops, loop_count)(ccv_nnc_micro_loop_index_term_t [(12)]){ { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 0 ? loops[0].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 1 ? loops[1].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 2 ? loops[2].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 3 ? loops[3].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 4 ? loops[4].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 5 ? loops[5].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 6 ? loops[6].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 7 ? loops[7].id : (ccv_nnc_micro_id_t){} } }
)),
706 ccv_nnc_micro_loop_expression_of_variable(ccv_nnc_micro_loop_variable_of_tensor(self->right->id, loop_count, ccv_nnc_micro_index_of_loops(loops, loop_count)(ccv_nnc_micro_loop_index_term_t [(12)]){ { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 0 ? loops[0].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 1 ? loops[1].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 2 ? loops[2].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 3 ? loops[3].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 4 ? loops[4].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 5 ? loops[5].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 6 ? loops[6].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 7 ? loops[7].id : (ccv_nnc_micro_id_t){} } }
))
707 )
708 );
709 loops[loop_count - 1].statement_count = 1;
710 loops[loop_count - 1].statements = (ccv_nnc_micro_loop_statement_t*)ccmallocmalloc(sizeof(ccv_nnc_micro_loop_statement_t));
711 loops[loop_count - 1].statements[0] = statement;
712 return (ccv_nnc_micro_function_t){
713 .block_count = 1,
714 .one_block = {
715 .loop_count = loop_count,
716 .loops = loops
717 }
718 };
719}
720
721static CCV_WARN_UNUSED(ccv_nnc_micro_function_t)ccv_nnc_micro_function_t __attribute__((warn_unused_result)) _ccv_nnc_micro_binary_emit_grad(const ccv_nnc_micro_io_t super, const int var_count)
722{
723 struct ccv_nnc_micro_io_binary_s* const self = (struct ccv_nnc_micro_io_binary_s*)super;
724 const int loop_count = self->super.dimensions;
725 assert(self->left->dimensions == loop_count)((void) sizeof ((self->left->dimensions == loop_count) ?
1 : 0), __extension__ ({ if (self->left->dimensions ==
loop_count) ; else __assert_fail ("self->left->dimensions == loop_count"
, "ccv_nnc_micro_core.c", 725, __extension__ __PRETTY_FUNCTION__
); }))
;
726 assert(self->right->dimensions == loop_count)((void) sizeof ((self->right->dimensions == loop_count)
? 1 : 0), __extension__ ({ if (self->right->dimensions
== loop_count) ; else __assert_fail ("self->right->dimensions == loop_count"
, "ccv_nnc_micro_core.c", 726, __extension__ __PRETTY_FUNCTION__
); }))
;
727 assert(loop_count <= CCV_NNC_MAX_DIM_ALLOC)((void) sizeof ((loop_count <= (12)) ? 1 : 0), __extension__
({ if (loop_count <= (12)) ; else __assert_fail ("loop_count <= CCV_NNC_MAX_DIM_ALLOC"
, "ccv_nnc_micro_core.c", 727, __extension__ __PRETTY_FUNCTION__
); }))
;
728 int i;
729 ccv_nnc_micro_loop_t* const left_loops = (ccv_nnc_micro_loop_t*)ccmallocmalloc(sizeof(ccv_nnc_micro_loop_t) * loop_count);
730 for (i = 0; i < loop_count; i++)
731 left_loops[i] = ccv_nnc_micro_for_in(ccv_nnc_micro_index_of_value(0), ccv_nnc_micro_index_of_axis_size(GRAD(self->super.id)(2 * (var_count) - 1 - (self->super.id)), i), i);
732 ccv_nnc_micro_loop_t* const right_loops = (ccv_nnc_micro_loop_t*)ccmallocmalloc(sizeof(ccv_nnc_micro_loop_t) * loop_count);
733 for (i = 0; i < loop_count; i++)
734 right_loops[i] = ccv_nnc_micro_for_in(ccv_nnc_micro_index_of_value(0), ccv_nnc_micro_index_of_axis_size(GRAD(self->super.id)(2 * (var_count) - 1 - (self->super.id)), i), i);
735 ccv_nnc_micro_loop_statement_t left_statement;
736 ccv_nnc_micro_loop_statement_t right_statement;
737 switch (self->binary_op)
738 {
739 case CCV_NNC_MICRO_BINARY_OP_DIV:
740 left_statement = ccv_nnc_micro_loop_assignment(
741 ccv_nnc_micro_loop_variable_of_tensor(GRAD(self->left->id)(2 * (var_count) - 1 - (self->left->id)), loop_count, ccv_nnc_micro_index_of_loops(left_loops, loop_count)(ccv_nnc_micro_loop_index_term_t [(12)]){ { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 0 ? left_loops[0].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 1 ? left_loops[1].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 2 ?
left_loops[2].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 3 ? left_loops[3].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 4 ? left_loops[4].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 5 ?
left_loops[5].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 6 ? left_loops[6].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 7 ? left_loops[7].id : (ccv_nnc_micro_id_t){} } }
),
742 ccv_nnc_micro_loop_expression_of_binary(
743 CCV_NNC_MICRO_BINARY_OP_DIV,
744 ccv_nnc_micro_loop_expression_of_variable(ccv_nnc_micro_loop_variable_of_tensor(GRAD(self->super.id)(2 * (var_count) - 1 - (self->super.id)), loop_count, ccv_nnc_micro_index_of_loops(left_loops, loop_count)(ccv_nnc_micro_loop_index_term_t [(12)]){ { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 0 ? left_loops[0].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 1 ? left_loops[1].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 2 ?
left_loops[2].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 3 ? left_loops[3].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 4 ? left_loops[4].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 5 ?
left_loops[5].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 6 ? left_loops[6].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 7 ? left_loops[7].id : (ccv_nnc_micro_id_t){} } }
)),
745 ccv_nnc_micro_loop_expression_of_variable(ccv_nnc_micro_loop_variable_of_tensor(self->right->id, loop_count, ccv_nnc_micro_index_of_loops(left_loops, loop_count)(ccv_nnc_micro_loop_index_term_t [(12)]){ { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 0 ? left_loops[0].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 1 ? left_loops[1].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 2 ?
left_loops[2].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 3 ? left_loops[3].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 4 ? left_loops[4].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 5 ?
left_loops[5].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 6 ? left_loops[6].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 7 ? left_loops[7].id : (ccv_nnc_micro_id_t){} } }
))
746 )
747 );
748 right_statement = ccv_nnc_micro_loop_assignment(
749 ccv_nnc_micro_loop_variable_of_tensor(GRAD(self->right->id)(2 * (var_count) - 1 - (self->right->id)), loop_count, ccv_nnc_micro_index_of_loops(right_loops, loop_count)(ccv_nnc_micro_loop_index_term_t [(12)]){ { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 0 ? right_loops[0].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 1 ? right_loops[1].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 2 ?
right_loops[2].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 3 ? right_loops[3].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 4 ? right_loops[4].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 5 ?
right_loops[5].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 6 ? right_loops[6].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 7 ? right_loops[7].id : (ccv_nnc_micro_id_t){} } }
),
750 ccv_nnc_micro_loop_expression_of_binary(
751 CCV_NNC_MICRO_BINARY_OP_MUL,
752 ccv_nnc_micro_loop_expression_of_binary(
753 CCV_NNC_MICRO_BINARY_OP_DIV,
754 ccv_nnc_micro_loop_expression_of_variable(ccv_nnc_micro_loop_variable_of_tensor(self->super.id, loop_count, ccv_nnc_micro_index_of_loops(right_loops, loop_count)(ccv_nnc_micro_loop_index_term_t [(12)]){ { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 0 ? right_loops[0].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 1 ? right_loops[1].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 2 ?
right_loops[2].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 3 ? right_loops[3].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 4 ? right_loops[4].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 5 ?
right_loops[5].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 6 ? right_loops[6].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 7 ? right_loops[7].id : (ccv_nnc_micro_id_t){} } }
)),
755 ccv_nnc_micro_loop_expression_of_variable(ccv_nnc_micro_loop_variable_of_tensor(self->right->id, loop_count, ccv_nnc_micro_index_of_loops(right_loops, loop_count)(ccv_nnc_micro_loop_index_term_t [(12)]){ { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 0 ? right_loops[0].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 1 ? right_loops[1].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 2 ?
right_loops[2].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 3 ? right_loops[3].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 4 ? right_loops[4].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 5 ?
right_loops[5].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 6 ? right_loops[6].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 7 ? right_loops[7].id : (ccv_nnc_micro_id_t){} } }
))
756 ),
757 ccv_nnc_micro_loop_expression_of_variable(ccv_nnc_micro_loop_variable_of_tensor(GRAD(self->super.id)(2 * (var_count) - 1 - (self->super.id)), loop_count, ccv_nnc_micro_index_of_loops(right_loops, loop_count)(ccv_nnc_micro_loop_index_term_t [(12)]){ { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 0 ? right_loops[0].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 1 ? right_loops[1].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 2 ?
right_loops[2].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 3 ? right_loops[3].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 4 ? right_loops[4].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 5 ?
right_loops[5].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 6 ? right_loops[6].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 7 ? right_loops[7].id : (ccv_nnc_micro_id_t){} } }
))
758 )
759 );
760 break;
761 case CCV_NNC_MICRO_BINARY_OP_MUL:
762 left_statement = ccv_nnc_micro_loop_assignment(
763 ccv_nnc_micro_loop_variable_of_tensor(GRAD(self->left->id)(2 * (var_count) - 1 - (self->left->id)), loop_count, ccv_nnc_micro_index_of_loops(left_loops, loop_count)(ccv_nnc_micro_loop_index_term_t [(12)]){ { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 0 ? left_loops[0].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 1 ? left_loops[1].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 2 ?
left_loops[2].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 3 ? left_loops[3].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 4 ? left_loops[4].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 5 ?
left_loops[5].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 6 ? left_loops[6].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 7 ? left_loops[7].id : (ccv_nnc_micro_id_t){} } }
),
764 ccv_nnc_micro_loop_expression_of_binary(
765 CCV_NNC_MICRO_BINARY_OP_MUL,
766 ccv_nnc_micro_loop_expression_of_variable(ccv_nnc_micro_loop_variable_of_tensor(GRAD(self->super.id)(2 * (var_count) - 1 - (self->super.id)), loop_count, ccv_nnc_micro_index_of_loops(left_loops, loop_count)(ccv_nnc_micro_loop_index_term_t [(12)]){ { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 0 ? left_loops[0].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 1 ? left_loops[1].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 2 ?
left_loops[2].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 3 ? left_loops[3].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 4 ? left_loops[4].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 5 ?
left_loops[5].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 6 ? left_loops[6].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 7 ? left_loops[7].id : (ccv_nnc_micro_id_t){} } }
)),
767 ccv_nnc_micro_loop_expression_of_variable(ccv_nnc_micro_loop_variable_of_tensor(self->right->id, loop_count, ccv_nnc_micro_index_of_loops(left_loops, loop_count)(ccv_nnc_micro_loop_index_term_t [(12)]){ { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 0 ? left_loops[0].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 1 ? left_loops[1].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 2 ?
left_loops[2].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 3 ? left_loops[3].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 4 ? left_loops[4].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 5 ?
left_loops[5].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 6 ? left_loops[6].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 7 ? left_loops[7].id : (ccv_nnc_micro_id_t){} } }
))
768 )
769 );
770 right_statement = ccv_nnc_micro_loop_assignment(
771 ccv_nnc_micro_loop_variable_of_tensor(GRAD(self->right->id)(2 * (var_count) - 1 - (self->right->id)), loop_count, ccv_nnc_micro_index_of_loops(right_loops, loop_count)(ccv_nnc_micro_loop_index_term_t [(12)]){ { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 0 ? right_loops[0].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 1 ? right_loops[1].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 2 ?
right_loops[2].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 3 ? right_loops[3].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 4 ? right_loops[4].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 5 ?
right_loops[5].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 6 ? right_loops[6].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 7 ? right_loops[7].id : (ccv_nnc_micro_id_t){} } }
),
772 ccv_nnc_micro_loop_expression_of_binary(
773 CCV_NNC_MICRO_BINARY_OP_MUL,
774 ccv_nnc_micro_loop_expression_of_variable(ccv_nnc_micro_loop_variable_of_tensor(self->left->id, loop_count, ccv_nnc_micro_index_of_loops(right_loops, loop_count)(ccv_nnc_micro_loop_index_term_t [(12)]){ { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 0 ? right_loops[0].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 1 ? right_loops[1].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 2 ?
right_loops[2].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 3 ? right_loops[3].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 4 ? right_loops[4].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 5 ?
right_loops[5].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 6 ? right_loops[6].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 7 ? right_loops[7].id : (ccv_nnc_micro_id_t){} } }
)),
775 ccv_nnc_micro_loop_expression_of_variable(ccv_nnc_micro_loop_variable_of_tensor(GRAD(self->super.id)(2 * (var_count) - 1 - (self->super.id)), loop_count, ccv_nnc_micro_index_of_loops(right_loops, loop_count)(ccv_nnc_micro_loop_index_term_t [(12)]){ { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 0 ? right_loops[0].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 1 ? right_loops[1].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 2 ?
right_loops[2].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 3 ? right_loops[3].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 4 ? right_loops[4].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 5 ?
right_loops[5].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 6 ? right_loops[6].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 7 ? right_loops[7].id : (ccv_nnc_micro_id_t){} } }
))
776 )
777 );
778 break;
779 case CCV_NNC_MICRO_BINARY_OP_PLUS:
780 left_statement = ccv_nnc_micro_loop_assignment(
781 ccv_nnc_micro_loop_variable_of_tensor(GRAD(self->left->id)(2 * (var_count) - 1 - (self->left->id)), loop_count, ccv_nnc_micro_index_of_loops(left_loops, loop_count)(ccv_nnc_micro_loop_index_term_t [(12)]){ { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 0 ? left_loops[0].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 1 ? left_loops[1].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 2 ?
left_loops[2].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 3 ? left_loops[3].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 4 ? left_loops[4].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 5 ?
left_loops[5].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 6 ? left_loops[6].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 7 ? left_loops[7].id : (ccv_nnc_micro_id_t){} } }
),
782 ccv_nnc_micro_loop_expression_of_variable(ccv_nnc_micro_loop_variable_of_tensor(GRAD(self->super.id)(2 * (var_count) - 1 - (self->super.id)), loop_count, ccv_nnc_micro_index_of_loops(left_loops, loop_count)(ccv_nnc_micro_loop_index_term_t [(12)]){ { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 0 ? left_loops[0].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 1 ? left_loops[1].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 2 ?
left_loops[2].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 3 ? left_loops[3].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 4 ? left_loops[4].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 5 ?
left_loops[5].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 6 ? left_loops[6].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 7 ? left_loops[7].id : (ccv_nnc_micro_id_t){} } }
))
783 );
784 right_statement = ccv_nnc_micro_loop_assignment(
785 ccv_nnc_micro_loop_variable_of_tensor(GRAD(self->right->id)(2 * (var_count) - 1 - (self->right->id)), loop_count, ccv_nnc_micro_index_of_loops(right_loops, loop_count)(ccv_nnc_micro_loop_index_term_t [(12)]){ { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 0 ? right_loops[0].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 1 ? right_loops[1].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 2 ?
right_loops[2].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 3 ? right_loops[3].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 4 ? right_loops[4].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 5 ?
right_loops[5].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 6 ? right_loops[6].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 7 ? right_loops[7].id : (ccv_nnc_micro_id_t){} } }
),
786 ccv_nnc_micro_loop_expression_of_variable(ccv_nnc_micro_loop_variable_of_tensor(GRAD(self->super.id)(2 * (var_count) - 1 - (self->super.id)), loop_count, ccv_nnc_micro_index_of_loops(right_loops, loop_count)(ccv_nnc_micro_loop_index_term_t [(12)]){ { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 0 ? right_loops[0].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 1 ? right_loops[1].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 2 ?
right_loops[2].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 3 ? right_loops[3].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 4 ? right_loops[4].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 5 ?
right_loops[5].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 6 ? right_loops[6].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 7 ? right_loops[7].id : (ccv_nnc_micro_id_t){} } }
))
787 );
788 break;
789 case CCV_NNC_MICRO_BINARY_OP_MINUS:
790 left_statement = ccv_nnc_micro_loop_assignment(
791 ccv_nnc_micro_loop_variable_of_tensor(GRAD(self->left->id)(2 * (var_count) - 1 - (self->left->id)), loop_count, ccv_nnc_micro_index_of_loops(left_loops, loop_count)(ccv_nnc_micro_loop_index_term_t [(12)]){ { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 0 ? left_loops[0].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 1 ? left_loops[1].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 2 ?
left_loops[2].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 3 ? left_loops[3].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 4 ? left_loops[4].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 5 ?
left_loops[5].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 6 ? left_loops[6].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 7 ? left_loops[7].id : (ccv_nnc_micro_id_t){} } }
),
792 ccv_nnc_micro_loop_expression_of_variable(ccv_nnc_micro_loop_variable_of_tensor(GRAD(self->super.id)(2 * (var_count) - 1 - (self->super.id)), loop_count, ccv_nnc_micro_index_of_loops(left_loops, loop_count)(ccv_nnc_micro_loop_index_term_t [(12)]){ { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 0 ? left_loops[0].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 1 ? left_loops[1].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 2 ?
left_loops[2].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 3 ? left_loops[3].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 4 ? left_loops[4].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 5 ?
left_loops[5].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 6 ? left_loops[6].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 7 ? left_loops[7].id : (ccv_nnc_micro_id_t){} } }
))
793 );
794 right_statement = ccv_nnc_micro_loop_assignment(
795 ccv_nnc_micro_loop_variable_of_tensor(GRAD(self->right->id)(2 * (var_count) - 1 - (self->right->id)), loop_count, ccv_nnc_micro_index_of_loops(right_loops, loop_count)(ccv_nnc_micro_loop_index_term_t [(12)]){ { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 0 ? right_loops[0].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 1 ? right_loops[1].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 2 ?
right_loops[2].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 3 ? right_loops[3].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 4 ? right_loops[4].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 5 ?
right_loops[5].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 6 ? right_loops[6].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 7 ? right_loops[7].id : (ccv_nnc_micro_id_t){} } }
),
796 ccv_nnc_micro_loop_expression_of_unary(
797 CCV_NNC_MICRO_UNARY_OP_NEG,
798 ccv_nnc_micro_loop_expression_of_variable(ccv_nnc_micro_loop_variable_of_tensor(GRAD(self->super.id)(2 * (var_count) - 1 - (self->super.id)), loop_count, ccv_nnc_micro_index_of_loops(right_loops, loop_count)(ccv_nnc_micro_loop_index_term_t [(12)]){ { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 0 ? right_loops[0].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 1 ? right_loops[1].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 2 ?
right_loops[2].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 3 ? right_loops[3].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 4 ? right_loops[4].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 5 ?
right_loops[5].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 6 ? right_loops[6].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 7 ? right_loops[7].id : (ccv_nnc_micro_id_t){} } }
))
799 )
800 );
801 break;
802 case CCV_NNC_MICRO_BINARY_OP_MIN:
803 left_statement = ccv_nnc_micro_loop_assignment(
804 ccv_nnc_micro_loop_variable_of_tensor(GRAD(self->left->id)(2 * (var_count) - 1 - (self->left->id)), loop_count, ccv_nnc_micro_index_of_loops(left_loops, loop_count)(ccv_nnc_micro_loop_index_term_t [(12)]){ { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 0 ? left_loops[0].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 1 ? left_loops[1].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 2 ?
left_loops[2].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 3 ? left_loops[3].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 4 ? left_loops[4].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 5 ?
left_loops[5].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 6 ? left_loops[6].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 7 ? left_loops[7].id : (ccv_nnc_micro_id_t){} } }
),
805 ccv_nnc_micro_loop_expression_of_ternary(
806 ccv_nnc_micro_loop_expression_of_binary(CCV_NNC_MICRO_BINARY_OP_LESS_THAN,
807 ccv_nnc_micro_loop_expression_of_variable(ccv_nnc_micro_loop_variable_of_tensor(self->right->id, loop_count, ccv_nnc_micro_index_of_loops(left_loops, loop_count)(ccv_nnc_micro_loop_index_term_t [(12)]){ { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 0 ? left_loops[0].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 1 ? left_loops[1].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 2 ?
left_loops[2].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 3 ? left_loops[3].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 4 ? left_loops[4].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 5 ?
left_loops[5].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 6 ? left_loops[6].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 7 ? left_loops[7].id : (ccv_nnc_micro_id_t){} } }
)),
808 ccv_nnc_micro_loop_expression_of_variable(ccv_nnc_micro_loop_variable_of_tensor(self->left->id, loop_count, ccv_nnc_micro_index_of_loops(left_loops, loop_count)(ccv_nnc_micro_loop_index_term_t [(12)]){ { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 0 ? left_loops[0].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 1 ? left_loops[1].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 2 ?
left_loops[2].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 3 ? left_loops[3].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 4 ? left_loops[4].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 5 ?
left_loops[5].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 6 ? left_loops[6].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 7 ? left_loops[7].id : (ccv_nnc_micro_id_t){} } }
))
809 ),
810 ccv_nnc_micro_loop_expression_of_value(0),
811 ccv_nnc_micro_loop_expression_of_variable(ccv_nnc_micro_loop_variable_of_tensor(GRAD(self->super.id)(2 * (var_count) - 1 - (self->super.id)), loop_count, ccv_nnc_micro_index_of_loops(left_loops, loop_count)(ccv_nnc_micro_loop_index_term_t [(12)]){ { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 0 ? left_loops[0].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 1 ? left_loops[1].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 2 ?
left_loops[2].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 3 ? left_loops[3].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 4 ? left_loops[4].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 5 ?
left_loops[5].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 6 ? left_loops[6].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 7 ? left_loops[7].id : (ccv_nnc_micro_id_t){} } }
))
812 )
813 );
814 right_statement = ccv_nnc_micro_loop_assignment(
815 ccv_nnc_micro_loop_variable_of_tensor(GRAD(self->right->id)(2 * (var_count) - 1 - (self->right->id)), loop_count, ccv_nnc_micro_index_of_loops(right_loops, loop_count)(ccv_nnc_micro_loop_index_term_t [(12)]){ { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 0 ? right_loops[0].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 1 ? right_loops[1].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 2 ?
right_loops[2].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 3 ? right_loops[3].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 4 ? right_loops[4].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 5 ?
right_loops[5].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 6 ? right_loops[6].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 7 ? right_loops[7].id : (ccv_nnc_micro_id_t){} } }
),
816 ccv_nnc_micro_loop_expression_of_ternary(
817 ccv_nnc_micro_loop_expression_of_binary(CCV_NNC_MICRO_BINARY_OP_LESS_THAN,
818 ccv_nnc_micro_loop_expression_of_variable(ccv_nnc_micro_loop_variable_of_tensor(self->left->id, loop_count, ccv_nnc_micro_index_of_loops(right_loops, loop_count)(ccv_nnc_micro_loop_index_term_t [(12)]){ { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 0 ? right_loops[0].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 1 ? right_loops[1].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 2 ?
right_loops[2].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 3 ? right_loops[3].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 4 ? right_loops[4].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 5 ?
right_loops[5].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 6 ? right_loops[6].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 7 ? right_loops[7].id : (ccv_nnc_micro_id_t){} } }
)),
819 ccv_nnc_micro_loop_expression_of_variable(ccv_nnc_micro_loop_variable_of_tensor(self->right->id, loop_count, ccv_nnc_micro_index_of_loops(right_loops, loop_count)(ccv_nnc_micro_loop_index_term_t [(12)]){ { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 0 ? right_loops[0].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 1 ? right_loops[1].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 2 ?
right_loops[2].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 3 ? right_loops[3].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 4 ? right_loops[4].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 5 ?
right_loops[5].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 6 ? right_loops[6].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 7 ? right_loops[7].id : (ccv_nnc_micro_id_t){} } }
))
820 ),
821 ccv_nnc_micro_loop_expression_of_value(0),
822 ccv_nnc_micro_loop_expression_of_variable(ccv_nnc_micro_loop_variable_of_tensor(GRAD(self->super.id)(2 * (var_count) - 1 - (self->super.id)), loop_count, ccv_nnc_micro_index_of_loops(right_loops, loop_count)(ccv_nnc_micro_loop_index_term_t [(12)]){ { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 0 ? right_loops[0].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 1 ? right_loops[1].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 2 ?
right_loops[2].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 3 ? right_loops[3].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 4 ? right_loops[4].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 5 ?
right_loops[5].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 6 ? right_loops[6].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 7 ? right_loops[7].id : (ccv_nnc_micro_id_t){} } }
))
823 )
824 );
825 break;
826 case CCV_NNC_MICRO_BINARY_OP_MAX:
827 left_statement = ccv_nnc_micro_loop_assignment(
828 ccv_nnc_micro_loop_variable_of_tensor(GRAD(self->left->id)(2 * (var_count) - 1 - (self->left->id)), loop_count, ccv_nnc_micro_index_of_loops(left_loops, loop_count)(ccv_nnc_micro_loop_index_term_t [(12)]){ { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 0 ? left_loops[0].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 1 ? left_loops[1].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 2 ?
left_loops[2].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 3 ? left_loops[3].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 4 ? left_loops[4].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 5 ?
left_loops[5].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 6 ? left_loops[6].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 7 ? left_loops[7].id : (ccv_nnc_micro_id_t){} } }
),
829 ccv_nnc_micro_loop_expression_of_ternary(
830 ccv_nnc_micro_loop_expression_of_binary(CCV_NNC_MICRO_BINARY_OP_LESS_THAN,
831 ccv_nnc_micro_loop_expression_of_variable(ccv_nnc_micro_loop_variable_of_tensor(self->left->id, loop_count, ccv_nnc_micro_index_of_loops(left_loops, loop_count)(ccv_nnc_micro_loop_index_term_t [(12)]){ { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 0 ? left_loops[0].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 1 ? left_loops[1].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 2 ?
left_loops[2].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 3 ? left_loops[3].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 4 ? left_loops[4].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 5 ?
left_loops[5].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 6 ? left_loops[6].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 7 ? left_loops[7].id : (ccv_nnc_micro_id_t){} } }
)),
832 ccv_nnc_micro_loop_expression_of_variable(ccv_nnc_micro_loop_variable_of_tensor(self->right->id, loop_count, ccv_nnc_micro_index_of_loops(left_loops, loop_count)(ccv_nnc_micro_loop_index_term_t [(12)]){ { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 0 ? left_loops[0].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 1 ? left_loops[1].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 2 ?
left_loops[2].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 3 ? left_loops[3].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 4 ? left_loops[4].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 5 ?
left_loops[5].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 6 ? left_loops[6].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 7 ? left_loops[7].id : (ccv_nnc_micro_id_t){} } }
))
833 ),
834 ccv_nnc_micro_loop_expression_of_value(0),
835 ccv_nnc_micro_loop_expression_of_variable(ccv_nnc_micro_loop_variable_of_tensor(GRAD(self->super.id)(2 * (var_count) - 1 - (self->super.id)), loop_count, ccv_nnc_micro_index_of_loops(left_loops, loop_count)(ccv_nnc_micro_loop_index_term_t [(12)]){ { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 0 ? left_loops[0].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 1 ? left_loops[1].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 2 ?
left_loops[2].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 3 ? left_loops[3].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 4 ? left_loops[4].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 5 ?
left_loops[5].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 6 ? left_loops[6].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 7 ? left_loops[7].id : (ccv_nnc_micro_id_t){} } }
))
836 )
837 );
838 right_statement = ccv_nnc_micro_loop_assignment(
839 ccv_nnc_micro_loop_variable_of_tensor(GRAD(self->right->id)(2 * (var_count) - 1 - (self->right->id)), loop_count, ccv_nnc_micro_index_of_loops(right_loops, loop_count)(ccv_nnc_micro_loop_index_term_t [(12)]){ { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 0 ? right_loops[0].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 1 ? right_loops[1].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 2 ?
right_loops[2].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 3 ? right_loops[3].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 4 ? right_loops[4].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 5 ?
right_loops[5].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 6 ? right_loops[6].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 7 ? right_loops[7].id : (ccv_nnc_micro_id_t){} } }
),
840 ccv_nnc_micro_loop_expression_of_ternary(
841 ccv_nnc_micro_loop_expression_of_binary(CCV_NNC_MICRO_BINARY_OP_LESS_THAN,
842 ccv_nnc_micro_loop_expression_of_variable(ccv_nnc_micro_loop_variable_of_tensor(self->right->id, loop_count, ccv_nnc_micro_index_of_loops(right_loops, loop_count)(ccv_nnc_micro_loop_index_term_t [(12)]){ { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 0 ? right_loops[0].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 1 ? right_loops[1].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 2 ?
right_loops[2].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 3 ? right_loops[3].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 4 ? right_loops[4].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 5 ?
right_loops[5].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 6 ? right_loops[6].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 7 ? right_loops[7].id : (ccv_nnc_micro_id_t){} } }
)),
843 ccv_nnc_micro_loop_expression_of_variable(ccv_nnc_micro_loop_variable_of_tensor(self->left->id, loop_count, ccv_nnc_micro_index_of_loops(right_loops, loop_count)(ccv_nnc_micro_loop_index_term_t [(12)]){ { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 0 ? right_loops[0].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 1 ? right_loops[1].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 2 ?
right_loops[2].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 3 ? right_loops[3].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 4 ? right_loops[4].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 5 ?
right_loops[5].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 6 ? right_loops[6].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 7 ? right_loops[7].id : (ccv_nnc_micro_id_t){} } }
))
844 ),
845 ccv_nnc_micro_loop_expression_of_value(0),
846 ccv_nnc_micro_loop_expression_of_variable(ccv_nnc_micro_loop_variable_of_tensor(GRAD(self->super.id)(2 * (var_count) - 1 - (self->super.id)), loop_count, ccv_nnc_micro_index_of_loops(right_loops, loop_count)(ccv_nnc_micro_loop_index_term_t [(12)]){ { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 0 ? right_loops[0].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 1 ? right_loops[1].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 2 ?
right_loops[2].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 3 ? right_loops[3].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 4 ? right_loops[4].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 5 ?
right_loops[5].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 6 ? right_loops[6].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 7 ? right_loops[7].id : (ccv_nnc_micro_id_t){} } }
))
847 )
848 );
849 break;
850 }
851 left_loops[loop_count - 1].statement_count = 1;
852 left_loops[loop_count - 1].statements = (ccv_nnc_micro_loop_statement_t*)ccmallocmalloc(sizeof(ccv_nnc_micro_loop_statement_t));
853 left_loops[loop_count - 1].statements[0] = left_statement;
854 right_loops[loop_count - 1].statement_count = 1;
855 right_loops[loop_count - 1].statements = (ccv_nnc_micro_loop_statement_t*)ccmallocmalloc(sizeof(ccv_nnc_micro_loop_statement_t));
856 right_loops[loop_count - 1].statements[0] = right_statement;
857 ccv_nnc_micro_loop_block_t* const blocks = (ccv_nnc_micro_loop_block_t*)ccmallocmalloc(sizeof(ccv_nnc_micro_loop_block_t) * 2);
858 blocks[0] = (ccv_nnc_micro_loop_block_t){
859 .loop_count = loop_count,
860 .loops = left_loops
861 };
862 blocks[1] = (ccv_nnc_micro_loop_block_t){
863 .loop_count = loop_count,
864 .loops = right_loops
865 };
866 return (ccv_nnc_micro_function_t){
867 .block_count = 2,
868 .blocks = blocks
869 };
870}
871
872static ccv_nnc_micro_tensor_t _ccv_nnc_micro_binary_return_shape(const ccv_nnc_micro_io_t super)
873{
874 struct ccv_nnc_micro_io_binary_s* const self = (struct ccv_nnc_micro_io_binary_s*)super;
875 ccv_nnc_micro_tensor_t var = {};
876 var.dimensions = self->super.dimensions;
877 var.input = self->left->id;
878 var.sibling = self->right->id;
879 return var;
880}
881
882static const ccv_nnc_micro_io_vtab_t ccv_nnc_micro_io_binary_isa = {
883 .emit = _ccv_nnc_micro_binary_emit,
884 .emit_grad = _ccv_nnc_micro_binary_emit_grad,
885 .return_shape = _ccv_nnc_micro_binary_return_shape
886};
887
888ccv_nnc_micro_io_t ccv_nnc_micro_binary(const uint32_t op, const ccv_nnc_micro_io_t x, const ccv_nnc_micro_io_t y)
889{
890 struct ccv_nnc_micro_io_binary_s* const self = (struct ccv_nnc_micro_io_binary_s*)cccalloccalloc(1, sizeof(struct ccv_nnc_micro_io_binary_s));
891 self->super.isa = &ccv_nnc_micro_io_binary_isa;
892 self->super.dimensions = x->dimensions;
893 self->super.id = 0;
894 self->super.inputs = &self->left;
895 self->super.input_size = 2;
896 self->binary_op = op;
897 self->left = x;
898 self->right = y;
899 assert(x->dimensions == y->dimensions)((void) sizeof ((x->dimensions == y->dimensions) ? 1 : 0
), __extension__ ({ if (x->dimensions == y->dimensions)
; else __assert_fail ("x->dimensions == y->dimensions"
, "ccv_nnc_micro_core.c", 899, __extension__ __PRETTY_FUNCTION__
); }))
;
900 return (ccv_nnc_micro_io_t)self;
901}
902
903struct ccv_nnc_micro_io_reduce_s {
904 struct ccv_nnc_micro_io_s super;
905 uint32_t reduce_op;
906 int axis_count;
907 ccv_nnc_micro_io_t x;
908 int axis[1];
909};
910
911static CCV_WARN_UNUSED(ccv_nnc_micro_function_t)ccv_nnc_micro_function_t __attribute__((warn_unused_result)) _ccv_nnc_micro_reduce_emit(const ccv_nnc_micro_io_t super)
912{
913 struct ccv_nnc_micro_io_reduce_s* const self = (struct ccv_nnc_micro_io_reduce_s*)super;
914 const int loop_count = self->super.dimensions;
915 assert(self->x->dimensions == loop_count)((void) sizeof ((self->x->dimensions == loop_count) ? 1
: 0), __extension__ ({ if (self->x->dimensions == loop_count
) ; else __assert_fail ("self->x->dimensions == loop_count"
, "ccv_nnc_micro_core.c", 915, __extension__ __PRETTY_FUNCTION__
); }))
;
916 // If axis_count == loop_count, we need extra loop to reduce.
917 int has_extra_loop = (self->axis_count == loop_count);
918 ccv_nnc_micro_loop_t* const loops = (ccv_nnc_micro_loop_t*)ccmallocmalloc(sizeof(ccv_nnc_micro_loop_t) * (loop_count + has_extra_loop));
919 int i, j, k;
920 int8_t reduce_axis[loop_count];
921 memset(reduce_axis, 0, sizeof(int8_t) * loop_count);
922 for (i = 0; i < self->axis_count; i++)
923 reduce_axis[self->axis[i]] = 1;
924 j = 0;
925 // If loop_count == reduce_axis_count, we have extra loop for carried variables and blocks.
926 if (has_extra_loop)
927 {
928 loops[0] = ccv_nnc_micro_for_in(ccv_nnc_micro_index_of_value(0), ccv_nnc_micro_index_of_value(1), 0);
929 k = 1;
930 } else
931 k = loop_count - self->axis_count;
932 for (i = 0; i < loop_count; i++)
933 if (reduce_axis[i])
934 {
935 loops[k] = ccv_nnc_micro_for_in(ccv_nnc_micro_index_of_value(0), ccv_nnc_micro_index_of_axis_size(self->x->id, i), i + has_extra_loop);
936 ++k;
937 } else {
938 loops[j] = ccv_nnc_micro_for_in(ccv_nnc_micro_index_of_value(0), ccv_nnc_micro_index_of_axis_size(self->x->id, i), i + has_extra_loop);
939 ++j;
940 }
941 const int carried_loop_idx = has_extra_loop ? 0 : loop_count - self->axis_count - 1;
942 loops[carried_loop_idx].carried_count = 1;
943 loops[carried_loop_idx].carrieds = (ccv_nnc_micro_loop_carried_t*)ccmallocmalloc(sizeof(ccv_nnc_micro_loop_carried_t));
944 loops[carried_loop_idx].carrieds[0] = ccv_nnc_micro_loop_carried(self->reduce_op, 0);
945 j = 0;
946 k = has_extra_loop ? 1 : loop_count - self->axis_count;
947 // If loop_count == reduce_axis_count, we have extra loop for carrieds and block.
948 ccv_nnc_micro_loop_index_term_t index[CCV_NNC_MAX_DIM_ALLOC(12)];
949 for (i = 0; i < loop_count; i++)
950 if (reduce_axis[i])
951 {
952 index[i] = ccv_nnc_micro_index_of_id(loops[k].id);
953 ++k;
954 } else {
955 index[i] = ccv_nnc_micro_index_of_id(loops[j].id);
956 ++j;
957 }
958 ccv_nnc_micro_loop_statement_t statement = ccv_nnc_micro_loop_compound_assignment_of_id(
959 loops[carried_loop_idx].carrieds[0].id,
960 ccv_nnc_micro_loop_expression_of_variable(ccv_nnc_micro_loop_variable_of_tensor(self->x->id, loop_count, index))
961 );
962 loops[carried_loop_idx + self->axis_count].statement_count = 1;
963 loops[carried_loop_idx + self->axis_count].statements = (ccv_nnc_micro_loop_statement_t*)ccmallocmalloc(sizeof(ccv_nnc_micro_loop_statement_t));
964 loops[carried_loop_idx + self->axis_count].statements[0] = statement;
965 j = 0;
966 for (i = 0; i < loop_count; i++)
967 if (reduce_axis[i])
968 index[i] = ccv_nnc_micro_index_of_value(0);
969 else {
970 index[i] = ccv_nnc_micro_index_of_id(loops[j].id);
971 ++j;
972 }
973 statement = ccv_nnc_micro_loop_assignment(
974 ccv_nnc_micro_loop_variable_of_tensor(self->super.id, loop_count, index),
975 ccv_nnc_micro_loop_expression_of_id(loops[carried_loop_idx].carrieds[0].id)
976 );
977 loops[carried_loop_idx].statement_count = 1;
978 loops[carried_loop_idx].statements = (ccv_nnc_micro_loop_statement_t*)ccmallocmalloc(sizeof(ccv_nnc_micro_loop_statement_t));
979 loops[carried_loop_idx].statements[0] = statement;
980 return (ccv_nnc_micro_function_t){
981 .block_count = 1,
982 .one_block = {
983 .carried_count = 1,
984 .loop_count = loop_count + has_extra_loop,
985 .loops = loops
986 }
987 };
988}
989
990static CCV_WARN_UNUSED(ccv_nnc_micro_function_t)ccv_nnc_micro_function_t __attribute__((warn_unused_result)) _ccv_nnc_micro_reduce_emit_grad(const ccv_nnc_micro_io_t super, const int var_count)
991{
992 struct ccv_nnc_micro_io_reduce_s* const self = (struct ccv_nnc_micro_io_reduce_s*)super;
993 assert(self->reduce_op == CCV_NNC_MICRO_REDUCE_OP_SUM)((void) sizeof ((self->reduce_op == CCV_NNC_MICRO_REDUCE_OP_SUM
) ? 1 : 0), __extension__ ({ if (self->reduce_op == CCV_NNC_MICRO_REDUCE_OP_SUM
) ; else __assert_fail ("self->reduce_op == CCV_NNC_MICRO_REDUCE_OP_SUM"
, "ccv_nnc_micro_core.c", 993, __extension__ __PRETTY_FUNCTION__
); }))
; // I haven't figure out how to do mean without add additional opcode.
994 const int loop_count = self->super.dimensions;
995 assert(self->x->dimensions == loop_count)((void) sizeof ((self->x->dimensions == loop_count) ? 1
: 0), __extension__ ({ if (self->x->dimensions == loop_count
) ; else __assert_fail ("self->x->dimensions == loop_count"
, "ccv_nnc_micro_core.c", 995, __extension__ __PRETTY_FUNCTION__
); }))
;
996 ccv_nnc_micro_loop_t* const loops = (ccv_nnc_micro_loop_t*)ccmallocmalloc(sizeof(ccv_nnc_micro_loop_t) * loop_count);
997 int i, j, k;
998 int8_t reduce_axis[loop_count];
999 memset(reduce_axis, 0, sizeof(int8_t) * loop_count);
1000 for (i = 0; i < self->axis_count; i++)
1001 reduce_axis[self->axis[i]] = 1;
1002 j = 0;
1003 k = loop_count - self->axis_count;
1004 for (i = 0; i < loop_count; i++)
1005 if (reduce_axis[i])
1006 {
1007 loops[k] = ccv_nnc_micro_for_in(ccv_nnc_micro_index_of_value(0), ccv_nnc_micro_index_of_axis_size(GRAD(self->x->id)(2 * (var_count) - 1 - (self->x->id)), i), i);
1008 ++k;
1009 } else {
1010 loops[j] = ccv_nnc_micro_for_in(ccv_nnc_micro_index_of_value(0), ccv_nnc_micro_index_of_axis_size(GRAD(self->x->id)(2 * (var_count) - 1 - (self->x->id)), i), i);
1011 ++j;
1012 }
1013 j = 0;
1014 k = loop_count - self->axis_count;
1015 // If loop_count == reduce_axis_count, we have extra loop for carrieds and block.
1016 ccv_nnc_micro_loop_index_term_t index[CCV_NNC_MAX_DIM_ALLOC(12)];
1017 for (i = 0; i < loop_count; i++)
1018 if (reduce_axis[i])
1019 {
1020 index[i] = ccv_nnc_micro_index_of_id(loops[k].id);
1021 ++k;
1022 } else {
1023 index[i] = ccv_nnc_micro_index_of_id(loops[j].id);
1024 ++j;
1025 }
1026 j = 0;
1027 ccv_nnc_micro_loop_index_term_t reduced_index[CCV_NNC_MAX_DIM_ALLOC(12)];
1028 for (i = 0; i < loop_count; i++)
1029 if (reduce_axis[i])
1030 reduced_index[i] = ccv_nnc_micro_index_of_value(0);
1031 else {
1032 reduced_index[i] = ccv_nnc_micro_index_of_id(loops[j].id);
1033 ++j;
1034 }
1035 ccv_nnc_micro_loop_statement_t statement = ccv_nnc_micro_loop_assignment(
1036 ccv_nnc_micro_loop_variable_of_tensor(GRAD(self->x->id)(2 * (var_count) - 1 - (self->x->id)), loop_count, index),
1037 ccv_nnc_micro_loop_expression_of_variable(ccv_nnc_micro_loop_variable_of_tensor(GRAD(self->super.id)(2 * (var_count) - 1 - (self->super.id)), loop_count, reduced_index))
1038 );
1039 loops[loop_count - 1].statement_count = 1;
1040 loops[loop_count - 1].statements = (ccv_nnc_micro_loop_statement_t*)ccmallocmalloc(sizeof(ccv_nnc_micro_loop_statement_t));
1041 loops[loop_count - 1].statements[0] = statement;
1042 return (ccv_nnc_micro_function_t){
1043 .block_count = 1,
1044 .one_block = {
1045 .carried_count = 1,
1046 .loop_count = loop_count,
1047 .loops = loops
1048 }
1049 };
1050}
1051
1052static ccv_nnc_micro_tensor_t _ccv_nnc_micro_reduce_return_shape(const ccv_nnc_micro_io_t super)
1053{
1054 struct ccv_nnc_micro_io_reduce_s* const self = (struct ccv_nnc_micro_io_reduce_s*)super;
1055 ccv_nnc_micro_tensor_t var = {};
1056 var.dimensions = self->super.dimensions;
1057 var.input = self->x->id;
1058 var.sibling = -1;
1059 var.shape = (ccv_nnc_micro_loop_index_term_t*)ccmallocmalloc(sizeof(ccv_nnc_micro_loop_index_term_t) * self->super.dimensions);
1060 int i;
1061 for (i = 0; i < self->super.dimensions; i++)
1062 var.shape[i] = ccv_nnc_micro_index_of_axis_size(self->x->id, i);
1063 for (i = 0; i < self->axis_count; i++)
1064 var.shape[self->axis[i]] = ccv_nnc_micro_index_of_value(1);
1065 return var;
1066}
1067
1068static const ccv_nnc_micro_io_vtab_t ccv_nnc_micro_io_reduce_isa = {
1069 .emit = _ccv_nnc_micro_reduce_emit,
1070 .emit_grad = _ccv_nnc_micro_reduce_emit_grad,
1071 .return_shape = _ccv_nnc_micro_reduce_return_shape
1072};
1073
1074ccv_nnc_micro_io_t ccv_nnc_micro_reduce(const uint8_t op, const int* const axis, const int axis_count, const ccv_nnc_micro_io_t x)
1075{
1076 struct ccv_nnc_micro_io_reduce_s* const self = (struct ccv_nnc_micro_io_reduce_s*)cccalloccalloc(1, sizeof(struct ccv_nnc_micro_io_reduce_s) + sizeof(int) * (axis_count - 1));
1077 self->super.isa = &ccv_nnc_micro_io_reduce_isa;
1078 self->super.dimensions = x->dimensions;
1079 self->super.id = 0;
1080 self->super.inputs = &self->x;
1081 self->super.input_size = 1;
1082 self->reduce_op = op;
1083 self->x = x;
1084 self->axis_count = axis_count;
1085 assert(axis_count <= x->dimensions)((void) sizeof ((axis_count <= x->dimensions) ? 1 : 0),
__extension__ ({ if (axis_count <= x->dimensions) ; else
__assert_fail ("axis_count <= x->dimensions", "ccv_nnc_micro_core.c"
, 1085, __extension__ __PRETTY_FUNCTION__); }))
;
1086 int i;
1087 for (i = 0; i < axis_count; i++)
1088 { assert(axis[i] < x->dimensions)((void) sizeof ((axis[i] < x->dimensions) ? 1 : 0), __extension__
({ if (axis[i] < x->dimensions) ; else __assert_fail (
"axis[i] < x->dimensions", "ccv_nnc_micro_core.c", 1088
, __extension__ __PRETTY_FUNCTION__); }))
; }
1089 memcpy(self->axis, axis, sizeof(int) * axis_count);
1090 return (ccv_nnc_micro_io_t)self;
1091}
1092
1093struct ccv_nnc_micro_io_select_s {
1094 struct ccv_nnc_micro_io_s super;
1095 int axis;
1096 ccv_nnc_micro_io_t x;
1097 ccv_nnc_micro_io_t index;
1098};
1099
1100static CCV_WARN_UNUSED(ccv_nnc_micro_function_t)ccv_nnc_micro_function_t __attribute__((warn_unused_result)) _ccv_nnc_micro_select_emit(const ccv_nnc_micro_io_t super)
1101{
1102 struct ccv_nnc_micro_io_select_s* const self = (struct ccv_nnc_micro_io_select_s*)super;
1103 const int loop_count = self->super.dimensions;
1104 assert(self->x->dimensions == loop_count)((void) sizeof ((self->x->dimensions == loop_count) ? 1
: 0), __extension__ ({ if (self->x->dimensions == loop_count
) ; else __assert_fail ("self->x->dimensions == loop_count"
, "ccv_nnc_micro_core.c", 1104, __extension__ __PRETTY_FUNCTION__
); }))
;
1105 assert(self->index->dimensions == loop_count)((void) sizeof ((self->index->dimensions == loop_count)
? 1 : 0), __extension__ ({ if (self->index->dimensions
== loop_count) ; else __assert_fail ("self->index->dimensions == loop_count"
, "ccv_nnc_micro_core.c", 1105, __extension__ __PRETTY_FUNCTION__
); }))
;
1106 ccv_nnc_micro_loop_t* const loops = (ccv_nnc_micro_loop_t*)ccmallocmalloc(sizeof(ccv_nnc_micro_loop_t) * loop_count);
1107 int i;
1108 for (i = 0; i < loop_count; i++)
1109 {
1110 if (i == self->axis)
1111 loops[i] = ccv_nnc_micro_for_in(ccv_nnc_micro_index_of_value(0), ccv_nnc_micro_index_of_value(1), i);
1112 else
1113 loops[i] = ccv_nnc_micro_for_in(ccv_nnc_micro_index_of_value(0), ccv_nnc_micro_index_of_axis_size(self->super.id, i), i);
1114 }
1115 ccv_nnc_micro_loop_index_term_t index[CCV_NNC_MAX_DIM_ALLOC(12)];
1116 for (i = 0; i < loop_count; i++)
1117 {
1118 if (i == self->axis)
1119 index[i] = ccv_nnc_micro_index_of_id(ccv_nnc_micro_id_of_tensor(self->index->id));
1120 else
1121 index[i] = ccv_nnc_micro_index_of_id(loops[i].id);
1122 }
1123 const ccv_nnc_micro_loop_statement_t statement = ccv_nnc_micro_loop_assignment(
1124 ccv_nnc_micro_loop_variable_of_tensor(self->super.id, loop_count, ccv_nnc_micro_index_of_loops(loops, loop_count)(ccv_nnc_micro_loop_index_term_t [(12)]){ { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 0 ? loops[0].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 1 ? loops[1].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 2 ? loops[2].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 3 ? loops[3].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 4 ? loops[4].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 5 ? loops[5].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 6 ? loops[6].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 7 ? loops[7].id : (ccv_nnc_micro_id_t){} } }
),
1125 ccv_nnc_micro_loop_expression_of_variable(ccv_nnc_micro_loop_variable_of_tensor(self->x->id, loop_count, index))
1126 );
1127 loops[loop_count - 1].statement_count = 1;
1128 loops[loop_count - 1].statements = (ccv_nnc_micro_loop_statement_t*)ccmallocmalloc(sizeof(ccv_nnc_micro_loop_statement_t));
1129 loops[loop_count - 1].statements[0] = statement;
1130 return (ccv_nnc_micro_function_t){
1131 .block_count = 1,
1132 .one_block = {
1133 .loop_count = loop_count,
1134 .loops = loops
1135 }
1136 };
1137}
1138
1139static CCV_WARN_UNUSED(ccv_nnc_micro_function_t)ccv_nnc_micro_function_t __attribute__((warn_unused_result)) _ccv_nnc_micro_select_emit_grad(const ccv_nnc_micro_io_t super, const int var_count)
1140{
1141 struct ccv_nnc_micro_io_select_s* const self = (struct ccv_nnc_micro_io_select_s*)super;
1142 const int loop_count = self->super.dimensions;
1143 assert(self->x->dimensions == loop_count)((void) sizeof ((self->x->dimensions == loop_count) ? 1
: 0), __extension__ ({ if (self->x->dimensions == loop_count
) ; else __assert_fail ("self->x->dimensions == loop_count"
, "ccv_nnc_micro_core.c", 1143, __extension__ __PRETTY_FUNCTION__
); }))
;
1144 assert(self->index->dimensions == loop_count)((void) sizeof ((self->index->dimensions == loop_count)
? 1 : 0), __extension__ ({ if (self->index->dimensions
== loop_count) ; else __assert_fail ("self->index->dimensions == loop_count"
, "ccv_nnc_micro_core.c", 1144, __extension__ __PRETTY_FUNCTION__
); }))
;
1145 ccv_nnc_micro_loop_t* const reset_loops = (ccv_nnc_micro_loop_t*)ccmallocmalloc(sizeof(ccv_nnc_micro_loop_t) * loop_count);
1146 int i;
1147 for (i = 0; i < loop_count; i++)
1148 reset_loops[i] = ccv_nnc_micro_for_in(ccv_nnc_micro_index_of_value(0), ccv_nnc_micro_index_of_axis_size(GRAD(self->x->id)(2 * (var_count) - 1 - (self->x->id)), i), i);
1149 const ccv_nnc_micro_loop_statement_t reset_statement = ccv_nnc_micro_loop_assignment(
1150 ccv_nnc_micro_loop_variable_of_tensor(GRAD(self->x->id)(2 * (var_count) - 1 - (self->x->id)), loop_count, ccv_nnc_micro_index_of_loops(reset_loops, loop_count)(ccv_nnc_micro_loop_index_term_t [(12)]){ { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 0 ? reset_loops[0].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 1 ? reset_loops[1].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 2 ?
reset_loops[2].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 3 ? reset_loops[3].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 4 ? reset_loops[4].id : (ccv_nnc_micro_id_t){} }, { .type
= CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count > 5 ?
reset_loops[5].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 6 ? reset_loops[6].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 7 ? reset_loops[7].id : (ccv_nnc_micro_id_t){} } }
),
1151 ccv_nnc_micro_loop_expression_of_value(0)
1152 );
1153 reset_loops[loop_count - 1].statement_count = 1;
1154 reset_loops[loop_count - 1].statements = (ccv_nnc_micro_loop_statement_t*)ccmallocmalloc(sizeof(ccv_nnc_micro_loop_statement_t));
1155 reset_loops[loop_count - 1].statements[0] = reset_statement;
1156 ccv_nnc_micro_loop_t* const loops = (ccv_nnc_micro_loop_t*)ccmallocmalloc(sizeof(ccv_nnc_micro_loop_t) * loop_count);
1157 for (i = 0; i < loop_count; i++)
1158 loops[i] = ccv_nnc_micro_for_in(ccv_nnc_micro_index_of_value(0), ccv_nnc_micro_index_of_axis_size(GRAD(self->x->id)(2 * (var_count) - 1 - (self->x->id)), i), i);
1159 ccv_nnc_micro_loop_index_term_t index[CCV_NNC_MAX_DIM_ALLOC(12)];
1160 for (i = 0; i < loop_count; i++)
1161 {
1162 if (i == self->axis)
1163 index[i] = ccv_nnc_micro_index_of_id(ccv_nnc_micro_id_of_tensor(self->index->id));
1164 else
1165 index[i] = ccv_nnc_micro_index_of_id(loops[i].id);
1166 }
1167 // This is only for x, nothing for index.
1168 const ccv_nnc_micro_loop_statement_t statement = ccv_nnc_micro_loop_compound_assignment_of_tensor(
1169 ccv_nnc_micro_loop_variable_of_tensor(GRAD(self->x->id)(2 * (var_count) - 1 - (self->x->id)), loop_count, index),
1170 ccv_nnc_micro_loop_expression_of_variable(ccv_nnc_micro_loop_variable_of_tensor(GRAD(self->super.id)(2 * (var_count) - 1 - (self->super.id)), loop_count, ccv_nnc_micro_index_of_loops(loops, loop_count)(ccv_nnc_micro_loop_index_term_t [(12)]){ { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 0 ? loops[0].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 1 ? loops[1].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 2 ? loops[2].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 3 ? loops[3].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 4 ? loops[4].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 5 ? loops[5].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = loop_count > 6 ? loops[6].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = loop_count
> 7 ? loops[7].id : (ccv_nnc_micro_id_t){} } }
))
1171 );
1172 loops[loop_count - 1].statement_count = 1;
1173 loops[loop_count - 1].statements = (ccv_nnc_micro_loop_statement_t*)ccmallocmalloc(sizeof(ccv_nnc_micro_loop_statement_t));
1174 loops[loop_count - 1].statements[0] = statement;
1175 ccv_nnc_micro_loop_block_t* const blocks = (ccv_nnc_micro_loop_block_t*)ccmallocmalloc(sizeof(ccv_nnc_micro_loop_block_t) * 2);
1176 blocks[0] = (ccv_nnc_micro_loop_block_t){
1177 .loop_count = loop_count,
1178 .loops = reset_loops
1179 };
1180 blocks[1] = (ccv_nnc_micro_loop_block_t){
1181 .loop_count = loop_count,
1182 .loops = loops
1183 };
1184 return (ccv_nnc_micro_function_t){
1185 .block_count = 2,
1186 .blocks = blocks
1187 };
1188}
1189
1190static ccv_nnc_micro_tensor_t _ccv_nnc_micro_select_return_shape(const ccv_nnc_micro_io_t super)
1191{
1192 struct ccv_nnc_micro_io_select_s* const self = (struct ccv_nnc_micro_io_select_s*)super;
1193 ccv_nnc_micro_tensor_t var = {};
1194 var.dimensions = self->super.dimensions;
1195 var.input = self->x->id;
1196 var.sibling = -1;
1197 var.shape = (ccv_nnc_micro_loop_index_term_t*)ccmallocmalloc(sizeof(ccv_nnc_micro_loop_index_term_t) * self->super.dimensions);
1198 int i;
1199 for (i = 0; i < self->super.dimensions; i++)
1200 {
1201 if (i != self->axis)
1202 var.shape[i] = ccv_nnc_micro_index_of_axis_size(self->x->id, i);
1203 else
1204 var.shape[i] = ccv_nnc_micro_index_of_value(1);
1205 }
1206 return var;
1207}
1208
1209static const ccv_nnc_micro_io_vtab_t ccv_nnc_micro_io_select_isa = {
1210 .emit = _ccv_nnc_micro_select_emit,
1211 .emit_grad = _ccv_nnc_micro_select_emit_grad,
1212 .return_shape = _ccv_nnc_micro_select_return_shape
1213};
1214
1215ccv_nnc_micro_io_t ccv_nnc_micro_select(const int axis, const ccv_nnc_micro_io_t x, const ccv_nnc_micro_io_t index)
1216{
1217 struct ccv_nnc_micro_io_select_s* const self = (struct ccv_nnc_micro_io_select_s*)cccalloccalloc(1, sizeof(struct ccv_nnc_micro_io_select_s));
1218 self->super.isa = &ccv_nnc_micro_io_select_isa;
1219 self->super.dimensions = x->dimensions;
1220 self->super.id = 0;
1221 self->super.inputs = &self->x;
1222 self->super.input_size = 2;
1223 self->x = x;
1224 self->index = index;
1225 self->axis = axis;
1226 assert(axis <= CCV_NNC_MAX_DIM_ALLOC)((void) sizeof ((axis <= (12)) ? 1 : 0), __extension__ ({ if
(axis <= (12)) ; else __assert_fail ("axis <= CCV_NNC_MAX_DIM_ALLOC"
, "ccv_nnc_micro_core.c", 1226, __extension__ __PRETTY_FUNCTION__
); }))
;
1227 return (ccv_nnc_micro_io_t)self;
1228}

./_ccv_nnc_micro.h

1/**********************************************************
2 * C-based/Cached/Core Computer Vision Library
3 * Liu Liu, 2010-02-01
4 **********************************************************/
5
6/**********************************************************
7 * CCV - Neural Network Collection
8 **********************************************************/
9
10#ifndef GUARD_ccv_nnc_micro_internal_h
11#define GUARD_ccv_nnc_micro_internal_h
12
13#include "ccv_nnc.h"
14
15enum {
16 CCV_NNC_MICRO_LOOP_ID,
17 CCV_NNC_MICRO_LOOP_CARRIED_ID,
18 CCV_NNC_MICRO_AXIS_SIZE_ID,
19 CCV_NNC_MICRO_TENSOR_ID,
20 CCV_NNC_MICRO_SCALAR_ID,
21};
22
23typedef struct {
24 uint8_t type;
25 uint8_t d; // Only used for axis_size, identify which axis for a tensor.
26 int16_t id;
27} ccv_nnc_micro_id_t;
28
29typedef struct {
30 ccv_nnc_micro_id_t left;
31 ccv_nnc_micro_id_t right;
32} ccv_nnc_micro_id_equal_assertion_t;
33
34enum {
35 CCV_NNC_MICRO_LOOP_INDEX_TYPE_NONE,
36 CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID,
37 CCV_NNC_MICRO_LOOP_INDEX_TYPE_VAL,
38 CCV_NNC_MICRO_LOOP_INDEX_TYPE_BINARY,
39 CCV_NNC_MICRO_LOOP_INDEX_TYPE_UNBOUND_SCALAR, // Unbounded scalar variable, shouldn't be there after fully-evaluated.
40};
41
42typedef struct ccv_nnc_micro_loop_index_binary_s ccv_nnc_micro_loop_index_binary_t;
43
44typedef struct {
45 int type;
46 union {
47 char* name; // binding variable name.
48 ccv_nnc_micro_id_t id;
49 int immediate_value;
50 ccv_nnc_micro_loop_index_binary_t* binary;
51 };
52} ccv_nnc_micro_loop_index_term_t;
53
54struct ccv_nnc_micro_loop_index_binary_s {
55 int op;
56 ccv_nnc_micro_loop_index_term_t left;
57 ccv_nnc_micro_loop_index_term_t right;
58};
59
60typedef struct {
61 ccv_nnc_micro_id_t id;
62 int index_count;
63 int no_check_bound[CCV_NNC_MAX_DIM_ALLOC(12)];
64 ccv_nnc_micro_loop_index_term_t index[CCV_NNC_MAX_DIM_ALLOC(12)];
65} ccv_nnc_micro_loop_variable_t;
66
67enum {
68 CCV_NNC_MICRO_LOOP_EXPR_TYPE_ID,
69 CCV_NNC_MICRO_LOOP_EXPR_TYPE_VAL,
70 CCV_NNC_MICRO_LOOP_EXPR_TYPE_VAR,
71 CCV_NNC_MICRO_LOOP_EXPR_TYPE_UNARY,
72 CCV_NNC_MICRO_LOOP_EXPR_TYPE_BINARY,
73 CCV_NNC_MICRO_LOOP_EXPR_TYPE_TERNAY,
74};
75
76typedef struct ccv_nnc_micro_loop_expression_s ccv_nnc_micro_loop_expression_t;
77
78typedef struct {
79 int unary_op;
80 ccv_nnc_micro_loop_expression_t* x;
81} ccv_nnc_micro_loop_unary_t;
82
83typedef struct {
84 int binary_op;
85 ccv_nnc_micro_loop_expression_t* left;
86 ccv_nnc_micro_loop_expression_t* right;
87} ccv_nnc_micro_loop_binary_t;
88
89typedef struct {
90 ccv_nnc_micro_loop_expression_t* pivot; // If it is 0, choose left, otherwise choose right.
91 ccv_nnc_micro_loop_expression_t* left;
92 ccv_nnc_micro_loop_expression_t* right;
93} ccv_nnc_micro_loop_ternary_t;
94
95struct ccv_nnc_micro_loop_expression_s {
96 int type;
97 union {
98 ccv_nnc_micro_id_t id; // If this is a compound assignment, the id to that.
99 ccv_nnc_micro_scalar_t immediate_value;
100 ccv_nnc_micro_loop_variable_t variable;
101 ccv_nnc_micro_loop_unary_t unary;
102 ccv_nnc_micro_loop_binary_t binary;
103 ccv_nnc_micro_loop_ternary_t ternary;
104 };
105};
106
107typedef struct {
108 ccv_nnc_micro_loop_variable_t lvalue;
109 ccv_nnc_micro_loop_expression_t rvalue;
110} ccv_nnc_micro_loop_assignment_t;
111
112
113typedef struct {
114 int type;
115 union {
116 ccv_nnc_micro_id_t id; // If this is a compound assignment, the id to that.
117 ccv_nnc_micro_loop_variable_t variable; // This only implies PLUS at the moment.
118 };
119} ccv_nnc_micro_loop_compound_assignment_lvalue_t;
120
121typedef struct {
122 ccv_nnc_micro_loop_compound_assignment_lvalue_t lvalue; // It shouldn't be unary or binary, only id or variable.
123 ccv_nnc_micro_loop_expression_t rvalue;
124} ccv_nnc_micro_loop_compound_assignment_t;
125
126enum {
127 CCV_NNC_MICRO_LOOP_STATEMENT_TYPE_ASSIGNMENT,
128 CCV_NNC_MICRO_LOOP_STATEMENT_TYPE_COMPOUND_ASSIGNMENT,
129};
130
131// A generic statement within a loop.
132// For our purpose, there will be two types of generic statement:
133// an assignment statement (for tensors).
134// an compound assignment statement (for loop carry overs).
135typedef struct {
136 int type;
137 union {
138 ccv_nnc_micro_loop_assignment_t assignment;
139 ccv_nnc_micro_loop_compound_assignment_t compound_assignment;
140 };
141} ccv_nnc_micro_loop_statement_t;
142
143typedef struct {
144 ccv_nnc_micro_id_t id;
145} ccv_nnc_micro_loop_carried_t; // The accumulating register.
146
147// A loop is identified with a loop counter id, some blocks inside this loop, some carry overs within
148// this loop and can be used outside of this loop.
149// If this loop has another loop nested (represented as the next one in the ccv_nnc_micro_nested_loop_t)
150// all blocks are executed after the nested loop finished.
151typedef struct {
152 ccv_nnc_micro_id_t id; // Loop counter's id, this will be used for indexing.
153 int carried_count;
154 int statement_count;
155 ccv_nnc_micro_loop_index_term_t start_index;
156 ccv_nnc_micro_loop_index_term_t end_index;
157 ccv_nnc_micro_loop_carried_t* carrieds;
158 ccv_nnc_micro_loop_statement_t* statements;
159} ccv_nnc_micro_loop_t;
160
161// A loop block contains many loops within each other.
162typedef struct {
163 int carried_count;
164 int loop_count;
165 ccv_nnc_micro_loop_t* loops;
166} ccv_nnc_micro_loop_block_t;
167
168typedef struct {
169 int input; // The one it derives its shape from. If shape is nullptr, it has the same shape as input. -1 means it is an input.
170 int sibling; // The sibling that has the same shape.
171 int dimensions;
172 int no_alloc; // No need to allocate this tensor.
173 ccv_nnc_micro_loop_index_term_t* shape;
174} ccv_nnc_micro_tensor_t;
175
176// A function contains a list of loop blocks that will be executed serially.
177// It also contains references to its dependencies so a function knows its inputs / outputs.
178typedef struct {
179 int block_count;
180 union {
181 ccv_nnc_micro_loop_block_t* blocks; // Heap-allocated blocks.
182 ccv_nnc_micro_loop_block_t one_block; // In-place block to optimize memory allocation for one block cases.
183 };
184} ccv_nnc_micro_function_t;
185
186typedef struct {
187 int input_size; // Size of inputs.
188 int output_size; // Size of outputs.
189 // Combined ops only have global vars, there is no local vars. All vars are tensors.
190 int var_count;
191 // loops are our constructs of IR ops really. It is hierarchical.
192 int function_count;
193 int* inputs;
194 int* outputs;
195 ccv_nnc_micro_tensor_t* vars;
196 ccv_nnc_micro_function_t* functions;
197} ccv_nnc_micro_program_t;
198
199// A combined op is constructed with many nested loops. These loops may have data dependencies
200// between each other, but they are ordered in topological order to make sure one is finished
201// after the another.
202struct ccv_nnc_micro_combine_s {
203 int parameter_size; // Size of parameters.
204 ccv_nnc_micro_program_t forward;
205 ccv_nnc_micro_program_t backward;
206 ccv_array_t* equal_assertions;
207};
208
209typedef uint32_t(*ccv_nnc_micro_scalar_lookup_f)(const void* const context, const char* const name);
210
211/**
212 * This is the virtual table for micro op.
213 */
214struct ccv_nnc_micro_io_vtab_s {
215 void (*bind_scalars)(const ccv_nnc_micro_io_t self, ccv_nnc_micro_scalar_lookup_f lookup, const void* const context); /**< Bind scalar name to a scoped id. */
216 void (*numbering)(const ccv_nnc_micro_io_t self, const int id, const int var_count); /**< Assign id to the output of this micro op. */
217 void (*equal_assertions)(const ccv_nnc_micro_io_t self, ccv_array_t* const equal_assertions); /**< Collect assertions about id equal. */
218 ccv_nnc_micro_function_t (*emit)(const ccv_nnc_micro_io_t self); /**< Emit instructions for this micro op. */
219 ccv_nnc_micro_function_t (*emit_grad)(const ccv_nnc_micro_io_t self, const int var_count); /**< Emit backward instructions for this micro op. */
220 ccv_nnc_micro_tensor_t (*return_shape)(const ccv_nnc_micro_io_t self); /**< The shape of the returned tensor. */
221 void (*deinit)(const ccv_nnc_micro_io_t self); /**< Deinit this micro io. */
222};
223
224extern const ccv_nnc_micro_io_vtab_t ccv_nnc_micro_io_input_isa;
225extern const ccv_nnc_micro_io_vtab_t ccv_nnc_micro_io_grad_isa;
226
227#define CCV_NNC_IS_MICRO_IO_INPUT(x)((x)->isa == &ccv_nnc_micro_io_input_isa) ((x)->isa == &ccv_nnc_micro_io_input_isa)
228#define CCV_NNC_IS_MICRO_IO_GRAD(x)((x)->isa == &ccv_nnc_micro_io_grad_isa) ((x)->isa == &ccv_nnc_micro_io_grad_isa)
229
230static inline void ccv_nnc_micro_numbering(const ccv_nnc_micro_io_t self, const int id, const int var_count)
231{
232 const ccv_nnc_micro_io_vtab_t* const isa = self->isa;
233 // If we numbering with negative id, we really just enumerate the grad.
234 if (id < 0 && !CCV_NNC_IS_MICRO_IO_GRAD(self)((self)->isa == &ccv_nnc_micro_io_grad_isa))
235 return;
236 if (isa->numbering)
237 isa->numbering(self, id, var_count);
238 else
239 self->id = id;
240}
241
242static inline void ccv_nnc_micro_equal_assertions(const ccv_nnc_micro_io_t self, ccv_array_t* const equal_assertions)
243{
244 const ccv_nnc_micro_io_vtab_t* const isa = self->isa;
245 if (isa->equal_assertions)
246 isa->equal_assertions(self, equal_assertions);
247}
248
249static inline void ccv_nnc_micro_bind_scalars(const ccv_nnc_micro_io_t self, ccv_nnc_micro_scalar_lookup_f lookup, const void* const context)
250{
251 const ccv_nnc_micro_io_vtab_t* const isa = self->isa;
252 if (isa->bind_scalars)
253 isa->bind_scalars(self, lookup, context);
254}
255
256static inline void ccv_nnc_micro_deinit(const ccv_nnc_micro_io_t self)
257{
258 const ccv_nnc_micro_io_vtab_t* const isa = self->isa;
259 if (isa->deinit)
260 isa->deinit(self);
261}
262
263static inline CCV_WARN_UNUSED(ccv_nnc_micro_function_t)ccv_nnc_micro_function_t __attribute__((warn_unused_result)) ccv_nnc_micro_emit(const ccv_nnc_micro_io_t self)
264{
265 const ccv_nnc_micro_io_vtab_t* const isa = self->isa;
266 return isa->emit(self);
267}
268
269static inline CCV_WARN_UNUSED(ccv_nnc_micro_function_t)ccv_nnc_micro_function_t __attribute__((warn_unused_result)) ccv_nnc_micro_emit_grad(const ccv_nnc_micro_io_t self, const int var_count)
270{
271 const ccv_nnc_micro_io_vtab_t* const isa = self->isa;
272 return isa->emit_grad(self, var_count);
273}
274
275static inline CCV_WARN_UNUSED(ccv_nnc_micro_tensor_t)ccv_nnc_micro_tensor_t __attribute__((warn_unused_result)) ccv_nnc_micro_return_shape(const ccv_nnc_micro_io_t self)
276{
277 const ccv_nnc_micro_io_vtab_t* const isa = self->isa;
278 return isa->return_shape(self);
279}
280
281/**
282 * Helpers to construct the micro IR.
283 */
284
285static inline ccv_nnc_micro_id_t ccv_nnc_micro_id_of_tensor(const int id)
286{
287 return (ccv_nnc_micro_id_t){
288 .type = CCV_NNC_MICRO_TENSOR_ID,
289 .id = id,
290 .d = 0
291 };
292}
293
294static inline ccv_nnc_micro_loop_index_term_t ccv_nnc_micro_index_of_value(const int value)
295{
296 return (ccv_nnc_micro_loop_index_term_t){
297 .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_VAL,
298 .immediate_value = value
299 };
300}
301
302static inline ccv_nnc_micro_loop_index_term_t ccv_nnc_micro_index_of_id(const ccv_nnc_micro_id_t id)
303{
304 return (ccv_nnc_micro_loop_index_term_t){
305 .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID,
306 .id = id
307 };
308}
309
310static inline ccv_nnc_micro_loop_index_term_t ccv_nnc_micro_index_of_axis_size(const int id, const int level)
311{
312 return (ccv_nnc_micro_loop_index_term_t){
313 .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID,
314 .id = {
315 .type = CCV_NNC_MICRO_AXIS_SIZE_ID,
316 .id = id,
317 .d = level
318 }
319 };
320}
321
322static inline ccv_nnc_micro_loop_t ccv_nnc_micro_for_in(const ccv_nnc_micro_loop_index_term_t start_index, const ccv_nnc_micro_loop_index_term_t end_index, const int level)
323{
324 return (ccv_nnc_micro_loop_t){
325 .start_index = start_index,
326 .end_index = end_index,
327 .carried_count = 0,
328 .carrieds = 0,
329 .statement_count = 0,
330 .statements = 0,
331 .id = {
332 .type = CCV_NNC_MICRO_LOOP_ID,
333 .d = 0,
334 .id = level,
335 }
336 };
337}
338
339// This is a macro because C cannot return array type.
340#define ccv_nnc_micro_index_of_loops(_loops, _loop_count)(ccv_nnc_micro_loop_index_term_t [(12)]){ { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = _loop_count > 0 ? _loops[0].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = _loop_count
> 1 ? _loops[1].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = _loop_count > 2 ? _loops[2].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = _loop_count
> 3 ? _loops[3].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = _loop_count > 4 ? _loops[4].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = _loop_count
> 5 ? _loops[5].id : (ccv_nnc_micro_id_t){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID
, .id = _loop_count > 6 ? _loops[6].id : (ccv_nnc_micro_id_t
){} }, { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = _loop_count
> 7 ? _loops[7].id : (ccv_nnc_micro_id_t){} } }
\
341 (ccv_nnc_micro_loop_index_term_t [CCV_NNC_MAX_DIM_ALLOC(12)]){ \
342 { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = _loop_count > 0 ? _loops[0].id : (ccv_nnc_micro_id_t){} }, \
343 { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = _loop_count > 1 ? _loops[1].id : (ccv_nnc_micro_id_t){} }, \
344 { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = _loop_count > 2 ? _loops[2].id : (ccv_nnc_micro_id_t){} }, \
345 { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = _loop_count > 3 ? _loops[3].id : (ccv_nnc_micro_id_t){} }, \
346 { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = _loop_count > 4 ? _loops[4].id : (ccv_nnc_micro_id_t){} }, \
347 { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = _loop_count > 5 ? _loops[5].id : (ccv_nnc_micro_id_t){} }, \
348 { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = _loop_count > 6 ? _loops[6].id : (ccv_nnc_micro_id_t){} }, \
349 { .type = CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID, .id = _loop_count > 7 ? _loops[7].id : (ccv_nnc_micro_id_t){} } \
350 }
351
352static inline ccv_nnc_micro_loop_variable_t ccv_nnc_micro_loop_variable_of_tensor(const int id, const int index_count, const ccv_nnc_micro_loop_index_term_t* const index)
353{
354 ccv_nnc_micro_loop_variable_t variable = {
355 .id = ccv_nnc_micro_id_of_tensor(id),
356 .index_count = index_count
357 };
358 int i;
359 for (i = 0; i < index_count; i++)
360 variable.index[i] = index[i];
361 return variable;
362}
363
364static inline ccv_nnc_micro_loop_expression_t ccv_nnc_micro_loop_expression_of_variable(const ccv_nnc_micro_loop_variable_t variable)
365{
366 return (ccv_nnc_micro_loop_expression_t){
367 .type = CCV_NNC_MICRO_LOOP_EXPR_TYPE_VAR,
368 .variable = variable
369 };
370}
371
372static inline ccv_nnc_micro_loop_expression_t ccv_nnc_micro_loop_expression_of_value(const float value)
373{
374 return (ccv_nnc_micro_loop_expression_t){
375 .type = CCV_NNC_MICRO_LOOP_EXPR_TYPE_VAL,
376 .immediate_value = {
377 .type = CCV_32F,
378 .f32 = value
379 }
380 };
381}
382
383static inline ccv_nnc_micro_loop_expression_t ccv_nnc_micro_loop_expression_of_id(const ccv_nnc_micro_id_t id)
384{
385 return (ccv_nnc_micro_loop_expression_t){
386 .type = CCV_NNC_MICRO_LOOP_EXPR_TYPE_ID,
387 .id = id
388 };
389}
390
391static inline ccv_nnc_micro_loop_statement_t ccv_nnc_micro_loop_assignment(const ccv_nnc_micro_loop_variable_t lvalue, const ccv_nnc_micro_loop_expression_t rvalue)
392{
393 return (ccv_nnc_micro_loop_statement_t){
394 .type = CCV_NNC_MICRO_LOOP_STATEMENT_TYPE_ASSIGNMENT,
395 .assignment = {
396 .lvalue = lvalue,
397 .rvalue = rvalue
398 }
399 };
400}
401
402static inline ccv_nnc_micro_loop_expression_t ccv_nnc_micro_loop_expression_of_unary(const int unary_op, const ccv_nnc_micro_loop_expression_t x)
403{
404 ccv_nnc_micro_loop_expression_t expression = {
405 .type = CCV_NNC_MICRO_LOOP_EXPR_TYPE_BINARY
406 };
407 expression.unary.unary_op = unary_op;
408 expression.unary.x = (ccv_nnc_micro_loop_expression_t*)ccmallocmalloc(sizeof(ccv_nnc_micro_loop_expression_t));
24
Memory is allocated
409 *expression.unary.x = x;
410 return expression;
411}
412
413static inline ccv_nnc_micro_loop_expression_t ccv_nnc_micro_loop_expression_of_binary(const int binary_op, const ccv_nnc_micro_loop_expression_t left, const ccv_nnc_micro_loop_expression_t right)
414{
415 ccv_nnc_micro_loop_expression_t expression = {
416 .type = CCV_NNC_MICRO_LOOP_EXPR_TYPE_BINARY
417 };
418 expression.binary.binary_op = binary_op;
419 expression.binary.left = (ccv_nnc_micro_loop_expression_t*)ccmallocmalloc(sizeof(ccv_nnc_micro_loop_expression_t));
420 *expression.binary.left = left;
421 expression.binary.right = (ccv_nnc_micro_loop_expression_t*)ccmallocmalloc(sizeof(ccv_nnc_micro_loop_expression_t));
422 *expression.binary.right = right;
423 return expression;
424}
425
426static inline ccv_nnc_micro_loop_expression_t ccv_nnc_micro_loop_expression_of_ternary(const ccv_nnc_micro_loop_expression_t pivot, const ccv_nnc_micro_loop_expression_t left, const ccv_nnc_micro_loop_expression_t right)
427{
428 ccv_nnc_micro_loop_expression_t expression = {
429 .type = CCV_NNC_MICRO_LOOP_EXPR_TYPE_TERNAY
430 };
431 expression.ternary.pivot = (ccv_nnc_micro_loop_expression_t*)ccmallocmalloc(sizeof(ccv_nnc_micro_loop_expression_t));
432 *expression.ternary.pivot = pivot;
433 expression.ternary.left = (ccv_nnc_micro_loop_expression_t*)ccmallocmalloc(sizeof(ccv_nnc_micro_loop_expression_t));
434 *expression.ternary.left = left;
435 expression.ternary.right = (ccv_nnc_micro_loop_expression_t*)ccmallocmalloc(sizeof(ccv_nnc_micro_loop_expression_t));
436 *expression.ternary.right = right;
437 return expression;
438}
439
440static inline ccv_nnc_micro_loop_statement_t ccv_nnc_micro_loop_compound_assignment_of_id(const ccv_nnc_micro_id_t lvalue, const ccv_nnc_micro_loop_expression_t rvalue)
441{
442 return (ccv_nnc_micro_loop_statement_t){
443 .type = CCV_NNC_MICRO_LOOP_STATEMENT_TYPE_COMPOUND_ASSIGNMENT,
444 .compound_assignment = {
445 .lvalue = {
446 .type = CCV_NNC_MICRO_LOOP_EXPR_TYPE_ID,
447 .id = lvalue
448 },
449 .rvalue = rvalue
450 }
451 };
452}
453
454static inline ccv_nnc_micro_loop_statement_t ccv_nnc_micro_loop_compound_assignment_of_tensor(const ccv_nnc_micro_loop_variable_t lvalue, const ccv_nnc_micro_loop_expression_t rvalue)
455{
456 return (ccv_nnc_micro_loop_statement_t){
457 .type = CCV_NNC_MICRO_LOOP_STATEMENT_TYPE_COMPOUND_ASSIGNMENT,
458 .compound_assignment = {
459 .lvalue = {
460 .type = CCV_NNC_MICRO_LOOP_EXPR_TYPE_VAR,
461 .variable = lvalue
462 },
463 .rvalue = rvalue
464 }
465 };
466}
467
468static inline ccv_nnc_micro_loop_carried_t ccv_nnc_micro_loop_carried(const uint8_t reduce_op, const int idx)
469{
470 return (ccv_nnc_micro_loop_carried_t){
471 .id = {
472 .type = CCV_NNC_MICRO_LOOP_CARRIED_ID,
473 .d = reduce_op,
474 .id = idx
475 }
476 };
477}
478
479// This method has to be mutable for efficiency reasons. Hence I kept it private.
480void ccv_nnc_micro_program_simplify(ccv_nnc_micro_program_t* const program, const ccv_nnc_micro_io_t* const inputs, const int input_size, const ccv_nnc_micro_io_t* const outputs, const int output_size, const ccv_array_t* const equal_assertions);
481ccv_nnc_micro_loop_index_term_t ccv_nnc_micro_loop_index_deep_copy(const ccv_nnc_micro_loop_index_term_t* const term);
482void ccv_nnc_micro_loop_index_free(ccv_nnc_micro_loop_index_term_t* const term);
483void ccv_nnc_micro_loop_variable_free(ccv_nnc_micro_loop_variable_t* const var);
484void ccv_nnc_micro_loop_statement_free(ccv_nnc_micro_loop_statement_t* const statement);
485void ccv_nnc_micro_loop_statement_lvalue_free(ccv_nnc_micro_loop_statement_t* const statement);
486void ccv_nnc_micro_loops_free(ccv_nnc_micro_loop_t* const loops, const int loop_count);
487
488#endif