C embedded assembly error: ‘asm’ operand has impossible constraints
C embedded assembly error: ‘asm’ operand has impossible constraints
当我在 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? and 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"
);
}
我想问题可能是输出操作数列表或输出操作数列表。
是什么原因导致我的代码出错?如何解决?
您在大多数整数寄存器上声明了 clobber,但随后您要求 13 个不同的输入变量。 32 位 ARM 只有 16 个寄存器,其中 2 个是 PC 和 SP,最多只剩下 14 个真正通用的寄存器。
我们可以通过删除 r0
.. r12
上的所有 clobber 来测试过多的 clobbers + 操作数是问题所在;这让它可以编译(变成不正确的代码!!)。 https://godbolt.org/z/Z6x78N这不是解决方案,因为它引入了巨大的错误,这就是我确认问题所在的方式。
任何时候你的内联 asm 模板以 mov
开始从输入寄存器操作数复制到 hard-coded 寄存器,你通常做错了。 即使您有足够的寄存器,编译器也将不得不发出代码以将变量放入寄存器,然后您的 hand-written asm 无缘无故地使用另一个 mov
来复制它。
有关更多指南,请参阅 https://whosebug.com/tags/inline-assembly/info。
首先使用 register int foo asm("r0")
向编译器询问该寄存器中的输入,或者更好 让编译器使用 [=16= 进行寄存器分配 ] 或等效的命名操作数,如 %[src1]
而不是 hard-coded r0
在你的 asm 模板中的任何地方。命名操作数的语法是 [name] "r" (C_var_name)
。它们 没有 匹配,但它们也不必是唯一的;使用与 C var 名称相同的 asm 操作数名称通常很方便。
然后您可以删除大多数 GP 寄存器上的破坏。您确实需要告诉编译器您 修改 的任何输入寄存器,例如通过使用 "+r"
约束而不是 "r"
(然后在 asm 修改它之后不使用该 C 变量)。或者使用 "=r"
输出约束和匹配的输入约束,如 "0" (var)
将该输入放入与输出操作数 0 相同的寄存器中。 "+r"
在包装函数中要容易得多,其中 C 变量反正以后不用了
如果你使用虚拟输出操作数让编译器进行寄存器分配,你可以删除向量寄存器上的破坏,但如果你只留下那些基本上没问题hard-coded。
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 string-literal 连接不引入换行符)。
read/write 操作数的 early-clobber 声明确保 none 操作数与 input-only 操作数共享一个寄存器,即使它们让编译器知道temp_comp1 == height
例如。因为 temp_comp1
的原始值仍然需要从寄存器 %[temp_comp1]
中读取,即使某些内容已被修改 %[height]
。所以他们不能都是 r4
例如。否则,如果没有 "+&r"
中的 &
,编译器 可以 选择它来提高效率,如果仅在读取所有输入后才写入输出。 (例如,当包装单个指令时,像 GNU C 内联 asm 被设计为高效地执行)。
side-note: char array1[16]
和 2 不需要是 volatile
; asm 语句中的 "memory"
破坏就足够了,即使您只是将指针传递给它们,而不是将它们用作 "m"
输入操作数。
当我在 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? and 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"
);
}
我想问题可能是输出操作数列表或输出操作数列表。 是什么原因导致我的代码出错?如何解决?
您在大多数整数寄存器上声明了 clobber,但随后您要求 13 个不同的输入变量。 32 位 ARM 只有 16 个寄存器,其中 2 个是 PC 和 SP,最多只剩下 14 个真正通用的寄存器。
我们可以通过删除 r0
.. r12
上的所有 clobber 来测试过多的 clobbers + 操作数是问题所在;这让它可以编译(变成不正确的代码!!)。 https://godbolt.org/z/Z6x78N这不是解决方案,因为它引入了巨大的错误,这就是我确认问题所在的方式。
任何时候你的内联 asm 模板以 mov
开始从输入寄存器操作数复制到 hard-coded 寄存器,你通常做错了。 即使您有足够的寄存器,编译器也将不得不发出代码以将变量放入寄存器,然后您的 hand-written asm 无缘无故地使用另一个 mov
来复制它。
有关更多指南,请参阅 https://whosebug.com/tags/inline-assembly/info。
首先使用 register int foo asm("r0")
向编译器询问该寄存器中的输入,或者更好 让编译器使用 [=16= 进行寄存器分配 ] 或等效的命名操作数,如 %[src1]
而不是 hard-coded r0
在你的 asm 模板中的任何地方。命名操作数的语法是 [name] "r" (C_var_name)
。它们 没有 匹配,但它们也不必是唯一的;使用与 C var 名称相同的 asm 操作数名称通常很方便。
然后您可以删除大多数 GP 寄存器上的破坏。您确实需要告诉编译器您 修改 的任何输入寄存器,例如通过使用 "+r"
约束而不是 "r"
(然后在 asm 修改它之后不使用该 C 变量)。或者使用 "=r"
输出约束和匹配的输入约束,如 "0" (var)
将该输入放入与输出操作数 0 相同的寄存器中。 "+r"
在包装函数中要容易得多,其中 C 变量反正以后不用了
如果你使用虚拟输出操作数让编译器进行寄存器分配,你可以删除向量寄存器上的破坏,但如果你只留下那些基本上没问题hard-coded。
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 string-literal 连接不引入换行符)。
read/write 操作数的 early-clobber 声明确保 none 操作数与 input-only 操作数共享一个寄存器,即使它们让编译器知道temp_comp1 == height
例如。因为 temp_comp1
的原始值仍然需要从寄存器 %[temp_comp1]
中读取,即使某些内容已被修改 %[height]
。所以他们不能都是 r4
例如。否则,如果没有 "+&r"
中的 &
,编译器 可以 选择它来提高效率,如果仅在读取所有输入后才写入输出。 (例如,当包装单个指令时,像 GNU C 内联 asm 被设计为高效地执行)。
side-note: char array1[16]
和 2 不需要是 volatile
; asm 语句中的 "memory"
破坏就足够了,即使您只是将指针传递给它们,而不是将它们用作 "m"
输入操作数。