Assembly 有没有办法优化这个x86汇编代码?
假设在eax、ecx中给定了值。写一段代码 它计算5*eax+3*ecx+1,并将结果存储在eax中。(* 这里的意思是乘法) 我的代码:Assembly 有没有办法优化这个x86汇编代码?,assembly,x86,Assembly,X86,假设在eax、ecx中给定了值。写一段代码 它计算5*eax+3*ecx+1,并将结果存储在eax中。(* 这里的意思是乘法) 我的代码: ;Initialize the values in eax and ecx mov eax,3 mov ecx,4 ;Compute 3*ecx mov ebx,eax mov eax,ecx mov edx,3 mul edx ; Compute 5*eax mov ecx,eax mov eax,ebx mov edx,5 mul edx ; Compu
;Initialize the values in eax and ecx
mov eax,3
mov ecx,4
;Compute 3*ecx
mov ebx,eax
mov eax,ecx
mov edx,3
mul edx
; Compute 5*eax
mov ecx,eax
mov eax,ebx
mov edx,5
mul edx
; Compute 5*eax + 3*ecx + 1
lea eax,[ecx + eax]
inc eax
如果“优化”是指优化指令计数,那么请使用lea
甚至更多:
;Initialize the values in eax and ecx
mov eax,3
mov ecx,4
;Compute 3*ecx
lea ecx,[ecx*2 + ecx]
; Compute 5*eax
lea eax,[eax*4 + eax]
; Compute 5*eax + 3*ecx + 1
lea eax,[ecx + eax + 1]
这也是16字节的机器代码大小少,如果我的眼睛服务于我的权利
使用lea
可以计算的规则列在指定偏移量的部分中。如果“优化”是指对指令计数进行优化,那么请确保使用lea
甚至更多:
;Initialize the values in eax and ecx
mov eax,3
mov ecx,4
;Compute 3*ecx
lea ecx,[ecx*2 + ecx]
; Compute 5*eax
lea eax,[eax*4 + eax]
; Compute 5*eax + 3*ecx + 1
lea eax,[ecx + eax + 1]
这也是16字节的机器代码大小少,如果我的眼睛服务于我的权利
使用lea
可以计算的规则列在指定偏移量的部分中。Michael(最优秀)的解决方案仍然可以稍微优化大小(短1字节),但这需要先进行一些代数操作
5*eax + 3*ecx + 1
= 2*eax + 3*eax + 3*ecx + 1
= 2*eax + 3*(eax + ecx) + 1
这可以通过
(Excluding initialization of EAX and ECX)
add ecx, eax ; 2 bytes
lea ecx,[ecx*2 + ecx] ; 3 bytes
lea eax,[eax*2 + ecx + 1] ; 4 bytes
Michael的(最优秀的)解决方案仍然可以稍微优化大小(短1字节),但这首先需要一点代数操作
5*eax + 3*ecx + 1
= 2*eax + 3*eax + 3*ecx + 1
= 2*eax + 3*(eax + ecx) + 1
这可以通过
(Excluding initialization of EAX and ECX)
add ecx, eax ; 2 bytes
lea ecx,[ecx*2 + ecx] ; 3 bytes
lea eax,[eax*2 + ecx + 1] ; 4 bytes
谢谢还有一个问题,我这样做错了吗?我的意思是,我应该专注于使用较少可能的指令来编写代码吗?如果你的目标是对代码进行速度优化或大小优化,那么就选择最好的指令来达到这个目标(注意:较少的指令并不一定意味着更小的机器代码或更快的代码)。否则,就用你觉得最容易理解的方式来写吧。我总是建议先让代码工作,然后再考虑在有意义的地方对其进行优化,这将取决于代码实际花费的大部分时间。经验告诉我,优化98%的代码非常容易,实际上不会影响大部分执行时间。:)谢谢还有一个问题,我这样做错了吗?我的意思是,我应该专注于使用较少可能的指令来编写代码吗?如果你的目标是对代码进行速度优化或大小优化,那么就选择最好的指令来达到这个目标(注意:较少的指令并不一定意味着更小的机器代码或更快的代码)。否则,就用你觉得最容易理解的方式来写吧。我总是建议先让代码工作,然后再考虑在有意义的地方对其进行优化,这将取决于代码实际花费的大部分时间。经验告诉我,优化98%的代码非常容易,实际上不会影响大部分执行时间。:)请注意,
imul
具有带有imm8
arg的表单。当然,lea
,lea
,add
方法会运行得更快。如果您的因素不适合使用lea
,那将非常有用。(如果有符号乘法是可以的,并且您不需要结果的高32或高64。)此外,如果我确实需要无符号mul
,我会先执行eax
的mul
来保存mov
指令,然后将值移到一边。然后将ecx
移动到eax
以设置下一个mul
。如果值不在regs中,您可以延迟加载第二个值。请注意,imul
具有带有imm8
arg的表单。当然,lea
,lea
,add
方法会运行得更快。如果您的因素不适合使用lea
,那将非常有用。(如果有符号乘法是可以的,并且您不需要结果的高32或高64。)此外,如果我确实需要无符号mul
,我会先执行eax
的mul
来保存mov
指令,然后将值移到一边。然后将ecx
移动到eax
以设置下一个mul
。如果值不在regs中,您可以延迟加载第二个。很好,但是这会运行得更慢,因为只有一个线性依赖链。最近英特尔CPU上的复杂LEA
指令以3周期延迟、1/周期吞吐量运行。(简单的LEA
运行1c延迟,2/周期吞吐量。)如果您只需将+1
作为LEA的一部分,并在末尾添加,会怎么样?@PeterCordes-感谢您的速度分析。值得注意的是,优化大小和优化速度可以产生不同的代码。lea-ecx,[ecx*2+ecx+1]/lea-eax,[eax*4+eax]/add-eax,ecx
与您的一样小,但这两个LEAs可以并行运行,因此,如果做更多的工作,您有时可以同时完成这两个任务。不过,我认为没有办法使用3组件寻址模式,这使得LEA的延迟为3个周期,而不是1个周期。(eax*4+eax
仍然是1个周期;在英特尔SnB上,+1等于3个周期。)您的延迟应该是1+1+3=5
延迟,但我的只有4个。我的另一个观点是,你不需要代数重排,只要把+1移到一个已经是LEA的op中就行了。很好,但是这会运行得更慢,因为只有一个线性依赖链。最近英特尔CPU上的复杂LEA
指令以3周期延迟、1/周期吞吐量运行。(简单的LEA
运行1c延迟,2/周期吞吐量。)如果您只需将+1
作为LEA的一部分,并在末尾添加,会怎么样?@PeterCordes-感谢您的速度分析。值得注意的是,优化大小和优化速度可以产生不同的代码。lea-ecx,[ecx*2+ecx+1]/lea-eax,[eax*4+eax]/add-eax,ecx
与您的一样小,但这两个LEAs可以并行运行,因此,如果做更多的工作,您有时可以同时完成这两个任务。我看不到使用3-compo的方法