Repository: opencv/opencv
File: modules/dnn/src/layers/attention_layer.cpp (C++)

Code before:

            // store back
            v_store_interleave(out_ptr + 2*d, out_even, out_odd);
        }
        // scalar tail
        for (; d < half_dim; ++d)
        {
            float s  = sin_ptr[d];
            float c  = cos_ptr[d];
            float xe = out_ptr[2*d];
            float xo = out_ptr[2*d+1];
            out_ptr[2*d]   = xe * c - xo * s;
            out_ptr[2*d+1] = xo * c + xe * s;
        }
#else
        // fallback: pure scalar
        for (size_t d = 0; d < half_dim; ++d)
        {
            float s  = sin_ptr[d];
            float c  = cos_ptr[d];
            float xe = out_ptr[2*d];
            float xo = out_ptr[2*d+1];
            out_ptr[2*d]   = xe * c - xo * s;
            out_ptr[2*d+1] = xo * c + xe * s;
        }
#endif
    }
}


static void precompRotationTables(float *data,
                                  size_t seq_len,
                                  size_t head_size) {
    // RoPE precomputation
    // RoPE is a positional encoding method used in transformer models.
    // It uses sine and cosine functions to encode the position of tokens in a sequence
    // initially introduced for NLP in https://arxiv.org/pdf/2104.09864

    // assume data is of shape [2,seq_ken,head_size]

    float* sin_table = data;
    float* cos_table = sin_table + seq_len * head_size;

    for (size_t pos = 0; pos < seq_len; ++pos) {
        for (size_t i = 0; i < head_size; ++i) {
            float theta = pos * std::pow(10000.f, -2.f * static_cast<float>(i) / static_cast<float>(head_size * 2));
            sin_table[pos * head_size + i] = std::sin(theta);
            cos_table[pos * head_size + i] = std::cos(theta);
        }
    }
}

Review comment (refactor):
No need to duplicate tail and scalar core. You can just close `#if (CV_SIMD || CV_SIMD_SCALABLE)` condition right after vectorized loop and extract `d` from ifdef.. In case, if vector intrinsics are not available, d = 0 and "tail" will be just main loop.

Code after:
            for (; i < d_half; ++i)
            {
                float s  = table_ptr[2*i  ];
                float c  = table_ptr[2*i+1];
                float xe = out_ptr[2*i];
                float xo = out_ptr[2*i+1];
                out_ptr[2*i]   = xe * c - xo * s;
                out_ptr[2*i+1] = xo * c + xe * s;
            }
        }
    };

    // This will spin up threads and run fn over [0, seq_len)
    parallel_for_(cv::Range(0, int(seq_len)), fn, nstripes);
}

static void precompRotationTable(float *data,
                                  size_t seq_len,
                                  size_t d) {
    // RoPE precomputation
    // RoPE is a positional encoding method used in transformer models.
    // It uses sine and cosine functions to encode the position of tokens in a sequence
    // initially introduced for NLP in https://arxiv.org/pdf/2104.09864

    // assume data is of shape [seq_ken,d]
    const float  logBase = std::log(10000.0f);
    const float  inv_d   = 1.0f / float(d);
    const size_t d_half = d / 2;
    for (size_t pos = 0; pos < seq_len; ++pos) {

        size_t i = 0;
        float* data_ptr = data + pos * d;

#if (CV_SIMD || CV_SIMD_SCALABLE)
        const size_t w = VTraits<v_float32>::vlanes();
        const v_float32 v_logBase = vx_setall_f32(logBase);
        const v_float32 v_inv_d   = vx_setall_f32(inv_d);
        const v_float32 v_neg2    = vx_setall_f32(-2.0f);

        for (; i + w <= d_half; i+=w) {
            int idx_buf[VTraits<v_float32>::max_nlanes];
            for (int k = 0; k < int(w); ++k)
                idx_buf[k] = int(i + k);
            // [i, i+1, …, i+w-1]
            v_float32 v_idx = v_cvt_f32(vx_load(idx_buf));
            // [10_000^(-i/d), 10_000^(-(i+1)/d), …, 10_000^(-(i+w-1)/d)]
            v_float32 v_theta = v_exp(v_mul(v_mul(v_neg2, v_mul(v_idx, v_inv_d)), v_logBase));
            v_theta = v_mul(vx_setall_f32(float(pos)), v_theta);
            v_float32 sin_v, cos_v;
            v_sincos(v_theta, sin_v, cos_v);
            // store back with interleave