1
0
mirror of https://github.com/golang/go synced 2024-11-18 09:34:53 -07:00

cmd/compile: adjust GOSSAFUNC html dumping to be more ABI-aware

Uses ,ABI instead of <ABI> because of problems with shell escaping
and windows file names, however if someone goes to all the trouble
of escaping the linker syntax and uses that instead, that works too.

Examples:
```
GOSSAFUNC=runtime.exitsyscall go build main.go
\# runtime
dumped SSA for exitsyscall,0 to ../../src/loopvar/ssa.html
dumped SSA for exitsyscall,1 to ../../src/loopvar/ssa.html

GOSSADIR=`pwd` GOSSAFUNC=runtime.exitsyscall go build main.go
\# runtime
dumped SSA for exitsyscall,0 to ../../src/loopvar/runtime.exitsyscall,0.html
dumped SSA for exitsyscall,1 to ../../src/loopvar/runtime.exitsyscall,1.html

GOSSAFUNC=runtime.exitsyscall,0 go build main.go
\# runtime
dumped SSA for exitsyscall,0 to ../../src/loopvar/ssa.html

GOSSAFUNC=runtime.exitsyscall\<1\> go build main.go
\# runtime
dumped SSA for exitsyscall,1 to ../../src/loopvar/ssa.html
```

Change-Id: Ia1138b61c797d0de49dbfae702dc306b9650a7f8
Reviewed-on: https://go-review.googlesource.com/c/go/+/532475
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Cherry Mui <cherryyz@google.com>
Run-TryBot: David Chase <drchase@google.com>
This commit is contained in:
David Chase 2023-10-03 12:14:53 -04:00
parent 0074125cef
commit a903639608
6 changed files with 56 additions and 16 deletions

View File

@ -8,6 +8,7 @@ import (
"cmd/compile/internal/base" "cmd/compile/internal/base"
"cmd/compile/internal/ir" "cmd/compile/internal/ir"
"cmd/compile/internal/types" "cmd/compile/internal/types"
"cmd/internal/obj"
"cmd/internal/src" "cmd/internal/src"
"fmt" "fmt"
"math" "math"
@ -261,12 +262,13 @@ type ABIConfig struct {
// Do we need anything more than this? // Do we need anything more than this?
offsetForLocals int64 // e.g., obj.(*Link).Arch.FixedFrameSize -- extra linkage information on some architectures. offsetForLocals int64 // e.g., obj.(*Link).Arch.FixedFrameSize -- extra linkage information on some architectures.
regAmounts RegAmounts regAmounts RegAmounts
which obj.ABI
} }
// NewABIConfig returns a new ABI configuration for an architecture with // NewABIConfig returns a new ABI configuration for an architecture with
// iRegsCount integer/pointer registers and fRegsCount floating point registers. // iRegsCount integer/pointer registers and fRegsCount floating point registers.
func NewABIConfig(iRegsCount, fRegsCount int, offsetForLocals int64) *ABIConfig { func NewABIConfig(iRegsCount, fRegsCount int, offsetForLocals int64, which uint8) *ABIConfig {
return &ABIConfig{offsetForLocals: offsetForLocals, regAmounts: RegAmounts{iRegsCount, fRegsCount}} return &ABIConfig{offsetForLocals: offsetForLocals, regAmounts: RegAmounts{iRegsCount, fRegsCount}, which: obj.ABI(which)}
} }
// Copy returns config. // Copy returns config.
@ -276,6 +278,11 @@ func (config *ABIConfig) Copy() *ABIConfig {
return config return config
} }
// Which returns the ABI number
func (config *ABIConfig) Which() obj.ABI {
return config.which
}
// LocalsOffset returns the architecture-dependent offset from SP for args and results. // LocalsOffset returns the architecture-dependent offset from SP for args and results.
// In theory this is only used for debugging; it ought to already be incorporated into // In theory this is only used for debugging; it ought to already be incorporated into
// results from the ABI-related methods // results from the ABI-related methods

View File

