【问题标题】:C embedded assembly error: ‘asm’ operand has impossible constraintsC 嵌入式汇编错误:“asm”操作数具有不可能的约束
【发布时间】:2019-10-26 19:00:45
【问题描述】:

当我在 C 语言中嵌入汇编时,在 ubuntu linux 14.04 中使用 shell 命令编译这些代码时遇到以下错误。

    IFR_temp_measure.cpp: In function ‘void BlockTempClc(char*, char*, 
     int, int, char, int, int, int, int*, int, int*, int)’:
     IFR_temp_measure.cpp:1843:6: error: ‘asm’ operand has impossible 
    constraints);
    ^
    &make: *** [IFR_temp_measure.o] Error 1

或者错误代码行1842,1843的位置是响应代码

    :"cc", "memory","q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7", "q8", "q10", "q11", "q12", "q13", "q14", "q15","r0", "r1", "r3", "r4", "r5","r6","r8", "r9", "r10", "r12"
            );

我已经尝试过解决这个问题,但是网上的参考资料很少,有一个链接器: Gcc inline assembly what does "'asm' operand has impossible constraints" mean?http://www.ethernut.de/en/documents/arm-inline-asm.html 但没有帮助。 我的代码如下:

    void BlockTempClc(char* src1,char* src2,int StrideDist,int height,char temp_comp1,int numofiterations,int temp_comp2,int temp_comp3,int *dstData,int width,int *dstSum,int step)
{

            volatile char array1[16] = {0,0,0,0,0,0,0,0,
                                       0,0,0,0,0,0,0,0};
            volatile char array2[16] = {0,0,1,0,2,0,3,0,
                                       4,0,5,0,6,0,7,0};
            asm volatile(   
            "mov        r0, %0; " //image[0]    
            "mov        r1, %1; "  //image[1] 
            "mov        r12,%11; " //m
            "mov        r3, %4; " //n
            "mov        r4, %2; " //store data
            "mov        r8, %12; " //step down for loading next line of image
            "mov        r5, %6; " //numofiterations
            "mov        r6, %3; " //out

            "mov.8 r9,%5;"//isp_temp_comp
            "mov.8 r10,%7;"//led_temp_comp
            "mov.8 r11,%8;"//fac_temp_comp


            "vdup.8 d20,r9;"//copy arm register value isp_temp_comp to neon  register
            "VMOV.S16 q9, d20; " //isp_temp_comp transfer to signed short type

            "VLD1.8     {d16,d17}, [%9];"//q8  array1 sum
            "VLD1.8     {d6,d7}, [%10];"//q3  array2

            "VMOV.S16   q0, #256; "
            "VMOV.S16   q1, #2730; " //Assign immediate number 2730 to each 16 bits of d1       

            ".loop:;"           

            "vdup.8 d21,r10;"//copy arm register value led_temp_comp to neon  register 
            "vdup.8 d22,r11;"//copy arm register value fac_temp_comp to neon  register 

            "VLD1.8    d14, [r1],r8; "    // q7  *(image[1] + tmp + n)  Load: Load Picture Pixels   r6:move step  ?
            "VLD1.8    d15, [r0],r8 "    // *(image[0] + tmp + n)  Load: Load Picture Pixels            

            "PLD        [r1]; " //Preload: one line in cache
            "PLD        [r0]; "  //?

            "VMOV.S16  q5, d14; " //q5    8*16  transfer to signed short type:*(image[1] + tmp + n) 
            "VMOV.S16  q6, d15; " //q6    8*16  transfer to signed short type : *(image[0] + tmp + n) 

            "VADD.S16  q12,q6, q9;"//*(image[0] + tmp + n) + isp_temp_comp              
            "VMOV.S16  q6, d21; " //led_temp_comp
            "VADD.S16  q13,q12, q6;"//*(image[0] + tmp + n) + isp_temp_comp+ + led_temp_comp
            "VMOV.S16  q6, d22; " //fac_temp_comp
            "VADD.S16  q14,q13, q6;"//*(image[0] + tmp + n) + isp_temp_comp+ + led_temp_comp+ fac_temp_comp
            "VSUB.S16  q15,q14, q1;"//*(image[0] + tmp + n) + isp_temp_comp+ + led_temp_comp+ fac_temp_comp-2730
            "VMLA.S16   q15, q5, q0;"//img_temp[m][n]=*(image[0] + tmp + n) + isp_temp_comp+ + led_temp_comp+ fac_temp_comp-2730+*(image[1] + tmp + n) *256 


            "VADD.S16  q2,q15, q8;"//sum                
            "VMOV.S16    q8, q2; " //q8


            "vdup.8 d20,r3;"//n 
            "vdup.8 d21,r12;"//m

            "VMOV.S16  q11, d20; " //n
            "VMOV.S16  q10, d21; " //m

            "VADD.S16  q4,q3, q11;"//(n,n+1,n+2,n+3,n+4,n+5,n+6,n+7)
            "VADD.S16  q7,q3, q10;"//(m,m+1,m+2,m+3,m+4,m+5,m+6,m+7)  q7


            "VST1.16     {d30[0]}, [r4]!; "//restore img_temp[m][n] to pointer data
            "VST1.16     {d14[0]}, [r4]!; "//restore m
            "VST1.16     {d8[0]}, [r4]!; "  //restore n

            "VST1.16     {d30[1]}, [r4]!; "     
            "VST1.16     {d14[1]}, [r4]!; "
            "VST1.16     {d8[1]}, [r4]!; "

            "VST1.16     {d30[2]}, [r4]!; "     
            "VST1.16     {d14[2]}, [r4]!; "
            "VST1.16     {d8[2]}, [r4]!; "

            "VST1.16     {d30[3]}, [r4]!; "     
            "VST1.16     {d14[3]}, [r4]!; "
            "VST1.16     {d8[3]}, [r4]!; "//response to array

            "subs        r5, r5, #1; "   // decrement: numofinteration -= 1;
            "bne        .loop; "        // Branch If Not Zero; to .loop
            "VST1.16     {d4[0]}, [r6]!; "//q2 refer to sum restore the final result to pointer out
            "VST1.16     {d4[1]}, [r6]!; "
            "VST1.16     {d4[2]}, [r6]!; "
            "VST1.16     {d4[3]}, [r6]!; "
            "VST1.16     {d5[0]}, [r6]!; "
            "VST1.16     {d5[1]}, [r6]!; "
            "VST1.16     {d5[2]}, [r6]!; "
            "VST1.16     {d5[3]}, [r6]!; "

            :"+r"(src1),"+r"(src2),"+r"(dstData),"+r"(dstSum),"+r"(height)
            :"r"(temp_comp1),"r"(numofiterations),"r"(temp_comp2),"r"(temp_comp3),
                "r"(array1),"r"(array2), "r"(width),"r"(step)
            :"cc", "memory","q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7", "q8", "q10", "q11", "q12", "q13", "q14", "q15","r0", "r1", "r3", "r4", "r5","r6","r8", "r9", "r10", "r12"
            );
}

