1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-21 19:33:03 +04:00

Merge pull request #29541 from velonica0:rvv-fix-cvtabs-gcc-build

core: fix RISC-V GCC build break in cvtabs_32f (#29369 follow-up) #29541

### Summary

`modules/core/src/convert_scale.simd.hpp` does not compile on RISC-V with GCC on current 5.x:

```
convert_scale.simd.hpp:44:13: error: 'useSIMD' was not declared in this scope
convert_scale.simd.hpp:45:37: error: 'VECSZ' was not declared in this scope
convert_scale.simd.hpp:55:28: error: 'va' was not declared in this scope
convert_scale.simd.hpp:55:32: error: 'vb' was not declared in this scope
```

This breaks every RISC-V + GCC build of the core module.

### Root cause

In #29369 `cvtabs_32f` ended up with a declaration guard and a usage guard that disagree:

```c
#if (CV_SIMD || (CV_SIMD_SCALABLE && !(defined(__GNUC__) && !defined(__clang__))))  // decl
    v_float32 va = ..., vb = ...;  const int VECSZ = ...;  const bool useSIMD = ...;
#endif
        ...
#if (CV_SIMD || CV_SIMD_SCALABLE)                                                   // usage
        if( useSIMD ) for( ; j < size.width; j += VECSZ ) { ... v_fma(v0, va, vb) ... }
```

On RISC-V `CV_SIMD == 0` and `CV_SIMD_SCALABLE == 1`, so under GCC the first is false and the second is true: the declarations are dropped while the loop using them is still compiled.

### Second commit (independent, droppable)

`useSIMD` asks "is this a 128-bit vector machine?" but tests `vlanes() != 8`. `vlanes()` is `VLEN/32 * LMUL`, so the literal `8` encodes both "VLEN == 128" **and** "LMUL == 2" — correct only while `v_float32` stays at LMUL=2. Under #29493 (LMUL=1) the same expression silently becomes "VLEN != 256": disabling SIMD on 256-bit machines and enabling it at VLEN=128, the exact case the workaround exists to avoid. CI cannot catch that regression, since the block is GCC-only.

VLEN is not recoverable from the universal intrinsics (every type scales with LMUL, so the factor never cancels), so this asks the hardware: `__riscv_vlenb()*8 != 128`. Behaviour is unchanged today — with LMUL=2, `vlanes() == 8` iff `VLEN == 128`.


### Testing

SpaceMIT K3, GCC 15.2, **unmodified LMUL=2 backend** (no #29493 changes involved):

| configuration | result |
| --- | --- |
| 5.x as-is | `opencv_core` fails to build (errors above) |
| + commit 1 | builds clean, 0 errors |
| + commits 1&2 | builds clean, 0 errors |
| `Core_ConvertScale*`, X100 @ VLEN=256 | 4/4 pass (incl. `Core_ConvertScaleAbs/ElemWiseTest.accuracy`) |
| `Core_ConvertScale*`, A100 @ VLEN=1024 | 4/4 pass |
| `useSIMD == false` path (temporary probe forcing it at VLEN=256) | passes |
This commit is contained in:
velonica0
2026-07-17 16:47:03 +08:00
committed by GitHub
parent 47d9544d90
commit 5aa9c9562a
+6 -6
View File
@@ -22,14 +22,14 @@ template<typename _Ts, typename _Td> inline void
cvtabs_32f( const _Ts* src, size_t sstep, _Td* dst, size_t dstep,
Size size, float a, float b )
{
// Excluding GNU in CV_SIMD_SCALABLE because of "opencv/issues/26936"
#if (CV_SIMD || (CV_SIMD_SCALABLE && !(defined(__GNUC__) && !defined(__clang__))) )
#if (CV_SIMD || CV_SIMD_SCALABLE)
v_float32 va = vx_setall_f32(a), vb = vx_setall_f32(b);
const int VECSZ = VTraits<v_float32>::vlanes()*2;
// GCC miscompiles this scalable block only on VLEN=128 RVV (opencv/issues/26936).
// v_float32 is LMUL=2, so vlanes()==8 means VLEN==128: use scalar there, keep SIMD elsewhere.
#if (CV_SIMD_SCALABLE && defined(__GNUC__) && !defined(__clang__))
const bool useSIMD = VTraits<v_float32>::vlanes() != 8;
// GCC miscompiles this scalable block only on VLEN=128 RVV (opencv/issues/26936);
// use scalar there, keep SIMD on wider vectors. Ask the hardware for VLEN directly:
// vlanes() would depend on the LMUL the universal intrinsics happen to use.
#if (CV_RVV && CV_SIMD_SCALABLE && defined(__GNUC__) && !defined(__clang__))
const bool useSIMD = __riscv_vlenb()*8 != 128;
#else
const bool useSIMD = true;
#endif