c65gm/internal/optimizer/optimizer.go

73 lines
1.9 KiB
Go

package optimizer
import "strings"
// Optimize applies all enabled peephole passes to the generated ASM lines.
// Each pass runs sequentially on a parsed representation of the lines.
// @@OPT markers are stripped from output.
// Returns optimized lines and the set of dissolved REGISTER variable names
// (variables that had all their stores/loads eliminated).
func Optimize(lines []SourceLine, cfg *Config) ([]string, map[string]bool) {
dissolved := map[string]bool{}
if cfg == nil || !cfg.Any() {
return SourceLineTexts(lines), dissolved
}
parsed := parseLines(lines)
original := parsed
if cfg.EnableStoreLoad {
parsed = passStoreReload(parsed, cfg)
parsed = passStoreTransfer(parsed, cfg)
}
if cfg.EnableLoad {
parsed = passLoadElimination(parsed, cfg)
}
if cfg.EnableImm {
parsed = passImmElimination(parsed)
}
if cfg.EnableJmp {
parsed = passJmpNext(parsed)
}
if cfg.EnableSelf {
parsed = passSelfAssignment(parsed)
}
if cfg.EnableRegisterVars && len(cfg.RegisterVars) > 0 {
parsed = passRegDead(parsed, cfg.RegisterVars)
}
parsed = stripOptMarkers(parsed)
if cfg.Debug {
original = stripOptMarkers(original)
parsed = debugDiff(original, parsed)
}
resultLines := linesToString(parsed)
if len(cfg.RegisterVars) > 0 {
dissolved = computeDissolved(resultLines, cfg.RegisterVars)
}
return resultLines, dissolved
}
// computeDissolved finds REGISTER variables that have no remaining references
// in the output and can have their memory allocation elided.
func computeDissolved(outputLines []string, registerVars map[string]bool) map[string]bool {
dissolved := map[string]bool{}
for name := range registerVars {
dissolved[name] = true
}
for _, line := range outputLines {
for name := range dissolved {
if strings.Contains(line, name) {
delete(dissolved, name)
}
}
if len(dissolved) == 0 {
break
}
}
return dissolved
}