go/src/cmd/compile/internal/gc/pgen_test.go
Russ Cox ffb0cb7044 [dev.regabi] cmd/compile: remove uses of Name.Offset, Name.copy
For globals, Name.Offset is used as a way to address a field within
a global during static initialization. This CL replaces that use with
a separate NameOffsetExpr (ONAMEOFFSET) node.

For locals, Name.Offset is the stack frame offset. This CL calls it
that (FrameOffset, SetFrameOffset).

Now there is no longer any use of Name.Offset or Name.SetOffset.

And now that copies of Names are not being made to change their
offsets, we can lock down use of ir.Copy on Names. The only
remaining uses are during inlining and in handling generic system
functions. At both those times you do want to create a new name
and that can be made explicit by calling the new CloneName method
instead. ir.Copy on a name now panics.

Passes buildall w/ toolstash -cmp.

Change-Id: I0b0a25b9d93aeff7cf4e4025ac53faec7dc8603b
Reviewed-on: https://go-review.googlesource.com/c/go/+/278914
Trust: Russ Cox <rsc@golang.org>
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
2020-12-18 17:52:53 +00:00

207 lines
5.1 KiB
Go

// Copyright 2015 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 gc
import (
"cmd/compile/internal/ir"
"cmd/compile/internal/types"
"cmd/internal/src"
"reflect"
"sort"
"testing"
)
func typeWithoutPointers() *types.Type {
return types.NewStruct(types.NoPkg, []*types.Field{
types.NewField(src.NoXPos, nil, types.New(types.TINT)),
})
}
func typeWithPointers() *types.Type {
return types.NewStruct(types.NoPkg, []*types.Field{
types.NewField(src.NoXPos, nil, types.NewPtr(types.New(types.TINT))),
})
}
func markUsed(n *ir.Name) *ir.Name {
n.SetUsed(true)
return n
}
func markNeedZero(n *ir.Name) *ir.Name {
n.SetNeedzero(true)
return n
}
// Test all code paths for cmpstackvarlt.
func TestCmpstackvar(t *testing.T) {
nod := func(xoffset int64, t *types.Type, s *types.Sym, cl ir.Class) *ir.Name {
if s == nil {
s = &types.Sym{Name: "."}
}
n := NewName(s)
n.SetType(t)
n.SetFrameOffset(xoffset)
n.SetClass(cl)
return n
}
testdata := []struct {
a, b *ir.Name
lt bool
}{
{
nod(0, nil, nil, ir.PAUTO),
nod(0, nil, nil, ir.PFUNC),
false,
},
{
nod(0, nil, nil, ir.PFUNC),
nod(0, nil, nil, ir.PAUTO),
true,
},
{
nod(0, nil, nil, ir.PFUNC),
nod(10, nil, nil, ir.PFUNC),
true,
},
{
nod(20, nil, nil, ir.PFUNC),
nod(10, nil, nil, ir.PFUNC),
false,
},
{
nod(10, nil, nil, ir.PFUNC),
nod(10, nil, nil, ir.PFUNC),
false,
},
{
nod(10, nil, nil, ir.PPARAM),
nod(20, nil, nil, ir.PPARAMOUT),
true,
},
{
nod(10, nil, nil, ir.PPARAMOUT),
nod(20, nil, nil, ir.PPARAM),
true,
},
{
markUsed(nod(0, nil, nil, ir.PAUTO)),
nod(0, nil, nil, ir.PAUTO),
true,
},
{
nod(0, nil, nil, ir.PAUTO),
markUsed(nod(0, nil, nil, ir.PAUTO)),
false,
},
{
nod(0, typeWithoutPointers(), nil, ir.PAUTO),
nod(0, typeWithPointers(), nil, ir.PAUTO),
false,
},
{
nod(0, typeWithPointers(), nil, ir.PAUTO),
nod(0, typeWithoutPointers(), nil, ir.PAUTO),
true,
},
{
markNeedZero(nod(0, &types.Type{}, nil, ir.PAUTO)),
nod(0, &types.Type{}, nil, ir.PAUTO),
true,
},
{
nod(0, &types.Type{}, nil, ir.PAUTO),
markNeedZero(nod(0, &types.Type{}, nil, ir.PAUTO)),
false,
},
{
nod(0, &types.Type{Width: 1}, nil, ir.PAUTO),
nod(0, &types.Type{Width: 2}, nil, ir.PAUTO),
false,
},
{
nod(0, &types.Type{Width: 2}, nil, ir.PAUTO),
nod(0, &types.Type{Width: 1}, nil, ir.PAUTO),
true,
},
{
nod(0, &types.Type{}, &types.Sym{Name: "abc"}, ir.PAUTO),
nod(0, &types.Type{}, &types.Sym{Name: "xyz"}, ir.PAUTO),
true,
},
{
nod(0, &types.Type{}, &types.Sym{Name: "abc"}, ir.PAUTO),
nod(0, &types.Type{}, &types.Sym{Name: "abc"}, ir.PAUTO),
false,
},
{
nod(0, &types.Type{}, &types.Sym{Name: "xyz"}, ir.PAUTO),
nod(0, &types.Type{}, &types.Sym{Name: "abc"}, ir.PAUTO),
false,
},
}
for _, d := range testdata {
got := cmpstackvarlt(d.a, d.b)
if got != d.lt {
t.Errorf("want %v < %v", d.a, d.b)
}
// If we expect a < b to be true, check that b < a is false.
if d.lt && cmpstackvarlt(d.b, d.a) {
t.Errorf("unexpected %v < %v", d.b, d.a)
}
}
}
func TestStackvarSort(t *testing.T) {
nod := func(xoffset int64, t *types.Type, s *types.Sym, cl ir.Class) *ir.Name {
n := NewName(s)
n.SetType(t)
n.SetFrameOffset(xoffset)
n.SetClass(cl)
return n
}
inp := []*ir.Name{
nod(0, &types.Type{}, &types.Sym{}, ir.PFUNC),
nod(0, &types.Type{}, &types.Sym{}, ir.PAUTO),
nod(0, &types.Type{}, &types.Sym{}, ir.PFUNC),
nod(10, &types.Type{}, &types.Sym{}, ir.PFUNC),
nod(20, &types.Type{}, &types.Sym{}, ir.PFUNC),
markUsed(nod(0, &types.Type{}, &types.Sym{}, ir.PAUTO)),
nod(0, typeWithoutPointers(), &types.Sym{}, ir.PAUTO),
nod(0, &types.Type{}, &types.Sym{}, ir.PAUTO),
markNeedZero(nod(0, &types.Type{}, &types.Sym{}, ir.PAUTO)),
nod(0, &types.Type{Width: 1}, &types.Sym{}, ir.PAUTO),
nod(0, &types.Type{Width: 2}, &types.Sym{}, ir.PAUTO),
nod(0, &types.Type{}, &types.Sym{Name: "abc"}, ir.PAUTO),
nod(0, &types.Type{}, &types.Sym{Name: "xyz"}, ir.PAUTO),
}
want := []*ir.Name{
nod(0, &types.Type{}, &types.Sym{}, ir.PFUNC),
nod(0, &types.Type{}, &types.Sym{}, ir.PFUNC),
nod(10, &types.Type{}, &types.Sym{}, ir.PFUNC),
nod(20, &types.Type{}, &types.Sym{}, ir.PFUNC),
markUsed(nod(0, &types.Type{}, &types.Sym{}, ir.PAUTO)),
markNeedZero(nod(0, &types.Type{}, &types.Sym{}, ir.PAUTO)),
nod(0, &types.Type{Width: 2}, &types.Sym{}, ir.PAUTO),
nod(0, &types.Type{Width: 1}, &types.Sym{}, ir.PAUTO),
nod(0, &types.Type{}, &types.Sym{}, ir.PAUTO),
nod(0, &types.Type{}, &types.Sym{}, ir.PAUTO),
nod(0, &types.Type{}, &types.Sym{Name: "abc"}, ir.PAUTO),
nod(0, &types.Type{}, &types.Sym{Name: "xyz"}, ir.PAUTO),
nod(0, typeWithoutPointers(), &types.Sym{}, ir.PAUTO),
}
sort.Sort(byStackVar(inp))
if !reflect.DeepEqual(want, inp) {
t.Error("sort failed")
for i := range inp {
g := inp[i]
w := want[i]
eq := reflect.DeepEqual(w, g)
if !eq {
t.Log(i, w, g)
}
}
}
}