Pregunta

Tengo un objetivo de procesador basado en ARM NEON Cortex-A8.Estaba optimizando mi código haciendo uso de NEON.Pero cuando compilo mi código aparece este extraño error.No sé cómo solucionar esto.

Estoy intentando compilar el siguiente código (PARTE 1) usando Code Sourcery (PARTE 2) en mi host.Y me sale este extraño error (PARTE 3).¿Estoy haciendo algo mal aquí?¿Alguien más puede compilar esto y ver si también recibe el mismo error de compilación?

Lo extraño es que, en el código, si comento el else if(step_size == 4) parte del código, entonces el error desaparece.Pero, lamentablemente, mi optimización no está completa sin él, así que necesito tenerlo.

Al principio pensé que era un problema con el compilador CodeSourcey (en mi host), así que compilé el programa directamente en mi objetivo (mi objetivo se ejecuta en Ubuntu).Utilicé gcc allí y una vez más, aparece el mismo error y cuando comento el else if(step_size == 4) parte, entonces el error desaparece.

¡Ayuda!


PARTE 1

#include<stdio.h>
#include"arm_neon.h"

#define IMAGE_HEIGHT 480
#define IMAGE_WIDTH  640

float32_t integral_image[IMAGE_HEIGHT][IMAGE_WIDTH];

float32x4_t box_area_compute3(int, int , int , int , unsigned int , float);

inline int min(int, int);

int main()
{

 box_area_compute3(1, 1, 4, 4, 2, 0);

 return 0;
}

float32x4_t box_area_compute3(int row, int col, int num_rows, int num_cols, unsigned int step_size, float three)
{
 unsigned int height = IMAGE_HEIGHT;
 unsigned int width = IMAGE_WIDTH;

 int temp_row = row + num_rows;
 int temp_col = col + num_cols;

 int r1 = (min(row, height))- 1 ;
 int r2 = (min(temp_row, height)) - 1;

 int c1 = (min(col, width)) - 1;
 int c2 = (min(temp_col, width)) - 1;

 float32x4_t v128_areas;

 if(step_size == 2)
 {
  float32x4x2_t top_left, top_right, bottom_left, bottom_right;
  top_left    = vld2q_f32((float32_t *)integral_image[r1] + c1);
  top_right   = vld2q_f32((float32_t *)integral_image[r1] + c2);
  bottom_left  = vld2q_f32((float32_t *)integral_image[r2] + c1);
  bottom_right  = vld2q_f32((float32_t *)integral_image[r2] + c2);

  v128_areas = vsubq_f32(vsubq_f32(vaddq_f32(top_left.val[0], bottom_right.val[0]), top_right.val[0]), bottom_left.val[0]);


 }
 else if(step_size == 4)
 {
  float32x4x4_t top_left, top_right, bottom_left, bottom_right;
  top_left   = vld4q_f32((float32_t *)integral_image[r1] + c1);
  top_right   = vld4q_f32((float32_t *)integral_image[r1] + c2);
  bottom_left  = vld4q_f32((float32_t *)integral_image[r2] + c1);
  bottom_right  = vld4q_f32((float32_t *)integral_image[r2] + c2);

  v128_areas = vsubq_f32(vsubq_f32(vaddq_f32(top_left.val[0], bottom_right.val[0]), top_right.val[0]), bottom_left.val[0]);

 }

 if(three == 3.0)
  v128_areas = vmulq_n_f32(v128_areas, three);

 return v128_areas;

}

inline int min(int X, int Y)
{
 return (X < Y ? X : Y);
}

PARTE 2

arm-none-linux-gnueabi-gcc -O0 -g3 -Wall -c -fmessage-length=0 -fcommon -MMD -MP -MF"main.d" -MT"main.d" -mcpu=cortex-a8 -marm -mfloat-abi=hard -mfpu=neon-vfpv4 -o"main.o" "../main.c"

PARTE 3

../main.c: In function 'box_area_compute3':
../main.c:65: error: unable to find a register to spill in class 'GENERAL_REGS'
../main.c:65: error: this is the insn:
(insn 226 225 227 5 c:\program files\codesourcery\sourcery g++\bin\../lib/gcc/arm-none-linux-gnueabi/4.4.1/include/arm_neon.h:9863 (parallel [
           (set (reg:XI 148 [ D.17028 ])
               (unspec:XI [
                       (mem:XI (reg:SI 3 r3 [301]) [0 S64 A64])
                       (reg:XI 148 [ D.17028 ])
                       (unspec:V4SF [
                               (const_int 0 [0x0])
                           ] 191)
                   ] 111))
           (set (reg:SI 3 r3 [301])
               (plus:SI (reg:SI 3 r3 [301])
                   (const_int 32 [0x20])))
       ]) 1605 {neon_vld4qav4sf} (nil))
../main.c:65: confused by earlier errors, bailing out
cs-make: *** [main.o] Error 1
¿Fue útil?

Solución 2

