This is a creation in Article, where the information may have evolved or changed.
The recently released Go 1.7 uses a new SSA-based compiled backend (currently only available in AMD64). The SSA makes the compiled code more efficient SSA, which consists mainly of BCE and common sub-expression elimination.
This article will show you some examples of how BCE works in Go 1.7.
In Go 1.7 We can use this command go build -gcflags="-d=ssa/check_bce/debug=1"
to show which line of our code needs to be checked out of bounds.
Example 1
//Example1.go PackageMainfuncF1 (S []int) {_ = S[0]//Line 5:bounds check_ = S[1]//Line 6:bounds check_ = S[2]//Line 7:bounds check}funcF2 (s []int) {_ = S[2]//Line 11:bounds check_ = S[1]//Line 12:bounds check eliminatd!_ = S[0]//Line 13:bounds check eliminatd!}funcF3 (S []int, indexint) {_ = S[index]//Line 17:bounds check_ = S[index]//Line 18:bounds check eliminatd!}funcF4 (A[5]int) {_ = a[4]//Line 22:bounds check eliminatd!}funcMain () {}
$ go build -gcflags="-d=ssa/check_bce/debug=1" example1.go# command-line-arguments./11.go:5: Found IsInBounds./11.go:6: Found IsInBounds./11.go:7: Found IsInBounds./11.go:11: Found IsInBounds./11.go:17: Found IsInBounds
We can see that the 12 rows and 13 lines inside this F2 function do not require cross-border checks, because the cross-check within 11 lines guarantees that 12, 13 lines of code will not cross the line.
But in the F1 must each row to check the cross-border, because the 5th line can not guarantee that the 6th, 7th line is safe, 6th line does not guarantee that the 7th line is safe.
function f3 inside, the Go 1.7 compiler knows that if the first row is safe, then the second line s[index]
is completely safe
The editor of Go 1.7 also correctly analyzes that the only line inside the F4 function (22 lines) is also safe.
Example 2
Example2.gopackage mainfunc f5 (s []int) { for I: = range s { _ = s[i] &N Bsp _ = S[i:len (s)] _ = s[:i+1] }}func f6 (s []int) { for I: = 0; I < Len (s); i + + { _ = s[i] _ = S[i:len (s)] _ = s[:i+ 1] }}func F7 (s []int) { for I: = Len (s)-1; I >= 0; I--{ _ = s[ I]//line 22:bounds check _ = S[i:len (s)] }}func F8 (s []int, index int) {&NBSP ; if Index >= 0 && Index < len (s) { _ = S[index] _ = S[index:len (s)] }}func F9 (s []int) { if len (s) > 2 { _, _, _ = S[0], s[1], s[2] }}func main () {}
$ go build -gcflags="-d=ssa/check_bce/debug=1" example2.go# command-line-arguments./11.go:22: Found IsInBounds
We can see that in Example 2 there is only one line that requires cross-border checking.
The Go 1.7 compiler is so clever that it makes a precise decision to say: All the code in F5 and F6 is safe.
But it seems like we're not as smart as we are, and it looks like 22 lines are safe.
Example 3
Example3.gopackage mainimport "Math/rand" func fa () {s: = []int{0, 1, 2, 3, 4, 5, 6} index: = Rand. INTN (7) _ = S[:index]//Line 9:bounds Check _ = S[index:]//Line 10:bounds check eliminatd!} Func FB (s []int, index int) {_ = S[:index]//Line 14:bounds Check _ = S[index:]//Line 15:bounds check//Not Smart enough or a bug?} Func FC () {s: = []int{0, 1, 2, 3, 4, 5, 6} s = s[:4] Index: = rand. INTN (7) _ = S[:index]//Line 22:bounds Check _ = S[index:]//Line 23:bounds Check}func main () {}
$ go build -gcflags="-d=ssa/check_bce/debug=1" example3.go# command-line-arguments./11.go:9: Found IsSliceInBounds./11.go:14: Found IsSliceInBounds./11.go:15: Found IsSliceInBounds./11.go:22: Found IsSliceInBounds./11.go:23: Found IsSliceInBounds
Ah! So many places need to cross-check.
But wait, why does the Go 1.7 compiler think line 10th is safe, but 15 rows and 23 rows are unsafe? Is it because the compiler is not smart enough or is this a bug?
In fact, the compiler is right here! Why? The reason is that the sub-slice may be larger than the original slice, see the following example:
package MainFunc Main () { &NBSP;S0: = Make ([]int, 5, Ten)//len (s0) = = 5, Cap (s0) = = index: = 8 &N Bsp //in Golang, for the subslice syntax s[a:b], //The valid rage for A is [0, Len (s)], //t He valid rage for B is [A, cap (s)]. //So, this line is no problem. _ = S0[:index] //But, above line was safe can ' t assure the following line is also safe. //In fact, it'll panic. _ = S0[index:]//Panic:runtime Error:slice bounds out of range}
so if s[:index]
is safe, but also when len (s) = = Cap (s)
, S[index:] is safe
. This is why in example 3 inside the FB and FC code also need to cross-check.
The Go 1.7 compiler was successfully detected in the function FA len(s) == cap(s)
. That's great! Golang team!
However, if S[index:] is safe, then S[:index] is always safe.
Example 4
Example4.gopackage mainimport "Math/rand" func fa2 () { s: = []int{0, 1, 2, 3, 4, 5, 6} index: = Rand. INTN (7) _ = S[index:]//Line 9:bounds check _ = S[:index]//Line 10:bounds check eliminatd! }func FB2 (s []int, index int) { _ = S[index:]//Line 14:bounds check _ = S[:index]//Line 15: Bounds check/Not smart enough?} Func fc2 () { s: = []int{0, 1, 2, 3, 4, 5, 6} s = S[:4] index: = Rand. INTN (7) _ = S[index:]//Line 22:bounds check _ = S[:index]//Line 23:bounds check ELIMINATD !} Func main () {}
$ go build -gcflags="-d=ssa/check_bce/debug=1" example4.go# command-line-arguments./11.go:9: Found IsSliceInBounds./11.go:14: Found IsSliceInBounds./11.go:15: Found IsSliceInBounds./11.go:22: Found IsSliceInBounds
In this example, the Go 1.7 compiler is calculated successfully in the FC2 function if the 22 row is safe, then 23 rows is also safe, but in FB2 there is no way to calculate if 14 rows of security in the case of 15 rows is also a safe situation.
Example 5
Although the current compiler (Go1.7.1 AMD64) is not smart enough to exclude some areas that do not require detection, we can do some hints to help the compiler eliminate these unnecessary cross-border checks.
Example5.gopackage MainFunc FD (IS []int, BS []byte] { if len (IS) >= $ { &NBSP;FO R _, N: = range BS { _ = is[n]//Line 7:bounds check, not smart enough. } }}func fd2 (is []int, BS []byte] { if len (IS) >= $ { &NB Sp is = is[:256]//Line 14:bounds check. A hint for the compiler. for _, N: = range BS { _ = is[n]//Line 16:bounds CH Eck eliminatd! } }}func Fe (Isa []int, ISB []int) { if len (ISA) > 0xFFF { & nbsp for _, N: = range ISB { _ = isa[n & 0xFFF]//Line 24:bounds CH Eck, not smart enough. } }}func Fe2 (Isa []int, ISB []int) { if len (ISA) > 0xFFF { isa =ISA[:0XFFF+1]//Line 31:bounds check. A hint for the compiler. for _, N: = range ISB { _ = isa[n & 0xFFF]//Line 33:bounds Check eliminatd! } }}func ff (s []int) []int { &NBSP;S2: = Make ([]int, Len (s)) &NBSP;F or I: = range s { s2[i] =-s[i]//Line 41:bounds check, not smart enough. &NBSP;} &nbs P return S2}func ff2 (S []int) []int { &NBSP;S2: = Make ([]int, Len (s)) &NBSP;S2 = S2[:len (s)]//Line 48: Bounds check. A hint for the compiler. for I: = range s { s2[i] =-s[i]//Line 50:bounds check eliminatd! } return S2}func main () {}
$ go build -gcflags="-d=ssa/check_bce/debug=1" example5.go# command-line-arguments./11.go:7: Found IsInBounds./11.go:14: Found IsSliceInBounds./11.go:24: Found IsInBounds./11.go:31: Found IsSliceInBounds./11.go:41: Found IsInBounds./11.go:48: Found IsSliceInBounds
Summarize
Although the BCE feature in the current 1.7 version is not perfect, it is very good in most cases. There's no doubt that the go compiler will do better in later versions, thanks to the go team for adding features like this
Reference documents
Gbounds Checking Elimination
Utilizing the Go 1.7 SSA Compiler
Original: HTTP://WWW.TAPIRGAMES.COM/BLOG/GOLANG-1.7-BCE
Go community: Https://gocn.io