Bug Summary

File:nnc/ccv_cnnp_model_core.c
Warning:line 115, column 1
Array access (via field 'flags') results in a null pointer dereference

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_cnnp_model_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/2025-03-24-220155-150127-1 -x c ccv_cnnp_model_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_cnnp_model.h"
6#include "3rdparty/khash/khash.h"
7
8// MARK - Baisc Layers
9
10static const ccv_cnnp_model_vtab_t ccv_cnnp_input_isa;
11
12#define CCV_CNNP_IS_MODEL_INPUT(x)((x)->isa == &ccv_cnnp_input_isa) ((x)->isa == &ccv_cnnp_input_isa)
13
14#define CCV_CNNP_IS_MODEL_PARAMETER(x)((x)->param_ref != 0 || (x)->param_sel != 0) ((x)->param_ref != 0 || (x)->param_sel != 0)
15
16typedef struct {
17 ccv_cnnp_model_t super;
18 int sequence_size;
19 ccv_cnnp_model_t* sequence[1];
20} ccv_cnnp_sequential_model_t;
21
22static void _ccv_cnnp_sequential_model_deinit(ccv_cnnp_model_t* const super)
23{
24 ccv_cnnp_sequential_model_t* const self = (ccv_cnnp_sequential_model_t*)super;
25 int i, j = 0;
26 for (i = 0; i < self->sequence_size; i++)
27 {
28 ccv_cnnp_model_t* const model = self->sequence[i];
29 if (model->deinit_state)
30 continue;
31 ccv_cnnp_model_deinit(model);
32 self->sequence[j++] = model;
33 }
34 self->sequence_size = j;
35}
36
37static void _ccv_cnnp_sequential_model_dealloc(ccv_cnnp_model_t* const super)
38{
39 ccv_cnnp_sequential_model_t* const self = (ccv_cnnp_sequential_model_t*)super;
40 int i;
41 for (i = 0; i < self->sequence_size; i++)
42 ccv_cnnp_model_free(self->sequence[i]);
43}
44
45static void _ccv_cnnp_sequential_model_build(ccv_cnnp_model_t* const super, ccv_nnc_symbolic_graph_t* const graph, const ccv_nnc_tensor_symbol_t* const inputs, const int input_size, ccv_nnc_tensor_symbol_t* const outputs, const int output_size)
46{
47 ccv_cnnp_sequential_model_t* const self = (ccv_cnnp_sequential_model_t*)super;
48 PRINT(CCV_CLI_VERBOSE, "[cnnp_sequential_model_build] 1. %p, sequence_size: %d\n", self, self->sequence_size)do { if ((CCV_CLI_VERBOSE & ccv_cli_get_output_levels()))
{ printf("[cnnp_sequential_model_build] 1. %p, sequence_size: %d\n"
, self, self->sequence_size); fflush(stdout); } } while (0
)
;
49 ccv_cnnp_model_t* const sub_model = self->sequence[0];
50 // Go through each sub model to build the graph.
51 ccv_nnc_tensor_symbol_t input;
52 sub_model->data = self->super.data;
53 ccv_cnnp_model_build(sub_model, graph, inputs, input_size, &input, 1);
54 sub_model->data = 0;
55 int i;
56 for (i = 1; i < self->sequence_size; i++)
57 {
58 ccv_nnc_tensor_symbol_t output;
59 ccv_cnnp_model_t* const sub_model = self->sequence[i];
60 // Go through each sub model to build the graph.
61 sub_model->data = self->super.data;
62 ccv_cnnp_model_build(sub_model, graph, &input, 1, &output, 1);
63 sub_model->data = 0;
64 input = output;
65 }
66 outputs[0] = input;
67 PRINT(CCV_CLI_VERBOSE, "[cnnp_sequential_model_build] 2. %p\n", self)do { if ((CCV_CLI_VERBOSE & ccv_cli_get_output_levels()))
{ printf("[cnnp_sequential_model_build] 2. %p\n", self); fflush
(stdout); } } while (0)
;
68}
69
70static void _ccv_cnnp_sequential_model_init_states(ccv_cnnp_model_t* const super, ccv_nnc_symbolic_graph_t* const graph, const ccv_cnnp_state_initializer_f initializer, void* const context)
71{
72 ccv_cnnp_sequential_model_t* const self = (ccv_cnnp_sequential_model_t*)super;
73 int i;
74 for (i = 0; i < self->sequence_size; i++)
75 ccv_cnnp_model_init_states(self->sequence[i], graph, initializer, context);
76}
77
78static void _ccv_cnnp_sequential_model_set_is_test(ccv_cnnp_model_t* const super, const int is_test, const ccv_cnnp_cmd_updater_f updater, void* const context)
79{
80 ccv_cnnp_sequential_model_t* const self = (ccv_cnnp_sequential_model_t*)super;
81 int i;
82 for (i = 0; i < self->sequence_size; i++)
83 ccv_cnnp_model_set_is_test(self->sequence[i], is_test, updater, context);
84}
85
86static ccv_cnnp_model_t* _ccv_cnnp_sequential_model_copy(const ccv_cnnp_model_t* const super, void* const context);
87
88static void _ccv_cnnp_sequential_model_add_to_parameter_indices(ccv_cnnp_model_t* const super, const int index, ccv_array_t* const parameter_indices)
89{
90 ccv_cnnp_sequential_model_t* const self = (ccv_cnnp_sequential_model_t*)super;
91 int i;
92 for (i = 0; i < self->sequence_size; i++)
93 ccv_cnnp_model_add_to_parameter_indices(self->sequence[i], index, parameter_indices);
94}
95
96static void _ccv_cnnp_sequential_model_notify(const ccv_cnnp_model_t* const super, const int tag, void* const payload)
97{
98 ccv_cnnp_sequential_model_t* const self = (ccv_cnnp_sequential_model_t*)super;
99 int i;
100 for (i = 0; i < self->sequence_size; i++)
101 ccv_cnnp_model_notify(self->sequence[i], tag, payload);
102}
103
104static const ccv_cnnp_model_vtab_t ccv_cnnp_sequential_model_isa = {
105 .deinit = _ccv_cnnp_sequential_model_deinit,
106 .dealloc = _ccv_cnnp_sequential_model_dealloc,
107 .build = _ccv_cnnp_sequential_model_build,
108 .init_states = _ccv_cnnp_sequential_model_init_states,
109 .copy = _ccv_cnnp_sequential_model_copy,
110 .set_is_test = _ccv_cnnp_sequential_model_set_is_test,
111 .add_to_parameter_indices = _ccv_cnnp_sequential_model_add_to_parameter_indices,
112 .notify = _ccv_cnnp_sequential_model_notify,
113};
114
115KHASH_MAP_INIT_INT64(model, ccv_cnnp_model_t*)typedef struct kh_model_s { khint_t n_buckets, size, n_occupied
, upper_bound; khint32_t *flags; khint64_t *keys; ccv_cnnp_model_t
* *vals; } kh_model_t; static inline __attribute__ ((__unused__
)) kh_model_t *kh_init_model(void) { return (kh_model_t*)calloc
(1,sizeof(kh_model_t)); } static inline __attribute__ ((__unused__
)) void kh_destroy_model(kh_model_t *h) { if (h) { free((void
*)h->keys); free(h->flags); free((void *)h->vals); free
(h); } } static inline __attribute__ ((__unused__)) void kh_clear_model
(kh_model_t *h) { if (h && h->flags) { memset(h->
flags, 0xaa, ((h->n_buckets) < 16? 1 : (h->n_buckets
)>>4) * sizeof(khint32_t)); h->size = h->n_occupied
= 0; } } static inline __attribute__ ((__unused__)) khint_t kh_get_model
(const kh_model_t *h, khint64_t key) { if (h->n_buckets) {
khint_t k, i, last, mask, step = 0; mask = h->n_buckets -
1; k = (khint32_t)((key)>>33^(key)^(key)<<11); i
= k & mask; last = i; while (!((h->flags[i>>4]>>
((i&0xfU)<<1))&2) && (((h->flags[i>>
4]>>((i&0xfU)<<1))&1) || !((h->keys[i]
) == (key)))) { i = (i + (++step)) & mask; if (i == last)
return h->n_buckets; } return ((h->flags[i>>4]>>
((i&0xfU)<<1))&3)? h->n_buckets : i; } else return
0; } static inline __attribute__ ((__unused__)) int kh_resize_model
(kh_model_t *h, khint_t new_n_buckets) { khint32_t *new_flags
= 0; khint_t j = 1; { (--(new_n_buckets), (new_n_buckets)|=(
new_n_buckets)>>1, (new_n_buckets)|=(new_n_buckets)>>
2, (new_n_buckets)|=(new_n_buckets)>>4, (new_n_buckets)
|=(new_n_buckets)>>8, (new_n_buckets)|=(new_n_buckets)>>
16, ++(new_n_buckets)); if (new_n_buckets < 4) new_n_buckets
= 4; if (h->size >= (khint_t)(new_n_buckets * __ac_HASH_UPPER
+ 0.5)) j = 0; else { new_flags = (khint32_t*)malloc(((new_n_buckets
) < 16? 1 : (new_n_buckets)>>4) * sizeof(khint32_t))
; if (!new_flags) return -1; memset(new_flags, 0xaa, ((new_n_buckets
) < 16? 1 : (new_n_buckets)>>4) * sizeof(khint32_t))
; if (h->n_buckets < new_n_buckets) { khint64_t *new_keys
= (khint64_t*)realloc((void *)h->keys,new_n_buckets * sizeof
(khint64_t)); if (!new_keys) { free(new_flags); return -1; } h
->keys = new_keys; if (1) { ccv_cnnp_model_t* *new_vals = (
ccv_cnnp_model_t**)realloc((void *)h->vals,new_n_buckets *
sizeof(ccv_cnnp_model_t*)); if (!new_vals) { free(new_flags)
; return -1; } h->vals = new_vals; } } } } if (j) { for (j
= 0; j != h->n_buckets; ++j) { if (((h->flags[j>>
4]>>((j&0xfU)<<1))&3) == 0) { khint64_t key
= h->keys[j]; ccv_cnnp_model_t* val; khint_t new_mask; new_mask
= new_n_buckets - 1; if (1) val = h->vals[j]; (h->flags
[j>>4]|=1ul<<((j&0xfU)<<1)); while (1) {
khint_t k, i, step = 0; k = (khint32_t)((key)>>33^(key
)^(key)<<11); i = k & new_mask; while (!((new_flags
[i>>4]>>((i&0xfU)<<1))&2)) i = (i +
(++step)) & new_mask; (new_flags[i>>4]&=~(2ul<<
((i&0xfU)<<1))); if (i < h->n_buckets &&
((h->flags[i>>4]>>((i&0xfU)<<1))&
3) == 0) { { khint64_t tmp = h->keys[i]; h->keys[i] = key
; key = tmp; } if (1) { ccv_cnnp_model_t* tmp = h->vals[i]
; h->vals[i] = val; val = tmp; } (h->flags[i>>4]|=
1ul<<((i&0xfU)<<1)); } else { h->keys[i] =
key; if (1) h->vals[i] = val; break; } } } } if (h->n_buckets
> new_n_buckets) { h->keys = (khint64_t*)realloc((void
*)h->keys,new_n_buckets * sizeof(khint64_t)); if (1) h->
vals = (ccv_cnnp_model_t**)realloc((void *)h->vals,new_n_buckets
* sizeof(ccv_cnnp_model_t*)); } free(h->flags); h->flags
= new_flags; h->n_buckets = new_n_buckets; h->n_occupied
= h->size; h->upper_bound = (khint_t)(h->n_buckets *
__ac_HASH_UPPER + 0.5); } return 0; } static inline __attribute__
((__unused__)) khint_t kh_put_model(kh_model_t *h, khint64_t
key, int *ret) { khint_t x; if (h->n_occupied >= h->
upper_bound) { if (h->n_buckets > (h->size<<1)
) { if (kh_resize_model(h, h->n_buckets - 1) < 0) { *ret
= -1; return h->n_buckets; } } else if (kh_resize_model(h
, h->n_buckets + 1) < 0) { *ret = -1; return h->n_buckets
; } } { khint_t k, i, site, last, mask = h->n_buckets - 1,
step = 0; x = site = h->n_buckets; k = (khint32_t)((key)>>
33^(key)^(key)<<11); i = k & mask; if (((h->flags
[i>>4]>>((i&0xfU)<<1))&2)) x = i; else
{ last = i; while (!((h->flags[i>>4]>>((i&
0xfU)<<1))&2) && (((h->flags[i>>4]
>>((i&0xfU)<<1))&1) || !((h->keys[i]) ==
(key)))) { if (((h->flags[i>>4]>>((i&0xfU
)<<1))&1)) site = i; i = (i + (++step)) & mask;
if (i == last) { x = site; break; } } if (x == h->n_buckets
) { if (((h->flags[i>>4]>>((i&0xfU)<<
1))&2) && site != h->n_buckets) x = site; else
x = i; } } } if (((h->flags[x>>4]>>((x&0xfU
)<<1))&2)) { h->keys[x] = key; (h->flags[x>>
4]&=~(3ul<<((x&0xfU)<<1))); ++h->size;
++h->n_occupied; *ret = 1; } else if (((h->flags[x>>
4]>>((x&0xfU)<<1))&1)) { h->keys[x] = key
; (h->flags[x>>4]&=~(3ul<<((x&0xfU)<<
1))); ++h->size; *ret = 2; } else *ret = 0; return x; } static
inline __attribute__ ((__unused__)) void kh_del_model(kh_model_t
*h, khint_t x) { if (x != h->n_buckets && !((h->
flags[x>>4]>>((x&0xfU)<<1))&3)) { (
h->flags[x>>4]|=1ul<<((x&0xfU)<<1));
--h->size; } }
4
Null pointer value stored to field 'flags'
9
Taking true branch
10
Taking false branch
11
Calling 'kh_resize_model'
12
Taking true branch
13
Assuming the condition is true
14
Taking true branch
15
Taking false branch
16
Returning without writing to 'h->flags'
17
Returning from 'kh_resize_model'
18
Taking false branch
19
Array access (via field 'flags') results in a null pointer dereference
116
117static ccv_cnnp_model_t* _ccv_cnnp_sequential_model_copy(const ccv_cnnp_model_t* const super, void* const context)
118{
119 const ccv_cnnp_sequential_model_t* const self = (const ccv_cnnp_sequential_model_t*)super;
120 ccv_cnnp_sequential_model_t* const sequential_model = (ccv_cnnp_sequential_model_t*)cccalloccalloc(1, sizeof(ccv_cnnp_sequential_model_t) + sizeof(ccv_cnnp_model_t*) * (self->sequence_size - 1) + sizeof(ccv_nnc_tensor_symbol_t));
121 sequential_model->super.isa = &ccv_cnnp_sequential_model_isa;
122 sequential_model->super.input_size = 1;
123 sequential_model->super.outputs = (ccv_nnc_tensor_symbol_t*)(sequential_model->sequence + self->sequence_size);
124 sequential_model->super.output_size = 1;
125 ccv_cnnp_model_copy_name(&sequential_model->super, self->super.name);
126 sequential_model->sequence_size = self->sequence_size;
127 int i;
128 khash_t(model)kh_model_t* model_map = context ? (khash_t(model)kh_model_t*)context : kh_init(model)kh_init_model();
129 for (i = 0; i < self->sequence_size; i++)
130 {
131 ccv_cnnp_model_t* const sub_model = self->sequence[i];
132 int ret;
133 khiter_t k = kh_put(model, model_map, (uint64_t)(uintptr_t)sub_model, &ret)kh_put_model(model_map, (uint64_t)(uintptr_t)sub_model, &
ret)
;
134 ccv_cnnp_model_t* model_copy;
135 if (ret != 0)
136 model_copy = kh_val(model_map, k)((model_map)->vals[k]) = _ccv_cnnp_model_copy(sub_model, model_map);
137 else
138 model_copy = kh_val(model_map, k)((model_map)->vals[k]);
139 sequential_model->sequence[i] = model_copy;
140 }
141 if (!context)
142 kh_destroy(model, model_map)kh_destroy_model(model_map);
143 return (ccv_cnnp_model_t*)sequential_model;
144}
145
146ccv_cnnp_model_t* ccv_cnnp_sequential_new(ccv_cnnp_model_t* const* const models, const int model_size, const int is_trainable, const char* const name)
147{
148 assert(model_size > 0)((void) sizeof ((model_size > 0) ? 1 : 0), __extension__ (
{ if (model_size > 0) ; else __assert_fail ("model_size > 0"
, "ccv_cnnp_model_core.c", 148, __extension__ __PRETTY_FUNCTION__
); }))
;
149 ccv_cnnp_sequential_model_t* const sequential_model = (ccv_cnnp_sequential_model_t*)cccalloccalloc(1, sizeof(ccv_cnnp_sequential_model_t) + sizeof(ccv_cnnp_model_t*) * (model_size - 1) + sizeof(ccv_nnc_tensor_symbol_t));
150 sequential_model->super.isa = &ccv_cnnp_sequential_model_isa;
151 sequential_model->super.input_size = models[0]->input_size;
152 sequential_model->super.outputs = (ccv_nnc_tensor_symbol_t*)(sequential_model->sequence + model_size);
153 sequential_model->super.output_size = 1;
154 sequential_model->super.is_trainable = is_trainable;
155 ccv_cnnp_model_copy_name(&sequential_model->super, name);
156 sequential_model->sequence_size = model_size;
157 memcpy(sequential_model->sequence, models, sizeof(ccv_cnnp_model_t*) * model_size);
158 return (ccv_cnnp_model_t*)sequential_model;
159}
160
161typedef struct {
162 ccv_cnnp_model_t super;
163 // The model's outputs, it is different from super.output_size, as latter is for actual tensor symbols.
164 int model_output_size;
165 // The name is similar to sequential model, but it is just topological sorted models.
166 int sequence_size;
167 int* model_outputs; // Which model, as in sequences, have some outputs.
168 ccv_cnnp_model_io_t sequence[1];
169} ccv_cnnp_functional_model_t;
170
171static void _ccv_cnnp_functional_model_deinit(ccv_cnnp_model_t* const super)
172{
173 ccv_cnnp_functional_model_t* const self = (ccv_cnnp_functional_model_t*)super;
174 int i, j = 0, k;
175 for (i = 0; i < self->sequence_size; i++)
176 {
177 ccv_cnnp_model_t* const model = self->sequence[i]->model;
178 if (!model || model->deinit_state)
179 continue;
180 self->sequence[j++] = (ccv_cnnp_model_io_t)model;
181 // Go through all their IO to remove itself as model.
182 assert(model->io)((void) sizeof ((model->io) ? 1 : 0), __extension__ ({ if (
model->io) ; else __assert_fail ("model->io", "ccv_cnnp_model_core.c"
, 182, __extension__ __PRETTY_FUNCTION__); }))
;
183 for (k = 0; k < model->io->rnum; k++)
184 {
185 ccv_cnnp_model_io_t model_io = *(ccv_cnnp_model_io_t*)ccv_array_get(model->io, k)((void*)(((char*)((model->io)->data)) + (size_t)(model->
io)->rsize * (size_t)(k)))
;
186 model_io->model = 0;
187 }
188 }
189 for (i = 0; i < j; i++)
190 ccv_cnnp_model_deinit((ccv_cnnp_model_t*)self->sequence[i]);
191 self->sequence_size = j;
192}
193
194static void _ccv_cnnp_functional_model_dealloc(ccv_cnnp_model_t* const super)
195{
196 ccv_cnnp_functional_model_t* const self = (ccv_cnnp_functional_model_t*)super;
197 int i;
198 for (i = 0; i < self->sequence_size; i++)
199 ccv_cnnp_model_free((ccv_cnnp_model_t*)self->sequence[i]);
200}
201
202KHASH_MAP_INIT_INT64(io_node, ccv_array_t*)typedef struct kh_io_node_s { khint_t n_buckets, size, n_occupied
, upper_bound; khint32_t *flags; khint64_t *keys; ccv_array_t
* *vals; } kh_io_node_t; static inline __attribute__ ((__unused__
)) kh_io_node_t *kh_init_io_node(void) { return (kh_io_node_t
*)calloc(1,sizeof(kh_io_node_t)); } static inline __attribute__
((__unused__)) void kh_destroy_io_node(kh_io_node_t *h) { if
(h) { free((void *)h->keys); free(h->flags); free((void
*)h->vals); free(h); } } static inline __attribute__ ((__unused__
)) void kh_clear_io_node(kh_io_node_t *h) { if (h && h
->flags) { memset(h->flags, 0xaa, ((h->n_buckets) <
16? 1 : (h->n_buckets)>>4) * sizeof(khint32_t)); h->
size = h->n_occupied = 0; } } static inline __attribute__ (
(__unused__)) khint_t kh_get_io_node(const kh_io_node_t *h, khint64_t
key) { if (h->n_buckets) { khint_t k, i, last, mask, step
= 0; mask = h->n_buckets - 1; k = (khint32_t)((key)>>
33^(key)^(key)<<11); i = k & mask; last = i; while (
!((h->flags[i>>4]>>((i&0xfU)<<1))&
2) && (((h->flags[i>>4]>>((i&0xfU)
<<1))&1) || !((h->keys[i]) == (key)))) { i = (i +
(++step)) & mask; if (i == last) return h->n_buckets;
} return ((h->flags[i>>4]>>((i&0xfU)<<
1))&3)? h->n_buckets : i; } else return 0; } static inline
__attribute__ ((__unused__)) int kh_resize_io_node(kh_io_node_t
*h, khint_t new_n_buckets) { khint32_t *new_flags = 0; khint_t
j = 1; { (--(new_n_buckets), (new_n_buckets)|=(new_n_buckets
)>>1, (new_n_buckets)|=(new_n_buckets)>>2, (new_n_buckets
)|=(new_n_buckets)>>4, (new_n_buckets)|=(new_n_buckets)
>>8, (new_n_buckets)|=(new_n_buckets)>>16, ++(new_n_buckets
)); if (new_n_buckets < 4) new_n_buckets = 4; if (h->size
>= (khint_t)(new_n_buckets * __ac_HASH_UPPER + 0.5)) j = 0
; else { new_flags = (khint32_t*)malloc(((new_n_buckets) <
16? 1 : (new_n_buckets)>>4) * sizeof(khint32_t)); if (
!new_flags) return -1; memset(new_flags, 0xaa, ((new_n_buckets
) < 16? 1 : (new_n_buckets)>>4) * sizeof(khint32_t))
; if (h->n_buckets < new_n_buckets) { khint64_t *new_keys
= (khint64_t*)realloc((void *)h->keys,new_n_buckets * sizeof
(khint64_t)); if (!new_keys) { free(new_flags); return -1; } h
->keys = new_keys; if (1) { ccv_array_t* *new_vals = (ccv_array_t
**)realloc((void *)h->vals,new_n_buckets * sizeof(ccv_array_t
*)); if (!new_vals) { free(new_flags); return -1; } h->vals
= new_vals; } } } } if (j) { for (j = 0; j != h->n_buckets
; ++j) { if (((h->flags[j>>4]>>((j&0xfU)<<
1))&3) == 0) { khint64_t key = h->keys[j]; ccv_array_t
* val; khint_t new_mask; new_mask = new_n_buckets - 1; if (1)
val = h->vals[j]; (h->flags[j>>4]|=1ul<<((
j&0xfU)<<1)); while (1) { khint_t k, i, step = 0; k
= (khint32_t)((key)>>33^(key)^(key)<<11); i = k &
new_mask; while (!((new_flags[i>>4]>>((i&0xfU
)<<1))&2)) i = (i + (++step)) & new_mask; (new_flags
[i>>4]&=~(2ul<<((i&0xfU)<<1))); if (
i < h->n_buckets && ((h->flags[i>>4]>>
((i&0xfU)<<1))&3) == 0) { { khint64_t tmp = h->
keys[i]; h->keys[i] = key; key = tmp; } if (1) { ccv_array_t
* tmp = h->vals[i]; h->vals[i] = val; val = tmp; } (h->
flags[i>>4]|=1ul<<((i&0xfU)<<1)); } else
{ h->keys[i] = key; if (1) h->vals[i] = val; break; } }
} } if (h->n_buckets > new_n_buckets) { h->keys = (
khint64_t*)realloc((void *)h->keys,new_n_buckets * sizeof(
khint64_t)); if (1) h->vals = (ccv_array_t**)realloc((void
*)h->vals,new_n_buckets * sizeof(ccv_array_t*)); } free(h
->flags); h->flags = new_flags; h->n_buckets = new_n_buckets
; h->n_occupied = h->size; h->upper_bound = (khint_t
)(h->n_buckets * __ac_HASH_UPPER + 0.5); } return 0; } static
inline __attribute__ ((__unused__)) khint_t kh_put_io_node(kh_io_node_t
*h, khint64_t key, int *ret) { khint_t x; if (h->n_occupied
>= h->upper_bound) { if (h->n_buckets > (h->size
<<1)) { if (kh_resize_io_node(h, h->n_buckets - 1) <
0) { *ret = -1; return h->n_buckets; } } else if (kh_resize_io_node
(h, h->n_buckets + 1) < 0) { *ret = -1; return h->n_buckets
; } } { khint_t k, i, site, last, mask = h->n_buckets - 1,
step = 0; x = site = h->n_buckets; k = (khint32_t)((key)>>
33^(key)^(key)<<11); i = k & mask; if (((h->flags
[i>>4]>>((i&0xfU)<<1))&2)) x = i; else
{ last = i; while (!((h->flags[i>>4]>>((i&
0xfU)<<1))&2) && (((h->flags[i>>4]
>>((i&0xfU)<<1))&1) || !((h->keys[i]) ==
(key)))) { if (((h->flags[i>>4]>>((i&0xfU
)<<1))&1)) site = i; i = (i + (++step)) & mask;
if (i == last) { x = site; break; } } if (x == h->n_buckets
) { if (((h->flags[i>>4]>>((i&0xfU)<<
1))&2) && site != h->n_buckets) x = site; else
x = i; } } } if (((h->flags[x>>4]>>((x&0xfU
)<<1))&2)) { h->keys[x] = key; (h->flags[x>>
4]&=~(3ul<<((x&0xfU)<<1))); ++h->size;
++h->n_occupied; *ret = 1; } else if (((h->flags[x>>
4]>>((x&0xfU)<<1))&1)) { h->keys[x] = key
; (h->flags[x>>4]&=~(3ul<<((x&0xfU)<<
1))); ++h->size; *ret = 2; } else *ret = 0; return x; } static
inline __attribute__ ((__unused__)) void kh_del_io_node(kh_io_node_t
*h, khint_t x) { if (x != h->n_buckets && !((h->
flags[x>>4]>>((x&0xfU)<<1))&3)) { (
h->flags[x>>4]|=1ul<<((x&0xfU)<<1));
--h->size; } }
203
204typedef struct {
205 ccv_array_t* nodes;
206 ccv_nnc_graph_exec_symbol_new_hook_f previous_func;
207 void* previous_context;
208} ccv_functional_model_build_node_hook_t;
209
210static void _ccv_cnnp_functional_model_build_node_new(void* context, const ccv_nnc_graph_exec_symbol_t symbol, const ccv_nnc_cmd_t cmd, const ccv_nnc_tensor_symbol_t* const inputs, const int input_size, const ccv_nnc_tensor_symbol_t* const outputs, const int output_size, const char* const name)
211{
212 ccv_functional_model_build_node_hook_t* const hook = (ccv_functional_model_build_node_hook_t*)context;
213 ccv_array_push(hook->nodes, &symbol);
214 if (hook->previous_func)
215 hook->previous_func(hook->previous_context, symbol, cmd, inputs, input_size, outputs, output_size, name);
216}
217
218static void _ccv_cnnp_functional_model_build(ccv_cnnp_model_t* const super, ccv_nnc_symbolic_graph_t* const graph, const ccv_nnc_tensor_symbol_t* const inputs, const int input_size, ccv_nnc_tensor_symbol_t* const outputs, const int output_size)
219{
220 ccv_cnnp_functional_model_t* const self = (ccv_cnnp_functional_model_t*)super;
221 PRINT(CCV_CLI_VERBOSE, "[cnnp_functional_model_build] 1. %p, input_size: %d, output_size: %d\n", self, input_size, output_size)do { if ((CCV_CLI_VERBOSE & ccv_cli_get_output_levels()))
{ printf("[cnnp_functional_model_build] 1. %p, input_size: %d, output_size: %d\n"
, self, input_size, output_size); fflush(stdout); } } while (
0)
;
222 assert(self->super.input_size == input_size)((void) sizeof ((self->super.input_size == input_size) ? 1
: 0), __extension__ ({ if (self->super.input_size == input_size
) ; else __assert_fail ("self->super.input_size == input_size"
, "ccv_cnnp_model_core.c", 222, __extension__ __PRETTY_FUNCTION__
); }))
;
223 assert(self->super.output_size == output_size)((void) sizeof ((self->super.output_size == output_size) ?
1 : 0), __extension__ ({ if (self->super.output_size == output_size
) ; else __assert_fail ("self->super.output_size == output_size"
, "ccv_cnnp_model_core.c", 223, __extension__ __PRETTY_FUNCTION__
); }))
;
224 int i, j, k;
225 for (i = 0; i < self->super.input_size; i++)
226 self->sequence[i]->outputs[0] = self->sequence[i]->model->outputs[0] = inputs[i]; // Assigning the output symbol of input layer to be the input symbol.
227 ccv_array_t* input_symbols = ccv_array_new(sizeof(ccv_nnc_tensor_symbol_t), 1, 0);
228 ccv_array_t* parameter_indices = 0;
229 khash_t(io_node)kh_io_node_t* io_node_map = kh_init(io_node)kh_init_io_node();
230 for (i = self->super.input_size; i < self->sequence_size; i++)
231 {
232 ccv_cnnp_model_t* const sub_model = self->sequence[i]->model;
233 ccv_array_clear(input_symbols);
234 const ccv_array_t* const incomings = self->sequence[i]->incomings;
235 if (incomings)
236 for (j = 0; j < incomings->rnum; j++)
237 {
238 const ccv_cnnp_model_io_t input = *(ccv_cnnp_model_io_t*)ccv_array_get(incomings, j)((void*)(((char*)((incomings)->data)) + (size_t)(incomings
)->rsize * (size_t)(j)))
;
239 if (CCV_CNNP_IS_MODEL_PARAMETER(input)((input)->param_ref != 0 || (input)->param_sel != 0))
240 {
241 if (!parameter_indices)
242 parameter_indices = ccv_array_new(sizeof(int), 0, 0);
243 else
244 ccv_array_clear(parameter_indices);
245 const int param_sel = input->param_sel > 0 ? input->param_sel - 1 : input->param_sel;
246 assert(input->param_sel != 0)((void) sizeof ((input->param_sel != 0) ? 1 : 0), __extension__
({ if (input->param_sel != 0) ; else __assert_fail ("input->param_sel != 0"
, "ccv_cnnp_model_core.c", 246, __extension__ __PRETTY_FUNCTION__
); }))
;
247 ccv_cnnp_model_add_to_parameter_indices(input->model, param_sel, parameter_indices);
248 assert(parameter_indices->rnum > 0)((void) sizeof ((parameter_indices->rnum > 0) ? 1 : 0),
__extension__ ({ if (parameter_indices->rnum > 0) ; else
__assert_fail ("parameter_indices->rnum > 0", "ccv_cnnp_model_core.c"
, 248, __extension__ __PRETTY_FUNCTION__); }))
;
249 const int param_ref = input->param_ref > 0 ? input->param_ref - 1 : input->param_ref;
250 assert(input->param_ref != 0)((void) sizeof ((input->param_ref != 0) ? 1 : 0), __extension__
({ if (input->param_ref != 0) ; else __assert_fail ("input->param_ref != 0"
, "ccv_cnnp_model_core.c", 250, __extension__ __PRETTY_FUNCTION__
); }))
;
251 if (param_ref >= 0)
252 {
253 assert(param_ref < parameter_indices->rnum)((void) sizeof ((param_ref < parameter_indices->rnum) ?
1 : 0), __extension__ ({ if (param_ref < parameter_indices
->rnum) ; else __assert_fail ("param_ref < parameter_indices->rnum"
, "ccv_cnnp_model_core.c", 253, __extension__ __PRETTY_FUNCTION__
); }))
;
254 const ccv_nnc_tensor_symbol_t parameter = ccv_cnnp_parameter_from_indice(super, *(int*)ccv_array_get(parameter_indices, param_ref)((void*)(((char*)((parameter_indices)->data)) + (size_t)(parameter_indices
)->rsize * (size_t)(param_ref)))
);
255 ccv_array_push(input_symbols, &parameter);
256 } else // Otherwise, all of them.
257 for (k = 0; k < parameter_indices->rnum; k++)
258 {
259 const ccv_nnc_tensor_symbol_t parameter = ccv_cnnp_parameter_from_indice(super, *(int*)ccv_array_get(parameter_indices, k)((void*)(((char*)((parameter_indices)->data)) + (size_t)(parameter_indices
)->rsize * (size_t)(k)))
);
260 ccv_array_push(input_symbols, &parameter);
261 }
262 } else {
263 for (k = 0; k < input->model->output_size; k++)
264 ccv_array_push(input_symbols, &input->outputs[k]);
265 }
266 }
267 // Go through each sub model to build the graph.
268 ccv_array_t* nodes;
269 ccv_functional_model_build_node_hook_t hook;
270 const ccv_array_t* const dependencies = self->sequence[i]->dependencies;
271 if ((dependencies && dependencies->rnum > 0) || self->sequence[i]->dependents > 0)
272 {
273 int ret;
274 khiter_t k = kh_put(io_node, io_node_map, (uint64_t)(uintptr_t)self->sequence[i], &ret)kh_put_io_node(io_node_map, (uint64_t)(uintptr_t)self->sequence
[i], &ret)
;
275 if (ret != 0)
276 nodes = kh_val(io_node_map, k)((io_node_map)->vals[k]) = ccv_array_new(sizeof(ccv_nnc_graph_exec_symbol_t), 1, 0);
277 else
278 nodes = kh_val(io_node_map, k)((io_node_map)->vals[k]);
279 hook.nodes = nodes;
280 hook.previous_context = ccv_nnc_graph_exec_symbol_new_hook(graph, _ccv_cnnp_functional_model_build_node_new, &hook, &hook.previous_func);
281 }
282 sub_model->data = self->super.data;
283 ccv_cnnp_model_build(sub_model, graph, (ccv_nnc_tensor_symbol_t*)ccv_array_get(input_symbols, 0)((void*)(((char*)((input_symbols)->data)) + (size_t)(input_symbols
)->rsize * (size_t)(0)))
, input_symbols->rnum, self->sequence[i]->outputs, sub_model->output_size);
284 if ((dependencies && dependencies->rnum > 0) || self->sequence[i]->dependents > 0)
285 {
286 ccv_nnc_graph_exec_symbol_new_hook(graph, hook.previous_func, hook.previous_context, 0);
287 if (dependencies)
288 for (j = 0; j < dependencies->rnum; j++)
289 {
290 const ccv_cnnp_model_io_t dependency = *(ccv_cnnp_model_io_t*)ccv_array_get(dependencies, j)((void*)(((char*)((dependencies)->data)) + (size_t)(dependencies
)->rsize * (size_t)(j)))
;
291 khiter_t k = kh_get(io_node, io_node_map, (uint64_t)(uintptr_t)dependency)kh_get_io_node(io_node_map, (uint64_t)(uintptr_t)dependency);
292 if (k == kh_end(io_node_map)((io_node_map)->n_buckets))
293 continue;
294 const ccv_array_t* const dependency_nodes = kh_val(io_node_map, k)((io_node_map)->vals[k]);
295 int x, y;
296 for (y = 0; y < dependency_nodes->rnum; y++)
297 for (x = 0; x < nodes->rnum; x++)
298 ccv_nnc_graph_exec_symbol_concat(graph, *(ccv_nnc_graph_exec_symbol_t*)ccv_array_get(dependency_nodes, y)((void*)(((char*)((dependency_nodes)->data)) + (size_t)(dependency_nodes
)->rsize * (size_t)(y)))
, *(ccv_nnc_graph_exec_symbol_t*)ccv_array_get(nodes, x)((void*)(((char*)((nodes)->data)) + (size_t)(nodes)->rsize
* (size_t)(x)))
);
299 }
300 }
301 sub_model->data = 0;
302 }
303 khiter_t it;
304 for (it = kh_begin(io_node_map)(khint_t)(0); it != kh_end(io_node_map)((io_node_map)->n_buckets); ++it)
305 {
306 if (!kh_exist(io_node_map, it)(!(((io_node_map)->flags[(it)>>4]>>(((it)&
0xfU)<<1))&3))
)
307 continue;
308 ccv_array_t* const nodes = kh_val(io_node_map, it)((io_node_map)->vals[it]);
309 ccv_array_free(nodes);
310 }
311 kh_destroy(io_node, io_node_map)kh_destroy_io_node(io_node_map);
312 ccv_array_free(input_symbols);
313 if (parameter_indices)
314 ccv_array_free(parameter_indices);
315 for (i = 0, k = 0; k < self->model_output_size; k++)
316 {
317 ccv_cnnp_model_t* const sub_model = self->sequence[self->model_outputs[k]]->model;
318 for (j = 0; j < sub_model->output_size; j++)
319 outputs[i + j] = self->sequence[self->model_outputs[k]]->outputs[j];
320 i += sub_model->output_size;
321 }
322 assert(i == output_size)((void) sizeof ((i == output_size) ? 1 : 0), __extension__ ({
if (i == output_size) ; else __assert_fail ("i == output_size"
, "ccv_cnnp_model_core.c", 322, __extension__ __PRETTY_FUNCTION__
); }))
;
323 PRINT(CCV_CLI_VERBOSE, "[cnnp_functional_model_build] 2. %p\n", self)do { if ((CCV_CLI_VERBOSE & ccv_cli_get_output_levels()))
{ printf("[cnnp_functional_model_build] 2. %p\n", self); fflush
(stdout); } } while (0)
;
324}
325
326static void _ccv_cnnp_functional_model_init_states(ccv_cnnp_model_t* const super, ccv_nnc_symbolic_graph_t* const graph, const ccv_cnnp_state_initializer_f initializer, void* const context)
327{
328 ccv_cnnp_functional_model_t* const self = (ccv_cnnp_functional_model_t*)super;
329 int i;
330 for (i = self->super.input_size; i < self->sequence_size; i++)
331 ccv_cnnp_model_init_states(self->sequence[i]->model, graph, initializer, context);
332}
333
334static void _ccv_cnnp_functional_model_set_is_test(ccv_cnnp_model_t* const super, const int is_test, const ccv_cnnp_cmd_updater_f updater, void* const context)
335{
336 ccv_cnnp_functional_model_t* const self = (ccv_cnnp_functional_model_t*)super;
337 int i;
338 for (i = self->super.input_size; i < self->sequence_size; i++)
339 ccv_cnnp_model_set_is_test(self->sequence[i]->model, is_test, updater, context);
340}
341
342static void _ccv_cnnp_functional_model_add_to_parameter_indices(ccv_cnnp_model_t* const super, const int index, ccv_array_t* const parameter_indices)
343{
344 ccv_cnnp_functional_model_t* const self = (ccv_cnnp_functional_model_t*)super;
345 int i;
346 for (i = self->super.input_size; i < self->sequence_size; i++)
347 ccv_cnnp_model_add_to_parameter_indices(self->sequence[i]->model, index, parameter_indices);
348}
349
350static void _ccv_cnnp_functional_model_notify(const ccv_cnnp_model_t* const super, const int tag, void* const payload)
351{
352 ccv_cnnp_functional_model_t* const self = (ccv_cnnp_functional_model_t*)super;
353 int i;
354 for (i = 0; i < self->sequence_size; i++)
355 {
356 const ccv_cnnp_model_t* const model = self->sequence[i]->model;
357 ccv_cnnp_model_notify(model, tag, payload);
358 }
359}
360
361static ccv_cnnp_model_t* _ccv_cnnp_functional_model_copy(const ccv_cnnp_model_t* const super, void* const context);
362
363static const ccv_cnnp_model_vtab_t ccv_cnnp_functional_model_isa = {
364 .deinit = _ccv_cnnp_functional_model_deinit,
365 .dealloc = _ccv_cnnp_functional_model_dealloc,
366 .build = _ccv_cnnp_functional_model_build,
367 .init_states = _ccv_cnnp_functional_model_init_states,
368 .copy = _ccv_cnnp_functional_model_copy,
369 .set_is_test = _ccv_cnnp_functional_model_set_is_test,
370 .add_to_parameter_indices = _ccv_cnnp_functional_model_add_to_parameter_indices,
371 .notify = _ccv_cnnp_functional_model_notify,
372};
373
374KHASH_MAP_INIT_INT64(model_io, ccv_cnnp_model_io_t)typedef struct kh_model_io_s { khint_t n_buckets, size, n_occupied
, upper_bound; khint32_t *flags; khint64_t *keys; ccv_cnnp_model_io_t
*vals; } kh_model_io_t; static inline __attribute__ ((__unused__
)) kh_model_io_t *kh_init_model_io(void) { return (kh_model_io_t
*)calloc(1,sizeof(kh_model_io_t)); } static inline __attribute__
((__unused__)) void kh_destroy_model_io(kh_model_io_t *h) { if
(h) { free((void *)h->keys); free(h->flags); free((void
*)h->vals); free(h); } } static inline __attribute__ ((__unused__
)) void kh_clear_model_io(kh_model_io_t *h) { if (h &&
h->flags) { memset(h->flags, 0xaa, ((h->n_buckets) <
16? 1 : (h->n_buckets)>>4) * sizeof(khint32_t)); h->
size = h->n_occupied = 0; } } static inline __attribute__ (
(__unused__)) khint_t kh_get_model_io(const kh_model_io_t *h,
khint64_t key) { if (h->n_buckets) { khint_t k, i, last, mask
, step = 0; mask = h->n_buckets - 1; k = (khint32_t)((key)
>>33^(key)^(key)<<11); i = k & mask; last = i
; while (!((h->flags[i>>4]>>((i&0xfU)<<
1))&2) && (((h->flags[i>>4]>>((i&
0xfU)<<1))&1) || !((h->keys[i]) == (key)))) { i =
(i + (++step)) & mask; if (i == last) return h->n_buckets
; } return ((h->flags[i>>4]>>((i&0xfU)<<
1))&3)? h->n_buckets : i; } else return 0; } static inline
__attribute__ ((__unused__)) int kh_resize_model_io(kh_model_io_t
*h, khint_t new_n_buckets) { khint32_t *new_flags = 0; khint_t
j = 1; { (--(new_n_buckets), (new_n_buckets)|=(new_n_buckets
)>>1, (new_n_buckets)|=(new_n_buckets)>>2, (new_n_buckets
)|=(new_n_buckets)>>4, (new_n_buckets)|=(new_n_buckets)
>>8, (new_n_buckets)|=(new_n_buckets)>>16, ++(new_n_buckets
)); if (new_n_buckets < 4) new_n_buckets = 4; if (h->size
>= (khint_t)(new_n_buckets * __ac_HASH_UPPER + 0.5)) j = 0
; else { new_flags = (khint32_t*)malloc(((new_n_buckets) <
16? 1 : (new_n_buckets)>>4) * sizeof(khint32_t)); if (
!new_flags) return -1; memset(new_flags, 0xaa, ((new_n_buckets
) < 16? 1 : (new_n_buckets)>>4) * sizeof(khint32_t))
; if (h->n_buckets < new_n_buckets) { khint64_t *new_keys
= (khint64_t*)realloc((void *)h->keys,new_n_buckets * sizeof
(khint64_t)); if (!new_keys) { free(new_flags); return -1; } h
->keys = new_keys; if (1) { ccv_cnnp_model_io_t *new_vals =
(ccv_cnnp_model_io_t*)realloc((void *)h->vals,new_n_buckets
* sizeof(ccv_cnnp_model_io_t)); if (!new_vals) { free(new_flags
); return -1; } h->vals = new_vals; } } } } if (j) { for (
j = 0; j != h->n_buckets; ++j) { if (((h->flags[j>>
4]>>((j&0xfU)<<1))&3) == 0) { khint64_t key
= h->keys[j]; ccv_cnnp_model_io_t val; khint_t new_mask; new_mask
= new_n_buckets - 1; if (1) val = h->vals[j]; (h->flags
[j>>4]|=1ul<<((j&0xfU)<<1)); while (1) {
khint_t k, i, step = 0; k = (khint32_t)((key)>>33^(key
)^(key)<<11); i = k & new_mask; while (!((new_flags
[i>>4]>>((i&0xfU)<<1))&2)) i = (i +
(++step)) & new_mask; (new_flags[i>>4]&=~(2ul<<
((i&0xfU)<<1))); if (i < h->n_buckets &&
((h->flags[i>>4]>>((i&0xfU)<<1))&
3) == 0) { { khint64_t tmp = h->keys[i]; h->keys[i] = key
; key = tmp; } if (1) { ccv_cnnp_model_io_t tmp = h->vals[
i]; h->vals[i] = val; val = tmp; } (h->flags[i>>4
]|=1ul<<((i&0xfU)<<1)); } else { h->keys[i
] = key; if (1) h->vals[i] = val; break; } } } } if (h->
n_buckets > new_n_buckets) { h->keys = (khint64_t*)realloc
((void *)h->keys,new_n_buckets * sizeof(khint64_t)); if (1
) h->vals = (ccv_cnnp_model_io_t*)realloc((void *)h->vals
,new_n_buckets * sizeof(ccv_cnnp_model_io_t)); } free(h->flags
); h->flags = new_flags; h->n_buckets = new_n_buckets; h
->n_occupied = h->size; h->upper_bound = (khint_t)(h
->n_buckets * __ac_HASH_UPPER + 0.5); } return 0; } static
inline __attribute__ ((__unused__)) khint_t kh_put_model_io(
kh_model_io_t *h, khint64_t key, int *ret) { khint_t x; if (h
->n_occupied >= h->upper_bound) { if (h->n_buckets
> (h->size<<1)) { if (kh_resize_model_io(h, h->
n_buckets - 1) < 0) { *ret = -1; return h->n_buckets; }
} else if (kh_resize_model_io(h, h->n_buckets + 1) < 0
) { *ret = -1; return h->n_buckets; } } { khint_t k, i, site
, last, mask = h->n_buckets - 1, step = 0; x = site = h->
n_buckets; k = (khint32_t)((key)>>33^(key)^(key)<<
11); i = k & mask; if (((h->flags[i>>4]>>(
(i&0xfU)<<1))&2)) x = i; else { last = i; while
(!((h->flags[i>>4]>>((i&0xfU)<<1))&
2) && (((h->flags[i>>4]>>((i&0xfU)
<<1))&1) || !((h->keys[i]) == (key)))) { if (((h
->flags[i>>4]>>((i&0xfU)<<1))&1)
) site = i; i = (i + (++step)) & mask; if (i == last) { x
= site; break; } } if (x == h->n_buckets) { if (((h->flags
[i>>4]>>((i&0xfU)<<1))&2) &&
site != h->n_buckets) x = site; else x = i; } } } if (((h
->flags[x>>4]>>((x&0xfU)<<1))&2)
) { h->keys[x] = key; (h->flags[x>>4]&=~(3ul<<
((x&0xfU)<<1))); ++h->size; ++h->n_occupied; *
ret = 1; } else if (((h->flags[x>>4]>>((x&
0xfU)<<1))&1)) { h->keys[x] = key; (h->flags[
x>>4]&=~(3ul<<((x&0xfU)<<1))); ++h->
size; *ret = 2; } else *ret = 0; return x; } static inline __attribute__
((__unused__)) void kh_del_model_io(kh_model_io_t *h, khint_t
x) { if (x != h->n_buckets && !((h->flags[x>>
4]>>((x&0xfU)<<1))&3)) { (h->flags[x>>
4]|=1ul<<((x&0xfU)<<1)); --h->size; } }
375
376static ccv_cnnp_model_t* _ccv_cnnp_functional_model_copy(const ccv_cnnp_model_t* const super, void* const context)
377{
378 const ccv_cnnp_functional_model_t* const self = (const ccv_cnnp_functional_model_t*)super;
379 ccv_cnnp_functional_model_t* const functional_model = (ccv_cnnp_functional_model_t*)cccalloccalloc(1, sizeof(ccv_cnnp_functional_model_t) + sizeof(ccv_cnnp_model_t*) * (self->sequence_size - 1) + sizeof(ccv_nnc_tensor_symbol_t) * self->super.output_size + sizeof(int) * self->model_output_size);
380 functional_model->super.isa = &ccv_cnnp_functional_model_isa;
381 functional_model->super.outputs = (ccv_nnc_tensor_symbol_t*)(functional_model->sequence + self->sequence_size);
382 functional_model->super.output_size = self->super.output_size;
383 functional_model->super.input_size = self->super.input_size;
384 ccv_cnnp_model_copy_name(&functional_model->super, self->super.name);
385 functional_model->sequence_size = self->sequence_size;
386 functional_model->model_output_size = self->model_output_size;
387 functional_model->model_outputs = (int*)(functional_model->super.outputs + functional_model->super.output_size);
388 memcpy(functional_model->model_outputs, self->model_outputs, sizeof(int) * self->model_output_size);
389 // Now the difficult part, copy over the model_io.
390 khash_t(model_io)kh_model_io_t* model_io_map = kh_init(model_io)kh_init_model_io();
391 khash_t(model)kh_model_t* model_map = context ? (khash_t(model)kh_model_t*)context : kh_init(model)kh_init_model();
1
Assuming 'context' is null
2
'?' condition is false
3
Calling 'kh_init_model'
5
Returning from 'kh_init_model'
392 int i, j;
393 for (i = 0; i < self->sequence_size; i++)
6
Assuming 'i' is < field 'sequence_size'
7
Loop condition is true. Entering loop body
394 {
395 const ccv_cnnp_model_t* const sub_model = self->sequence[i]->model;
396 int ret;
397 khiter_t k = kh_put(model, model_map, (uint64_t)(uintptr_t)sub_model, &ret)kh_put_model(model_map, (uint64_t)(uintptr_t)sub_model, &
ret)
;
8
Calling 'kh_put_model'
398 ccv_cnnp_model_t* model_copy;
399 if (ret != 0)
400 model_copy = kh_val(model_map, k)((model_map)->vals[k]) = _ccv_cnnp_model_copy(sub_model, model_map);
401 else
402 model_copy = kh_val(model_map, k)((model_map)->vals[k]);
403 ccv_cnnp_model_io_t model_io = functional_model->sequence[i] = ccmallocmalloc(sizeof(struct ccv_cnnp_model_io_s) + sizeof(ccv_nnc_tensor_symbol_t) * sub_model->output_size);
404 model_io->param_ref = 0;
405 model_io->param_sel = 0;
406 model_io->visit = 0;
407 model_io->model = model_copy;
408 model_io->dependencies = 0;
409 model_io->dependents = 0;
410 model_io->incomings = 0;
411 model_io->outgoings = 0;
412 model_io->outputs = (ccv_nnc_tensor_symbol_t*)(model_io + 1);
413 if (!model_copy->io)
414 model_copy->io = ccv_array_new(sizeof(ccv_cnnp_model_io_t), 1, 0);
415 ccv_array_push(model_copy->io, &model_io);
416 k = kh_put(model_io, model_io_map, (uint64_t)(uintptr_t)self->sequence[i], &ret)kh_put_model_io(model_io_map, (uint64_t)(uintptr_t)self->sequence
[i], &ret)
;
417 kh_val(model_io_map, k)((model_io_map)->vals[k]) = functional_model->sequence[i];
418 }
419 for (i = self->super.input_size; i < self->sequence_size; i++)
420 {
421 if (self->sequence[i]->incomings)
422 for (j = 0; j < self->sequence[i]->incomings->rnum; j++)
423 {
424 const ccv_cnnp_model_io_t input = *(ccv_cnnp_model_io_t*)ccv_array_get(self->sequence[i]->incomings, j)((void*)(((char*)((self->sequence[i]->incomings)->data
)) + (size_t)(self->sequence[i]->incomings)->rsize *
(size_t)(j)))
;
425 if (CCV_CNNP_IS_MODEL_PARAMETER(input)((input)->param_ref != 0 || (input)->param_sel != 0)) // I am pretty sure this is not in the model_io_map.
426 {
427 int ret;
428 khiter_t k = kh_put(model_io, model_io_map, (uint64_t)(uintptr_t)input, &ret)kh_put_model_io(model_io_map, (uint64_t)(uintptr_t)input, &
ret)
;
429 if (ret != 0)
430 {
431 // The model may not exist on the map due to wrapping (it is inside another sequential or functional model).
432 khiter_t m = kh_get(model, model_map, (uint64_t)(uintptr_t)input->model)kh_get_model(model_map, (uint64_t)(uintptr_t)input->model);
433 assert(m != kh_end(model_map))((void) sizeof ((m != ((model_map)->n_buckets)) ? 1 : 0), __extension__
({ if (m != ((model_map)->n_buckets)) ; else __assert_fail
("m != kh_end(model_map)", "ccv_cnnp_model_core.c", 433, __extension__
__PRETTY_FUNCTION__); }))
;
434 ccv_cnnp_model_t* const model_copy = kh_val(model_map, m)((model_map)->vals[m]);
435 ccv_cnnp_model_io_t model_io = ccmallocmalloc(sizeof(struct ccv_cnnp_model_io_s));
436 model_io->param_ref = input->param_ref;
437 model_io->param_sel = input->param_sel;
438 model_io->visit = 0;
439 model_io->model = model_copy;
440 model_io->incomings = 0;
441 model_io->dependencies = 0;
442 model_io->dependents = 0;
443 model_io->outgoings = 0;
444 model_io->outputs = 0;
445 if (!model_copy->io)
446 model_copy->io = ccv_array_new(sizeof(ccv_cnnp_model_io_t), 1, 0);
447 ccv_array_push(model_copy->io, &model_io);
448 kh_val(model_io_map, k)((model_io_map)->vals[k]) = model_io;
449 if (input->outgoings)
450 {
451 model_io->outgoings = ccv_array_new(sizeof(ccv_cnnp_model_io_t), input->outgoings->rnum, 0);
452 int x;
453 for (x = 0; x < input->outgoings->rnum; x++)
454 {
455 khiter_t k = kh_get(model_io, model_io_map, (uint64_t)(uintptr_t)(*(ccv_cnnp_model_io_t*)ccv_array_get(input->outgoings, x)))kh_get_model_io(model_io_map, (uint64_t)(uintptr_t)(*(ccv_cnnp_model_io_t
*)((void*)(((char*)((input->outgoings)->data)) + (size_t
)(input->outgoings)->rsize * (size_t)(x)))))
;
456 assert(k != kh_end(model_io_map))((void) sizeof ((k != ((model_io_map)->n_buckets)) ? 1 : 0
), __extension__ ({ if (k != ((model_io_map)->n_buckets)) ;
else __assert_fail ("k != kh_end(model_io_map)", "ccv_cnnp_model_core.c"
, 456, __extension__ __PRETTY_FUNCTION__); }))
;
457 ccv_cnnp_model_io_t outgoing_io = kh_val(model_io_map, k)((model_io_map)->vals[k]);
458 ccv_array_push(model_io->outgoings, &outgoing_io);
459 }
460 }
461 }
462 }
463 }
464 }
465 if (!context)
466 kh_destroy(model, model_map)kh_destroy_model(model_map);
467 for (i = 0; i < self->sequence_size; i++)
468 {
469 const ccv_cnnp_model_io_t model_io = self->sequence[i];
470 ccv_cnnp_model_io_t model_io_copy = functional_model->sequence[i];
471 model_io_copy->param_ref = model_io->param_ref;
472 model_io_copy->param_sel = model_io->param_sel;
473 if (model_io->incomings)
474 {
475 model_io_copy->incomings = ccv_array_new(sizeof(ccv_cnnp_model_io_t), model_io->incomings->rnum, 0);
476 for (j = 0; j < model_io->incomings->rnum; j++)
477 {
478 khiter_t k = kh_get(model_io, model_io_map, (uint64_t)(uintptr_t)(*(ccv_cnnp_model_io_t*)ccv_array_get(model_io->incomings, j)))kh_get_model_io(model_io_map, (uint64_t)(uintptr_t)(*(ccv_cnnp_model_io_t
*)((void*)(((char*)((model_io->incomings)->data)) + (size_t
)(model_io->incomings)->rsize * (size_t)(j)))))
;
479 assert(k != kh_end(model_io_map))((void) sizeof ((k != ((model_io_map)->n_buckets)) ? 1 : 0
), __extension__ ({ if (k != ((model_io_map)->n_buckets)) ;
else __assert_fail ("k != kh_end(model_io_map)", "ccv_cnnp_model_core.c"
, 479, __extension__ __PRETTY_FUNCTION__); }))
;
480 ccv_cnnp_model_io_t input_io = kh_val(model_io_map, k)((model_io_map)->vals[k]);
481 ccv_array_push(model_io_copy->incomings, &input_io);
482 }
483 }
484 if (model_io->dependencies)
485 {
486 model_io_copy->dependencies = ccv_array_new(sizeof(ccv_cnnp_model_io_t), model_io->dependencies->rnum, 0);
487 for (j = 0; j < model_io->dependencies->rnum; j++)
488 {
489 khiter_t k = kh_get(model_io, model_io_map, (uint64_t)(uintptr_t)(*(ccv_cnnp_model_io_t*)ccv_array_get(model_io->dependencies, j)))kh_get_model_io(model_io_map, (uint64_t)(uintptr_t)(*(ccv_cnnp_model_io_t
*)((void*)(((char*)((model_io->dependencies)->data)) + (
size_t)(model_io->dependencies)->rsize * (size_t)(j))))
)
;
490 assert(k != kh_end(model_io_map))((void) sizeof ((k != ((model_io_map)->n_buckets)) ? 1 : 0
), __extension__ ({ if (k != ((model_io_map)->n_buckets)) ;
else __assert_fail ("k != kh_end(model_io_map)", "ccv_cnnp_model_core.c"
, 490, __extension__ __PRETTY_FUNCTION__); }))
;
491 ccv_cnnp_model_io_t input_io = kh_val(model_io_map, k)((model_io_map)->vals[k]);
492 ccv_array_push(model_io_copy->dependencies, &input_io);
493 }
494 }
495 model_io_copy->dependents = model_io->dependents;
496 if (model_io->outgoings)
497 {
498 model_io_copy->outgoings = ccv_array_new(sizeof(ccv_cnnp_model_io_t), model_io->outgoings->rnum, 0);
499 for (j = 0; j < model_io->outgoings->rnum; j++)
500 {
501 khiter_t k = kh_get(model_io, model_io_map, (uint64_t)(uintptr_t)(*(ccv_cnnp_model_io_t*)ccv_array_get(model_io->outgoings, j)))kh_get_model_io(model_io_map, (uint64_t)(uintptr_t)(*(ccv_cnnp_model_io_t
*)((void*)(((char*)((model_io->outgoings)->data)) + (size_t
)(model_io->outgoings)->rsize * (size_t)(j)))))
;
502 assert(k != kh_end(model_io_map))((void) sizeof ((k != ((model_io_map)->n_buckets)) ? 1 : 0
), __extension__ ({ if (k != ((model_io_map)->n_buckets)) ;
else __assert_fail ("k != kh_end(model_io_map)", "ccv_cnnp_model_core.c"
, 502, __extension__ __PRETTY_FUNCTION__); }))
;
503 ccv_cnnp_model_io_t outgoing_io = kh_val(model_io_map, k)((model_io_map)->vals[k]);
504 ccv_array_push(model_io_copy->outgoings, &outgoing_io);
505 }
506 }
507 }
508 kh_destroy(model_io, model_io_map)kh_destroy_model_io(model_io_map);
509 return (ccv_cnnp_model_t*)functional_model;
510}
511
512ccv_cnnp_model_t* ccv_cnnp_model_new(const ccv_cnnp_model_io_t* const inputs, const int input_size, const ccv_cnnp_model_io_t* const outputs, const int output_size, const int is_trainable, const char* const name)
513{
514 assert(output_size > 0)((void) sizeof ((output_size > 0) ? 1 : 0), __extension__ (
{ if (output_size > 0) ; else __assert_fail ("output_size > 0"
, "ccv_cnnp_model_core.c", 514, __extension__ __PRETTY_FUNCTION__
); }))
;
515 // Do topological sort.
516 ccv_array_t* const reverse_top = ccv_array_new(sizeof(ccv_cnnp_model_io_t), output_size, 0);
517 int i, j, k;
518 // Go through output one by one, reverse traversal them, to detect potential overlap (overlap means, for example,
519 // outputs[1] is an incoming node for outputs[0]. Thus, if we reverse them, we may have outputs[0] build before outputs[1],
520 // hence, having issues.
521 for (i = 0; i < output_size; i++)
522 outputs[i]->visit = 2;
523 for (i = output_size - 1; i >= 0; i--)
524 {
525 if (outputs[i]->visit == 3) // If we need to remove it, no need to visit.
526 continue;
527 assert(outputs[i]->visit == 2)((void) sizeof ((outputs[i]->visit == 2) ? 1 : 0), __extension__
({ if (outputs[i]->visit == 2) ; else __assert_fail ("outputs[i]->visit == 2"
, "ccv_cnnp_model_core.c", 527, __extension__ __PRETTY_FUNCTION__
); }))
;
528 ccv_array_clear(reverse_top);
529 ccv_array_push(reverse_top, &outputs[i]);
530 for (j = 0; j < reverse_top->rnum; j++)
531 {
532 const ccv_cnnp_model_io_t output = *(ccv_cnnp_model_io_t*)ccv_array_get(reverse_top, j)((void*)(((char*)((reverse_top)->data)) + (size_t)(reverse_top
)->rsize * (size_t)(j)))
;
533 assert(!CCV_CNNP_IS_MODEL_INPUT(output->model))((void) sizeof ((!((output->model)->isa == &ccv_cnnp_input_isa
)) ? 1 : 0), __extension__ ({ if (!((output->model)->isa
== &ccv_cnnp_input_isa)) ; else __assert_fail ("!CCV_CNNP_IS_MODEL_INPUT(output->model)"
, "ccv_cnnp_model_core.c", 533, __extension__ __PRETTY_FUNCTION__
); }))
;
534 // If it is input, push it here.
535 if (output->incomings && !CCV_CNNP_IS_MODEL_PARAMETER(output)((output)->param_ref != 0 || (output)->param_sel != 0))
536 for (k = 0; k < output->incomings->rnum; k++)
537 {
538 const ccv_cnnp_model_io_t input = *(ccv_cnnp_model_io_t*)ccv_array_get(output->incomings, k)((void*)(((char*)((output->incomings)->data)) + (size_t
)(output->incomings)->rsize * (size_t)(k)))
;
539 // If it is an input or parameter, skip.
540 if (CCV_CNNP_IS_MODEL_INPUT(input->model)((input->model)->isa == &ccv_cnnp_input_isa) || CCV_CNNP_IS_MODEL_PARAMETER(input)((input)->param_ref != 0 || (input)->param_sel != 0))
541 continue;
542 if (input->visit == 1 || input->visit == 3) // Visited, skip.
543 continue;
544 // If this is an output, we need to remove it from the output array. Otherwise mark it as visited.
545 input->visit = input->visit == 2 ? 3 : 1;
546 ccv_array_push(reverse_top, &input);
547 }
548 // Similar for dependencies.
549 if (output->dependencies && !CCV_CNNP_IS_MODEL_PARAMETER(output)((output)->param_ref != 0 || (output)->param_sel != 0))
550 for (k = 0; k < output->dependencies->rnum; k++)
551 {
552 const ccv_cnnp_model_io_t dependency = *(ccv_cnnp_model_io_t*)ccv_array_get(output->dependencies, k)((void*)(((char*)((output->dependencies)->data)) + (size_t
)(output->dependencies)->rsize * (size_t)(k)))
;
553 // If it is an input or parameter, skip.
554 if (CCV_CNNP_IS_MODEL_INPUT(dependency->model)((dependency->model)->isa == &ccv_cnnp_input_isa) || CCV_CNNP_IS_MODEL_PARAMETER(dependency)((dependency)->param_ref != 0 || (dependency)->param_sel
!= 0)
)
555 continue;
556 if (dependency->visit == 1 || dependency->visit == 3) // Visited, skip.
557 continue;
558 // If this is an output, we need to remove it from the output array. Otherwise mark it as visited.
559 dependency->visit = dependency->visit == 2 ? 3 : 1;
560 ccv_array_push(reverse_top, &dependency);
561 }
562 }
563 for (j = 1; j < reverse_top->rnum; j++)
564 {
565 const ccv_cnnp_model_io_t output = *(ccv_cnnp_model_io_t*)ccv_array_get(reverse_top, j)((void*)(((char*)((reverse_top)->data)) + (size_t)(reverse_top
)->rsize * (size_t)(j)))
;
566 if (output->visit == 1) // Clean the visit back.
567 output->visit = 0;
568 }
569 }
570 ccv_array_clear(reverse_top);
571 for (i = 0; i < output_size; i++) // We will assign sequence in reverse order, thus, reverse the reverse top when copying the outputs.
572 {
573 if (outputs[output_size - 1 - i]->visit == 2)
574 ccv_array_push(reverse_top, &outputs[output_size - 1 - i]);
575 assert(outputs[output_size - 1 - i]->visit == 2 || outputs[output_size - 1 - i]->visit == 3)((void) sizeof ((outputs[output_size - 1 - i]->visit == 2 ||
outputs[output_size - 1 - i]->visit == 3) ? 1 : 0), __extension__
({ if (outputs[output_size - 1 - i]->visit == 2 || outputs
[output_size - 1 - i]->visit == 3) ; else __assert_fail ("outputs[output_size - 1 - i]->visit == 2 || outputs[output_size - 1 - i]->visit == 3"
, "ccv_cnnp_model_core.c", 575, __extension__ __PRETTY_FUNCTION__
); }))
;
576 outputs[output_size - 1 - i]->visit = 0; // Clean up all visits.
577 }
578 // Go from the output, until we meet inputs.
579 uint64_t input_bitmask[((input_size - 1) >> 6) + 1];
580 memset(input_bitmask, 0, sizeof(uint64_t) * (((input_size - 1) >> 6) + 1));
581 int tensor_output_size = 0; // io can be mapped to multiple tensor outputs, therefore, need to compute the exact tensor output size.
582 for (i = 0; i < output_size; i++)
583 tensor_output_size += outputs[i]->model->output_size;
584 for (i = 0; i < reverse_top->rnum; i++)
585 {
586 const ccv_cnnp_model_io_t output = *(ccv_cnnp_model_io_t*)ccv_array_get(reverse_top, i)((void*)(((char*)((reverse_top)->data)) + (size_t)(reverse_top
)->rsize * (size_t)(i)))
;
587 assert(!CCV_CNNP_IS_MODEL_INPUT(output->model))((void) sizeof ((!((output->model)->isa == &ccv_cnnp_input_isa
)) ? 1 : 0), __extension__ ({ if (!((output->model)->isa
== &ccv_cnnp_input_isa)) ; else __assert_fail ("!CCV_CNNP_IS_MODEL_INPUT(output->model)"
, "ccv_cnnp_model_core.c", 587, __extension__ __PRETTY_FUNCTION__
); }))
;
588 // If it is input, push it here.
589 if (output->incomings && !CCV_CNNP_IS_MODEL_PARAMETER(output)((output)->param_ref != 0 || (output)->param_sel != 0))
590 for (j = 0; j < output->incomings->rnum; j++)
591 {
592 const ccv_cnnp_model_io_t input = *(ccv_cnnp_model_io_t*)ccv_array_get(output->incomings, j)((void*)(((char*)((output->incomings)->data)) + (size_t
)(output->incomings)->rsize * (size_t)(j)))
;
593 ++input->visit; // Mark it as visited.
594 if (input->visit != input->outgoings->rnum + input->dependents) // Not all dependencies visited.
595 continue;
596 if (!CCV_CNNP_IS_MODEL_INPUT(input->model)((input->model)->isa == &ccv_cnnp_input_isa) && !CCV_CNNP_IS_MODEL_PARAMETER(input)((input)->param_ref != 0 || (input)->param_sel != 0))
597 ccv_array_push(reverse_top, &input);
598 else if (CCV_CNNP_IS_MODEL_INPUT(input->model)((input->model)->isa == &ccv_cnnp_input_isa)) {
599 for (k = 0; k < input_size; k++)
600 if (input == inputs[k])
601 break;
602 assert(k < input_size)((void) sizeof ((k < input_size) ? 1 : 0), __extension__ (
{ if (k < input_size) ; else __assert_fail ("k < input_size"
, "ccv_cnnp_model_core.c", 602, __extension__ __PRETTY_FUNCTION__
); }))
;
603 input_bitmask[k >> 6] |= ((uint64_t)1 << (k & 63));
604 }
605 }
606 if (output->dependencies && !CCV_CNNP_IS_MODEL_PARAMETER(output)((output)->param_ref != 0 || (output)->param_sel != 0))
607 for (j = 0; j < output->dependencies->rnum; j++)
608 {
609 const ccv_cnnp_model_io_t dependency = *(ccv_cnnp_model_io_t*)ccv_array_get(output->dependencies, j)((void*)(((char*)((output->dependencies)->data)) + (size_t
)(output->dependencies)->rsize * (size_t)(j)))
;
610 ++dependency->visit; // Mark it as visited.
611 if (dependency->visit != (dependency->outgoings ? dependency->outgoings->rnum : 0) + dependency->dependents) // Not all dependencies visited.
612 continue;
613 if (!CCV_CNNP_IS_MODEL_INPUT(dependency->model)((dependency->model)->isa == &ccv_cnnp_input_isa) && !CCV_CNNP_IS_MODEL_PARAMETER(dependency)((dependency)->param_ref != 0 || (dependency)->param_sel
!= 0)
)
614 ccv_array_push(reverse_top, &dependency);
615 else if (CCV_CNNP_IS_MODEL_INPUT(dependency->model)((dependency->model)->isa == &ccv_cnnp_input_isa)) {
616 for (k = 0; k < input_size; k++)
617 if (dependency == inputs[k])
618 break;
619 assert(k < input_size)((void) sizeof ((k < input_size) ? 1 : 0), __extension__ (
{ if (k < input_size) ; else __assert_fail ("k < input_size"
, "ccv_cnnp_model_core.c", 619, __extension__ __PRETTY_FUNCTION__
); }))
;
620 input_bitmask[k >> 6] |= ((uint64_t)1 << (k & 63));
621 }
622 }
623 }
624 for (i = 0; i < reverse_top->rnum; i++)
625 {
626 const ccv_cnnp_model_io_t output = *(ccv_cnnp_model_io_t*)ccv_array_get(reverse_top, i)((void*)(((char*)((reverse_top)->data)) + (size_t)(reverse_top
)->rsize * (size_t)(i)))
;
627 output->visit = 0; // Clean the visit back.
628 }
629 for (i = 0; i < input_size; i++)
630 inputs[i]->visit = 0; // Clean the visit back.
631 for (i = 0; i < input_size; i++)
632 { assert((input_bitmask[i >> 6] & ((uint64_t)1 << (i & 63))))((void) sizeof (((input_bitmask[i >> 6] & ((uint64_t
)1 << (i & 63)))) ? 1 : 0), __extension__ ({ if ((input_bitmask
[i >> 6] & ((uint64_t)1 << (i & 63)))) ; else
__assert_fail ("(input_bitmask[i >> 6] & ((uint64_t)1 << (i & 63)))"
, "ccv_cnnp_model_core.c", 632, __extension__ __PRETTY_FUNCTION__
); }))
; } // Assuming they all match.
633 const int sequence_size = reverse_top->rnum + input_size;
634 ccv_cnnp_functional_model_t* const functional_model = (ccv_cnnp_functional_model_t*)cccalloccalloc(1, sizeof(ccv_cnnp_functional_model_t) + sizeof(ccv_cnnp_model_t*) * (sequence_size - 1) + sizeof(ccv_nnc_tensor_symbol_t) * tensor_output_size + sizeof(int) * output_size);
635 functional_model->super.isa = &ccv_cnnp_functional_model_isa;
636 functional_model->super.outputs = (ccv_nnc_tensor_symbol_t*)(functional_model->sequence + sequence_size);
637 functional_model->super.output_size = tensor_output_size;
638 functional_model->super.input_size = input_size;
639 functional_model->super.is_trainable = is_trainable;
640 functional_model->model_output_size = output_size;
641 functional_model->model_outputs = (int*)(functional_model->super.outputs + tensor_output_size);
642 ccv_cnnp_model_copy_name(&functional_model->super, name);
643 functional_model->sequence_size = sequence_size;
644 memcpy(functional_model->sequence, inputs, sizeof(ccv_cnnp_model_io_t) * input_size);
645 for (i = 0; i < reverse_top->rnum; i++)
646 functional_model->sequence[input_size + i] = *(ccv_cnnp_model_io_t*)ccv_array_get(reverse_top, reverse_top->rnum - 1 - i)((void*)(((char*)((reverse_top)->data)) + (size_t)(reverse_top
)->rsize * (size_t)(reverse_top->rnum - 1 - i)))
;
647 for (i = 0; i < output_size; i++)
648 {
649 for (j = sequence_size - 1; j >= input_size; j--)
650 if (functional_model->sequence[j] == outputs[i])
651 {
652 functional_model->model_outputs[i] = j;
653 break;
654 }
655 }
656 ccv_array_free(reverse_top);
657 return (ccv_cnnp_model_t*)functional_model;
658}
659
660static ccv_cnnp_model_t* _ccv_cnnp_input_copy(const ccv_cnnp_model_t* const self, void* const context)
661{
662 ccv_cnnp_model_t* const input = (ccv_cnnp_model_t*)cccalloccalloc(1, sizeof(ccv_cnnp_model_t) + sizeof(ccv_nnc_tensor_symbol_t));
663 input->isa = &ccv_cnnp_input_isa;
664 input->outputs = (ccv_nnc_tensor_symbol_t*)(input + 1);
665 input->output_size = 1;
666 return input;
667}
668
669static const ccv_cnnp_model_vtab_t ccv_cnnp_input_isa = {
670 .copy = _ccv_cnnp_input_copy,
671};
672
673ccv_cnnp_model_io_t ccv_cnnp_input(void)
674{
675 ccv_cnnp_model_t* const input = (ccv_cnnp_model_t*)cccalloccalloc(1, sizeof(ccv_cnnp_model_t) + sizeof(ccv_nnc_tensor_symbol_t));
676 input->isa = &ccv_cnnp_input_isa;
677 input->io = ccv_array_new(sizeof(ccv_cnnp_model_io_t), 1, 0);
678 ccv_cnnp_model_io_t input_io = ccmallocmalloc(sizeof(struct ccv_cnnp_model_io_s) + sizeof(ccv_nnc_tensor_symbol_t));
679 input_io->param_ref = 0;
680 input_io->param_sel = 0;
681 input_io->visit = 0;
682 input_io->incomings = 0;
683 input_io->dependencies = 0;
684 input_io->dependents = 0;
685 input_io->outgoings = 0;
686 input_io->model = input;
687 input_io->outputs = (ccv_nnc_tensor_symbol_t*)(input_io + 1);
688 ccv_array_push(input->io, &input_io);
689 input->outputs = (ccv_nnc_tensor_symbol_t*)(input + 1);
690 input->output_size = 1;
691 return input_io;
692}
693
694// MARK - Dynamic Layer
695
696typedef struct {
697 ccv_cnnp_model_t super;
698 ccv_cnnp_model_dynamic_f func;
699 void* context;
700 ccv_cnnp_model_t* model;
701} ccv_cnnp_dynamic_model_t;
702
703static void _ccv_cnnp_dynamic_model_deinit(ccv_cnnp_model_t* const super)
704{
705 ccv_cnnp_dynamic_model_t* const self = (ccv_cnnp_dynamic_model_t*)super;
706 if (self->model)
707 ccv_cnnp_model_deinit(self->model);
708}
709
710static void _ccv_cnnp_dynamic_model_dealloc(ccv_cnnp_model_t* const super)
711{
712 ccv_cnnp_dynamic_model_t* const self = (ccv_cnnp_dynamic_model_t*)super;
713 if (self->model)
714 ccv_cnnp_model_free(self->model);
715}
716
717static void _ccv_cnnp_dynamic_model_build(ccv_cnnp_model_t* const super, ccv_nnc_symbolic_graph_t* const graph, const ccv_nnc_tensor_symbol_t* const inputs, const int input_size, ccv_nnc_tensor_symbol_t* const outputs, const int output_size)
718{
719 ccv_cnnp_dynamic_model_t* const self = (ccv_cnnp_dynamic_model_t*)super;
720 PRINT(CCV_CLI_VERBOSE, "[cnnp_dynamic_model_build] 1. %p, func: %p\n", self, self->func)do { if ((CCV_CLI_VERBOSE & ccv_cli_get_output_levels()))
{ printf("[cnnp_dynamic_model_build] 1. %p, func: %p\n", self
, self->func); fflush(stdout); } } while (0)
;
721 if (!self->model)
722 {
723 ccv_nnc_tensor_param_t input_params[input_size];
724 int i;
725 for (i = 0; i < input_size; i++)
726 input_params[i] = ccv_nnc_tensor_symbol_params(graph, inputs[i]);
727 self->model = self->func(input_params, input_size, self->context);
728 // Update to use the settings of the compiled model.
729 self->super.input_size = self->model->input_size;
730 self->super.outputs = self->model->outputs;
731 self->super.output_size = self->model->output_size;
732 }
733 self->model->data = self->super.data;
734 ccv_cnnp_model_build(self->model, graph, inputs, input_size, outputs, output_size);
735 self->model->data = 0;
736 PRINT(CCV_CLI_VERBOSE, "[cnnp_dynamic_model_build] 2. %p\n", self)do { if ((CCV_CLI_VERBOSE & ccv_cli_get_output_levels()))
{ printf("[cnnp_dynamic_model_build] 2. %p\n", self); fflush
(stdout); } } while (0)
;
737}
738
739static void _ccv_cnnp_dynamic_model_init_states(ccv_cnnp_model_t* const super, ccv_nnc_symbolic_graph_t* const graph, const ccv_cnnp_state_initializer_f initializer, void* const context)
740{
741 ccv_cnnp_dynamic_model_t* const self = (ccv_cnnp_dynamic_model_t*)super;
742 assert(self->model)((void) sizeof ((self->model) ? 1 : 0), __extension__ ({ if
(self->model) ; else __assert_fail ("self->model", "ccv_cnnp_model_core.c"
, 742, __extension__ __PRETTY_FUNCTION__); }))
;
743 ccv_cnnp_model_init_states(self->model, graph, initializer, context);
744}
745
746static void _ccv_cnnp_dynamic_model_set_is_test(ccv_cnnp_model_t* const super, const int is_test, const ccv_cnnp_cmd_updater_f updater, void* const context)
747{
748 ccv_cnnp_dynamic_model_t* const self = (ccv_cnnp_dynamic_model_t*)super;
749 assert(self->model)((void) sizeof ((self->model) ? 1 : 0), __extension__ ({ if
(self->model) ; else __assert_fail ("self->model", "ccv_cnnp_model_core.c"
, 749, __extension__ __PRETTY_FUNCTION__); }))
;
750 ccv_cnnp_model_set_is_test(self->model, is_test, updater, context);
751}
752
753static ccv_cnnp_model_t* _ccv_cnnp_dynamic_model_copy(const ccv_cnnp_model_t* const super, void* const context);
754
755static void _ccv_cnnp_dynamic_model_add_to_parameter_indices(ccv_cnnp_model_t* const super, const int index, ccv_array_t* const parameter_indices)
756{
757 ccv_cnnp_dynamic_model_t* const self = (ccv_cnnp_dynamic_model_t*)super;
758 assert(self->model)((void) sizeof ((self->model) ? 1 : 0), __extension__ ({ if
(self->model) ; else __assert_fail ("self->model", "ccv_cnnp_model_core.c"
, 758, __extension__ __PRETTY_FUNCTION__); }))
;
759 ccv_cnnp_model_add_to_parameter_indices(self->model, index, parameter_indices);
760}
761
762static void _ccv_cnnp_dynamic_model_notify(const ccv_cnnp_model_t* const super, const int tag, void* const payload)
763{
764 ccv_cnnp_dynamic_model_t* const self = (ccv_cnnp_dynamic_model_t*)super;
765 if (self->model)
766 ccv_cnnp_model_notify(self->model, tag, payload);
767}
768
769static const ccv_cnnp_model_vtab_t ccv_cnnp_dynamic_model_isa = {
770 .deinit = _ccv_cnnp_dynamic_model_deinit,
771 .dealloc = _ccv_cnnp_dynamic_model_dealloc,
772 .build = _ccv_cnnp_dynamic_model_build,
773 .init_states = _ccv_cnnp_dynamic_model_init_states,
774 .copy = _ccv_cnnp_dynamic_model_copy,
775 .set_is_test = _ccv_cnnp_dynamic_model_set_is_test,
776 .add_to_parameter_indices = _ccv_cnnp_dynamic_model_add_to_parameter_indices,
777 .notify = _ccv_cnnp_dynamic_model_notify,
778};
779
780ccv_cnnp_model_t* ccv_cnnp_dynamic_new(ccv_cnnp_model_dynamic_f func, void* const context, const char* const name)
781{
782 ccv_cnnp_dynamic_model_t* const dynamic_model = (ccv_cnnp_dynamic_model_t*)cccalloccalloc(1, sizeof(ccv_cnnp_dynamic_model_t));
783 dynamic_model->super.isa = &ccv_cnnp_dynamic_model_isa;
784 dynamic_model->super.is_trainable = -1;
785 dynamic_model->func = func;
786 dynamic_model->context = context;
787 ccv_cnnp_model_copy_name(&dynamic_model->super, name);
788 return (ccv_cnnp_model_t*)dynamic_model;
789}
790
791static ccv_cnnp_model_t* _ccv_cnnp_dynamic_model_copy(const ccv_cnnp_model_t* const super, void* const context)
792{
793 const ccv_cnnp_dynamic_model_t* const self = (const ccv_cnnp_dynamic_model_t*)super;
794 return ccv_cnnp_dynamic_new(self->func, self->context, self->super.name);
795}
796
797// MARK - Command Layer
798
799typedef struct {
800 ccv_cnnp_model_t super;
801 ccv_nnc_cmd_t cmd;
802 ccv_nnc_hint_t hint;
803 ccv_nnc_tensor_symbol_t* input_symbols; // This is only valid for INIT_SHARED_TENSOR / INIT_SHARED_TENSOR_AS_TRAINABLE
804 ccv_nnc_tensor_symbol_t* output_symbols; // This is just for the output symbol (in case we need to have no tensor symbol).
805 ccv_cnnp_cmd_exec_io_t* inputs;
806 int flags;
807 int input_size;
808 int* outputs;
809 int output_size;
810} ccv_cnnp_model_cmd_exec_t;
811
812static void _ccv_cnnp_cmd_exec_build(ccv_cnnp_model_t* const super, ccv_nnc_symbolic_graph_t* const graph, const ccv_nnc_tensor_symbol_t* const inputs, const int input_size, ccv_nnc_tensor_symbol_t* const outputs, const int output_size)
813{
814 ccv_cnnp_model_cmd_exec_t* const self = (ccv_cnnp_model_cmd_exec_t*)super;
815 PRINT(CCV_CLI_VERBOSE, "[cnnp_cmd_exec_build] -\n")do { if ((CCV_CLI_VERBOSE & ccv_cli_get_output_levels()))
{ printf("[cnnp_cmd_exec_build] -\n"); fflush(stdout); } } while
(0)
;
816 ccv_nnc_tensor_param_t input_params[ccv_max(1, self->input_size)({ typeof (1) _a = (1); typeof (self->input_size) _b = (self
->input_size); (_a > _b) ? _a : _b; })
];
817 int i, j;
818 for (i = 0, j = 0; i < self->input_size; i++)
819 if (self->inputs[i].type == CCV_CNNP_IO)
820 {
821 self->input_symbols[i] = inputs[j++];
822 input_params[i] = ccv_nnc_tensor_symbol_params(graph, self->input_symbols[i]);
823 } else if (self->inputs[i].type == CCV_CNNP_NO_TENSOR) {
824 self->input_symbols[i] = NO_TENSOR_SYMBOL(const ccv_nnc_tensor_symbol_t){.d = CCV_NNC_NO_TENSOR_SYMBOL
}
;
825 } else if (!self->input_symbols[i].graph) {
826 // Otherwise, we only create this symbol if it doesn't exist.
827 const ccv_nnc_tensor_param_t params = self->inputs[i].init_state.info;
828 input_params[i] = params;
829 self->input_symbols[i] = ccv_nnc_tensor_symbol_new(graph, params, 0);
830 }
831 // We cannot simply mark the outputs as auto, because the subsequent build call may require this output to have params setup.
832 // Infer the parameters here.
833 ccv_nnc_tensor_param_t output_params[ccv_max(1, self->output_size)({ typeof (1) _a = (1); typeof (self->output_size) _b = (self
->output_size); (_a > _b) ? _a : _b; })
];
834 ccv_nnc_hint_tensor_auto(self->cmd, input_params, self->input_size, self->hint, output_params, self->output_size);
835 for (i = 0, j = 0; i < self->output_size; i++)
836 if (self->outputs[i] == CCV_CNNP_IO)
837 self->output_symbols[i] = outputs[j++] = ccv_nnc_tensor_symbol_new(graph, output_params[i], 0);
838 else if (self->outputs[i] == CCV_CNNP_TENSOR_NOT_OUTPUT)
839 self->output_symbols[i] = ccv_nnc_tensor_symbol_new(graph, output_params[i], 0);
840 else
841 self->output_symbols[i] = NO_TENSOR_SYMBOL(const ccv_nnc_tensor_symbol_t){.d = CCV_NNC_NO_TENSOR_SYMBOL
}
;
842 ccv_nnc_graph_exec_symbol_new(graph, self->cmd, self->input_symbols, self->input_size, self->output_symbols, self->output_size, 0);
843}
844
845static void _ccv_cnnp_cmd_exec_init_states(ccv_cnnp_model_t* const super, ccv_nnc_symbolic_graph_t* const graph, const ccv_cnnp_state_initializer_f initializer, void* const context)
846{
847 ccv_cnnp_model_cmd_exec_t* const self = (ccv_cnnp_model_cmd_exec_t*)super;
848 int i;
849 for (i = 0; i < self->input_size; i++)
850 if (self->inputs[i].type == CCV_CNNP_INIT_SHARED_TENSOR || self->inputs[i].type == CCV_CNNP_INIT_SHARED_TENSOR_AS_TRAINABLE)
851 self->inputs[i].init_state.init(self->input_symbols[i], initializer, context, self->inputs[i].init_state.context);
852}
853
854static void _ccv_cnnp_cmd_exec_add_to_output(ccv_cnnp_model_t* const super, const ccv_cnnp_add_to_array_f add_to_array, void* const outputs)
855{
856 ccv_cnnp_model_cmd_exec_t* const self = (ccv_cnnp_model_cmd_exec_t*)super;
857 int i;
858 for (i = 0; i < self->input_size; i++)
859 if (self->inputs[i].type == CCV_CNNP_INIT_SHARED_TENSOR)
860 add_to_array(outputs, self->input_symbols[i], 0); // Push this as retainable because it need to be init.
861}
862
863static void _ccv_cnnp_cmd_exec_add_to_parameter(ccv_cnnp_model_t* const super, const ccv_cnnp_add_to_array_f add_to_array, void* const parameters, const int is_trainable)
864{
865 ccv_cnnp_model_cmd_exec_t* const self = (ccv_cnnp_model_cmd_exec_t*)super;
866 int i;
867 for (i = 0; i < self->input_size; i++)
868 if (self->inputs[i].type == CCV_CNNP_INIT_SHARED_TENSOR_AS_TRAINABLE)
869 add_to_array(parameters, self->input_symbols[i], is_trainable); // Push this as parameter.
870}
871
872static void _ccv_cnnp_cmd_exec_deinit(ccv_cnnp_model_t* const super)
873{
874 ccv_cnnp_model_cmd_exec_t* const self = (ccv_cnnp_model_cmd_exec_t*)super;
875 int i, j;
876 for (i = 0; i < self->input_size; i++)
877 if ((self->inputs[i].type == CCV_CNNP_INIT_SHARED_TENSOR || self->inputs[i].type == CCV_CNNP_INIT_SHARED_TENSOR_AS_TRAINABLE) &&
878 self->inputs[i].init_state.context)
879 {
880 void* const context = self->inputs[i].init_state.context;
881 if (self->inputs[i].init_state.deinit)
882 self->inputs[i].init_state.deinit(context);
883 self->inputs[i].init_state.init = 0;
884 self->inputs[i].init_state.deinit = 0;
885 self->inputs[i].init_state.context = 0;
886 for (j = i + 1; j < self->input_size; j++)
887 if (self->inputs[j].init_state.context == context)
888 {
889 self->inputs[j].init_state.init = 0;
890 self->inputs[j].init_state.deinit = 0;
891 self->inputs[j].init_state.context = 0;
892 }
893 }
894}
895
896static ccv_cnnp_model_t* _ccv_cnnp_cmd_exec_copy(const ccv_cnnp_model_t* const super, void* const context);
897
898static const ccv_cnnp_model_vtab_t ccv_cnnp_cmd_exec_isa = {
899 .build = _ccv_cnnp_cmd_exec_build,
900 .init_states = _ccv_cnnp_cmd_exec_init_states,
901 .add_to_parameter = _ccv_cnnp_cmd_exec_add_to_parameter,
902 .add_to_output = _ccv_cnnp_cmd_exec_add_to_output,
903 .deinit = _ccv_cnnp_cmd_exec_deinit,
904 .copy = _ccv_cnnp_cmd_exec_copy,
905};
906
907static ccv_cnnp_model_t* _ccv_cnnp_cmd_exec(const ccv_nnc_cmd_t cmd, int copy_io, const ccv_nnc_hint_t hint, const int flags, const ccv_cnnp_cmd_exec_io_t* const inputs, const int input_size, const int* const outputs, const int output_size, const int is_trainable, const char* const name)
908{
909 assert(input_size >= 0)((void) sizeof ((input_size >= 0) ? 1 : 0), __extension__ (
{ if (input_size >= 0) ; else __assert_fail ("input_size >= 0"
, "ccv_cnnp_model_core.c", 909, __extension__ __PRETTY_FUNCTION__
); }))
;
910 assert(output_size > 0)((void) sizeof ((output_size > 0) ? 1 : 0), __extension__ (
{ if (output_size > 0) ; else __assert_fail ("output_size > 0"
, "ccv_cnnp_model_core.c", 910, __extension__ __PRETTY_FUNCTION__
); }))
;
911 int i;
912 int io_input_size = 0;
913 for (i = 0; i < input_size; i++)
914 if (inputs[i].type == CCV_CNNP_IO)
915 ++io_input_size;
916 else {
917 assert(inputs[i].type == CCV_CNNP_INIT_SHARED_TENSOR || inputs[i].type == CCV_CNNP_INIT_SHARED_TENSOR_AS_TRAINABLE)((void) sizeof ((inputs[i].type == CCV_CNNP_INIT_SHARED_TENSOR
|| inputs[i].type == CCV_CNNP_INIT_SHARED_TENSOR_AS_TRAINABLE
) ? 1 : 0), __extension__ ({ if (inputs[i].type == CCV_CNNP_INIT_SHARED_TENSOR
|| inputs[i].type == CCV_CNNP_INIT_SHARED_TENSOR_AS_TRAINABLE
) ; else __assert_fail ("inputs[i].type == CCV_CNNP_INIT_SHARED_TENSOR || inputs[i].type == CCV_CNNP_INIT_SHARED_TENSOR_AS_TRAINABLE"
, "ccv_cnnp_model_core.c", 917, __extension__ __PRETTY_FUNCTION__
); }))
;
918 assert(inputs[i].init_state.init)((void) sizeof ((inputs[i].init_state.init) ? 1 : 0), __extension__
({ if (inputs[i].init_state.init) ; else __assert_fail ("inputs[i].init_state.init"
, "ccv_cnnp_model_core.c", 918, __extension__ __PRETTY_FUNCTION__
); }))
;
919 }
920 int io_output_size = 0;
921 for (i = 0; i < output_size; i++)
922 if (outputs[i] == CCV_CNNP_IO)
923 ++io_output_size;
924 else {
925 assert(outputs[i] == CCV_CNNP_TENSOR_NOT_OUTPUT || outputs[i] == CCV_CNNP_NO_TENSOR)((void) sizeof ((outputs[i] == CCV_CNNP_TENSOR_NOT_OUTPUT || outputs
[i] == CCV_CNNP_NO_TENSOR) ? 1 : 0), __extension__ ({ if (outputs
[i] == CCV_CNNP_TENSOR_NOT_OUTPUT || outputs[i] == CCV_CNNP_NO_TENSOR
) ; else __assert_fail ("outputs[i] == CCV_CNNP_TENSOR_NOT_OUTPUT || outputs[i] == CCV_CNNP_NO_TENSOR"
, "ccv_cnnp_model_core.c", 925, __extension__ __PRETTY_FUNCTION__
); }))
;
926 }
927 assert(io_output_size > 0)((void) sizeof ((io_output_size > 0) ? 1 : 0), __extension__
({ if (io_output_size > 0) ; else __assert_fail ("io_output_size > 0"
, "ccv_cnnp_model_core.c", 927, __extension__ __PRETTY_FUNCTION__
); }))
;
928 ccv_cnnp_model_cmd_exec_t* const model_cmd_exec = (ccv_cnnp_model_cmd_exec_t*)cccalloccalloc(1, sizeof(ccv_cnnp_model_cmd_exec_t) + sizeof(ccv_nnc_tensor_symbol_t) * (io_output_size + input_size + output_size) + sizeof(ccv_cnnp_cmd_exec_io_t) * input_size + sizeof(int) * output_size);
929 model_cmd_exec->super.isa = &ccv_cnnp_cmd_exec_isa;
930 model_cmd_exec->super.input_size = io_input_size;
931 model_cmd_exec->super.outputs = (ccv_nnc_tensor_symbol_t*)(model_cmd_exec + 1);
932 model_cmd_exec->super.output_size = io_output_size;
933 model_cmd_exec->super.is_trainable = is_trainable;
934 ccv_cnnp_model_copy_name(&model_cmd_exec->super, name);
935 model_cmd_exec->cmd = cmd;
936 model_cmd_exec->hint = hint;
937 model_cmd_exec->flags = flags;
938 model_cmd_exec->input_size = input_size;
939 model_cmd_exec->input_symbols = model_cmd_exec->super.outputs + io_output_size;
940 model_cmd_exec->output_symbols = model_cmd_exec->input_symbols + input_size;
941 model_cmd_exec->inputs = (ccv_cnnp_cmd_exec_io_t*)(model_cmd_exec->output_symbols + output_size);
942 if (input_size > 0)
943 {
944 memcpy(model_cmd_exec->inputs, inputs, sizeof(ccv_cnnp_cmd_exec_io_t) * input_size);
945 if (copy_io)
946 for (i = 0; i < input_size; i++)
947 if (inputs[i].type != CCV_CNNP_IO && inputs[i].init_state.copy)
948 model_cmd_exec->inputs[i].init_state.context = inputs[i].init_state.copy(inputs[i].init_state.context);
949 }
950 model_cmd_exec->output_size = output_size;
951 model_cmd_exec->outputs = (int*)(model_cmd_exec->inputs + input_size);
952 if (output_size > 0)
953 memcpy(model_cmd_exec->outputs, outputs, sizeof(int) * output_size);
954 return (ccv_cnnp_model_t*)model_cmd_exec;
955}
956
957ccv_cnnp_model_t* ccv_cnnp_cmd_exec(const ccv_nnc_cmd_t cmd, const ccv_nnc_hint_t hint, const int flags, const ccv_cnnp_cmd_exec_io_t* const inputs, const int input_size, const int* const outputs, const int output_size, const int is_trainable, const char* const name)
958{
959 return _ccv_cnnp_cmd_exec(cmd, 0, hint, flags, inputs, input_size, outputs, output_size, is_trainable, name);
960}
961
962static ccv_cnnp_model_t* _ccv_cnnp_cmd_exec_copy(const ccv_cnnp_model_t* const super, void* const context)
963{
964 const ccv_cnnp_model_cmd_exec_t* const self = (const ccv_cnnp_model_cmd_exec_t*)super;
965 return _ccv_cnnp_cmd_exec(self->cmd, 1, self->hint, self->flags, self->inputs, self->input_size, self->outputs, self->output_size, self->super.is_trainable, self->super.name);
966}
967
968static void _ccv_cnnp_cmd_exec_io_copy(const ccv_nnc_tensor_symbol_t tensor_symbol, const ccv_cnnp_state_initializer_f initializer, void* const initializer_context, void* const context)
969{
970 initializer(initializer_context, CMD_DATA_TRANSFER_FORWARD()ccv_nnc_cmd(CCV_NNC_DATA_TRANSFER_FORWARD, 0, ccv_nnc_cmd_auto
, 0)
, ccv_nnc_no_hint, 0, (ccv_nnc_tensor_t*)context, tensor_symbol);
971}
972
973ccv_cnnp_cmd_exec_io_init_state_t ccv_cnnp_cmd_exec_io_copy(const ccv_nnc_tensor_t* const tensor)
974{
975 return (ccv_cnnp_cmd_exec_io_init_state_t){
976 .info = tensor->info,
977 .context = (void *)tensor,
978 .init = _ccv_cnnp_cmd_exec_io_copy,
979 };
980}
981
982typedef struct {
983 ccv_nnc_cmd_t cmd;
984 ccv_nnc_hint_t hint;
985 int flags;
986} ccv_cnnp_cmd_exec_io_set_by_t;
987
988static void _ccv_cnnp_cmd_exec_io_set_by(const ccv_nnc_tensor_symbol_t tensor_symbol, const ccv_cnnp_state_initializer_f initializer, void* const initializer_context, void* const context)
989{
990 const ccv_cnnp_cmd_exec_io_set_by_t* const set_by = (ccv_cnnp_cmd_exec_io_set_by_t*)context;
991 initializer(initializer_context, set_by->cmd, set_by->hint, set_by->flags, 0, tensor_symbol);
992}
993
994static void* _ccv_cnnp_cmd_exec_io_set_by_copy(void* const context)
995{
996 ccv_cnnp_cmd_exec_io_set_by_t* const set_by = (ccv_cnnp_cmd_exec_io_set_by_t*)ccmallocmalloc(sizeof(ccv_cnnp_cmd_exec_io_set_by_t));
997 memcpy(set_by, context, sizeof(ccv_cnnp_cmd_exec_io_set_by_t));
998 return set_by;
999}
1000
1001ccv_cnnp_cmd_exec_io_init_state_t ccv_cnnp_cmd_exec_io_set_by(const ccv_nnc_cmd_t cmd, const ccv_nnc_hint_t hint, const int flags, const ccv_nnc_tensor_param_t params)
1002{
1003 ccv_cnnp_cmd_exec_io_set_by_t* const set_by = (ccv_cnnp_cmd_exec_io_set_by_t*)ccmallocmalloc(sizeof(ccv_cnnp_cmd_exec_io_set_by_t));
1004 set_by->cmd = cmd;
1005 set_by->hint = hint;
1006 set_by->flags = flags;
1007 return (ccv_cnnp_cmd_exec_io_init_state_t){
1008 .info = params,
1009 .context = set_by,
1010 .init = _ccv_cnnp_cmd_exec_io_set_by,
1011 .copy = _ccv_cnnp_cmd_exec_io_set_by_copy,
1012 .deinit = ccfreefree,
1013 };
1014}