有没有一种方法可以在gcc中使用编译时与内联asm一起计算的表达式?
我有一些代码基本上需要在汇编语句中使用一个小表达式,其中的表达式与I*4相当简单,但GCC在编译时似乎没有意识到这一点(尝试了no-O标志和-O3)。对于第三种用法,“i”和“n”约束在下面的代码段中都不起作用有没有一种方法可以在gcc中使用编译时与内联asm一起计算的表达式?,gcc,assembly,compiler-errors,inline-assembly,Gcc,Assembly,Compiler Errors,Inline Assembly,我有一些代码基本上需要在汇编语句中使用一个小表达式,其中的表达式与I*4相当简单,但GCC在编译时似乎没有意识到这一点(尝试了no-O标志和-O3)。对于第三种用法,“i”和“n”约束在下面的代码段中都不起作用 #include <stdint.h> #include <stdlib.h> #define SHIFT(h, l, c) __asm__ volatile ( \ "shld %2, %1, %0\n\t" \ "sal %2, %1\n\t
#include <stdint.h>
#include <stdlib.h>
#define SHIFT(h, l, c) __asm__ volatile ( \
"shld %2, %1, %0\n\t" \
"sal %2, %1\n\t" \
: "+r"(h), "+r"(l) : "i"(c))
void main(void) {
uint64_t a, b;
SHIFT(a, b, 1); /* 1 */
SHIFT(a, b, 2*4); /* 2 */
size_t i;
for(i=0; i<24; i++) {
SHIFT(a, b, (i*4)); /* 3 */
}
}
我也试过了
"shld $" #c ", %1...
但这也有其自身的问题,因为帕伦家族在严格化后依然存在。我的意图是整个循环都展开,但是-funroll所有循环在这个过程中似乎没有足够早地发生,从而导致i*4变成常数。有什么想法吗?另一种方法非常难看,但如果有一种方法可以在宏中自动执行此操作,那总比没有好:
SHIFT(a, b, 1);
SHIFT(a, b, 2);
...
SHIFT(a, b, 24);
是否有任何特定原因将asm块标记为易失性?当volatile存在时,几乎不可能执行任何优化。不确定为什么要向左移动23*4=92,但是 可能有。可以使用uu builtin_constant_p()和u builtin_choose_expr()选择要编译的表达式;差不多
__builtin_choose_expr(__builtin_constant_p(c), SHIFT(h, l, c), slower_code_here);
如果它在这里选择较慢的代码,那么它“无法”确定c
是常数。如果它抱怨一个“不可能的约束”,那么它知道它是常量,但由于某种原因无法将其转化为立即变量
有时,它认为是和不是恒定的东西令人惊讶;前几天我在玩游戏,它抱怨类似于\uuuuuBuiltin\uChoose\uExpr(sizeof(char[\uuuBuiltin\uChoose\uExpr(…,1,-1)]),…)
(我假设%2、%1、%0的顺序是故意的;我本来希望%0、%1、%2,但是文档很模糊,我永远记不起使用了哪种asm语法。)您假设编译器每次都会展开循环并替换
I*4
的值。。。这是一个有点多的假设。*4
看起来您需要某种寻址修改,为什么不传入i
并编写指令来执行*4
?仔细查看约束GCC句柄,并确保您的指令真的包含了约束可能带来的所有组合。您的“丑陋”方式可以通过使用Boost预处理器库实现(实际上是一组cpp
宏,也是Boost中唯一可以与普通C一起使用的部分):
#包括
#定义移位a(z,CNT,b)uuu asm_uuvolatile(\
shld%2,%1,%0\n\t\
sal%2,%1\n\t\
:“+r”(a),“+r”(b)
:“我”(CNT*4)
:“抄送”);
真空总管(真空){
uint64_t a,b;
//不管怎样。。。
从(1,25,a,b)到(1,25,b)的升压(PP)(重复)
}
这里剩下的“丑陋”一点是宏
BOOST\u PP\u REPEAT*
可以“迭代”到一个用户提供的参数中,因此在本例中,您必须将a
或b
嵌入到实际的宏名中。也许这可以通过另一个间接层来解决(将SHIFT(a)
转换为SHIFT\u a
?)。未尝试。我怀疑您是否仍对这个问题的反馈感兴趣,但由于您从未接受过任何其他答案
OP代码有一些问题,但经过一点清理,您会得到:
#include <stdint.h>
#define SHIFT(h, l, c) __asm__ volatile ( \
"shld %b2, %1, %0\n\t" \
"sal %b2, %1\n\t" \
: "+r"(h), "+r"(l) : "Jc"(c))
int main(void) {
uint64_t a, b;
a = b = 0;
SHIFT(a, b, 1); /* 1 */
SHIFT(a, b, 2*4); /* 2 */
size_t i;
for(i=0; i<16; i++) {
SHIFT(a, b, (i*4)); /* 3 */
}
}
有趣的是,如果您使用i*6而不是i*4,您会看到gcc使用immediates直到60,然后开始使用cl
塔达 我这样做只是为了避免它被优化,因为在这个例子中没有使用返回值。我尝试删除volatile,添加初始值,并在最后添加printf,但结果相同(不可能约束上的编译错误)。我的印象是,一个易失性asm仍然可以移动,您是否有一个链接描述它阻碍的优化(除了删除未使用的代码)呢?好的,那么问题可能与以下主题有关:
#include <boost/preprocessor/repetition/repeat.hpp>
#define SHIFT_a(z, CNT, b) __asm__ volatile ( \
"shld %2, %1, %0\n\t" \
"sal %2, %1\n\t" \
: "+r"(a), "+r"(b)
: "i"(CNT * 4)
: "cc");
void main(void) {
uint64_t a, b;
// whatever ...
BOOST_PP_REPEAT_FROM_TO(1, 25, SHIFT_a, b)
}
#include <stdint.h>
#define SHIFT(h, l, c) __asm__ volatile ( \
"shld %b2, %1, %0\n\t" \
"sal %b2, %1\n\t" \
: "+r"(h), "+r"(l) : "Jc"(c))
int main(void) {
uint64_t a, b;
a = b = 0;
SHIFT(a, b, 1); /* 1 */
SHIFT(a, b, 2*4); /* 2 */
size_t i;
for(i=0; i<16; i++) {
SHIFT(a, b, (i*4)); /* 3 */
}
}
/APP
# 12 "shl.cpp" 1
shld $1, %rdx, %rax
sal $1, %rdx
# 0 "" 2
# 13 "shl.cpp" 1
shld $8, %rdx, %rax
sal $8, %rdx
# 0 "" 2
# 16 "shl.cpp" 1
shld $0, %rdx, %rax
sal $0, %rdx
# 0 "" 2
# 16 "shl.cpp" 1
shld $4, %rdx, %rax
sal $4, %rdx
...
# 0 "" 2
# 16 "shl.cpp" 1
shld $60, %rdx, %rax
sal $60, %rdx
# 0 "" 2
/NO_APP