Skip to content

Commit

Permalink
go/ssa: add Function.DomPostorder
Browse files Browse the repository at this point in the history
Plus a test.

Fixes golang/go#46941

Change-Id: I8aa495bb18359fdc6acae86876a89687c1ba1d13
Reviewed-on: https://go-review.googlesource.com/c/tools/+/557055
LUCI-TryBot-Result: Go LUCI <[email protected]>
Reviewed-by: Tim King <[email protected]>
  • Loading branch information
adonovan committed Jan 19, 2024
1 parent cd7b510 commit e1555a3
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 13 deletions.
31 changes: 18 additions & 13 deletions go/ssa/dom.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,20 +40,25 @@ func (b *BasicBlock) Dominates(c *BasicBlock) bool {
return b.dom.pre <= c.dom.pre && c.dom.post <= b.dom.post
}

type byDomPreorder []*BasicBlock

func (a byDomPreorder) Len() int { return len(a) }
func (a byDomPreorder) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a byDomPreorder) Less(i, j int) bool { return a[i].dom.pre < a[j].dom.pre }

// DomPreorder returns a new slice containing the blocks of f in
// dominator tree preorder.
// DomPreorder returns a new slice containing the blocks of f
// in a preorder traversal of the dominator tree.
func (f *Function) DomPreorder() []*BasicBlock {
n := len(f.Blocks)
order := make(byDomPreorder, n)
copy(order, f.Blocks)
sort.Sort(order)
return order
slice := append([]*BasicBlock(nil), f.Blocks...)
sort.Slice(slice, func(i, j int) bool {
return slice[i].dom.pre < slice[j].dom.pre
})
return slice
}

// DomPostorder returns a new slice containing the blocks of f
// in a postorder traversal of the dominator tree.
// (This is not the same as a postdominance order.)
func (f *Function) DomPostorder() []*BasicBlock {
slice := append([]*BasicBlock(nil), f.Blocks...)
sort.Slice(slice, func(i, j int) bool {
return slice[i].dom.post < slice[j].dom.post
})
return slice
}

// domInfo contains a BasicBlock's dominance information.
Expand Down
56 changes: 56 additions & 0 deletions go/ssa/dom_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Copyright 2024 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package ssa_test

import (
"fmt"
"path/filepath"
"testing"

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

func TestDominatorOrder(t *testing.T) {
const src = `package p
func f(cond bool) {
// (Print operands match BasicBlock IDs.)
print(0)
if cond {
print(1)
} else {
print(2)
}
print(3)
}
`
dir := t.TempDir()
cfg := &packages.Config{
Dir: dir,
Mode: packages.LoadSyntax,
Overlay: map[string][]byte{
filepath.Join(dir, "p.go"): []byte(src),
},
}
initial, err := packages.Load(cfg, "./p.go")
if err != nil {
t.Fatal(err)
}
if packages.PrintErrors(initial) > 0 {
t.Fatal("packages contain errors")
}
_, pkgs := ssautil.Packages(initial, 0)
p := pkgs[0]
p.Build()
f := p.Func("f")

if got, want := fmt.Sprint(f.DomPreorder()), "[0 1 2 3]"; got != want {
t.Errorf("DomPreorder: got %v, want %s", got, want)
}
if got, want := fmt.Sprint(f.DomPostorder()), "[1 2 3 0]"; got != want {
t.Errorf("DomPostorder: got %v, want %s", got, want)
}
}

0 comments on commit e1555a3

Please sign in to comment.