package main

func f(p *int, x int, b bool) {
    if p == nil {
        return
    }
    g()
    if b {
        *p = x
    } else {
        *p = x + 1
    }
}
func g()

When compiled, the register allocator spills p and x before the call to g. It then restores both p and x in both the then and else branches. It could instead do the restores before the if b check, which would require only one restore of each.

The tricky part is to do the restores before the if only if we're sure that they won't be dropped again before their use in both branches.

This comes up a lot in write barrier code:

package main

func f(p **int, q *int) {
    if p == nil {
        return
    }
    g()
    *p = q
}
func g()

p and q are restored in both the write-barrier-on and write-barrier-off branches in the generated code. This is particularly ugly in the write barrier code because the write-barrier-off code block goes from having 0 instructions to having >0 instructions, meaning we need an additional jump as well.

Comment From: gabyhelp

Related Issues

Related Code Changes

(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.)