为什么GCC将字复制到返回寄存器中,而不是字节?
GCC(4.4.7)没有直接将字节从结构移动到为什么GCC将字复制到返回寄存器中,而不是字节?,c,gcc,optimization,x86-64,C,Gcc,Optimization,X86 64,GCC(4.4.7)没有直接将字节从结构移动到%eax,这是有逻辑原因的,还是仅仅是优化疏忽 考虑以下计划: struct foo { unsigned char x; }; struct bar { unsigned int x; }; int foo (const struct foo *x, int y) { return x->x * y; } int bar (const struct bar *x, int y) { return x->x * y; } 使用GCC编
%eax
,这是有逻辑原因的,还是仅仅是优化疏忽
考虑以下计划:
struct foo { unsigned char x; };
struct bar { unsigned int x; };
int foo (const struct foo *x, int y) { return x->x * y; }
int bar (const struct bar *x, int y) { return x->x * y; }
使用GCC编译时,foo()
和bar()
的差异比我预期的要大:
foo:
.LFB0:
.cfi_startproc
movzbl (%rdi), %edx
movl %esi, %eax
imull %edx, %eax
ret
.cfi_endproc
bar:
.LFB1:
.cfi_startproc
movl (%rdi), %eax
imull %esi, %eax
ret
.cfi_endproc
我期望foo()
与bar()
一样,只是使用了不同的移动指令
我要注意的是,在
clang-500.2.79
下,编译器生成我所期望的foo()
的代码,并且foo()
和bar()
具有相同数量的指令(正如我所期望的GCC一样,但是是错误的)。因为在函数foo中乘以uchar x和uint y,编译器必须首先将uchar x升级为int,指令movzbl就是这样做的
看
之后,我使用gcc 4.6.1和-O3选项重新编译了您的代码,得到了如下汇编:
foo:
.LFB34:
.cfi_startproc
movzbl (%rdi), %eax
imull %esi, %eax
ret
.cfi_endproc
bar:
.LFB35:
.cfi_startproc
movl (%rdi), %eax
imull %esi, %eax
ret
.cfi_endproc
它不再使用%edx了。简短的回答 为什么GCC将字复制到返回寄存器中,而不是字节 因为你要求它返回一个单词而不是一个字节。编译器根据您的代码执行了要求的操作。在一种情况下,您要求提升尺码,但在两种情况下,您都要求取消签名以进行签名。实现这一点的方法不止一种,而clang/llvm和gcc恰好有所不同 GCC(4.4.7)没有将字节从结构直接移动到%eax中是否有逻辑原因,或者这只是一个优化疏忽 我认为,根据我们在当前编译器中看到的情况,这是一个疏忽。请参阅下面生成的代码。(-每种情况下使用的氧气)
与这个问题相关的有趣实验
struct foo { unsigned char x; };
struct bar { unsigned int x; };
char foo (const struct foo *x, char y) { return x->x * y; }
char bar (const struct bar *x, char y) { return x->x * y; }
叮当声
叮当声
gcc和clangforx86使用非指定字符生成与上面相同的代码,但是
手臂
最后一个指令集对读者来说是一个练习,在反汇编中有一点线索…该指令与
条中的movl
相匹配,尽管-这不是差异中有趣的部分…您是说进入%edx
的基本原理是整数提升,但是进入%eax
也会进行升级,并允许删除一条指令。之后我尝试使用gcc 4.6.3和-O3选项编译这些代码,我发现从foo生成的汇编就像bar一样,没有使用%edx。@dwelch:谢谢你的建议。在使用小型内存系统时,需要将内容存储为字节(甚至位)。我原以为在使用这些字节进行算术运算时,使用这些字节不会对CPU周期数造成重大影响,但指令大小增加33%并非无关紧要,因此问题就来了。@nicky_zs:谢谢,这意味着4.4
优化得不够好。你能用4.6
作为你答案的一部分发布你的发现吗?注意:我希望foo()
做一个.x
到int
(标准促销),然后int
*int
(确实如此),而我希望bar()
执行y
到无符号
,然后执行无符号
*无符号
。(穆尔对伊穆尔)。Hmmm@chux:我认为这是有符号整数溢出未定义的情况之一,因此编译器可以选择这样做。问题是编译器并不完美,即使是好的编译器也不会总是选择你本该选择的、没有指出的指令,但根据我研究编译器输出的经验,像gcc或clang这样的编译器有时会更好,有时会更差。有时选择非常好的解决方案有时会被绊倒非常糟糕。通常,如果你选择利用或浪费时间取决于你对它的感觉,当然是在C中,您可以操纵编译器来执行某些操作。在这种情况下,大小在一种情况下跳跃,然后是无符号和有符号的,这要求编译器进行这些转换,并为编译器明智地或不添加更多指令打开了大门。如果要隔离一个目标,可以进行大量调优,但也可以对任何目标进行常规调优(不要在代码中进行太多转换)。
0000000000000000 <foo>:
0: 0f b6 07 movzbl (%rdi),%eax
3: 0f af c6 imul %esi,%eax
6: c3 retq
0000000000000010 <bar>:
10: 8b 07 mov (%rdi),%eax
12: 0f af c6 imul %esi,%eax
15: c3 retq
00000000 <foo>:
0: 90820000 lbu v0,0(a0)
4: 00000000 nop
8: 00450018 mult v0,a1
c: 00001012 mflo v0
10: 03e00008 jr ra
14: 00000000 nop
00000018 <bar>:
18: 8c820000 lw v0,0(a0)
1c: 00000000 nop
20: 00a20018 mult a1,v0
24: 00001012 mflo v0
28: 03e00008 jr ra
2c: 00000000 nop
00000000 <foo>:
0: e5d00000 ldrb r0, [r0]
4: e0000091 mul r0, r1, r0
8: e12fff1e bx lr
0000000c <bar>:
c: e5900000 ldr r0, [r0]
10: e0000091 mul r0, r1, r0
14: e12fff1e bx lr
struct foo { unsigned char x; };
struct bar { unsigned int x; };
char foo (const struct foo *x, char y) { return x->x * y; }
char bar (const struct bar *x, char y) { return x->x * y; }
0000000000000000 <foo>:
0: 8a 07 mov (%rdi),%al
2: 40 f6 e6 mul %sil
5: 0f be c0 movsbl %al,%eax
8: c3 retq
0000000000000010 <bar>:
10: 0f af 37 imul (%rdi),%esi
13: 40 0f be c6 movsbl %sil,%eax
17: c3 retq
0000000000000000 <foo>:
0: 89 f0 mov %esi,%eax
2: f6 27 mulb (%rdi)
4: c3 retq
0000000000000010 <bar>:
10: 89 f0 mov %esi,%eax
12: f6 27 mulb (%rdi)
14: c3 retq
00000000 <foo>:
0: e5d00000 ldrb r0, [r0]
4: e0010190 mul r1, r0, r1
8: e20100ff and r0, r1, #255 ; 0xff
c: e12fff1e bx lr
00000010 <bar>:
10: e5900000 ldr r0, [r0]
14: e0010190 mul r1, r0, r1
18: e20100ff and r0, r1, #255 ; 0xff
1c: e12fff1e bx lr
00000000 <foo>:
0: 90820000 lbu v0,0(a0)
4: 00052e00 sll a1,a1,0x18
8: 00052e03 sra a1,a1,0x18
c: 00a20018 mult a1,v0
10: 00001012 mflo v0
14: 00021600 sll v0,v0,0x18
18: 03e00008 jr ra
1c: 00021603 sra v0,v0,0x18
00000020 <bar>:
20: 8c820000 lw v0,0(a0)
24: 00052e00 sll a1,a1,0x18
28: 00052e03 sra a1,a1,0x18
2c: 00a20018 mult a1,v0
30: 00001012 mflo v0
34: 00021600 sll v0,v0,0x18
38: 03e00008 jr ra
3c: 00021603 sra v0,v0,0x18
struct foo { unsigned char x; };
struct bar { unsigned int x; };
unsigned char foo (const struct foo *x, unsigned char y) { return x->x * y; }
unsigned char bar (const struct bar *x, unsigned char y) { return x->x * y; }
00000000 <foo>:
0: e5d00000 ldrb r0, [r0]
4: e0010190 mul r1, r0, r1
8: e20100ff and r0, r1, #255 ; 0xff
c: e12fff1e bx lr
00000010 <bar>:
10: e5900000 ldr r0, [r0]
14: e0010190 mul r1, r0, r1
18: e20100ff and r0, r1, #255 ; 0xff
1c: e12fff1e bx lr
00000000 <foo>:
0: 90820000 lbu v0,0(a0)
4: 30a500ff andi a1,a1,0xff
8: 00a20018 mult a1,v0
c: 00001012 mflo v0
10: 03e00008 jr ra
14: 304200ff andi v0,v0,0xff
00000018 <bar>:
18: 8c820000 lw v0,0(a0)
1c: 30a500ff andi a1,a1,0xff
20: 00a20018 mult a1,v0
24: 00001012 mflo v0
28: 03e00008 jr ra
2c: 304200ff andi v0,v0,0xff
00000000 <_foo>:
0: 1166 mov r5, -(sp)
2: 1185 mov sp, r5
4: 9f40 0004 movb *4(r5), r0
8: 45c0 ff00 bic $-400, r0
c: 1001 mov r0, r1
e: 7075 0006 mul 6(r5), r1
12: 1040 mov r1, r0
14: 1585 mov (sp)+, r5
16: 0087 rts pc
00000018 <_bar>:
18: 1166 mov r5, -(sp)
1a: 1185 mov sp, r5
1c: 1d41 0006 mov 6(r5), r1
20: 707d 0004 mul *4(r5), r1
24: 1040 mov r1, r0
26: 1585 mov (sp)+, r5
28: 0087 rts pc
gcc --version
gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
clang --version
clang version 3.4 (branches/release_34 201060)
Target: x86_64-unknown-linux-gnu
Thread model: posix
arm-none-eabi-gcc --version
arm-none-eabi-gcc (GCC) 4.8.2
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
mips-elf-gcc --version
mips-elf-gcc (GCC) 4.8.2
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.