#include <stdint.h>
static inline void mulq(uint64_t *high, uint64_t *low, uint64_t x, uint64_t y)
{
asm ("mulq %[y]"
: "=d" (*high), "=a" (*low)
: "a" (x), [y] "rm" (y)
);
}
这段代码是正确的,但不是最优的。MULQ是可交换的,因此如果y
恰好已经在RAX中,那么将y
保留在其所在的位置并进行乘法是正确的。但是GCC不知道这一点,所以它会发出额外的指令将操作数移到它们预定义的位置。我想告诉GCC,它可以将任何一个输入放在任何一个位置,只要一个输入最终在RAX中,并且MULQ引用了另一个位置。GCC对此有一个语法,称为“多重替代约束”。请注意逗号(但是整个asm()是断开的;请参见下面):
asm ("mulq %[y]"
: "=d,d" (*high), "=a,a" (*low)
: "a,rm" (x), [y] "rm,a" (y)
);
不幸的是,这是错误的。如果GCC选择第二个替代约束,它将发出“mulq%rax”。为了明确起见,请考虑以下函数:
uint64_t f()
{
uint64_t high, low;
uint64_t rax;
asm("or %0,%0": "=a" (rax));
mulq(&high, &low, 7, rax);
return high;
}
使用gcc-o3-c-fkeep-inline-functions mulq.c
编译后,GCC发出以下程序集:
0000000000000010 <f>:
10: or %rax,%rax
13: mov $0x7,%edx
18: mul %rax
1b: mov %rdx,%rax
1e: retq
如何重写这个内联asm以便在每种情况下都生成正确的输出?
这个2012年的问题在2019年仍然很相关。尽管gcc已经发生了变化,一些生成的代码在2012年并不是最优的,但现在已经是了,相反的情况也是如此。
受Whitlock分析的启发,我在9种不同的情况下测试了MULQ
,其中X
和Y
都是常量(5
、6
)或内存中的值(bar
、ZAR
)或RAX
(F1()
、F2()
):
uint64_t h1() { uint64_t h, l; mulq(&h, &l, 5, 6); return h + l; }
uint64_t h2() { uint64_t h, l; mulq(&h, &l, 5, bar); return h + l; }
uint64_t h3() { uint64_t h, l; mulq(&h, &l, 5, f1()); return h + l; }
uint64_t h4() { uint64_t h, l; mulq(&h, &l, bar, 5); return h + l; }
uint64_t h5() { uint64_t h, l; mulq(&h, &l, bar, zar); return h + l; }
uint64_t h6() { uint64_t h, l; mulq(&h, &l, bar, f1()); return h + l; }
uint64_t h7() { uint64_t h, l; mulq(&h, &l, f1(), 5); return h + l; }
uint64_t h8() { uint64_t h, l; mulq(&h, &l, f1(), bar); return h + l; }
uint64_t h9() { uint64_t h, l; mulq(&h, &l, f1(), f2()); return h + l; }
我已经测试了5个实现:Staufk、Whitlock、Hale、Burdo和我自己的:
inline void mulq(uint64_t *high, uint64_t *low, uint64_t x, uint64_t y) {
asm("mulq %[y]" : [a]"=a,a"(*low), "=d,d"(*high) : "%a,rm"(x), [y]"rm,a"(y) : "cc");
}
所有的实现仍然不能在所有情况下产生最优的代码。其他的代码不能为H3、
H4
和H6
生成最佳代码,而Whitlock和我的代码只能为H3
生成最佳代码:
h3():
callq 4004d0 <f1()>
mov %rax,%r8
mov $0x5,%eax
mul %r8
add %rdx,%rax
retq
在其他条件相同的情况下,可以看出我的比惠特洛克的简单。通过额外的间接级和使用GCC的内置函数(在clang中也可用,但我没有测试过),可以通过调用这个函数而不是mulq
,获得最佳的h3
:
inline void mulq_fixed(uint64_t* high, uint64_t* low, uint64_t x, uint64_t y) {
if (__builtin_constant_p(x))
mulq(high, low, y, x);
else
mulq(high, low, x, y);
}
产量:
h3():
callq 4004d0 <f1()>
mov $0x5,%edx
mul %rdx
add %rdx,%rax
retq
在模板中没有方法来确定选择了哪个替代方案。但是,您可以使用builtin_constant_p之类的builtin包装asm语句,以实现所需的结果。
您可以在编译器资源管理器中查看。
注意:Whitlock的实现还有另一个较小的、意想不到的缺点。您需要在编译器资源管理器中检查选项11010,否则输出是误导性的,函数h1
、...、h9
出现两次使用指令mulq
。这是因为编译器资源管理器的解析器不能正确处理汇编指令.ifnc
/.else
/.endif
,只需删除它们,并显示两个可能的路径(.if
和.else
)。或者,您可以取消选中option.text。
我在函数中有以下代码: 现在我不知道为什么这不起作用。Gcc说:“错误:'asm'操作数有不可能的约束”我一直在学习Gcc内联汇编教程,我认为这是将参数从c代码带到内联汇编块的正确方法。 我还使用了为32位x86构建的gcc交叉编译器。
我有一个包含一系列事件及其时间戳的数据库。 我在这里读到这是可以在SQLite中实现的,我想知道是否也可以在presto中实现。我查看了文档,但找不到一个类似的函数来执行SQLite中的操作。
我必须在两个字符串变量中进行选择--第一个具有非值。如果它们都是-那么我想退出该方法。这可以在下面的一段代码中完成: 也可以用简短的形式完成: 我正在纠结如何用 注意:我只能使用Java 8语法(所以没有)
尝试使用gcc:https://github.com/wolf9466/cpuminer-multi/blob/master/cryptonight_aesni.c编译此源文件时遇到此错误 “CRYPTONIGT_AESNI.c:162:4:错误:操作数约束不一致”
问题内容: 我有两个mysql表-销售表: 和一个项目表: sales表包含每个 ItemID的 多个记录-每个 SaleWeek一个 。我想通过加入两个表来选择出售的所有商品,如下所示: 但是,这将基于每个 SaleWeek* 的多个条目返回多个 ItemId 值。我可以做一个单独的选择,只返回一个 ItemID 吗?-我不想查询最新的 SaleWeek, 因为有些项目可能没有最新的
这里是一个虚拟的*z++=*x++**y++指令。请注意,x、y和z指针寄存器必须指定为输入/输出,因为asm会修改它们。 在第一个示例中,在输入操作数中列出和有什么意义?同一份文件指出: 特别是,如果不将输入操作数指定为输出操作数,就无法指定输入操作数被修改。