Coverage Report

Created: 2026-04-14 19:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/home/liu/actions-runner/_work/ccv/ccv/lib/nnc/cmd/pad/ccv_nnc_pad_cpu_ref.c
Line
Count
Source
1
#include "ccv.h"
2
#include "ccv_internal.h"
3
#include "nnc/ccv_nnc.h"
4
#include "nnc/ccv_nnc_easy.h"
5
#include "nnc/ccv_nnc_internal.h"
6
#ifdef USE_OPENMP
7
#include <omp.h>
8
#endif
9
#ifdef USE_DISPATCH
10
#include <dispatch/dispatch.h>
11
#endif
12
13
static int _ccv_nnc_pad_forw(const ccv_nnc_cmd_t cmd, const ccv_nnc_hint_t hint, const int flags, ccv_nnc_tensor_t* const* const inputs, const int input_size, ccv_nnc_tensor_t* const* const outputs, const int output_size, ccv_nnc_stream_context_t* const stream_context)
14
16
{
15
16
  assert(input_size == 1);
16
16
  ccv_nnc_tensor_view_t* const a = (ccv_nnc_tensor_view_t*)inputs[0];
17
16
  ccv_nnc_tensor_view_t* const b = (ccv_nnc_tensor_view_t*)outputs[0];
18
16
  assert(ccv_nnc_tensor_nd(a->info.dim) <= CCV_NNC_MAX_DIM + 2);
19
16
  assert(ccv_nnc_tensor_nd(b->info.dim) <= CCV_NNC_MAX_DIM + 2);
20
  // Assuming this is float 32.
21
16
  int adim[CCV_NNC_MAX_DIM_ALLOC];
22
16
  int bdim[CCV_NNC_MAX_DIM_ALLOC];
23
16
  ccv_nnc_tensor_view_get_dim(a, adim);
24
16
  ccv_nnc_tensor_view_get_dim(b, bdim);
25
16
  int astride[CCV_NNC_MAX_DIM_ALLOC];
26
16
  int bstride[CCV_NNC_MAX_DIM_ALLOC];
27
16
  assert(CCV_NNC_MAX_DIM == 2); // Need to change this logic for CCV_NNC_MAX_DIM == other number.
28
16
  ccv_nnc_tensor_view_get_stride(a, astride);
29
16
  ccv_nnc_tensor_view_get_stride(b, bstride);
30
16
  int i[CCV_NNC_MAX_DIM + 2];
31
16
  int x;
32
16
  float* const ap = a->data.f32;
33
16
  float* const bp = b->data.f32;
34
16
  const int nd = ccv_nnc_tensor_nd(a->info.dim);
35
16
  const int offset = CCV_NNC_MAX_DIM + 2 - nd;
36
16
  assert(offset >= 0);
37
56
  
for (x = 0; 16
x < nd;
x++40
) // We don't support negative pad.
38
40
    { assert(cmd.info.size.dim[x] >= 0 && cmd.info.pad.end[x] >= 0); }
39
16
  int begin[CCV_NNC_MAX_DIM_ALLOC];
40
56
  for (x = 0; x < nd; 
x++40
)
41
40
    begin[x + offset] = cmd.info.size.dim[x];
42
40
  for (x = 0; x < offset; 
x++24
)
43
24
    begin[x] = 0;
44
  // Non-optimal case, need to do skip if needed.
45
16
  if (cmd.info.pad.type == CCV_NNC_PAD_ZERO)
46
6
  {
47
16
    for (i[0] = 0; i[0] < bdim[0]; 
i[0]++10
)
48
10
    {
49
10
      float* const ap0 = (i[0] >= begin[0] && 
i[0] < adim[0] + begin[0]8
) ?
ap + (i[0] - begin[0]) * astride[0]7
:
03
;
50
10
      float* const bp0 = bp + i[0] * bstride[0];
51
42
      for (i[1] = 0; i[1] < bdim[1]; 
i[1]++32
)
52
32
      {
53
32
        float* const ap1 = (ap0 && 
i[1] >= begin[1]20
&&
i[1] < adim[1] + begin[1]15
) ?
ap0 + (i[1] - begin[1]) * astride[1]11
:
021
;
54
32
        float* bp1 = bp0 + i[1] * bstride[1];
55
154
        for (i[2] = 0; i[2] < bdim[2]; 
i[2]++122
)
56
122
        {
57
122
          float* const ap2 = (ap1 && 
i[2] >= begin[2]47
&&
i[2] < adim[2] + begin[2]32
) ?
ap1 + (i[2] - begin[2]) * astride[2]24
:
098
;
58
789
          for (x = 0; x < bdim[3]; 
x++667
)
59
667
            bp1[x] = (ap2 && 
x >= begin[3]148
&&
x < adim[3] + begin[3]142
) ?
ap2[x - begin[3]]122
:
0545
;
60
122
          bp1 += bstride[2];
61
122
        }
62
32
      }
63
10
    }
64
10
  } else if (cmd.info.pad.type == CCV_NNC_PAD_REFLECT) {
65
15
    for (i[0] = 0; i[0] < bdim[0]; 
i[0]++10
)
66
10
    {
67
10
      float* const ap0 = ap + (i[0] - begin[0] > adim[0] - 1 ? 
adim[0] - 2 - (i[0] - begin[0] - adim[0])1
:
abs(i[0] - begin[0])9
) * astride[0];
68
10
      float* const bp0 = bp + i[0] * bstride[0];
69
41
      for (i[1] = 0; i[1] < bdim[1]; 
i[1]++31
)
70
31
      {
71
31
        float* const ap1 = ap0 + (i[1] - begin[1] > adim[1] - 1 ? 
adim[1] - 2 - (i[1] - begin[1] - adim[1])7
:
abs(i[1] - begin[1])24
) * astride[1];
72
31
        float* bp1 = bp0 + i[1] * bstride[1];
73
126
        for (i[2] = 0; i[2] < bdim[2]; 
i[2]++95
)
74
95
        {
75
95
          float* const ap2 = ap1 + (i[2] - begin[2] > adim[2] - 1 ? 
adim[2] - 2 - (i[2] - begin[2] - adim[2])0
: abs(i[2] - begin[2])) * astride[2];
76
341
          for (x = 0; x < bdim[3]; 
x++246
)
77
246
            bp1[x] = ap2[(x - begin[3] > adim[3] - 1 ? 
adim[3] - 2 - (x - begin[3] - adim[3])95
:
abs(x - begin[3])151
)];
78
95
          bp1 += bstride[2];
79
95
        }
80
31
      }
81
10
    }
82
5
  } else {
83
5
    assert(cmd.info.pad.type == CCV_NNC_PAD_REPLICATE);
84
14
    
for (i[0] = 0; 5
i[0] < bdim[0];
i[0]++9
)
85
9
    {
86
9
      float* const ap0 = ap + ccv_min(adim[0] - 1, ccv_max(0, i[0] - begin[0])) * astride[0];
87
9
      float* const bp0 = bp + i[0] * bstride[0];
88
35
      for (i[1] = 0; i[1] < bdim[1]; 
i[1]++26
)
89
26
      {
90
26
        float* const ap1 = ap0 + ccv_min(adim[1] - 1, ccv_max(0, i[1] - begin[1])) * astride[1];
91
26
        float* bp1 = bp0 + i[1] * bstride[1];
92
106
        for (i[2] = 0; i[2] < bdim[2]; 
i[2]++80
)
93
80
        {
94
80
          float* const ap2 = ap1 + ccv_min(adim[2] - 1, ccv_max(0, i[2] - begin[2])) * astride[2];
95
290
          for (x = 0; x < bdim[3]; 
x++210
)
96
210
            bp1[x] = ap2[ccv_min(adim[3] - 1, ccv_max(0, x - begin[3]))];
97
80
          bp1 += bstride[2];
98
80
        }
99
26
      }
100
9
    }
101
5
  }
102
16
  return CCV_NNC_EXEC_SUCCESS;
103
16
}
104
105
static int _ccv_nnc_pad_back(const ccv_nnc_cmd_t cmd, const ccv_nnc_hint_t hint, const int flags, ccv_nnc_tensor_t* const* const inputs, const int input_size, ccv_nnc_tensor_t* const* const outputs, const int output_size, ccv_nnc_stream_context_t* const stream_context)
106
4
{
107
4
  assert(input_size == 1);
108
4
  ccv_nnc_tensor_view_t* const a = (ccv_nnc_tensor_view_t*)inputs[0];
109
4
  ccv_nnc_tensor_view_t* const b = (ccv_nnc_tensor_view_t*)outputs[0];
110
4
  assert(ccv_nnc_tensor_nd(a->info.dim) <= CCV_NNC_MAX_DIM + 2);
111
4
  assert(ccv_nnc_tensor_nd(b->info.dim) <= CCV_NNC_MAX_DIM + 2);
112
  // Assuming this is float 32.
113
4
  int adim[CCV_NNC_MAX_DIM_ALLOC];
114
4
  int bdim[CCV_NNC_MAX_DIM_ALLOC];
115
4
  ccv_nnc_tensor_view_get_dim(a, adim);
116
4
  ccv_nnc_tensor_view_get_dim(b, bdim);
117
4
  int astride[CCV_NNC_MAX_DIM_ALLOC];
118
4
  int bstride[CCV_NNC_MAX_DIM_ALLOC];
119
4
  assert(CCV_NNC_MAX_DIM == 2); // Need to change this logic for CCV_NNC_MAX_DIM == other number.
120
4
  ccv_nnc_tensor_view_get_stride(a, astride);
121
4
  ccv_nnc_tensor_view_get_stride(b, bstride);
122
4
  int i[CCV_NNC_MAX_DIM + 2];
123
4
  int x;
124
4
  float* const ap = a->data.f32;
125
4
  float* const bp = b->data.f32;
126
4
  const int nd = ccv_nnc_tensor_nd(a->info.dim);
127
4
  const int offset = CCV_NNC_MAX_DIM + 2 - nd;
128
4
  assert(offset >= 0);
129
14
  
for (x = 0; 4
x < nd;
x++10
) // We don't support negative pad.
130
10
    { assert(cmd.info.size.dim[x] >= 0 && cmd.info.pad.end[x] >= 0); }
131
4
  int begin[CCV_NNC_MAX_DIM_ALLOC];
132
14
  for (x = 0; x < nd; 
x++10
)
133
10
    begin[x + offset] = cmd.info.size.dim[x];
134
10
  for (x = 0; x < offset; 
x++6
)
135
6
    begin[x] = 0;
136
  // Non-optimal case, need to do skip if needed.
137
9
  for (i[0] = 0; i[0] < bdim[0]; 
i[0]++5
)
138
5
  {
139
5
    float* const ap0 = ap + (i[0] + begin[0]) * astride[0];
140
5
    float* const bp0 = bp + i[0] * bstride[0];
141
12
    for (i[1] = 0; i[1] < bdim[1]; 
i[1]++7
)
142
7
    {
143
7
      float* const ap1 = ap0 + (i[1] + begin[1]) * astride[1];
144
7
      float* bp1 = bp0 + i[1] * bstride[1];
145
20
      for (i[2] = 0; i[2] < bdim[2]; 
i[2]++13
)
146
13
      {
147
13
        float* const ap2 = ap1 + (i[2] + begin[2]) * astride[2];
148
39
        for (x = 0; x < bdim[3]; 
x++26
)
149
26
          bp1[x] = ap2[x + begin[3]];
150
13
        bp1 += bstride[2];
151
13
      }
152
7
    }
153
5
  }
154
4
  return CCV_NNC_EXEC_SUCCESS;
155
4
}
156
157
REGISTER_COMMAND_BACKEND(CCV_NNC_PAD_FORWARD, CCV_NNC_BACKEND_CPU_REF)(ccv_nnc_cmd_backend_registry_t* const registry)
158
1
{
159
1
  registry->tensor_formats = CCV_TENSOR_FORMAT_NHWC | CCV_TENSOR_FORMAT_NCHW;
160
1
  registry->tensor_datatypes = CCV_32F;
161
1
  registry->tensor_memory = CCV_TENSOR_CPU_MEMORY;
162
1
  registry->algorithms = 1;
163
1
  registry->exec = _ccv_nnc_pad_forw;
164
1
}
165
166
REGISTER_COMMAND_BACKEND(CCV_NNC_PAD_BACKWARD, CCV_NNC_BACKEND_CPU_REF)(ccv_nnc_cmd_backend_registry_t* const registry)
167
1
{
168
1
  registry->tensor_formats = CCV_TENSOR_FORMAT_NHWC | CCV_TENSOR_FORMAT_NCHW;
169
1
  registry->tensor_datatypes = CCV_32F;
170
1
  registry->tensor_memory = CCV_TENSOR_CPU_MEMORY;
171
1
  registry->algorithms = 1;
172
1
  registry->exec = _ccv_nnc_pad_back;
173
1
}