blob: 34b540afa8bce75cc214fd68776da0549648cff0 [file]
// 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 ssa
import (
"fmt"
"io"
"os"
"path/filepath"
"strings"
"sync"
"time"
"cmd/internal/src"
)
type Compiler interface {
Compile(f *Func, htmlWriter HTMLWriter)
Passes() []Pass
}
type HTMLWriter interface {
Enabled() bool
FlushPhases()
WritePhase(phase, title string)
WriteColumn(phase, title, class, html string)
DebugInfo(v func(*Value) string)
TimeFormatting() time.Duration
Close()
}
type Pass struct {
Name string
Fn func(*Func)
Required bool
Disabled bool
Time bool // report time to run pass
Mem bool // report mem stats to run pass
Stats int // pass reports own "stats" (e.g., branches removed)
Debug int // pass performs some debugging. =1 should be in error-testing-friendly Warnl format.
Test int // pass-specific ad-hoc option, perhaps useful in development
Dump map[string]bool // dump if function name matches
Keywords map[string]int64 // ad hoc parameters, typically for experiments/tuning
UsedKW map[string]bool // if a keyword is supplied to a phase, note that it was used.
}
var kwMu sync.Mutex
// DumpFileForPhase creates a file from the function name and phase name,
// warning and returning nil if this is not possible.
func (f *Func) DumpFileForPhase(phaseName string) io.WriteCloser {
f.dumpFileSeq++
fname := fmt.Sprintf("%s_%02d__%s.dump", f.Name, int(f.dumpFileSeq), phaseName)
fname = strings.ReplaceAll(fname, " ", "_")
fname = strings.ReplaceAll(fname, "/", "_")
fname = strings.ReplaceAll(fname, ":", "_")
if ssaDir := os.Getenv("GOSSADIR"); ssaDir != "" {
fname = filepath.Join(ssaDir, fname)
}
fi, err := os.Create(fname)
if err != nil {
f.Warnl(src.NoXPos, "Unable to create after-phase dump file %s", fname)
return nil
}
return fi
}
// DumpFile creates a file from the phase name and function name
// Dumping is done to files to avoid buffering huge strings before
// output.
func (f *Func) DumpFile(phaseName string) {
fi := f.DumpFileForPhase(phaseName)
if fi != nil {
p := StringFuncPrinter{w: fi}
FprintFunc(p, f)
fi.Close()
}
}
func (p *Pass) AddDump(s string) {
if p.Dump == nil {
p.Dump = make(map[string]bool)
}
p.Dump[s] = true
}
func (p *Pass) String() string {
if p == nil {
return "nil pass"
}
return p.Name
}
func (p *Pass) Val(kw string, ifUnset int64) int64 {
if p == nil || p.Keywords == nil {
return ifUnset
}
if v, ok := p.Keywords[kw]; ok {
kwMu.Lock()
p.UsedKW[kw] = true
kwMu.Unlock()
return v
}
return ifUnset
}