9
\$\begingroup\$

I'm trying to do a Bilinear interpolation on the ARM Neon. However, I find that my vectorized code is slower than the regular one, on a BeagleBone Black. Any idea why this could happen?

I'm using gprof to debug and compiling with the following flags:

NonNeonFlags: g -Wall -pg -O3 -ffast-math
NeonFlags: $(NonNeonFlags) -D__ARM__ -march=armv7-a -mtune=cortex-a8 -mfloat-abi=hard -mfpu=neon

interp.h

typedef struct InterpValues {
    float32_t ab; //< a,b
    float32_t a1b; //< a+1,b
    float32_t ab1; //< a, b+1
    float32_t a1b1; //< a+1, b+1
} InterpValues;

typedef struct InterpCoords {
    float32_t x1; //< x1
    float32_t x2; //< x2
} InterpCoords;

interp_neon.cpp

void interp_neon(InterpValues* values, InterpCoords* coords, float32_t* r, int n) 
{
    const float32_t INIT_ONE[4] = {1.0, 1.0, 1.0, 1.0};

    float32x4x2_t x34;// = vld2q_f32(init_x1_x2);
    float32x4_t aux;
    float32x4_t vResult;
    float32x4_t ONE = vld1q_f32(INIT_ONE);

    for (int i=0;i<n;i+=4) 
    {
        float32x4x4_t vValues = vld4q_f32((float32_t*) values);
        float32x4x2_t vCoords = vld2q_f32((float32_t*) coords);

        #define x1 vCoords.val[0]
        #define x2 vCoords.val[1]
        #define x3 x34.val[0]
        #define x4 x34.val[1]
        #define Iab vValues.val[0]
        #define Ia1b vValues.val[1]
        #define Iab1 vValues.val[2]
        #define Ia1b1 vValues.val[3]

        x3 = vmlsq_f32(ONE, x1, ONE);
        x4 = vmlsq_f32(ONE, x2, ONE);

        // Ia,b * x3 * x4
        aux = vmulq_f32(x3, x4);
        vResult = vmulq_f32(Iab, aux);

        // Ia+1,b * x1 * x4
        aux = vmulq_f32(x1, x4);
        vResult = vmlaq_f32(vResult, Ia1b, aux);

        // Ia,b+1 * x2 * x3
        aux = vmulq_f32(x2, x3);
        vResult = vmlaq_f32(vResult, Iab1, aux);

        // Ia+1,b+1 * x1 * x2
        aux = vmulq_f32(x1, x2);
        vResult = vmlaq_f32(vResult, Ia1b1, aux);

        vst1q_f32(r, vResult);

        r += 4;
        values += 4;
        coords += 4;

        #undef x1
        #undef x2
        #undef x3
        #undef x4
        #undef Iab
        #undef Ia1b
        #undef Iab1
        #undef Ia1b1
    }   
}

interp.cpp

void interp(InterpValues* values, InterpCoords* coords, float32_t* r, int n) 
{
    for (int i=0;i<n;++i) 
    {
        float32_t x3 = 1.0 - coords[i].x1;
        float32_t x4 = 1.0 - coords[i].x2;
        r[i] =
            values[i].ab * x3 * x4 +
            values[i].a1b * coords[i].x1 * x4 +
            values[i].ab1 * coords[i].x2 * x3 +
            values[i].a1b1 * coords[i].x1 * coords[i].x2;
    }   
}
\$\endgroup\$
  • 1
    \$\begingroup\$ Why are you using .cpp file extensions for C? \$\endgroup\$ – nhgrif Feb 22 '16 at 0:53
  • \$\begingroup\$ I'm using classes on some parts of the process. But your point is right, I could use only the c extension on this code. \$\endgroup\$ – Josejulio Feb 22 '16 at 3:04
  • \$\begingroup\$ I got better results when moving from intrinsics to Neon ASM. So i guess I'm either using wrong the intrinsics or the gcc compiler is doing a bad job here. \$\endgroup\$ – Josejulio Jul 14 '16 at 22:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.