编译ARM NEON时出现未知的GCC错误(严重)

我有一个基于ARM NEON Cortex-A8的处理器目标。 我通过使用NEON来优化我的代码。 但是当我编译我的代码时,我得到了这个奇怪的错误。 不知道如何解决这个问题。

我正在尝试使用主机上的Code Sourcery(PART2)编译以下代码(第1部分)。 我得到了这个奇怪的错误(PART3)。 我在这里做错了吗? 任何人都可以编译它,看看他们是否也得到相同的编译错误?

奇怪的是,在代码中,如果我注释掉else if(step_size == 4)代码的一部分,那么错误就会消失。 但是,遗憾的是我的优化并不完整,所以我必须拥有它。

起初我认为它是CodeSourcey编译器(在我的主机上)的问题,所以我直接在我的目标上编译程序(我的目标在Ubuntu上运行)。 我在那里使用了gcc,再一次,我得到了同样的错误,当我注释掉else if(step_size == 4)部分时,错误就消失了。

救命!


第1部分

 #include #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); } 

第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" 

第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 

我无法测试这个,因为我没有它的工具链,但这种类型的错误通常可以通过重新编写代码来解决。 通常这不应该发生,并且应该报告为错误,但是您使用的是处理器特定的function,这可能不如编译器的其他部分那样经过良好测试和优化。

由于它是一个寄存器溢出错误并且你有几个指针涉及我高度怀疑编译器可能正在尝试将更多数据加载到寄存器中而不是因为担心可能会出现一些混叠(这可能不是’实际上正在发生)。 下面我将讨论这种可能性,以及从编译器的角度做一些其他可能会降低代码复杂性的事情(虽然看起来可能不是这样)。

 #include #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); } 

我希望这有帮助,我没有引入任何错误。

好吧,我已经联系了Code Sourcery关于这个问题,他们认为这是GCC编译器中的一个错误。 所以我在汇编中编写了do_it4(){…..}函数,而不是使用teh intrinsics。 现在它运作良好!

这条线:

 float32x4x4_t top_left, top_right, bottom_left, bottom_right; 

使用所有16​​个q寄存器! 编译器无法处理这个问题并不令人惊讶。 您可能已经通过重写来修复此问题以使用更少的寄存器。

ARM NEON Cortex-A8支持vfpv3,Cortex-A5支持vfpv4和neon2(至于:如果使用-mfloat-abi = hard,你可以跳过在软件缺失指令中模拟的能力,因此你无法生成可以优化的代码对于vfpv4,但将使用软件模拟在vfpv3上运行)