package optimizer import "strings" // passImmElimination removes redundant immediate loads. // Pattern: lda #N; ... (no A modification) ...; lda #N → remove second // Applies to A, X, Y. func passImmElimination(lines []asmLine) []asmLine { rs := newRegState() var result []asmLine for _, line := range lines { if !line.isCode { if line.isLabel { rs.reset() } result = append(result, line) continue } if isChainBreaker(line.opcode) { rs.reset() result = append(result, line) continue } if isRedundantImm(line, rs) { continue // remove line } updateRegState(line, rs) result = append(result, line) } return result } func isRedundantImm(line asmLine, rs *regState) bool { if !isImmediate(line.operand) { return false } val := parseValueAfterHash(line.operand) if val < 0 { return false // unparseable (label ref, label) } switch line.opcode { case "lda": if rs.a.val == val { return true } rs.loadImm("a", val) case "ldx": if rs.x.val == val { return true } rs.loadImm("x", val) case "ldy": if rs.y.val == val { return true } rs.loadImm("y", val) } return false } // parseValueAfterHash extracts the numeric value after '#'. Returns -1 for unparseable. func parseValueAfterHash(operand string) int { if len(operand) < 2 { return -1 } s := operand[1:] // ACME high/low byte operators are not evaluable at optimize time if strings.HasPrefix(s, "<") || strings.HasPrefix(s, ">") { return -1 } return parseHexOrDec(s) }