我想问题可能是输出操作数列表或输出操作数列表。 是什么原因导致我的代码出错?如何解决?

【问题讨论】:

  • using a shell command 什么shell命令?哪个编译器,编译器选项,编译器版本,你是怎么编译代码的?
  • 删除部分代码,直到消息不再出现。然后调查那部分。
  • 您是否只为arm-v7a 构建?
  • 旁注:char array1[16] 和 2 不需要是 volatile,asm 语句中的 "memory" clobber 就足够了,即使您只是将指针传递给它们,而不是使用它们作为"m" 输入操作数。
  • 如果分配得当,单个vst3.16 指令将替换循环内的12 个vst1.16s。您可以简单地将循环后的 8 个vst1.16s 替换为vst1.16 {d4, d5}, [r6]!

标签: c inline-assembly neon


【解决方案1】:

您在大多数整数寄存器上声明了clobbers,但随后您要求提供 13 个不同的输入变量。 32 位 ARM 只有 16 个寄存器,其中 2 个是 PC 和 SP,最多只剩下 14 个真正的通用寄存器。

我们可以通过删除r0..r12 上的所有clobbers 来测试是否存在过多的clobbers + 操作数;这让它编译(成不正确的代码!!)。 https://godbolt.org/z/Z6x78N不是解决方案,因为它引入了巨大的错误,这正是我确认这是问题的方式。