Bueno, me comuniqué con Code Sourcery sobre este problema y lo consideraron como un error en el compilador GCC.Entonces escribí la función do_it4(){.....} en ensamblador en lugar de usar los intrínsecos.¡Ahora funciona bien!

Otros consejos

No puedo probar esto porque no tengo la cadena de herramientas para ello, pero este tipo de error a menudo se puede solucionar modificando un poco el código.En general, esto no debería suceder y debería informarse como un error, pero está utilizando una funcionalidad específica del procesador, que probablemente esté menos probada y pulida que el resto del compilador.

Dado que se trata de un error de derrame de registros y hay varios indicadores involucrados, sospecho altamente que el compilador puede estar intentando cargar más datos en los registros de los necesarios por temor a que pueda haber algún alias (que probablemente no sea así). en realidad no sucede).A continuación abordaré esta posibilidad y haré algunas otras cosas que pueden disminuir la complejidad del código desde la perspectiva del compilador (aunque puede que no parezca que este sea el caso).

#include<stdio.h>
#include"arm_neon.h"

#define IMAGE_HEIGHT 480
#define IMAGE_WIDTH  640

float32_t integral_image[IMAGE_HEIGHT][IMAGE_WIDTH];

float32x4_t box_area_compute3(int, int , int , int , unsigned int , float);

inline int min(int, int);

int main()
{

 box_area_compute3(1, 1, 4, 4, 2, 0);

 return 0;
}

/* By putting these in separate functions the compiler will initially
 * think about them by themselves, without the complications of the
 * surrounding code.  This may give it the abiltiy to optimise the
 * code somewhat before trying to inline it.
 * This may also serve to make it more obvious to the compiler that
 * the local variables are dead after their use (since they are
 * dead after the call returns, and that the lifetimes of some variable
 * cannot actually overlap (hopefully reducing the register needs).
 */
static inline float32x4_t do_it2(float32_t *tl, float32_t *tr, float32_t *bl, float32_t * br) {
    float32x4x2_t top_left, top_right, bottom_left, bottom_right;
    float32x4_t A, B;

    top_left = vld2q_f32(tl);
    top_right = vld2q_f32(tr);
    bottom_left = vld2q_f32(bl);
    bottom_right = vld2q_f32(br);

    /* By spreading this across several statements I have created several
     * additional sequence points.  The compiler does not think that it
     * has to dereference all of the pointers before doing any of the
     * computations.... maybe. */
    A = vaddq_f32(*top_left.val, *bottom_right.val);
    B = vsubq_f32(A, *top_right.val);
    return vsubq_f32(B, *bottom_left);
}

static inline float32x4_t do_it4(float32_t *tl, float32_t *tr, float32_t *bl, float32_t * br) {
    float32x4x4_t top_left, top_right, bottom_left, bottom_right;
    float32x4_t A, B;

    top_left = vld4q_f32(tl);
    top_right = vld4q_f32(tr);
    bottom_left = vld4q_f32(bl);
    bottom_right = vld4q_f32(br);

    A = vaddq_f32(*top_left.val, *bottom_right.val);
    B = vsubq_f32(A, *top_right.val);
    return vsubq_f32(B, *bottom_left);
}

float32x4_t box_area_compute3(int row, int col, int num_rows, int num_cols, unsigned int step_size, float three)
{
 unsigned int height = IMAGE_HEIGHT;
 unsigned int width = IMAGE_WIDTH;

 int temp_row = row + num_rows;
 int temp_col = col + num_cols;

 int r1 = (min(row, height))- 1 ;
 int r2 = (min(temp_row, height)) - 1;

 int c1 = (min(col, width)) - 1;
 int c2 = (min(temp_col, width)) - 1;

 float32x4_t v128_areas;

     float32_t *tl = (float32_t *)integral_image[r1] + c1;
 float32_t *tr = (float32_t *)integral_image[r1] + c2;
 float32_t *bl = (float32_t *)integral_image[r2] + c1;
 float32_t *br = (float32_t *)integral_image[r2] + c2;


 switch (step_size) {
    case 2:
      v128_areas = do_it2(tl, tr, bl, br);
      break;

 case 4:
      v128_areas = do_it4(tl, tr, bl, br);
      break;
 }

 if(three == 3.0)
  v128_areas = vmulq_n_f32(v128_areas, three);

 return v128_areas;

}

inline int min(int X, int Y)
{
 return (X < Y ? X : Y);
}

Espero que esto ayude y que no haya introducido ningún error.

La línea:

float32x4x4_t top_left, top_right, bottom_left, bottom_right;

¡Utiliza los 16 registros q!No es sorprendente que el compilador no pueda manejar esto.Probablemente podría haber solucionado este problema reescribiendo para utilizar menos registros.

ARM NEON Cortex-A8 tiene soporte para vfpv3, Cortex-A5 tiene soporte para vfpv4 y neon2 (en cuanto a:si usa -mfloat-abi=hard, omitirá la capacidad de emular en las instrucciones que faltan en el software, por lo que no puede generar código que estaría optimizado para vfpv4 pero que se ejecutaría en vfpv3 con emulación de software).

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top