Hi,
Recently I encountered a problem which seems to be related to SSA 
optimization 
and feels hard to figure out what some SSA operation means.

Code:
case1:
func main() {
    var x int
    go func() {
        for {   
            x++          //no matter "-N" compile flags is specified or 
not, 'x++' will be optimized
        }
    }()
    println(x)
}

case2:
func main() {
    var x int
    go func() {
        for {   
            x++          
            dummy()   // when empty function 'dummy' is added to this 
infinite loop, ''x++' stays last
        }
    }()
    println(x)
}

//go:noinline
func dummy() {
}

I tried 'GOSSAFUNC=main.func1 go tool compile case2.go' and found the key 
point is
deadcode phase in SSA. Here is CFG before 'early deadcode' phase:

``` *ssaoptx.go*
5  go func() {
6      for {
7          x++
8          dummy()
9      }
10 }()
```

``` *early copyelim*

   - b1:
   - 
      - v1 (?) = InitMem <mem>
      - v2 (?) = SP <uintptr>
      - v3 (?) = SB <uintptr>
      - v4 (?) = LocalAddr <**int> {&x} v2 v1
      - v5 (5) = Arg <*int> {&x} (&x[*int])
      - v9 (?) = Const64 <int> [1]
   - Plain → b2 (*+6*)


   - b2: ← b1 b4
   - 
      - v14 (7) = Phi <mem> v1 v12
      - v15 (7) = Copy <*int> v5 (&x[*int])
   - Plain → b3 (7)


   - b3: ← b2
   - 
      - v6 (7) = Copy <*int> v5 (&x[*int])
      - v7 (7) = Copy <mem> v14
      - v8 (*+7*) = Load <int> v5 v14
      - v10 (7) = Add64 <int> v8 v9
      - v11 (7) = Store <mem> {int} v5 v10 v14
      - v12 (*+8*) = StaticCall <mem> {"".dummy} v11
   - Plain → b4 (8)


   - b4: ← b3
   - Plain → b2 (7)


   - b5:
   - 
      - v13 (10) = Unknown <mem>
   - Ret v13

```
deadcode phase will traverse all blocks and find out the reachable blocks 
(In above example is b1,b2,b3,b4, while b5 is isolated block), Second it 
will
find out live values based on reachable blocks and eliminate dead values.

The call of dummy function makes v8,v10,v11 all live so 'x++' isn't 
optimized.
I have read ssa/README.md but still had some questions.

1. The role of InitMem.
     It seems that every function starts with it, are some initialize work 
like 
     stack space allocation and named return values initialization done by 
it?

2.  The meaning of 'v14 (7) = Phi <mem> v1 v12'.
      It looks like v14 = Φ(v1, v12), but I don't know why InitMem and 
dummy function
      call will affect here.

3.  The meaning of of  StaticCall's argument .
      Some ssa operations are easy to understand,  for example,  
      'v8 (*+7*) = Load <int> v5 v14' means v8<int>=Load(v5) and v14 is the 
memory state            which implies this load operation must happens 
after v14 is determined.

      That's all I know from README.md, but about other operations like 
StaticCall
       I can't get enough information. Here is the relevant souce In 
genericOps.go:
       ```
       {name: "StaticCall", argLength: 1, aux: "CallOff", call: true},     
      
 // call function aux.(*obj.LSym), arg0=memory.  auxint=arg size.  Returns 
memory.
      ```
      For 'v12 (*+8*) = StaticCall <mem> {"".dummy} v11' the only argument 
is v11 but
      obviously v11 seems not the address of dummy function.

4.  As threre are other incomprehensible ssa operations except InitMem, 
Phi, ... ,
      Is there any documents which can help understanding?
     
'Thanks for you time.

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/2d078627-62d6-4885-9c53-9bc9f5629d90n%40googlegroups.com.

Reply via email to