Skip to content

x/tools/go/ssa/interp: phi nodes are not executed in parallel (the "swap problem") #69929

@chai2010

Description

@chai2010

Go version

go1.23

Output of go env in your module/workspace:

GO111MODULE=''
GOARCH='amd64'
GOBIN=''
GOCACHE='/Users/chai/Library/Caches/go-build'
GOENV='/Users/chai/Library/Application Support/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFLAGS=''
GOHOSTARCH='amd64'
GOHOSTOS='darwin'
GOINSECURE=''
GOMODCACHE='/Users/chai/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='darwin'
GOPATH='/Users/chai/go'
GOPRIVATE=''
GOPROXY='https://goproxy.cn,direct'
GOROOT='/usr/local/go'
GOSUMDB='off'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/usr/local/go/pkg/tool/darwin_amd64'
GOVCS=''
GOVERSION='go1.23.1'
GODEBUG=''
GOTELEMETRY='local'
GOTELEMETRYDIR='/Users/chai/Library/Application Support/go/telemetry'
GCCGO='gccgo'
GOAMD64='v1'
AR='ar'
CC='clang'
CXX='clang++'
CGO_ENABLED='1'
GOMOD='/dev/null'
GOWORK=''
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
PKG_CONFIG='pkg-config'
GOGCCFLAGS='-fPIC -arch x86_64 -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -ffile-prefix-map=/var/folders/d0/q0b3c09s2_nb6sjjhbnf0t1h0000gq/T/go-build2141529561=/tmp/go-build -gno-record-gcc-switches -fno-common'

What did you do?

i use x/tools/go/ssa to print ssa text:

https://go.dev/play/p/dxj4fTu2M5G

package main

import (
	"go/ast"
	"go/parser"
	"go/token"
	"go/types"
	"log"
	"os"

	"golang.org/x/tools/go/ssa"
)

const src = `
package main

func main() {
	root = &mapNode{}
	insert()
	println(root)
}

var root *mapNode

type mapNode struct {
	Child *mapNode
}

func insert() {
	var x *mapNode = root
	var y *mapNode = x
	for x != nil {
		y = x
		println(y)
		x = x.Child
	}
	println(y)
}
`

func main() {
	fset := token.NewFileSet()
	f, err := parser.ParseFile(fset, "hello.go", src, parser.AllErrors)
	if err != nil {
		log.Fatal(err)
	}

	info := &types.Info{
		Types:      make(map[ast.Expr]types.TypeAndValue),
		Defs:       make(map[*ast.Ident]types.Object),
		Uses:       make(map[*ast.Ident]types.Object),
		Implicits:  make(map[ast.Node]types.Object),
		Selections: make(map[*ast.SelectorExpr]*types.Selection),
		Scopes:     make(map[ast.Node]*types.Scope),
	}

	conf := types.Config{Importer: nil}
	pkg, err := conf.Check("hello.go", fset, []*ast.File{f}, info)
	if err != nil {
		log.Fatal(err)
	}

	var ssaProg = ssa.NewProgram(fset, ssa.SanityCheckFunctions)
	var ssaPkg = ssaProg.CreatePackage(pkg, []*ast.File{f}, info, true)

	ssaPkg.Build()

	ssaPkg.WriteTo(os.Stdout)
	ssaPkg.Func("insert").WriteTo(os.Stdout)
}

What did you see happen?

the insert func ssa:

# Name: hello.go.insert
# Package: hello.go
# Location: hello.go:16:6
func insert():
0:                                                                entry P:0 S:1
	t0 = *root                                                     *mapNode
	jump 3
1:                                                             for.body P:1 S:1
	t1 = println(t5)                                                     ()
	t2 = &t5.Child [#0]                                           **mapNode
	t3 = *t2                                                       *mapNode
	jump 3
2:                                                             for.done P:1 S:0
	t4 = println(t6)                                                     ()
	return
3:                                                             for.loop P:2 S:2
	t5 = phi [0: t0, 1: t3] #x                                     *mapNode
	t6 = phi [0: t0, 1: t5] #y                                     *mapNode
	t7 = t5 != nil:*mapNode                                            bool
	if t7 goto 1 else 2

What did you expect to see?

i guess the ssa lose the y = x in for loop. the test code should print(root) twice.

t1 = *root
jump 3

3:
t6 = t1 = *root
t7 = t1 = *toot
t8 = t6 != nil = true
if t8 goto 1 else 2 = goto 1

1:
println(t6) = println(*root)
t3 = &t6.Child = root.Child
t4 = *t3 = t6.Child = root.Child
jump 3

3:
t6 = t4 = t6.Child = root.Child
t7 = t6 = root.Child
t8 = t6 != nil = root.Child != nil = false
if t8 goto 1 else 2 = goto 2

2:
println(t7) = println(root.Child)
return

but the ssa print(root) and print(root.Child).

Metadata

Metadata

Assignees

Labels

ToolsThis label describes issues relating to any tools in the x/tools repository.

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions