Pau*_*l R 10
你可以这样做,只需一条movaps
指令:
.section .rodata # put your constants in the read-only data section
.p2align 4 # align to 16 = 1<<4
LC0:
.long 1082130432
.long 1077936128
.long 1073741824
.long 1065353216
.text
foo:
movaps LC0(%rip), %xmm0
Run Code Online (Sandbox Code Playgroud)
加载数据加载通常比将其嵌入指令流更好,特别是因为它需要多少指令.这是CPU执行的几个额外的uop,用于一个任意常量,这个常量不能从具有几个移位的所有常量生成.
如果它更容易,你可以在jit-compile的函数之前或之后放置常量,而不是在单独的部分中.但由于CPU已经拆分了L1d/L1i缓存和TLB,因此通常最好将常量与指令分开.
如果常量的两半都相同,则可以使用SSE3进行广播加载
movddup (m64), %xmm0
.
小智 7
作为10000种方法之一,使用SSE4.1 pinsrq
mov rax, first half
movq xmm0, rax ; better than pinsrq xmm0,rax,0 for performance and code-size
mov rax, second half
pinsrq xmm0, rax, 1
Run Code Online (Sandbox Code Playgroud)
最好的解决方案(特别是如果你想坚持SSE2 - 即避免使用AVX)用你的立即值的两个64位半来初始化两个寄存器(比如xmm0和xmm1),做MOVLHPS xmm0,xmm1为了初始化64位值,最简单的解决方案是使用通用寄存器(例如,AX),然后使用MOVQ将其值传输到XMM寄存器.所以序列将是这样的:
MOV RAX, <first_half>
MOVQ XMM0, RAX
MOV RAX, <second_half>
MOVQ XMM1, RAX
MOVLHPS XMM0,XMM1
Run Code Online (Sandbox Code Playgroud)
在指令流中有多种嵌入常量的方法:
因此,虽然没有办法立即加载到XMM
寄存器中,但可以从" 紧接着 "代码执行的值存储的值进行PC相对加载(64位).这创造了类似的东西:
.align 4
.val:
.long 0x12345678
.long 0x9abcdef0
.long 0xfedbca98
.long 0x76543210
func:
movdqa .val(%rip), %xmm0
Run Code Online (Sandbox Code Playgroud)
当你拆卸:
0000000000000000 : 0: 78 56 34 12 f0 de bc 9a 8: 98 ca db fe 10 32 54 76 0000000000000010 : 10: 66 0f 6f 05 e8 ff ff movdqa -0x18(%rip),%xmm0 # 0
这是完全紧凑,23字节.
其他选项是在堆栈上构造值并再次从那里加载它.在没有%rip
-relative内存访问的32位x86中,仍然可以在24字节中执行此操作(假设堆栈指针在条目上对齐;否则,需要未对齐的加载):
00000000 : 0: 68 78 56 34 12 push $0x12345678 5: 68 f0 de bc 9a push $0x9abcdef0 a: 68 98 ca db fe push $0xfedbca98 f: 68 10 32 54 76 push $0x76543210 14: 66 0f 6f 04 24 movdqa (%esp),%xmm0
在64位(ABI保证函数入口处的堆栈指针对齐)需要27字节:
0000000000000000 : 0: 48 b8 f0 de bc 9a 78 56 34 12 movabs $0x123456789abcdef0,%rax a: 50 push %rax b: 48 b8 10 32 54 76 98 ba dc fe movabs $0xfedcba9876543210,%rax 15: 50 push %rax 16: 66 0f 6f 04 24 movdqa (%rsp),%xmm0
如果你将这些中的任何一个与MOVLHPS
版本进行比较,你会发现它是最长的:
0000000000000000 : 0: 48 b8 f0 de bc 9a 78 56 34 12 movabs $0x123456789abcdef0,%rax a: 66 48 0f 6e c0 movq %rax,%xmm0 f: 48 b8 10 32 54 76 98 ba dc fe movabs $0xfedcba9876543210,%rax 19: 66 48 0f 6e c8 movq %rax,%xmm1 1e: 0f 16 c1 movlhps %xmm1,%xmm0
在33字节.
直接从指令存储器加载的另一个好处是movdqa
它不依赖于之前的任何东西.最有可能的是,@ Paul R给出的第一个版本是你能获得的最快版本.