1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-31 08:13:04 +04:00

Merge pull request #24166 from hanliutong:rewrite-remaining

Rewrite Universal Intrinsic code: ImgProc (CV_SIMD_WIDTH related Part) #24166

Related PR: #24058, #24132. The goal of this series of PRs is to modify the SIMD code blocks in the opencv/modules/imgproc folder by using the new Universal Intrinsic API.

The modification of this PR mainly focuses on the code that uses the `CV_SIMD_WIDTH` macro. This macro is sometimes used for loop tail processing, such as `box_filter.simd.hpp` and `morph.simd.hpp`.

```cpp
#if CV_SIMD
int i = 0;
for (i < n - v_uint16::nlanes; i += v_uint16::nlanes) {
// some universal intrinsic code
// e.g. v_uint16...
}
#if CV_SIMD_WIDTH > 16
for (i < n - v_uint16x8::nlanes; i += v_uint16x8::nlanes) {
// handle loop tail by 128 bit SIMD
// e.g. v_uint16x8
}
#endif //CV_SIMD_WIDTH 
#endif// CV_SIMD
```
The main contradiction is that the variable-length Universal Intrinsic backend cannot use 128bit fixed-length data structures. Therefore, this PR uses the scalar loop to handle the loop tail.

This PR is marked as draft because the modification of the `box_filter.simd.hpp` file caused a compilation error. The cause of the error is initially believed to be due to an internal error in the GCC compiler.

```bash
box_filter.simd.hpp:1162:5: internal compiler error: Segmentation fault
 1162 |     }
      |     ^
0xe03883 crash_signal
        /wafer/share/gcc/gcc/toplev.cc:314
0x7ff261c4251f ???
        ./signal/../sysdeps/unix/sysv/linux/x86_64/libc_sigaction.c:0
0x6bde48 hash_set<rtl_ssa::set_info*, false, default_hash_traits<rtl_ssa::set_info*> >::iterator::operator*()
        /wafer/share/gcc/gcc/hash-set.h:125
0x6bde48 extract_single_source
        /wafer/share/gcc/gcc/config/riscv/riscv-vsetvl.cc:1184
0x6bde48 extract_single_source
        /wafer/share/gcc/gcc/config/riscv/riscv-vsetvl.cc:1174
0x119ad9e pass_vsetvl::propagate_avl() const
        /wafer/share/gcc/gcc/config/riscv/riscv-vsetvl.cc:4087
0x119ceaf pass_vsetvl::execute(function*)
        /wafer/share/gcc/gcc/config/riscv/riscv-vsetvl.cc:4344
0x119ceaf pass_vsetvl::execute(function*)
        /wafer/share/gcc/gcc/config/riscv/riscv-vsetvl.cc:4325
Please submit a full bug report, with preprocessed source (by using -freport-bug).
Please include the complete backtrace with any bug report.
```

This PR can be compiled with Clang 16, and `opencv_test_imgproc` is passed on QEMU.

### Pull Request Readiness Checklist

See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request

- [ ] I agree to contribute to the project under Apache 2 License.
- [ ] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV
- [ ] The PR is proposed to the proper branch
- [ ] There is a reference to the original bug report and related work
- [ ] There is accuracy test, performance test and test data in opencv_extra repository, if applicable
      Patch to opencv_extra has the same branch name.