任何时候您的内联 asm 模板以 mov 开头以从输入寄存器操作数复制到硬编码寄存器中,您通常都做错了。 即使您有足够的寄存器,编译器将不得不发出代码以将变量放入寄存器,然后您的手写 asm 使用另一个 mov 无缘无故地复制它。

有关更多指南,请参阅https://stackoverflow.com/tags/inline-assembly/info

首先使用register int foo asm("r0") 向编译器询问该寄存器中的输入,或者更好地让编译器进行寄存器分配,使用%0 或类似@987654329 的等效命名操作数@ 而不是在你的 asm 模板中到处都是硬编码的 r0。命名操作数的语法是[name] "r" (C_var_name)。它们没有必须匹配,但它们也不必是唯一的;使用与 C var 名称相同的 asm 操作数名称通常很方便。

然后,您可以删除大多数 GP 寄存器上的 clobbers。您确实需要告诉编译器您修改的任何输入寄存器,例如通过使用 "+r" 约束而不是 "r" (然后在 asm 修改它之后不使用该 C 变量)。或者使用"=r" 输出约束和匹配的输入约束(如"0" (var))将该输入放在与输出操作数0 相同的寄存器中。"+r" 在包装函数中要容易得多,因为此后无论如何都不使用C 变量。

如果你使用虚拟输出操作数让编译器进行寄存器分配,你可以删除向量寄存器上的破坏,但如果你只保留那些硬编码,基本上就可以了。

asm(  // "mov        r0, %[src1]; "   // remove this and just use %[src1] instead of r0

      "... \n\t"
      "VST1.16     {d30[0]}, [%[dstData]]!   \n\t"  //restore img_temp[m][n] to pointer data
      "... \n\t"

    : [src1]"+&r"(src1), [src2]"+&r"(src2), [dstData]"+&r"(dstData),
      [dstSum]"+&r"(dstSum), [height]"+&r"(height)

    : [temp_comp1] "r"(temp_comp1),  [niter] "r"(numofiterations),
      [temp_comp2] "r"(temp_comp2), [temp_comp3] "r"(temp_comp3),
      ...
    : "memory", "cc", all the q and d regs you use.  // but not r0..r13
   );

您可以查看编译器的 asm 输出,了解它是如何填充您提供的 asm 模板中的 %0%[name] 操作数的。使用"instruction \n\t" 使其可读,; 将所有指令放在 asm 输出中的同一行。 (C 字符串文字连接不引入换行符)。

读/写操作数上的 early-clobber 声明确保没有一个仅输入操作数与它们共享寄存器,即使它们让编译器知道 temp_comp1 == height。因为temp_comp1 的原始值仍然需要从寄存器%[temp_comp1] 中读取,即使在修改了%[height] 之后也是如此。例如,它们不能都是r4。否则,如果没有"+&r" 中的&,编译器可以选择仅在读取所有输入后才写入输出以提高效率。 (例如,在包装单个指令时,例如 GNU C 内联汇编旨在高效执行)。


旁注:char array1[16] 和 2 不需要是 volatile; asm 语句中的 "memory" clobber 就足够了,即使您只是将指针传递给它们,而不是将它们用作 "m" 输入操作数。

【讨论】:

  • 感谢您的详细解释。我根据您的建议更改了代码,编译时可以通过代码。但是,出现如下错误:
  • @JiankangLiu:一旦你的循环被编译,调试你的循环是一个完全独立的问题。 (除非您在应用此答案时引入了错误)。您可能应该问一个单独的调试问题,以避免混淆这个一般问题的通用答案,希望对未来的读者有用。
猜你喜欢
  • 2010-12-01
  • 1970-01-01
  • 2014-10-24
  • 2018-02-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多