Coverage Report

Created: 2024-08-18 16:21

/home/liu/actions-runner/_work/ccv/ccv/lib/nnc/ccv_nnc_micro_interpret.c
Line
Count
Source (jump to first uncovered line)
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
7
// MARK - Level-1 API
8
9
static int _ccv_nnc_micro_index_interpret(const ccv_nnc_micro_loop_index_term_t index, const int* const loop_counter, const int* const shapes, const ccv_nnc_micro_scalar_t* const values, const int parameter_size)
10
40.3k
{
11
40.3k
  switch (index.type)
12
40.3k
  {
13
5.32k
    case CCV_NNC_MICRO_LOOP_INDEX_TYPE_VAL:
14
5.32k
      return index.immediate_value;
15
30.6k
    case CCV_NNC_MICRO_LOOP_INDEX_TYPE_ID:
16
30.6k
      switch (index.id.type)
17
30.6k
      {
18
955
        case CCV_NNC_MICRO_AXIS_SIZE_ID:
19
955
          return shapes[index.id.id * CCV_NNC_MAX_DIM_ALLOC + index.id.d];
20
29.6k
        case CCV_NNC_MICRO_LOOP_ID:
21
29.6k
          return loop_counter[index.id.id];
22
20
        case CCV_NNC_MICRO_SCALAR_ID:
23
20
          switch (values[index.id.id].type)
24
20
          {
25
0
            case CCV_8U:
26
0
              return values[index.id.id].u8;
27
20
            case CCV_32S:
28
20
              return values[index.id.id].i32;
29
0
            case CCV_64S:
30
0
              return (int)values[index.id.id].i64;
31
20
          }
32
0
          break;
33
30.6k
      }
34
0
      break;
35
4.35k
    case CCV_NNC_MICRO_LOOP_INDEX_TYPE_BINARY: {
36
4.35k
      const int left = _ccv_nnc_micro_index_interpret(index.binary->left, loop_counter, shapes, values, parameter_size);
37
4.35k
      const int right = _ccv_nnc_micro_index_interpret(index.binary->right, loop_counter, shapes, values, parameter_size);
38
4.35k
      switch (index.binary->op)
39
4.35k
      {
40
4.33k
        case CCV_NNC_MICRO_BINARY_OP_PLUS:
41
4.33k
          return left + right;
42
16
        case CCV_NNC_MICRO_BINARY_OP_MINUS:
43
16
          return left - right;
44
0
        case CCV_NNC_MICRO_BINARY_OP_MUL:
45
0
          return left * right;
46
0
        case CCV_NNC_MICRO_BINARY_OP_DIV:
47
0
          return left / right;
48
0
        case CCV_NNC_MICRO_BINARY_OP_MAX:
49
0
          return ccv_max(left, right);
50
0
        case CCV_NNC_MICRO_BINARY_OP_MIN:
51
0
          return ccv_min(left, right);
52
4.35k
      }
53
0
      break;
54
4.35k
    }
55
40.3k
  }
56
0
  return 0;
57
40.3k
}
58
59
static float _ccv_nnc_micro_expression_interpret(const ccv_nnc_micro_loop_expression_t* const expression, const int* const loop_counter, const ccv_nnc_micro_scalar_t* const carrieds, const int carried_count, float* const* const vars_mem, const int* const shapes, const ccv_nnc_micro_scalar_t* const values, const int parameter_size, int* const out_of_bound_ref)
60
7.15k
{
61
7.15k
  int i;
62
7.15k
  switch (expression->type)
63
7.15k
  {
64
28
    case CCV_NNC_MICRO_LOOP_EXPR_TYPE_ID: {
65
28
      assert(expression->id.type == CCV_NNC_MICRO_LOOP_CARRIED_ID);
66
28
      return carrieds[expression->id.id].f32;
67
28
    }
68
354
    case CCV_NNC_MICRO_LOOP_EXPR_TYPE_VAL: {
69
354
      return expression->immediate_value.f32;
70
28
    }
71
4.53k
    case CCV_NNC_MICRO_LOOP_EXPR_TYPE_VAR: {
72
4.53k
      const ccv_nnc_micro_loop_variable_t variable = expression->variable;
73
4.53k
      assert(variable.id.type == CCV_NNC_MICRO_TENSOR_ID);
74
4.53k
      float* ptr = vars_mem[variable.id.id];
75
4.53k
      size_t size = 1;
76
4.53k
      int out_of_bound = 0;
77
26.6k
      for (i = variable.index_count - 1; !out_of_bound && i >= 0; 
i--22.1k
)
78
22.1k
      {
79
22.1k
        const int index = _ccv_nnc_micro_index_interpret(variable.index[i], loop_counter, shapes, values, parameter_size);
80
22.1k
        if (!variable.no_check_bound[i] &&
81
22.1k
          
(2.88k
index < 02.88k
||
index >= shapes[variable.id.id * 2.88k
CCV_NNC_MAX_DIM_ALLOC2.88k
+ i]))
82
0
          out_of_bound = 1;
83
22.1k
        ptr += index * size;
84
22.1k
        size *= shapes[variable.id.id * CCV_NNC_MAX_DIM_ALLOC + i];
85
22.1k
      }
86
4.53k
      if (out_of_bound)
87
0
      {
88
0
        *out_of_bound_ref = 1;
89
0
        return 0;
90
0
      }
91
4.53k
      return ptr[0];
92
4.53k
    }
93
0
    case CCV_NNC_MICRO_LOOP_EXPR_TYPE_UNARY: {
94
0
      const float left = _ccv_nnc_micro_expression_interpret(expression->unary.x, loop_counter, carrieds, carried_count, vars_mem, shapes, values, parameter_size, out_of_bound_ref);
95
0
      if (*out_of_bound_ref)
96
0
        return 0;
97
0
      switch (expression->unary.unary_op)
98
0
      {
99
0
        case CCV_NNC_MICRO_UNARY_OP_EXP:
100
0
          return exp(left);
101
0
        case CCV_NNC_MICRO_UNARY_OP_LOG:
102
0
          return log(left);
103
0
      }
104
0
      break;
105
0
    }
106
2.23k
    case CCV_NNC_MICRO_LOOP_EXPR_TYPE_BINARY: {
107
2.23k
      const float left = _ccv_nnc_micro_expression_interpret(expression->binary.left, loop_counter, carrieds, carried_count, vars_mem, shapes, values, parameter_size, out_of_bound_ref);
108
2.23k
      if (*out_of_bound_ref)
109
0
        return 0;
110
2.23k
      const float right = _ccv_nnc_micro_expression_interpret(expression->binary.right, loop_counter, carrieds, carried_count, vars_mem, shapes, values, parameter_size, out_of_bound_ref);
111
2.23k
      if (*out_of_bound_ref)
112
0
        return 0;
113
2.23k
      switch (expression->binary.binary_op)
114
2.23k
      {
115
0
        case CCV_NNC_MICRO_BINARY_OP_PLUS:
116
0
          return left + right;
117
0
        case CCV_NNC_MICRO_BINARY_OP_MINUS:
118
0
          return left - right;
119
2.23k
        case CCV_NNC_MICRO_BINARY_OP_MUL:
120
2.23k
          return left * right;
121
0
        case CCV_NNC_MICRO_BINARY_OP_DIV:
122
0
          return left / right;
123
0
        case CCV_NNC_MICRO_BINARY_OP_MAX:
124
0
          return ccv_max(left, right);
125
0
        case CCV_NNC_MICRO_BINARY_OP_MIN:
126
0
          return ccv_min(left, right);
127
2.23k
      }
128
0
      break;
129
2.23k
    }
130
7.15k
  }
131
0
  return 0;
132
7.15k
}
133
134
static void _ccv_nnc_micro_statement_interpret(const ccv_nnc_micro_loop_statement_t statement, const int* const loop_counter, ccv_nnc_micro_scalar_t* const carrieds, const int carried_count, float* const* const vars_mem, const int* const shapes, const ccv_nnc_micro_scalar_t* const values, const int parameter_size)
135
2.68k
{
136
2.68k
  int i;
137
2.68k
  switch (statement.type)
138
2.68k
  {
139
454
    case CCV_NNC_MICRO_LOOP_STATEMENT_TYPE_ASSIGNMENT: {
140
454
      assert(statement.assignment.lvalue.id.type == CCV_NNC_MICRO_TENSOR_ID);
141
454
      const ccv_nnc_micro_loop_variable_t variable = statement.assignment.lvalue;
142
454
      float* ptr = vars_mem[variable.id.id];
143
454
      size_t size = 1;
144
454
      int out_of_bound = 0;
145
2.20k
      for (i = variable.index_count - 1; !out_of_bound && i >= 0; 
i--1.75k
)
146
1.75k
      {
147
1.75k
        const int index = _ccv_nnc_micro_index_interpret(variable.index[i], loop_counter, shapes, values, parameter_size);
148
1.75k
        if (!variable.no_check_bound[i] &&
149
1.75k
          
(0
index < 00
||
index >= shapes[variable.id.id * 0
CCV_NNC_MAX_DIM_ALLOC0
+ i]))
150
0
          out_of_bound = 1;
151
1.75k
        ptr += index * size;
152
1.75k
        size *= shapes[variable.id.id * CCV_NNC_MAX_DIM_ALLOC + i];
153
1.75k
      }
154
454
      if (out_of_bound)
155
0
        return;
156
454
      const float val = _ccv_nnc_micro_expression_interpret(&statement.assignment.rvalue, loop_counter, carrieds, carried_count, vars_mem, shapes, values, parameter_size, &out_of_bound);
157
454
      if (out_of_bound)
158
0
        return;
159
454
      ptr[0] = val;
160
454
      break;
161
454
    }
162
2.23k
    case CCV_NNC_MICRO_LOOP_STATEMENT_TYPE_COMPOUND_ASSIGNMENT: {
163
2.23k
      int out_of_bound = 0;
164
2.23k
      const float rvalue = _ccv_nnc_micro_expression_interpret(&statement.compound_assignment.rvalue, loop_counter, carrieds, carried_count, vars_mem, shapes, values, parameter_size, &out_of_bound);
165
2.23k
      if (out_of_bound)
166
0
        return;
167
2.23k
      switch (statement.compound_assignment.lvalue.type)
168
2.23k
      {
169
744
        case CCV_NNC_MICRO_LOOP_EXPR_TYPE_ID: {
170
744
          assert(statement.compound_assignment.lvalue.id.type == CCV_NNC_MICRO_LOOP_CARRIED_ID);
171
744
          switch (statement.compound_assignment.lvalue.id.d)
172
744
          {
173
0
            case CCV_NNC_MICRO_REDUCE_OP_MAX:
174
0
              carrieds[statement.compound_assignment.lvalue.id.id].f32 = ccv_max(carrieds[statement.compound_assignment.lvalue.id.id].f32, rvalue);
175
0
              break;
176
0
            case CCV_NNC_MICRO_REDUCE_OP_MIN:
177
0
              carrieds[statement.compound_assignment.lvalue.id.id].f32 = ccv_min(carrieds[statement.compound_assignment.lvalue.id.id].f32, rvalue);
178
0
              break;
179
0
            case CCV_NNC_MICRO_REDUCE_OP_ARGMAX:
180
0
              assert(0);
181
0
              break;
182
0
            case CCV_NNC_MICRO_REDUCE_OP_ARGMIN:
183
0
              assert(0);
184
0
              break;
185
0
            case CCV_NNC_MICRO_REDUCE_OP_MEAN:
186
0
              carrieds[statement.compound_assignment.lvalue.id.id].f32 += rvalue;
187
0
              break;
188
744
            case CCV_NNC_MICRO_REDUCE_OP_SUM:
189
744
              carrieds[statement.compound_assignment.lvalue.id.id].f32 += rvalue;
190
744
              break;
191
0
            case CCV_NNC_MICRO_REDUCE_OP_PROD:
192
0
              carrieds[statement.compound_assignment.lvalue.id.id].f32 *= rvalue;
193
0
              break;
194
744
          }
195
744
          break;
196
744
        }
197
1.48k
        case CCV_NNC_MICRO_LOOP_EXPR_TYPE_VAR: {
198
1.48k
          assert(statement.compound_assignment.lvalue.id.type == CCV_NNC_MICRO_TENSOR_ID);
199
1.48k
          const ccv_nnc_micro_loop_variable_t variable = statement.compound_assignment.lvalue.variable;
200
1.48k
          float* ptr = vars_mem[variable.id.id];
201
1.48k
          size_t size = 1;
202
7.34k
          for (i = variable.index_count - 1; !out_of_bound && i >= 0; 
i--5.85k
)
203
5.85k
          {
204
5.85k
            const int index = _ccv_nnc_micro_index_interpret(variable.index[i], loop_counter, shapes, values, parameter_size);
205
5.85k
            if (!variable.no_check_bound[i] &&
206
5.85k
              
(1.44k
index < 01.44k
||
index >= shapes[variable.id.id * 1.44k
CCV_NNC_MAX_DIM_ALLOC1.44k
+ i]))
207
0
              out_of_bound = 1;
208
5.85k
            ptr += index * size;
209
5.85k
            size *= shapes[variable.id.id * CCV_NNC_MAX_DIM_ALLOC + i];
210
5.85k
          }
211
1.48k
          if (out_of_bound)
212
0
            return;
213
1.48k
          ptr[0] += rvalue;
214
1.48k
          break;
215
1.48k
        }
216
2.23k
      }
217
2.23k
      break;
218
2.23k
    }
219
2.68k
  }
220
2.68k
}
221
222
static void _ccv_nnc_micro_loop_interpret(const ccv_nnc_micro_loop_t* const loops, const int loop_count, const int index, int* const loop_counter, ccv_nnc_micro_scalar_t* const carrieds, const int carried_count, float* const* const vars_mem, const int* const shapes, const ccv_nnc_micro_scalar_t* const values, const int parameter_size)
223
2.78k
{
224
2.78k
  if (index >= loop_count)
225
1.91k
    return;
226
871
  const int start_index = _ccv_nnc_micro_index_interpret(loops[index].start_index, loop_counter, shapes, values, parameter_size);
227
871
  const int end_index = _ccv_nnc_micro_index_interpret(loops[index].end_index, loop_counter, shapes, values, parameter_size);
228
871
  int i, j;
229
871
  const ccv_nnc_micro_loop_statement_t* const statements = loops[index].statements;
230
871
  const int statement_count = loops[index].statement_count;
231
871
  const ccv_nnc_micro_loop_carried_t* const carried_refs = loops[index].carrieds;
232
871
  const int carried_ref_count = loops[index].carried_count;
233
3.64k
  for (i = start_index; i < end_index; 
i++2.77k
)
234
2.77k
  {
235
2.77k
    loop_counter[loops[index].id.id] = i;
236
2.79k
    for (j = 0; j < carried_ref_count; 
j++28
)
237
28
    {
238
28
      assert(carried_refs[j].id.type == CCV_NNC_MICRO_LOOP_CARRIED_ID);
239
28
      assert(carried_refs[j].id.id < carried_count);
240
28
      switch (carried_refs[j].id.d)
241
28
      {
242
0
        case CCV_NNC_MICRO_REDUCE_OP_MAX:
243
0
          carrieds[carried_refs[j].id.id].f32 = -FLT_MAX;
244
0
          break;
245
0
        case CCV_NNC_MICRO_REDUCE_OP_MIN:
246
0
          carrieds[carried_refs[j].id.id].f32 = FLT_MAX;
247
0
          break;
248
0
        case CCV_NNC_MICRO_REDUCE_OP_ARGMAX:
249
0
          carrieds[carried_refs[j].id.id].i32 = -1;
250
0
          break;
251
0
        case CCV_NNC_MICRO_REDUCE_OP_ARGMIN:
252
0
          carrieds[carried_refs[j].id.id].i32 = -1;
253
0
          break;
254
0
        case CCV_NNC_MICRO_REDUCE_OP_MEAN:
255
0
          carrieds[carried_refs[j].id.id].f32 = 0;
256
0
          break;
257
28
        case CCV_NNC_MICRO_REDUCE_OP_SUM:
258
28
          carrieds[carried_refs[j].id.id].f32 = 0;
259
28
          break;
260
0
        case CCV_NNC_MICRO_REDUCE_OP_PROD:
261
0
          carrieds[carried_refs[j].id.id].f32 = 1;
262
0
          break;
263
28
      }
264
28
    }
265
2.77k
    _ccv_nnc_micro_loop_interpret(loops, loop_count, index + 1, loop_counter, carrieds, carried_count, vars_mem, shapes, values, parameter_size);
266
5.45k
    for (j = 0; j < statement_count; 
j++2.68k
)
267
2.68k
      _ccv_nnc_micro_statement_interpret(statements[j], loop_counter, carrieds, carried_count, vars_mem, shapes, values, parameter_size);
268
2.77k
  }
269
871
}
270
271
void ccv_nnc_micro_combine_interpret(ccv_nnc_micro_combine_t* const combine, const uint32_t cmd, ccv_nnc_tensor_t* const* const inputs, const int input_size, const ccv_nnc_micro_scalar_t* const values, const int parameter_size, ccv_nnc_tensor_t* const* const outputs, const int output_size)
272
6
{
273
  // We haven't optimized for emit_grad at the moment yet.
274
6
  assert(cmd == CCV_NNC_CUSTOM_FORWARD || cmd == CCV_NNC_CUSTOM_BACKWARD);
275
6
  int i, j;
276
6
  const ccv_nnc_micro_program_t* const program = cmd == CCV_NNC_CUSTOM_FORWARD ? 
&combine->forward3
:
&combine->backward3
;
277
6
  const int var_count = program->var_count;
278
6
  assert(input_size == program->input_size);
279
6
  assert(output_size == program->output_size);
280
6
  assert(parameter_size == combine->parameter_size);
281
6
  int* const shapes = (int*)cccalloc(var_count, sizeof(int) * CCV_NNC_MAX_DIM_ALLOC);
282
6
  ccv_nnc_micro_tensor_t* const vars = program->vars;
283
21
  for (i = 0; i < input_size; 
i++15
)
284
15
    memcpy(shapes + program->inputs[i] * CCV_NNC_MAX_DIM_ALLOC, &inputs[i]->info.dim, sizeof(int) * CCV_NNC_MAX_DIM_ALLOC);
285
6
  int loop_counter[CCV_NNC_MAX_DIM_ALLOC];
286
60
  for (i = 0; i < var_count; 
i++54
)
287
54
  {
288
54
    int flag = 0;
289
186
    for (j = 0; !flag && 
j < input_size171
;
j++132
)
290
132
      flag = (program->inputs[j] == i);
291
54
    if (flag)
292
15
      continue;
293
39
    if (vars[i].shape)
294
18
    {
295
120
      for (j = 0; j < vars[i].dimensions; 
j++102
)
296
102
        shapes[i * CCV_NNC_MAX_DIM_ALLOC + j] = _ccv_nnc_micro_index_interpret(vars[i].shape[j], loop_counter, shapes, values, parameter_size);
297
18
    } else
298
21
      memcpy(shapes + i * CCV_NNC_MAX_DIM_ALLOC, shapes + vars[i].input * CCV_NNC_MAX_DIM_ALLOC, sizeof(int) * CCV_NNC_MAX_DIM_ALLOC);
299
39
  }
300
6
  const ccv_array_t* const equal_assertions = combine->equal_assertions;
301
14
  for (i = 0; i < equal_assertions->rnum; 
i++8
)
302
8
  {
303
8
    ccv_nnc_micro_id_equal_assertion_t* const equal_assertion = ccv_array_get(equal_assertions, i);
304
8
    assert(shapes[equal_assertion->left.id * CCV_NNC_MAX_DIM_ALLOC + equal_assertion->left.d] == shapes[equal_assertion->right.id * CCV_NNC_MAX_DIM_ALLOC + equal_assertion->right.d]);
305
8
  }
306
6
  size_t total_size = 0;
307
60
  for (i = 0; i < var_count; 
i++54
)
308
54
  {
309
54
    int flag = 0;
310
186
    for (j = 0; !flag && 
j < input_size171
;
j++132
)
311
132
      flag = (program->inputs[j] == i);
312
117
    for (j = 0; !flag && 
j < output_size93
;
j++63
)
313
63
      flag = (program->outputs[j] == i);
314
54
    if (flag)
315
24
      continue;
316
30
    if (vars[i].no_alloc) // This is skipped.
317
27
      continue;
318
    // allocating memory for these.
319
3
    size_t size = 1;
320
12
    for (j = 0; j < vars[i].dimensions; 
j++9
)
321
9
      size *= shapes[i * CCV_NNC_MAX_DIM_ALLOC + j];
322
3
    total_size += size;
323
3
  }
324
6
  float** const vars_mem = (float**)ccmalloc(sizeof(float*) * var_count + sizeof(float) * total_size);
325
6
  float* ptr = (float*)(vars_mem + var_count);
326
  // Assuming these are not tensor_view_t.
327
15
  for (i = 0; i < output_size; 
i++9
)
328
9
  {
329
9
    assert(CCV_IS_TENSOR_CONTIGUOUS(outputs[i]));
330
9
    vars_mem[program->outputs[i]] = outputs[i]->data.f32;
331
9
  }
332
60
  
for (i = 0; 6
i < var_count;
i++54
)
333
54
  {
334
54
    int flag = 0;
335
186
    for (j = 0; !flag && 
j < input_size171
;
j++132
)
336
132
      flag = (program->inputs[j] == i);
337
117
    for (j = 0; !flag && 
j < output_size93
;
j++63
)
338
63
      flag = (program->outputs[j] == i);
339
54
    if (flag)
340
24
      continue;
341
30
    if (vars[i].no_alloc) // This is skipped.
342
27
    {
343
27
      vars_mem[i] = 0;
344
27
      continue;
345
27
    }
346
    // allocating memory for these.
347
3
    size_t size = 1;
348
12
    for (j = 0; j < vars[i].dimensions; 
j++9
)
349
9
      size *= shapes[i * CCV_NNC_MAX_DIM_ALLOC + j];
350
3
    vars_mem[i] = ptr;
351
3
    ptr += size;
352
3
  }
353
21
  for (i = 0; i < input_size; 
i++15
)
354
15
  {
355
15
    assert(CCV_IS_TENSOR_CONTIGUOUS(inputs[i]));
356
15
    vars_mem[program->inputs[i]] = inputs[i]->data.f32;
357
15
  }
358
6
  ccv_nnc_micro_function_t* const functions = program->functions;
359
6
  const int function_count = program->function_count;
360
6
  int max_carried_count = 0;
361
12
  for (i = 0; i < function_count; 
i++6
)
362
6
  {
363
6
    const int block_count = functions[i].block_count;
364
6
    ccv_nnc_micro_loop_block_t* const blocks = block_count == 1 ? 
&functions[i].one_block2
:
functions[i].blocks4
;
365
21
    for (j = 0; j < block_count; 
j++15
)
366
15
      max_carried_count = ccv_max(max_carried_count, blocks[j].carried_count);
367
6
  }
368
6
  ccv_nnc_micro_scalar_t* const carrieds = max_carried_count > 0 ? (ccv_nnc_micro_scalar_t*)ccmalloc(sizeof(ccv_nnc_micro_scalar_t) * max_carried_count) : 
00
;
369
12
  for (i = 0; i < function_count; 
i++6
)
370
6
  {
371
6
    const int block_count = functions[i].block_count;
372
6
    ccv_nnc_micro_loop_block_t* const blocks = block_count == 1 ? 
&functions[i].one_block2
:
functions[i].blocks4
;
373
21
    for (j = 0; j < block_count; 
j++15
)
374
15
      _ccv_nnc_micro_loop_interpret(blocks[j].loops, blocks[j].loop_count, 0, loop_counter, carrieds, blocks[j].carried_count, vars_mem, shapes, values, parameter_size);
375
6
  }
376
6
  if (carrieds)
377
6
    ccfree(carrieds);
378
6
  ccfree(vars_mem);
379
6
  ccfree(shapes);
380
6
}