@ -361,8 +361,8 @@ func NewConfig(arch string, types Types, ctxt *obj.Link, optimize, softfloat boo
c.floatParamRegs = nil // no FP registers in softfloat mode c.floatParamRegs = nil // no FP registers in softfloat mode
} }
c.ABI0 = abi.NewABIConfig(0, 0, ctxt.Arch.FixedFrameSize) c.ABI0 = abi.NewABIConfig(0, 0, ctxt.Arch.FixedFrameSize, 0)
c.ABI1 = abi.NewABIConfig(len(c.intParamRegs), len(c.floatParamRegs), ctxt.Arch.FixedFrameSize) c.ABI1 = abi.NewABIConfig(len(c.intParamRegs), len(c.floatParamRegs), ctxt.Arch.FixedFrameSize, 1)
// On Plan 9, floating point operations are not allowed in note handler. // On Plan 9, floating point operations are not allowed in note handler.
if buildcfg.GOOS == "plan9" { if buildcfg.GOOS == "plan9" {

View File

@ -10,6 +10,7 @@ import (
"cmd/compile/internal/ir" "cmd/compile/internal/ir"
"cmd/compile/internal/typecheck" "cmd/compile/internal/typecheck"
"cmd/compile/internal/types" "cmd/compile/internal/types"
"cmd/internal/obj"
"cmd/internal/src" "cmd/internal/src"
"fmt" "fmt"
"math" "math"
@ -109,6 +110,21 @@ func (f *Func) NumValues() int {
return f.vid.num() return f.vid.num()
} }
// NameABI returns the function name followed by comma and the ABI number.
// This is intended for use with GOSSAFUNC and HTML dumps, and differs from
// the linker's "<1>" convention because "<" and ">" require shell quoting
// and are not legal file names (for use with GOSSADIR) on Windows.
func (f *Func) NameABI() string {
return FuncNameABI(f.Name, f.ABISelf.Which())
}
// FuncNameABI returns n followed by a comma and the value of a.
// This is a separate function to allow a single point encoding
// of the format, which is used in places where there's not a Func yet.
func FuncNameABI(n string, a obj.ABI) string {
return fmt.Sprintf("%s,%d", n, a)
}
// newSparseSet returns a sparse set that can store at least up to n integers. // newSparseSet returns a sparse set that can store at least up to n integers.
func (f *Func) newSparseSet(n int) *sparseSet { func (f *Func) newSparseSet(n int) *sparseSet {
return f.Cache.allocSparseSet(n) return f.Cache.allocSparseSet(n)

View File

@ -741,7 +741,7 @@ function toggleDarkMode() {
</head>`) </head>`)
w.WriteString("<body>") w.WriteString("<body>")
w.WriteString("<h1>") w.WriteString("<h1>")
w.WriteString(html.EscapeString(w.Func.Name)) w.WriteString(html.EscapeString(w.Func.NameABI()))
w.WriteString("</h1>") w.WriteString("</h1>")
w.WriteString(` w.WriteString(`
<a href="#" onclick="toggle_visibility('help');return false;" id="helplink">help</a> <a href="#" onclick="toggle_visibility('help');return false;" id="helplink">help</a>
@ -784,7 +784,7 @@ func (w *HTMLWriter) Close() {
io.WriteString(w.w, "</body>") io.WriteString(w.w, "</body>")
io.WriteString(w.w, "</html>") io.WriteString(w.w, "</html>")
w.w.Close() w.w.Close()
fmt.Printf("dumped SSA to %v\n", w.path) fmt.Printf("dumped SSA for %s to %v\n", w.Func.NameABI(), w.path)
} }
// WritePhase writes f in a column headed by title. // WritePhase writes f in a column headed by title.

View File

@ -314,12 +314,29 @@ func (s *state) emitOpenDeferInfo() {
// worker indicates which of the backend workers is doing the processing. // worker indicates which of the backend workers is doing the processing.
func buildssa(fn *ir.Func, worker int) *ssa.Func { func buildssa(fn *ir.Func, worker int) *ssa.Func {
name := ir.FuncName(fn) name := ir.FuncName(fn)
abiSelf := abiForFunc(fn, ssaConfig.ABI0, ssaConfig.ABI1)
printssa := false printssa := false
if ssaDump != "" { // match either a simple name e.g. "(*Reader).Reset", package.name e.g. "compress/gzip.(*Reader).Reset", or subpackage name "gzip.(*Reader).Reset" // match either a simple name e.g. "(*Reader).Reset", package.name e.g. "compress/gzip.(*Reader).Reset", or subpackage name "gzip.(*Reader).Reset"
pkgDotName := base.Ctxt.Pkgpath + "." + name // optionally allows an ABI suffix specification in the GOSSAHASH, e.g. "(*Reader).Reset<0>" etc
printssa = name == ssaDump || if strings.Contains(ssaDump, name) { // in all the cases the function name is entirely contained within the GOSSAFUNC string.
strings.HasSuffix(pkgDotName, ssaDump) && (pkgDotName == ssaDump || strings.HasSuffix(pkgDotName, "/"+ssaDump)) nameOptABI := name
if strings.Contains(ssaDump, ",") { // ABI specification
nameOptABI = ssa.FuncNameABI(name, abiSelf.Which())
} else if strings.HasSuffix(ssaDump, ">") { // if they use the linker syntax instead....
l := len(ssaDump)
if l >= 3 && ssaDump[l-3] == '<' {
nameOptABI = ssa.FuncNameABI(name, abiSelf.Which())
ssaDump = ssaDump[:l-3] + "," + ssaDump[l-2:l-1]
}
}
pkgDotName := base.Ctxt.Pkgpath + "." + nameOptABI
printssa = nameOptABI == ssaDump || // "(*Reader).Reset"
pkgDotName == ssaDump || // "compress/gzip.(*Reader).Reset"
strings.HasSuffix(pkgDotName, ssaDump) && strings.HasSuffix(pkgDotName, "/"+ssaDump) // "gzip.(*Reader).Reset"
} }
var astBuf *bytes.Buffer var astBuf *bytes.Buffer
if printssa { if printssa {
astBuf = &bytes.Buffer{} astBuf = &bytes.Buffer{}
@ -366,10 +383,10 @@ func buildssa(fn *ir.Func, worker int) *ssa.Func {
if fn.Pragma&ir.Nosplit != 0 { if fn.Pragma&ir.Nosplit != 0 {
s.f.NoSplit = true s.f.NoSplit = true
} }
s.f.ABI0 = ssaConfig.ABI0.Copy() // Make a copy to avoid racy map operations in type-register-width cache. s.f.ABI0 = ssaConfig.ABI0
s.f.ABI1 = ssaConfig.ABI1.Copy() s.f.ABI1 = ssaConfig.ABI1
s.f.ABIDefault = abiForFunc(nil, s.f.ABI0, s.f.ABI1) s.f.ABIDefault = abiForFunc(nil, ssaConfig.ABI0, ssaConfig.ABI1)
s.f.ABISelf = abiForFunc(fn, s.f.ABI0, s.f.ABI1) s.f.ABISelf = abiSelf
s.panics = map[funcLine]*ssa.Block{} s.panics = map[funcLine]*ssa.Block{}
s.softFloat = s.config.SoftFloat s.softFloat = s.config.SoftFloat
@ -381,7 +398,7 @@ func buildssa(fn *ir.Func, worker int) *ssa.Func {
if printssa { if printssa {
ssaDF := ssaDumpFile ssaDF := ssaDumpFile
if ssaDir != "" { if ssaDir != "" {
ssaDF = filepath.Join(ssaDir, base.Ctxt.Pkgpath+"."+name+".html") ssaDF = filepath.Join(ssaDir, base.Ctxt.Pkgpath+"."+s.f.NameABI()+".html")
ssaD := filepath.Dir(ssaDF) ssaD := filepath.Dir(ssaDF)
os.MkdirAll(ssaD, 0755) os.MkdirAll(ssaD, 0755)
} }

View File

@ -22,7 +22,7 @@ import (
// AMD64 registers available: // AMD64 registers available:
// - integer: RAX, RBX, RCX, RDI, RSI, R8, R9, r10, R11 // - integer: RAX, RBX, RCX, RDI, RSI, R8, R9, r10, R11
// - floating point: X0 - X14 // - floating point: X0 - X14
var configAMD64 = abi.NewABIConfig(9, 15, 0) var configAMD64 = abi.NewABIConfig(9, 15, 0, 1)
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
ssagen.Arch.LinkArch = &x86.Linkamd64 ssagen.Arch.LinkArch = &x86.Linkamd64