package optimizer import "strings" // passStoreReload removes redundant reloads immediately after stores. // Pattern: sta X; ...(non-A-modifying)...; lda X → remove lda func passStoreReload(lines []asmLine, cfg *Config) []asmLine { var result []asmLine for i := 0; i < len(lines); i++ { line := lines[i] if line.isCode && line.opcode == "sta" && isSafeStldOperand(line.operand, cfg) { res := findMatchingLoad(lines, i+1, line.operand, cfg) if res.found { result = append(result, line) for j := i + 1; j < res.idx; j++ { result = append(result, lines[j]) } i = res.idx // skip the lda on next iteration continue } } result = append(result, line) } return result } type matchResult struct { idx int found bool } // findMatchingLoad scans forward from `start` for `lda operand`. // Only passes through comments and non-A-modifying code. func findMatchingLoad(lines []asmLine, start int, operand string, cfg *Config) matchResult { for i := start; i < len(lines); i++ { l := lines[i] if l.optMarker || l.isComment { continue } if l.isLabel { return matchResult{} } if l.isCode && l.opcode == "lda" && l.operand == operand && isSafeStldOperand(l.operand, cfg) { return matchResult{i, true} } if modifiesA(l) { return matchResult{} } } return matchResult{} } // modifiesA returns true if the instruction puts a new value into A. func modifiesA(line asmLine) bool { if !line.isCode { return false } switch line.opcode { case "lda", "adc", "sbc", "and", "ora", "eor", "pla", "txa", "tya": return true case "asl", "lsr", "rol", "ror": return line.operand == "" || line.operand == "a" case "inc", "dec": return false default: return false } } // isSafeStldOperand returns true if the operand is safe for store-then-reload optimization. // Unsafe: I/O addresses (in cfg.IOMap), self-modifying code pattern (+N), indexed/indirect. func isSafeStldOperand(operand string, cfg *Config) bool { if strings.ContainsAny(operand, "(,+") { return false } // Check if operand is a direct hex address in an I/O region if strings.HasPrefix(operand, "$") { addr := parseHexOrDec(operand) if addr >= 0 && addr < 65536 && cfg.IOMap[addr] { return false } } return true }