Coverage Report

Created: 2026-04-18 18:15

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/home/liu/actions-runner/_work/ccv/ccv/lib/nnc/cmd/blas/ccv_nnc_rotate_half_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_rotate_half_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
0
{
15
0
  assert(input_size == 1);
16
0
  assert(output_size == 1);
17
0
  ccv_nnc_tensor_view_t* const a = (ccv_nnc_tensor_view_t*)inputs[0];
18
0
  ccv_nnc_tensor_view_t* const b = (ccv_nnc_tensor_view_t*)outputs[0];
19
0
  assert(ccv_nnc_tensor_nd(a->info.dim) <= CCV_NNC_MAX_DIM + 2);
20
0
  assert(ccv_nnc_tensor_nd(b->info.dim) <= CCV_NNC_MAX_DIM + 2);
21
0
  int adim[CCV_NNC_MAX_DIM_ALLOC];
22
0
  ccv_nnc_tensor_view_get_dim(a, adim);
23
0
  assert(ccv_nnc_tensor_view_check_dim(b, adim));
24
0
  const int half = adim[CCV_NNC_MAX_DIM + 1] / 2;
25
0
  assert(half > 0);
26
0
  assert(adim[CCV_NNC_MAX_DIM + 1] == half * 2);
27
0
  int x;
28
0
  if (!CCV_IS_TENSOR_VIEW(a) && !CCV_IS_TENSOR_VIEW(b))
29
0
  {
30
0
    const int count = ccv_nnc_tensor_count(a->info);
31
0
    assert(count % (half * 2) == 0);
32
0
    const int row_count = count / (half * 2);
33
0
    float* const ap = a->data.f32;
34
0
    float* const bp = b->data.f32;
35
0
    int i;
36
0
    if (ap == bp)
37
0
    {
38
0
      for (i = 0; i < row_count; i++)
39
0
      {
40
0
        float* const row = bp + i * half * 2;
41
0
        for (x = 0; x < half; x++)
42
0
        {
43
0
          float t;
44
0
          CCV_SWAP(row[x], row[x + half], t);
45
0
        }
46
0
      }
47
0
    } else {
48
0
      for (i = 0; i < row_count; i++)
49
0
      {
50
0
        const float* const ap0 = ap + i * half * 2;
51
0
        float* const bp0 = bp + i * half * 2;
52
0
        memcpy(bp0, ap0 + half, sizeof(float) * half);
53
0
        memcpy(bp0 + half, ap0, sizeof(float) * half);
54
0
      }
55
0
    }
56
0
    return CCV_NNC_EXEC_SUCCESS;
57
0
  }
58
0
  assert(CCV_NNC_MAX_DIM == 2); // Need to change this logic for CCV_NNC_MAX_DIM == other number.
59
0
  int astride[CCV_NNC_MAX_DIM_ALLOC];
60
0
  int bstride[CCV_NNC_MAX_DIM_ALLOC];
61
0
  ccv_nnc_tensor_view_get_stride(a, astride);
62
0
  ccv_nnc_tensor_view_get_stride(b, bstride);
63
0
  int i[CCV_NNC_MAX_DIM + 2];
64
0
  float* const ap = a->data.f32;
65
0
  float* const bp = b->data.f32;
66
0
  for (i[0] = 0; i[0] < adim[0]; i[0]++)
67
0
  {
68
0
    float* const ap0 = ap + i[0] * astride[0];
69
0
    float* const bp0 = bp + i[0] * bstride[0];
70
0
    for (i[1] = 0; i[1] < adim[1]; i[1]++)
71
0
    {
72
0
      float* const ap1 = ap0 + i[1] * astride[1];
73
0
      float* const bp1 = bp0 + i[1] * bstride[1];
74
0
      for (i[2] = 0; i[2] < adim[2]; i[2]++)
75
0
      {
76
0
        float* const ap2 = ap1 + i[2] * astride[2];
77
0
        float* const bp2 = bp1 + i[2] * bstride[2];
78
0
        if (ap2 == bp2 && astride[CCV_NNC_MAX_DIM + 1] == bstride[CCV_NNC_MAX_DIM + 1])
79
0
        {
80
0
          for (x = 0; x < half; x++)
81
0
          {
82
0
            float t;
83
0
            CCV_SWAP(bp2[x * bstride[CCV_NNC_MAX_DIM + 1]], bp2[(x + half) * bstride[CCV_NNC_MAX_DIM + 1]], t);
84
0
          }
85
0
        } else {
86
0
          for (x = 0; x < half; x++)
87
0
          {
88
0
            bp2[x * bstride[CCV_NNC_MAX_DIM + 1]] = ap2[(x + half) * astride[CCV_NNC_MAX_DIM + 1]];
89
0
            bp2[(x + half) * bstride[CCV_NNC_MAX_DIM + 1]] = ap2[x * astride[CCV_NNC_MAX_DIM + 1]];
90
0
          }
91
0
        }
92
0
      }
93
0
    }
94
0
  }
95
0
  return CCV_NNC_EXEC_SUCCESS;
96
0
}
97
98
static int _ccv_nnc_rotate_half_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)
99
0
{
100
0
  assert(input_size >= 1);
101
0
  assert(output_size == 1);
102
0
  return _ccv_nnc_rotate_half_forw(cmd, hint, flags, inputs, 1, outputs, output_size, stream_context);
103
0
}
104
105
REGISTER_COMMAND_BACKEND(CCV_NNC_ROTATE_HALF_FORWARD, CCV_NNC_BACKEND_CPU_REF)(ccv_nnc_cmd_backend_registry_t* const registry)
106
1
{
107
1
  registry->tensor_formats = CCV_TENSOR_FORMAT_NHWC | CCV_TENSOR_FORMAT_NCHW | CCV_TENSOR_FORMAT_CHWN;
108
1
  registry->tensor_datatypes = CCV_32F;
109
1
  registry->tensor_memory = CCV_TENSOR_CPU_MEMORY;
110
1
  registry->algorithms = 1;
111
1
  registry->exec = _ccv_nnc_rotate_half_forw;
112
1
}
113
114
REGISTER_COMMAND_BACKEND(CCV_NNC_ROTATE_HALF_BACKWARD, CCV_NNC_BACKEND_CPU_REF)(ccv_nnc_cmd_backend_registry_t* const registry)
115
1
{
116
1
  registry->tensor_formats = CCV_TENSOR_FORMAT_NHWC | CCV_TENSOR_FORMAT_NCHW | CCV_TENSOR_FORMAT_CHWN;
117
1
  registry->tensor_datatypes = CCV_32F;
118
1
  registry->tensor_memory = CCV_TENSOR_CPU_MEMORY;
119
1
  registry->algorithms = 1;
120
1
  registry->exec = _ccv_nnc_rotate_half_back;
121
1
}