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 }