我很好奇是否有人可以为我阐明这一点。我正在研究一些数字数据转换的东西,并且我有几个进行数据转换的函数,我使用两个宏定义它们:
#define CONV_VIA_CAST(name, dtype, vtype) \
static inline void name(void *data, void *view, size_t len) { \
vtype *vptr = (vtype*)view; \
dtype *dptr = (dtype*)data; \
for (size_t ii=0; ii < len/sizeof(vtype); ii++) { \
*vptr++ = (vtype)*dptr++; \
} \
}
#define CONV_VIA_FUNC(name, dtype, vtype, via) \
static inline void name(void *data, void *view, size_t len) { \
vtype *vptr = (vtype*)view; \
dtype *dptr = (dtype*)data; \
for (size_t ii=0; ii < len/sizeof(vtype); ii++) { \
*vptr++ = (vtype)via(*dptr++); \
} \
}
当我定义一个 float 到 int 的转换时:
CONV_VIA_FUNC(f_to_i, float, int16_t, lrintf);
我得到了一个很好的简洁的小块组装 -O3 :
0x0000000000401fb0 <+0>: shr %rdx
0x0000000000401fb3 <+3>: je 0x401fd3 <f_to_i+35>
0x0000000000401fb5 <+5>: xor %eax,%eax
0x0000000000401fb7 <+7>: nopw 0x0(%rax,%rax,1)
0x0000000000401fc0 <+16>: cvtss2si (%rdi,%rax,4),%rcx
0x0000000000401fc6 <+22>: mov %cx,(%rsi,%rax,2)
0x0000000000401fca <+26>: add $0x1,%rax
0x0000000000401fce <+30>: cmp %rdx,%rax
0x0000000000401fd1 <+33>: jne 0x401fc0 <f_to_i+16>
0x0000000000401fd3 <+35>: repz retq
但是,当我定义一个 float->double(或 double->float)函数时:
CONV_VIA_CAST(f_to_d, float, double);
我得到了这个怪物:
0x0000000000402040 <+0>: mov %rdx,%r8
0x0000000000402043 <+3>: shr $0x3,%r8
0x0000000000402047 <+7>: test %r8,%r8
0x000000000040204a <+10>: je 0x402106 <f_to_d+198>
0x0000000000402050 <+16>: shr $0x5,%rdx
0x0000000000402054 <+20>: lea 0x0(,%rdx,4),%r9
0x000000000040205c <+28>: test %r9,%r9
0x000000000040205f <+31>: je 0x402108 <f_to_d+200>
0x0000000000402065 <+37>: lea (%rdi,%r8,4),%rax
0x0000000000402069 <+41>: cmp $0xb,%r8
0x000000000040206d <+45>: lea (%rsi,%r8,8),%r10
0x0000000000402071 <+49>: seta %cl
0x0000000000402074 <+52>: cmp %rax,%rsi
0x0000000000402077 <+55>: seta %al
0x000000000040207a <+58>: cmp %r10,%rdi
0x000000000040207d <+61>: seta %r10b
0x0000000000402081 <+65>: or %r10d,%eax
0x0000000000402084 <+68>: test %al,%cl
0x0000000000402086 <+70>: je 0x402108 <f_to_d+200>
0x000000000040208c <+76>: xorps %xmm3,%xmm3
0x000000000040208f <+79>: xor %eax,%eax
0x0000000000402091 <+81>: xor %ecx,%ecx
0x0000000000402093 <+83>: nopl 0x0(%rax,%rax,1)
0x0000000000402098 <+88>: movaps %xmm3,%xmm0
0x000000000040209b <+91>: add $0x1,%rcx
0x000000000040209f <+95>: movlps (%rdi,%rax,1),%xmm0
0x00000000004020a3 <+99>: movhps 0x8(%rdi,%rax,1),%xmm0
0x00000000004020a8 <+104>: movhlps %xmm0,%xmm1
0x00000000004020ab <+107>: cvtps2pd %xmm0,%xmm2
0x00000000004020ae <+110>: cvtps2pd %xmm1,%xmm0
0x00000000004020b1 <+113>: movlpd %xmm2,(%rsi,%rax,2)
0x00000000004020b6 <+118>: movhpd %xmm2,0x8(%rsi,%rax,2)
0x00000000004020bc <+124>: movlpd %xmm0,0x10(%rsi,%rax,2)
0x00000000004020c2 <+130>: movhpd %xmm0,0x18(%rsi,%rax,2)
0x00000000004020c8 <+136>: add $0x10,%rax
0x00000000004020cc <+140>: cmp %rcx,%rdx
0x00000000004020cf <+143>: ja 0x402098 <f_to_d+88>
0x00000000004020d1 <+145>: cmp %r9,%r8
0x00000000004020d4 <+148>: lea (%rsi,%r9,8),%rsi
0x00000000004020d8 <+152>: lea (%rdi,%r9,4),%rdi
0x00000000004020dc <+156>: je 0x40210d <f_to_d+205>
0x00000000004020de <+158>: mov %r9,%rdx
0x00000000004020e1 <+161>: mov %r9,%rax
0x00000000004020e4 <+164>: neg %rdx
0x00000000004020e7 <+167>: lea (%rsi,%rdx,8),%rcx
0x00000000004020eb <+171>: lea (%rdi,%rdx,4),%rdx
0x00000000004020ef <+175>: nop
0x00000000004020f0 <+176>: movss (%rdx,%rax,4),%xmm0
0x00000000004020f5 <+181>: cvtps2pd %xmm0,%xmm0
0x00000000004020f8 <+184>: movsd %xmm0,(%rcx,%rax,8)
0x00000000004020fd <+189>: add $0x1,%rax
0x0000000000402101 <+193>: cmp %rax,%r8
0x0000000000402104 <+196>: ja 0x4020f0 <f_to_d+176>
0x0000000000402106 <+198>: repz retq
0x0000000000402108 <+200>: xor %r9d,%r9d
0x000000000040210b <+203>: jmp 0x4020de <f_to_d+158>
0x000000000040210d <+205>: nopl (%rax)
0x0000000000402110 <+208>: retq
任何人都可以阐明浮动->双转换的幕后情况吗?也许如何编写它来获得更有效的组装?如果这很重要,我正在使用 gcc 4.6.3。