- [ ] The feature is well documented and sample code can be built with the project CMake
This commit is contained in:
HAN Liutong
2023-09-19 20:12:52 +08:00
committed by GitHub
parent b870ad46bf
commit 320c0bf419
3 changed files with 269 additions and 269 deletions
+85 -85
View File
@@ -106,12 +106,12 @@ struct MorphNoVec
int operator()(uchar**, int, uchar*, int) const { return 0; }
};
#if CV_SIMD
#if CV_SIMD // TODO: enable for CV_SIMD_SCALABLE, GCC 13 related
template<class VecUpdate> struct MorphRowVec
{
typedef typename VecUpdate::vtype vtype;
typedef typename vtype::lane_type stype;
typedef typename VTraits<vtype>::lane_type stype;
MorphRowVec(int _ksize, int _anchor) : ksize(_ksize), anchor(_anchor) {}
int operator()(const uchar* src, uchar* dst, int width, int cn) const
{
@@ -121,52 +121,52 @@ template<class VecUpdate> struct MorphRowVec
width *= cn;
VecUpdate updateOp;
for( i = 0; i <= width - 4*vtype::nlanes; i += 4*vtype::nlanes )
for( i = 0; i <= width - 4*VTraits<vtype>::vlanes(); i += 4*VTraits<vtype>::vlanes() )
{
vtype s0 = vx_load((const stype*)src + i);
vtype s1 = vx_load((const stype*)src + i + vtype::nlanes);
vtype s2 = vx_load((const stype*)src + i + 2*vtype::nlanes);
vtype s3 = vx_load((const stype*)src + i + 3*vtype::nlanes);
vtype s1 = vx_load((const stype*)src + i + VTraits<vtype>::vlanes());
vtype s2 = vx_load((const stype*)src + i + 2*VTraits<vtype>::vlanes());
vtype s3 = vx_load((const stype*)src + i + 3*VTraits<vtype>::vlanes());
for (k = cn; k < _ksize; k += cn)
{
s0 = updateOp(s0, vx_load((const stype*)src + i + k));
s1 = updateOp(s1, vx_load((const stype*)src + i + k + vtype::nlanes));
s2 = updateOp(s2, vx_load((const stype*)src + i + k + 2*vtype::nlanes));
s3 = updateOp(s3, vx_load((const stype*)src + i + k + 3*vtype::nlanes));
s1 = updateOp(s1, vx_load((const stype*)src + i + k + VTraits<vtype>::vlanes()));
s2 = updateOp(s2, vx_load((const stype*)src + i + k + 2*VTraits<vtype>::vlanes()));
s3 = updateOp(s3, vx_load((const stype*)src + i + k + 3*VTraits<vtype>::vlanes()));
}
v_store((stype*)dst + i, s0);
v_store((stype*)dst + i + vtype::nlanes, s1);
v_store((stype*)dst + i + 2*vtype::nlanes, s2);
v_store((stype*)dst + i + 3*vtype::nlanes, s3);
v_store((stype*)dst + i + VTraits<vtype>::vlanes(), s1);
v_store((stype*)dst + i + 2*VTraits<vtype>::vlanes(), s2);
v_store((stype*)dst + i + 3*VTraits<vtype>::vlanes(), s3);
}
if( i <= width - 2*vtype::nlanes )
if( i <= width - 2*VTraits<vtype>::vlanes() )
{
vtype s0 = vx_load((const stype*)src + i);
vtype s1 = vx_load((const stype*)src + i + vtype::nlanes);
vtype s1 = vx_load((const stype*)src + i + VTraits<vtype>::vlanes());
for( k = cn; k < _ksize; k += cn )
{
s0 = updateOp(s0, vx_load((const stype*)src + i + k));
s1 = updateOp(s1, vx_load((const stype*)src + i + k + vtype::nlanes));
s1 = updateOp(s1, vx_load((const stype*)src + i + k + VTraits<vtype>::vlanes()));
}
v_store((stype*)dst + i, s0);
v_store((stype*)dst + i + vtype::nlanes, s1);
i += 2*vtype::nlanes;
v_store((stype*)dst + i + VTraits<vtype>::vlanes(), s1);
i += 2*VTraits<vtype>::vlanes();
}
if( i <= width - vtype::nlanes )
if( i <= width - VTraits<vtype>::vlanes() )
{
vtype s = vx_load((const stype*)src + i);
for( k = cn; k < _ksize; k += cn )
s = updateOp(s, vx_load((const stype*)src + i + k));
v_store((stype*)dst + i, s);
i += vtype::nlanes;
i += VTraits<vtype>::vlanes();
}
if( i <= width - vtype::nlanes/2 )
if( i <= width - VTraits<vtype>::vlanes()/2 )
{
vtype s = vx_load_low((const stype*)src + i);
for( k = cn; k < _ksize; k += cn )
s = updateOp(s, vx_load_low((const stype*)src + i + k));
v_store_low((stype*)dst + i, s);
i += vtype::nlanes/2;
i += VTraits<vtype>::vlanes()/2;
}
return i - i % cn;
@@ -179,7 +179,7 @@ template<class VecUpdate> struct MorphRowVec
template<class VecUpdate> struct MorphColumnVec
{
typedef typename VecUpdate::vtype vtype;
typedef typename vtype::lane_type stype;
typedef typename VTraits<vtype>::lane_type stype;
MorphColumnVec(int _ksize, int _anchor) : ksize(_ksize), anchor(_anchor) {}
int operator()(const uchar** _src, uchar* _dst, int dststep, int count, int width) const
{
@@ -189,7 +189,7 @@ template<class VecUpdate> struct MorphColumnVec
VecUpdate updateOp;
for( i = 0; i < count + ksize - 1; i++ )
CV_Assert( ((size_t)_src[i] & (CV_SIMD_WIDTH-1)) == 0 );
CV_Assert( ((size_t)_src[i] & (VTraits<v_uint8>::vlanes()-1)) == 0 );
const stype** src = (const stype**)_src;
stype* dst = (stype*)_dst;
@@ -197,58 +197,58 @@ template<class VecUpdate> struct MorphColumnVec
for( ; _ksize > 1 && count > 1; count -= 2, dst += dststep*2, src += 2 )
{
for( i = 0; i <= width - 4*vtype::nlanes; i += 4*vtype::nlanes)
for( i = 0; i <= width - 4*VTraits<vtype>::vlanes(); i += 4*VTraits<vtype>::vlanes())
{
const stype* sptr = src[1] + i;
vtype s0 = vx_load_aligned(sptr);
vtype s1 = vx_load_aligned(sptr + vtype::nlanes);
vtype s2 = vx_load_aligned(sptr + 2*vtype::nlanes);
vtype s3 = vx_load_aligned(sptr + 3*vtype::nlanes);
vtype s1 = vx_load_aligned(sptr + VTraits<vtype>::vlanes());
vtype s2 = vx_load_aligned(sptr + 2*VTraits<vtype>::vlanes());
vtype s3 = vx_load_aligned(sptr + 3*VTraits<vtype>::vlanes());
for( k = 2; k < _ksize; k++ )
{
sptr = src[k] + i;
s0 = updateOp(s0, vx_load_aligned(sptr));
s1 = updateOp(s1, vx_load_aligned(sptr + vtype::nlanes));
s2 = updateOp(s2, vx_load_aligned(sptr + 2*vtype::nlanes));
s3 = updateOp(s3, vx_load_aligned(sptr + 3*vtype::nlanes));
s1 = updateOp(s1, vx_load_aligned(sptr + VTraits<vtype>::vlanes()));
s2 = updateOp(s2, vx_load_aligned(sptr + 2*VTraits<vtype>::vlanes()));
s3 = updateOp(s3, vx_load_aligned(sptr + 3*VTraits<vtype>::vlanes()));
}
sptr = src[0] + i;
v_store(dst + i, updateOp(s0, vx_load_aligned(sptr)));
v_store(dst + i + vtype::nlanes, updateOp(s1, vx_load_aligned(sptr + vtype::nlanes)));
v_store(dst + i + 2*vtype::nlanes, updateOp(s2, vx_load_aligned(sptr + 2*vtype::nlanes)));
v_store(dst + i + 3*vtype::nlanes, updateOp(s3, vx_load_aligned(sptr + 3*vtype::nlanes)));
v_store(dst + i + VTraits<vtype>::vlanes(), updateOp(s1, vx_load_aligned(sptr + VTraits<vtype>::vlanes())));
v_store(dst + i + 2*VTraits<vtype>::vlanes(), updateOp(s2, vx_load_aligned(sptr + 2*VTraits<vtype>::vlanes())));
v_store(dst + i + 3*VTraits<vtype>::vlanes(), updateOp(s3, vx_load_aligned(sptr + 3*VTraits<vtype>::vlanes())));
sptr = src[k] + i;
v_store(dst + dststep + i, updateOp(s0, vx_load_aligned(sptr)));
v_store(dst + dststep + i + vtype::nlanes, updateOp(s1, vx_load_aligned(sptr + vtype::nlanes)));
v_store(dst + dststep + i + 2*vtype::nlanes, updateOp(s2, vx_load_aligned(sptr + 2*vtype::nlanes)));
v_store(dst + dststep + i + 3*vtype::nlanes, updateOp(s3, vx_load_aligned(sptr + 3*vtype::nlanes)));
v_store(dst + dststep + i + VTraits<vtype>::vlanes(), updateOp(s1, vx_load_aligned(sptr + VTraits<vtype>::vlanes())));
v_store(dst + dststep + i + 2*VTraits<vtype>::vlanes(), updateOp(s2, vx_load_aligned(sptr + 2*VTraits<vtype>::vlanes())));
v_store(dst + dststep + i + 3*VTraits<vtype>::vlanes(), updateOp(s3, vx_load_aligned(sptr + 3*VTraits<vtype>::vlanes())));
}
if( i <= width - 2*vtype::nlanes )
if( i <= width - 2*VTraits<vtype>::vlanes() )
{
const stype* sptr = src[1] + i;
vtype s0 = vx_load_aligned(sptr);
vtype s1 = vx_load_aligned(sptr + vtype::nlanes);
vtype s1 = vx_load_aligned(sptr + VTraits<vtype>::vlanes());
for( k = 2; k < _ksize; k++ )
{
sptr = src[k] + i;
s0 = updateOp(s0, vx_load_aligned(sptr));
s1 = updateOp(s1, vx_load_aligned(sptr + vtype::nlanes));
s1 = updateOp(s1, vx_load_aligned(sptr + VTraits<vtype>::vlanes()));
}
sptr = src[0] + i;
v_store(dst + i, updateOp(s0, vx_load_aligned(sptr)));
v_store(dst + i + vtype::nlanes, updateOp(s1, vx_load_aligned(sptr + vtype::nlanes)));
v_store(dst + i + VTraits<vtype>::vlanes(), updateOp(s1, vx_load_aligned(sptr + VTraits<vtype>::vlanes())));
sptr = src[k] + i;
v_store(dst + dststep + i, updateOp(s0, vx_load_aligned(sptr)));
v_store(dst + dststep + i + vtype::nlanes, updateOp(s1, vx_load_aligned(sptr + vtype::nlanes)));
i += 2*vtype::nlanes;
v_store(dst + dststep + i + VTraits<vtype>::vlanes(), updateOp(s1, vx_load_aligned(sptr + VTraits<vtype>::vlanes())));
i += 2*VTraits<vtype>::vlanes();
}
if( i <= width - vtype::nlanes )
if( i <= width - VTraits<vtype>::vlanes() )
{
vtype s0 = vx_load_aligned(src[1] + i);
@@ -257,9 +257,9 @@ template<class VecUpdate> struct MorphColumnVec
v_store(dst + i, updateOp(s0, vx_load_aligned(src[0] + i)));
v_store(dst + dststep + i, updateOp(s0, vx_load_aligned(src[k] + i)));
i += vtype::nlanes;
i += VTraits<vtype>::vlanes();
}
if( i <= width - vtype::nlanes/2 )
if( i <= width - VTraits<vtype>::vlanes()/2 )
{
vtype s0 = vx_load_low(src[1] + i);
@@ -268,66 +268,66 @@ template<class VecUpdate> struct MorphColumnVec
v_store_low(dst + i, updateOp(s0, vx_load_low(src[0] + i)));
v_store_low(dst + dststep + i, updateOp(s0, vx_load_low(src[k] + i)));
i += vtype::nlanes/2;
i += VTraits<vtype>::vlanes()/2;
}
}
for( ; count > 0; count--, dst += dststep, src++ )
{
for( i = 0; i <= width - 4*vtype::nlanes; i += 4*vtype::nlanes)
for( i = 0; i <= width - 4*VTraits<vtype>::vlanes(); i += 4*VTraits<vtype>::vlanes())
{
const stype* sptr = src[0] + i;
vtype s0 = vx_load_aligned(sptr);
vtype s1 = vx_load_aligned(sptr + vtype::nlanes);
vtype s2 = vx_load_aligned(sptr + 2*vtype::nlanes);
vtype s3 = vx_load_aligned(sptr + 3*vtype::nlanes);
vtype s1 = vx_load_aligned(sptr + VTraits<vtype>::vlanes());
vtype s2 = vx_load_aligned(sptr + 2*VTraits<vtype>::vlanes());
vtype s3 = vx_load_aligned(sptr + 3*VTraits<vtype>::vlanes());
for( k = 1; k < _ksize; k++ )
{
sptr = src[k] + i;
s0 = updateOp(s0, vx_load_aligned(sptr));
s1 = updateOp(s1, vx_load_aligned(sptr + vtype::nlanes));
s2 = updateOp(s2, vx_load_aligned(sptr + 2*vtype::nlanes));
s3 = updateOp(s3, vx_load_aligned(sptr + 3*vtype::nlanes));
s1 = updateOp(s1, vx_load_aligned(sptr + VTraits<vtype>::vlanes()));
s2 = updateOp(s2, vx_load_aligned(sptr + 2*VTraits<vtype>::vlanes()));
s3 = updateOp(s3, vx_load_aligned(sptr + 3*VTraits<vtype>::vlanes()));
}
v_store(dst + i, s0);
v_store(dst + i + vtype::nlanes, s1);
v_store(dst + i + 2*vtype::nlanes, s2);
v_store(dst + i + 3*vtype::nlanes, s3);
v_store(dst + i + VTraits<vtype>::vlanes(), s1);
v_store(dst + i + 2*VTraits<vtype>::vlanes(), s2);
v_store(dst + i + 3*VTraits<vtype>::vlanes(), s3);
}
if( i <= width - 2*vtype::nlanes )
if( i <= width - 2*VTraits<vtype>::vlanes() )
{
const stype* sptr = src[0] + i;
vtype s0 = vx_load_aligned(sptr);
vtype s1 = vx_load_aligned(sptr + vtype::nlanes);
vtype s1 = vx_load_aligned(sptr + VTraits<vtype>::vlanes());
for( k = 1; k < _ksize; k++ )
{
sptr = src[k] + i;
s0 = updateOp(s0, vx_load_aligned(sptr));
s1 = updateOp(s1, vx_load_aligned(sptr + vtype::nlanes));
s1 = updateOp(s1, vx_load_aligned(sptr + VTraits<vtype>::vlanes()));
}
v_store(dst + i, s0);
v_store(dst + i + vtype::nlanes, s1);
i += 2*vtype::nlanes;
v_store(dst + i + VTraits<vtype>::vlanes(), s1);
i += 2*VTraits<vtype>::vlanes();
}
if( i <= width - vtype::nlanes )
if( i <= width - VTraits<vtype>::vlanes() )
{
vtype s0 = vx_load_aligned(src[0] + i);
for( k = 1; k < _ksize; k++ )
s0 = updateOp(s0, vx_load_aligned(src[k] + i));
v_store(dst + i, s0);
i += vtype::nlanes;
i += VTraits<vtype>::vlanes();
}
if( i <= width - vtype::nlanes/2 )
if( i <= width - VTraits<vtype>::vlanes()/2 )
{
vtype s0 = vx_load_low(src[0] + i);
for( k = 1; k < _ksize; k++ )
s0 = updateOp(s0, vx_load_low(src[k] + i));
v_store_low(dst + i, s0);
i += vtype::nlanes/2;
i += VTraits<vtype>::vlanes()/2;
}
}
@@ -341,7 +341,7 @@ template<class VecUpdate> struct MorphColumnVec
template<class VecUpdate> struct MorphVec
{
typedef typename VecUpdate::vtype vtype;
typedef typename vtype::lane_type stype;
typedef typename VTraits<vtype>::lane_type stype;
int operator()(uchar** _src, int nz, uchar* _dst, int width) const
{
CV_INSTRUMENT_REGION();
@@ -351,56 +351,56 @@ template<class VecUpdate> struct MorphVec
int i, k;
VecUpdate updateOp;
for( i = 0; i <= width - 4*vtype::nlanes; i += 4*vtype::nlanes )
for( i = 0; i <= width - 4*VTraits<vtype>::vlanes(); i += 4*VTraits<vtype>::vlanes() )
{
const stype* sptr = src[0] + i;
vtype s0 = vx_load(sptr);
vtype s1 = vx_load(sptr + vtype::nlanes);
vtype s2 = vx_load(sptr + 2*vtype::nlanes);
vtype s3 = vx_load(sptr + 3*vtype::nlanes);
vtype s1 = vx_load(sptr + VTraits<vtype>::vlanes());
vtype s2 = vx_load(sptr + 2*VTraits<vtype>::vlanes());
vtype s3 = vx_load(sptr + 3*VTraits<vtype>::vlanes());
for( k = 1; k < nz; k++ )
{
sptr = src[k] + i;
s0 = updateOp(s0, vx_load(sptr));
s1 = updateOp(s1, vx_load(sptr + vtype::nlanes));
s2 = updateOp(s2, vx_load(sptr + 2*vtype::nlanes));
s3 = updateOp(s3, vx_load(sptr + 3*vtype::nlanes));
s1 = updateOp(s1, vx_load(sptr + VTraits<vtype>::vlanes()));
s2 = updateOp(s2, vx_load(sptr + 2*VTraits<vtype>::vlanes()));
s3 = updateOp(s3, vx_load(sptr + 3*VTraits<vtype>::vlanes()));
}
v_store(dst + i, s0);
v_store(dst + i + vtype::nlanes, s1);
v_store(dst + i + 2*vtype::nlanes, s2);
v_store(dst + i + 3*vtype::nlanes, s3);
v_store(dst + i + VTraits<vtype>::vlanes(), s1);
v_store(dst + i + 2*VTraits<vtype>::vlanes(), s2);
v_store(dst + i + 3*VTraits<vtype>::vlanes(), s3);
}
if( i <= width - 2*vtype::nlanes )
if( i <= width - 2*VTraits<vtype>::vlanes() )
{
const stype* sptr = src[0] + i;
vtype s0 = vx_load(sptr);
vtype s1 = vx_load(sptr + vtype::nlanes);
vtype s1 = vx_load(sptr + VTraits<vtype>::vlanes());
for( k = 1; k < nz; k++ )
{
sptr = src[k] + i;
s0 = updateOp(s0, vx_load(sptr));
s1 = updateOp(s1, vx_load(sptr + vtype::nlanes));
s1 = updateOp(s1, vx_load(sptr + VTraits<vtype>::vlanes()));
}
v_store(dst + i, s0);
v_store(dst + i + vtype::nlanes, s1);
i += 2*vtype::nlanes;
v_store(dst + i + VTraits<vtype>::vlanes(), s1);
i += 2*VTraits<vtype>::vlanes();
}
if( i <= width - vtype::nlanes )
if( i <= width - VTraits<vtype>::vlanes() )
{
vtype s0 = vx_load(src[0] + i);
for( k = 1; k < nz; k++ )
s0 = updateOp(s0, vx_load(src[k] + i));
v_store(dst + i, s0);
i += vtype::nlanes;
i += VTraits<vtype>::vlanes();
}
if( i <= width - vtype::nlanes/2 )
if( i <= width - VTraits<vtype>::vlanes()/2 )
{
vtype s0 = vx_load_low(src[0] + i);
for( k = 1; k < nz; k++ )
s0 = updateOp(s0, vx_load_low(src[k] + i));
v_store_low(dst + i, s0);
i += vtype::nlanes/2;
i += VTraits<vtype>::vlanes()/2;
}
return i;
}