编译器对于三目运算的代码生成和优化

本文需要用到的指令

mov A,B			; 将B的值复制到A中
sub A,B			; A-B 且将结果放入A中
neg A			 ; 对 A 进行求补 ,0-A 并将结果放入A中 ,当运算结果为0时 ,CF位为 0 , 否则都为1
sbb A,B			; A-B-CF 且将结果放入A中
and A,B			; A&B 且将结果放入A
add A,B 		; A+B 且将结果放入A
cmp A,B	    ; A-B 但不保存结果 , 只影响标志位
cmovxx REG1,REG2 	; 满足条件则将 REG2的内容复制到REG1中
setxxx REG  ; 满足条件则将REG置为1,否则置为0
	xxx 取值
	z : 相等
	e : 相等	(equ)
	l : 小于 - 有符号	(less)
	g : 大于 - 有符号  (greadter)
	b : 小于 - 无符号	(blow)
	a : 大于 - 无符号 (above)
test A,B		; A&B 但不保存结果 , 只会影响标志位
dec A      ; A-1 , 且将结果保存到 A 中 

情况一 : 表达式二三皆为常量 , 表达式一为等式

示例
int a = argc == 8 ? 2 : 5
int b = argc == 0 ? 4 : 3
在 VC++6.0 中的情况
int a = argc == 8 ? 2 : 5
; 以下为反汇编代码 
mov eax,[argc]
sub eax,8
neg eax
sbb eax,eax
and eax,3
add eax,2
int b = argc == 0 ? 4 : 3
; 以下为反汇编代码
mov eax,[argc]
neg eax
sbb eax,eax
and al,0FF
add eax,4
以下为上诉代码分析
以第一段代码为例
mov eax,[argc]
sub eax,8					 ; eax = argc == 8 ? 0 : !0
neg eax						  ; CF = eax == 0 ? 0 : 1
sbb eax,eax					; eax = CF == 0 ? 0 : -1
and eax,3					 ; eax = eax == 0 ? 0 : 3
add eax,2					 ; eax = eax == 0 ? 2 : 5
第二段代码同理

由此可得出以下代码定式 : arg == A ? B : C
mov reg,[arg]
sub reg,A			if A == 0 可省略这一步
neg	reg
sbb reg,reg
and reg,C-B
add reg,B
以下为 VS2022中的情况
int a = argc == 8 ? 2 : 5
; 以下为反汇编代码 
mov eax,[argc]
cmp eax,8
mov ecx,2
mov eax,5
cmovz eax,ecx
int b = argc == 0 ? 4 : 3
; 以下为反汇编代码
mov eax,[argc]
test eax,eax
mov ecx,4
mov eax,3
cmovz eax,ecx
以下为上诉代码分析
以第一段代码为例
mov eax,[argc]
cmp eax,8						; ZF ? eax == 8 ? 1 : 0
mov ecx,2						
mov eax,5
cmovz eax,ecx				; eax = ZF == 1 ? 2 : 5
第二段代码同理(只是将cmp eax,0 改成了 test eax,eax)

由此可得出以下代码定式 : arg == A ? B : C
mov reg1,[arg]
cmp reg1,A
mov reg2,B
mov reg1,C
cmovz reg1,reg2

情况二 : 表达式二三皆为常量 , 表达式一为不等式

示例
int a = argc >=  8 ? 20 : 15;
int b = argc <= 0 ? 2 : 4;
在 VC++6.0 中的情况
int a = argc >=  8 ? 20 : 15;
;以下为反汇编代码
mov eax,[argc]
xor ecx,ecx
cmp eax,8
setl cl				;这里有可能会是 setge , 这里指令不同会略微影响下面指令中的数值
dec ecx
and ecx,5
add ecx,15
int b = argc <= 0 ? 2 : 4;
;以下为反汇编代码
mov eax,[argc]
xor ecx,ecx
cmp eax,0
setg cl				;这里有可能会是 setle , 这里指令不同会略微影响下面指令中的数值
dec ecx
and ecx,-2
add ecx,4
以下为上诉代码分析
以第一段代码为例
mov eax,[argc]			
xor ecx,ecx				
cmp eax,8			
setl cl						; cl = eax < 8 ? 1 : 0 
dec ecx						; ecx = eax < 8 ? 0 : -1
and ecx,5				 ; ecx = eax < 8 ? 0 : 5
add ecx,15				 ; ecx = eax < 8 ? 15 : 20
第二段代码同理

由此可得出以下代码定式 : arg >= A ? B : C
mov REG1,[arg]
xor REG2,REG2
cmp REG1,A
setl REG2
dec REG2
and REG2,B-C
add REG2,C
在 VS2022 中的情况
int a = argc >=  8 ? 20 : 15;
;以下为反汇编代码
mov eax,[argc]
cmp eax,8
mov eax,20
mov ecx,15
cmovl eax,ecx 
int b = argc <= 0 ? 2 : 4;
;以下为反汇编代码
cmp eax,0
mov eax,2
mov ecx,4
cmovg eax,ecx 
以下为上诉代码分析
以第一段代码为例
mov eax,[argc]
cmp eax,8
mov eax,20
mov ecx,15
cmovl eax,ecx 			; eax = eax < 8 ? 15 : 20
第二段代码同理

由此可得出以下代码定式 : arg >= A ? B : C
mov REG1,[arg]
cmp REG1,A
mov REG1,B
mov REG2,C
cmovl REG1,REG2

情况三 : 表达式二三为变量 , 表达式一为不等式

示例
int a = argc >= 8 ? argc/3 : argc*3
在 VC++6.0 中的情况
int a = argc >= 8 ? argc/3 : argc*3
; 以下为反汇编代码
mov eax,[argc]
cmp eax, 8
jl ELSE_NODE
argc/3 反汇编代码
jmp END_IF
ELSE_NODE:
argc*3 反汇编代码
END_IF
以上代码没什么好分析的 , 就是编译成了 if-else 的结构
在 VS2022 中的情况 (分情况 , 有时会成if-else结构,有时会成以下结构)
int a = argc >= 8 ? argc/3 : argc*3
; 以下为反汇编代码
mov edx,[argc]
argc/3 的反汇编代码
mov eax,argc/3
argc*3 的反汇编代码
mov ecx,argc*3
cmp edx,8
cmovl eax,ecx
以上代码与前两种情况一致 , 无本质区别
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值