How Are Loops Translated to Assembly?

栏目: IT技术 · 发布时间: 4年前

内容简介::information_source:Loops are powerful concepts in programming and quite easy to handle. However, it has to be translated into basic instructions the computer can understand. The way it is compiled could also impact other components in the standard library

How Are Loops Translated to Assembly?

Illustration created for “A Journey With Go”, made from the original Go Gopher, created by Renee French.

:information_source: This article is based on Go 1.13.

Loops are powerful concepts in programming and quite easy to handle. However, it has to be translated into basic instructions the computer can understand. The way it is compiled could also impact other components in the standard library. Let’s start by analyzing the range loop.

Loop assembly

A range loop iterates an array, slice, or channel. Here is an example of a function that adds up numbers with looping on the slice:

func main() {
l := []int{9, 45, 23, 67, 78}
t := 0

for _, v := range l {
t += v
}

println(t)
}

The command go tool compile -S main.go dumps the generated assembly code, and here is the output related to the range loop:

0x0041 00065 (main.go:4)   XORL   AX, AX
0x0043 00067 (main.go:4)   XORL   CX, CX

0x0045 00069 (main.go:7)   JMP    82
0x0047 00071 (main.go:7)   MOVQ   ""..autotmp_5+16(SP)(AX*8), DX
0x004c 00076 (main.go:7)   INCQ   AX
0x004f 00079 (main.go:8)   ADDQ   DX, CX
0x0052 00082 (main.go:7)   CMPQ   AX, $5
0x0056 00086 (main.go:7)   JLT    710x0058 00088 (main.go:11)  MOVQ   CX, "".t+8(SP)

I split the instructions in two parts: the initialization and the loop itself. The first two instructions initialize two registers to zero:

0x0041 00065 (main.go:4)   XORL   AX, AX
0x0043 00067 (main.go:4)   XORL   CX, CX

The register AX contains the current position in the loop, while CX contains the value of the variable t . Here is the visual representation with the instructions and general-purpose registers:

How Are Loops Translated to Assembly?

The loop starts with an instruction JMP 82 that stands for “ Jump to instruction 82”. This targeted instruction can be identified thanks to the second column:

The next instruction CMPQ AX, $5 stands for “ Compare register AX and the value 5.” It actually subtracts the values of the register DX from AX and stores the result to another register. This value can now be used in the next instruction JLT 71 , which stands for “Jump to instruction 71 if less than 0.” Here is the updated diagram:

How Are Loops Translated to Assembly?

If the condition is not satisfied, the program will not jump and continue to the next instruction after the loop.

So, we now have the skeleton of the loop. Here is the loop converted back to Go:

goto end
start
:
?
end:
if i < 5 {
goto start
}

println(t)

The body of the loop is missing, here are the instructions:

0x0047 00071 (main.go:7)   MOVQ   ""..autotmp_5+16(SP)(AX*8), DX
0x004c 00076 (main.go:7)   INCQ   AX
0x004f 00079 (main.go:8)   ADDQ   DX, CX

The first instruction MOVQ ""..autotmp_5+16(SP)(AX*8), DX stands for “ Move memory from source to destination. ” It is composed by:

  • The slice ""..autotmp_5+16(SP) . SP is the stack pointer — our current memory frame — and autotmp_* is an auto-generated variable name.
  • An offset of 8 (int is 8 bits on a 64-bit architecture) multiplied by the value of the register AX, current position in the loop.
  • A destination represented by the register DX that now contains the current value of the loop.

Then, INCQ stands for “ Increment ” and will increment the current position of the loop:

How Are Loops Translated to Assembly?

The last instruction of the loop body is ADDQ DX, CX that stands for “ Add DX into CX. ” We have seen previously that DX contains the current value of the loop, and CX is the register that contains the content of the variable t :

How Are Loops Translated to Assembly?

It will loop until the loop counter reaches five. Then, the instruction right after the loop shows the register CX moves its value to t :

0x0058 00088 (main.go:11)   MOVQ   CX, "".t+8(SP)

Here is the diagram at its final state:

How Are Loops Translated to Assembly?

We can also finalize the translation of the loop in Go:

func main() {
l := []int{9, 45, 23, 67, 78}
t := 0
i := 0

var tmp int

goto end
start
:
tmp = l[i]
i++
t += tmp
end:
if i < 5 {
goto start
}

println(t)
}

Generating the assembly code for this new program will give the exact same output.

Improvements

The way a loop is translated internally could have an impact on other features such as the Go scheduler. Prior to Go 1.10, a loop was compiled like the following code:

func main() {
l := []int{9, 45, 23, 67, 78}
t := 0
i := 0

var tmp int
p := uintptr(unsafe.Pointer(&l[0]))

if i >= 5 {
goto end
}
body:
tmp = *(*int)(unsafe.Pointer(p))
p += unsafe.Sizeof(l[0])
i++
t += tmp
if i < 5 {
goto body
}
end:
println(t)
}

The problem with this implementation is that the pointer p is past the end of the allocation when i reaches five. That issue makes the loop not easily preemptible since its body is not safe. The optimization of the compilation of the loop makes sure it does not create any past-the-end pointer. This improvement has been made in preparation for a non-cooperative preemption in the Go scheduler. You can find more details about it in the proposal “ Proposal: Non-cooperative goroutine preemption .”


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

计算机程序设计艺术(第2卷)

计算机程序设计艺术(第2卷)

Donald E. Knuth / 苏运霖 / 国防工业出版社 / 2002-8 / 98.00元

本书是国内外业界广泛关注的7卷本《计算机程序设计艺术》第2卷的最新版。本卷对半数值算法领域做了全面介绍,分“随机数”和“算术”两章。本卷总结了主要算法范例及这些算法的基本理论,广泛剖析了计算机程序设计与数值分析间的相互联系,其中特别值得注意的是作者对随机数生成程序的重新处理和对形式幂级数计算的讨论。 本书附有大量习题和答案,标明了难易程度及数学概念的使用。 本书内容精辟,语言流畅,引人入胜,可供从......一起来看看 《计算机程序设计艺术(第2卷)》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

在线进制转换器
在线进制转换器

各进制数互转换器

随机密码生成器
随机密码生成器

多种字符组合密码