mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
To break up package gc, we need to put these calculations somewhere
lower in the import graph, either an existing or new package. Package types
already needs this code and is using hacks to get it without an import cycle.
We can remove the hacks and set up for the new package gc by moving the
code into package types itself.
[git-generate]
cd src/cmd/compile/internal/gc
rf '
# Remove old import cycle hacks in gc.
rm TypecheckInit:/types.Widthptr =/-0,/types.Dowidth =/+0 \
../ssa/export_test.go:/types.Dowidth =/-+
ex {
import "cmd/compile/internal/types"
types.Widthptr -> Widthptr
types.Dowidth -> dowidth
}
# Disable CalcSize in tests instead of base.Fatalf
sub dowidth:/base.Fatalf\("dowidth without betypeinit"\)/ \
// Assume this is a test. \
return
# Move size calculation into cmd/compile/internal/types
mv Widthptr PtrSize
mv Widthreg RegSize
mv slicePtrOffset SlicePtrOffset
mv sliceLenOffset SliceLenOffset
mv sliceCapOffset SliceCapOffset
mv sizeofSlice SliceSize
mv sizeofString StringSize
mv skipDowidthForTracing SkipSizeForTracing
mv dowidth CalcSize
mv checkwidth CheckSize
mv widstruct calcStructOffset
mv sizeCalculationDisabled CalcSizeDisabled
mv defercheckwidth DeferCheckSize
mv resumecheckwidth ResumeCheckSize
mv typeptrdata PtrDataSize
mv \
PtrSize RegSize SlicePtrOffset SkipSizeForTracing typePos align.go PtrDataSize \
size.go
mv size.go cmd/compile/internal/types
'
: # Remove old import cycle hacks in types.
cd ../types
rf '
ex {
Widthptr -> PtrSize
Dowidth -> CalcSize
}
rm Widthptr Dowidth
'
Change-Id: Ib96cdc6bda2617235480c29392ea5cfb20f60cd8
Reviewed-on: https://go-review.googlesource.com/c/go/+/279234
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>
154 lines
3.8 KiB
Go
154 lines
3.8 KiB
Go
// Copyright 2020 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
|
|
|
|
// This file contains utility routines and harness infrastructure used
|
|
// by the ABI tests in "abiutils_test.go".
|
|
|
|
import (
|
|
"cmd/compile/internal/ir"
|
|
"cmd/compile/internal/types"
|
|
"cmd/internal/src"
|
|
"fmt"
|
|
"strings"
|
|
"testing"
|
|
"text/scanner"
|
|
)
|
|
|
|
func mkParamResultField(t *types.Type, s *types.Sym, which ir.Class) *types.Field {
|
|
field := types.NewField(src.NoXPos, s, t)
|
|
n := NewName(s)
|
|
n.Class_ = which
|
|
field.Nname = n
|
|
n.SetType(t)
|
|
return field
|
|
}
|
|
|
|
// mkstruct is a helper routine to create a struct type with fields
|
|
// of the types specified in 'fieldtypes'.
|
|
func mkstruct(fieldtypes []*types.Type) *types.Type {
|
|
fields := make([]*types.Field, len(fieldtypes))
|
|
for k, t := range fieldtypes {
|
|
if t == nil {
|
|
panic("bad -- field has no type")
|
|
}
|
|
f := types.NewField(src.NoXPos, nil, t)
|
|
fields[k] = f
|
|
}
|
|
s := types.NewStruct(types.LocalPkg, fields)
|
|
return s
|
|
}
|
|
|
|
func mkFuncType(rcvr *types.Type, ins []*types.Type, outs []*types.Type) *types.Type {
|
|
q := lookup("?")
|
|
inf := []*types.Field{}
|
|
for _, it := range ins {
|
|
inf = append(inf, mkParamResultField(it, q, ir.PPARAM))
|
|
}
|
|
outf := []*types.Field{}
|
|
for _, ot := range outs {
|
|
outf = append(outf, mkParamResultField(ot, q, ir.PPARAMOUT))
|
|
}
|
|
var rf *types.Field
|
|
if rcvr != nil {
|
|
rf = mkParamResultField(rcvr, q, ir.PPARAM)
|
|
}
|
|
return types.NewSignature(types.LocalPkg, rf, inf, outf)
|
|
}
|
|
|
|
type expectedDump struct {
|
|
dump string
|
|
file string
|
|
line int
|
|
}
|
|
|
|
func tokenize(src string) []string {
|
|
var s scanner.Scanner
|
|
s.Init(strings.NewReader(src))
|
|
res := []string{}
|
|
for tok := s.Scan(); tok != scanner.EOF; tok = s.Scan() {
|
|
res = append(res, s.TokenText())
|
|
}
|
|
return res
|
|
}
|
|
|
|
func verifyParamResultOffset(t *testing.T, f *types.Field, r ABIParamAssignment, which string, idx int) int {
|
|
n := ir.AsNode(f.Nname).(*ir.Name)
|
|
if n.FrameOffset() != int64(r.Offset) {
|
|
t.Errorf("%s %d: got offset %d wanted %d t=%v",
|
|
which, idx, r.Offset, n.Offset_, f.Type)
|
|
return 1
|
|
}
|
|
return 0
|
|
}
|
|
|
|
func makeExpectedDump(e string) expectedDump {
|
|
return expectedDump{dump: e}
|
|
}
|
|
|
|
func difftokens(atoks []string, etoks []string) string {
|
|
if len(atoks) != len(etoks) {
|
|
return fmt.Sprintf("expected %d tokens got %d",
|
|
len(etoks), len(atoks))
|
|
}
|
|
for i := 0; i < len(etoks); i++ {
|
|
if etoks[i] == atoks[i] {
|
|
continue
|
|
}
|
|
|
|
return fmt.Sprintf("diff at token %d: expected %q got %q",
|
|
i, etoks[i], atoks[i])
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func abitest(t *testing.T, ft *types.Type, exp expectedDump) {
|
|
|
|
types.CalcSize(ft)
|
|
|
|
// Analyze with full set of registers.
|
|
regRes := ABIAnalyze(ft, configAMD64)
|
|
regResString := strings.TrimSpace(regRes.String())
|
|
|
|
// Check results.
|
|
reason := difftokens(tokenize(regResString), tokenize(exp.dump))
|
|
if reason != "" {
|
|
t.Errorf("\nexpected:\n%s\ngot:\n%s\nreason: %s",
|
|
strings.TrimSpace(exp.dump), regResString, reason)
|
|
}
|
|
|
|
// Analyze again with empty register set.
|
|
empty := ABIConfig{}
|
|
emptyRes := ABIAnalyze(ft, empty)
|
|
emptyResString := emptyRes.String()
|
|
|
|
// Walk the results and make sure the offsets assigned match
|
|
// up with those assiged by dowidth. This checks to make sure that
|
|
// when we have no available registers the ABI assignment degenerates
|
|
// back to the original ABI0.
|
|
|
|
// receiver
|
|
failed := 0
|
|
rfsl := ft.Recvs().Fields().Slice()
|
|
poff := 0
|
|
if len(rfsl) != 0 {
|
|
failed |= verifyParamResultOffset(t, rfsl[0], emptyRes.inparams[0], "receiver", 0)
|
|
poff = 1
|
|
}
|
|
// params
|
|
pfsl := ft.Params().Fields().Slice()
|
|
for k, f := range pfsl {
|
|
verifyParamResultOffset(t, f, emptyRes.inparams[k+poff], "param", k)
|
|
}
|
|
// results
|
|
ofsl := ft.Results().Fields().Slice()
|
|
for k, f := range ofsl {
|
|
failed |= verifyParamResultOffset(t, f, emptyRes.outparams[k], "result", k)
|
|
}
|
|
|
|
if failed != 0 {
|
|
t.Logf("emptyres:\n%s\n", emptyResString)
|
|
}
|
|
}
|