我編寫了一個非常漂亮的大整數的大整數庫,但限於512位(由於各種原因比GMP更快)。我正在嘗試將lib的大小進行概括。所以我必須循環adcq指令。ASM塊功能和ABI x86-64
// long addition little indian order due the technique incq-jnz
// I can not use compare because it destroy the Carry Bit
template<int n>
void test_add(boost::uint64_t*, boost::uint64_t*){
asm volatile (
"clc \n"
"movq %0, %%rcx \n"
"loop: \n"
"movq 8(%%rsi,%%rcx,8), %%rax \n" /* original -8(%%rsi,%%rbx,8) */
"adcq %%rax , 8(%%rdi,%%rcx,8) \n" /* original -8(%%rsi,%%rbx,8) */
"incq %%rcx \n" /* original decq */
"jnz loop \n"
:
:"g"(n)
:"rax","rcx","cc","memory"
);
}
int main(int argc, char* argv[]) {
boost::uint64_t c[4],d[4];
c[0] = -1;
c[1] = -1;
c[2] = -1;
c[3] = 0;
d[0] = 1;
d[1] = 0;
d[2] = 0;
d[3] = 0;
test_add<-4>(&d[3],&c[3]); // <-- BigEndian to LittleEndian
這東西效果很好的調試模式-O0但只要我使用的優化,段錯誤/
我真的不明白,因爲我尊重ABI的RSI和RDI,撞註冊,使用良好的寄存器,所以我用GCC -O0 -S編譯和-02 -S
對於-O0 -SI得到
3 .globl main
4 .type main, @function
5 main:
6 .LFB1:
7 .cfi_startproc
8 .cfi_personality 0x3,__gxx_personality_v0
9 pushq %rbp
10 .cfi_def_cfa_offset 16
11 .cfi_offset 6, -16
12 movq %rsp, %rbp
13 .cfi_def_cfa_register 6
14 subq $80, %rsp
15 movl %edi, -68(%rbp)
16 movq %rsi, -80(%rbp)
17 movq $-1, -32(%rbp)
18 movq $-1, -24(%rbp)
19 movq $-1, -16(%rbp)
20 movq $0, -8(%rbp)
21 movq $1, -64(%rbp)
22 movq $0, -56(%rbp)
23 movq $0, -48(%rbp)
24 movq $0, -40(%rbp)
25 leaq -32(%rbp), %rax
26 leaq 24(%rax), %rdx
27 leaq -64(%rbp), %rax
28 addq $24, %rax
29 movq %rdx, %rsi
30 movq %rax, %rdi
31 call _Z8test_addILin4EEvPyS0_
32 movl $0, %eax
33 leave
34 .cfi_def_cfa 7, 8
35 ret
36 .cfi_endproc
37 .LFE1:
38 .size main, .-main
39 .section . enter code here `enter code here`text._Z8test_addILin4EEvPyS0_,"axG",@progbits,_Z8test_addILin4EEvPyS0_,comdat
40 .weak _Z8test_addILin4EEvPyS0_
41 .type _Z8test_addILin4EEvPyS0_, @function
42 _Z8test_addILin4EEvPyS0_:
43 .LFB2:
44 .cfi_startproc
45 .cfi_personality 0x3,__gxx_personality_v0
46 pushq %rbp
47 .cfi_def_cfa_offset 16
48 .cfi_offset 6, -16
49 movq %rsp, %rbp
50 .cfi_def_cfa_register 6
51 movq %rdi, -8(%rbp)
52 movq %rsi, -16(%rbp)
53 #APP
54 # 14 "test.cpp" 1
55 clc
56 movq $-4, %rcx
57 loop:
58 movq 8(%rsi,%rcx,8), %rax
59 adcq %rax , 8(%rdi,%rcx,8)
60 incq %rcx
61 jnz loop
62
63 # 0 "" 2
64 #NO_APP
65 leave
66 .cfi_def_cfa 7, 8
67 ret
68 .cfi_endproc
69 .LFE2:
70 .size _Z8test_addILin4EEvPyS0_, .-_Z8test_addILin4EEvPyS0_
71 .ident "GCC: (GNU) 4.4.6 20120305 (Red Hat 4.4.6-4)"
72 .section .note.GNU-stack,"",@progbits
20-30行,我們看到編譯整理堆棧傳遞AR g到rsi和rdi (第29 - 30行)和電話。完美的,因爲在ABI
如果我現在期待的優化版本,我得到
1 .file "test.cpp"
2 .text
3 .p2align 4,,15
4 .globl main
5 .type main, @function
6 main:
7 .LFB1:
8 .cfi_startproc
9 .cfi_personality 0x3,__gxx_personality_v0
10 #APP
11 # 14 "test.cpp" 1
12 clc
13 movq $-4, %rcx
14 loop:
15 movq 8(%rsi,%rcx,8), %rax
16 adcq %rax , 8(%rdi,%rcx,8)
17 incq %rcx
18 jnz loop
19
20 # 0 "" 2
21 #NO_APP
22 xorl %eax, %eax
23 ret
24 .cfi_endproc
25 .LFE1:
26 .size main, .-main
27 .ident "GCC: (GNU) 4.4.6 20120305 (Red Hat 4.4.6-4)"
28 .section .note.GNU-stack,"",@progbits
那麼再見了ABI,我不明白。堆棧由什麼管理?
一位ASM大師有個想法嗎?我拒絕把這個函數放到一個獨立的文件中,好吧元編程精神。
乾杯。
-------編輯:
我發現您的解決方案中的錯誤,如果我把它變成一個循環:
#include <boost/cstdint.hpp> //boost type
template<long n>
void test_add(boost::uint64_t* x, boost::uint64_t const* y) {
boost::uint64_t dummy;
boost::uint64_t loop_index(n);
__asm__ __volatile__ (
"clc\n\t"
"1:\n\t"
"movq (%[y],%[counter],8), %[dummy]\n\t"
"adcq %[dummy], (%[x], %[counter], 8)\n\t"
"incq %[counter]\n\t"
"jnz 1b\n\t"
: [dummy] "=&r" (dummy)
: [x] "r" (x), [y] "r" (y), [counter] "r" (loop_index)
: "memory", "cc");
}
int main(int argc, char* argv[]) {
boost::uint64_t c[3],d[3];
c[0] = -1;
c[1] = -1;
c[2] = -1;
c[3] = 0;
d[0] = 1;
d[1] = 0;
d[2] = 0;
d[3] = 0;
for(int i=0; i < 0xfff; ++i)
test_add<-4>(&c[4],&d[4]);
return 0;
}
將爲下列ASM:
movq $-4, %rdx <---------------------template parameter
leaq -32(%rsp), %rcx
movq $-1, -32(%rsp)
movq $-1, -24(%rsp)
movq $-1, -16(%rsp)
movq $0, -8(%rsp)
movq $1, -64(%rsp)
movq $0, -56(%rsp)
movq $0, -48(%rsp)
movq $0, -40(%rsp)
.p2align 4,,10
.p2align 3
.L2: <-------- OUPUT loop
#APP
# 16 "main.cpp" 1
clc
1: <-------- INPUT loop
movq (%rcx,%rdx,8), %rsi
adcq %rsi, (%rsp, %rdx, 8)
incq %rdx <------------ rdx++ -> (-4)++ (for the @nd iteration of L2 it is not reset to -4)
jnz 1b
# 0 "" 2
#NO_APP
addl $1, %eax
cmpl $4095, %eax <----- test second loop
jne .L2
好用於輸出迴路的第二次迭代,RDX不reflush至-4,因此,米ovq指令給出了不好的讀數,segfault。我補丁非常糟糕(我用-4重新設置),我只是在jnz之後加上「movq $ -4,%[counter] \ n \ t」,但我需要更一般的東西。它是否存在將計數器重置爲模板參數值的約束條件?
目前修正爲:
template<long n>
void test_add(boost::uint64_t* x, boost::uint64_t const* y) {
boost::uint64_t dummy;
__asm__ __volatile__ (
"clc\n\t"
"movq %[counter_value], %[counter]\n\t" // set the counter to the template value, it's not sure if the function is reused
"1:\n\t"
"movq (%[y],%[counter],8), %[dummy]\n\t"
"adcq %[dummy], (%[x], %[counter], 8)\n\t"
"incq %[counter]\n\t"
"jnz 1b\n\t"
: [dummy] "=&r" (dummy)
: [x] "r" (x), [y] "r" (y), [counter] "r" (n), [counter_value] "i" (n)
: "memory", "cc");
}
命名參數是一個很好的舉措:這確實有助於確定代碼生成。 – wallyk
1)如果我插入一個循環,解決方案是不穩定的,segfault再次:/。我只想做的是:adcq x [0] + = y [0]; adcq x [1] + = y [1]; adcq x [2] + = y [2]; adcq x [3] + = y [3]; 那爲什麼我使用incq。目前我將所有內核手動編寫在.cpp文件中,直到x86-64,power64的512位。我有很多線路,它不是一個完整的內聯解決方案。 2)對於通用,我仍然有一個。 –
我意外地遺漏了'CLC',很抱歉。不應該導致segfault,但我從來沒有得到任何。你確定錯誤在那裏,而不是由編譯器挑選一組特定的寄存器觸發的嗎?您是否使用過調試器來查明問題? – Jester