c65gm/internal/optimizer/debug.go

64 lines
1.6 KiB
Go

package optimizer
import "fmt"
// debugDiff produces annotated output showing original vs optimized code.
// Lines that were removed are shown with "[removed]" annotation.
func debugDiff(original, optimized []asmLine) []asmLine {
// Count [removed] annotations from the walk, then derive optCount from
// origCount - removedCount. This avoids mismatches when later pipeline
// steps (e.g. removeUnusedFunctions) remove code that the optimizer saw.
origCount := countCodeLines(original)
var body []asmLine
oi := 0
opi := 0
removedCount := 0
for oi < len(original) {
origLine := original[oi]
if opi < len(optimized) && linesMatch(origLine, optimized[opi]) {
body = append(body, optimized[opi])
oi++
opi++
} else if !origLine.isCode {
body = append(body, origLine)
oi++
} else {
body = append(body, asmLine{
text: fmt.Sprintf("; [removed] %s", origLine.text),
isComment: true,
})
removedCount++
oi++
}
}
for ; opi < len(optimized); opi++ {
body = append(body, optimized[opi])
}
optCount := origCount - removedCount
header := fmt.Sprintf("; --- peephole: %d asm lines → %d (%d saved) ---",
origCount, optCount, removedCount)
result := []asmLine{{text: header, isComment: true}}
result = append(result, body...)
return result
}
// linesMatch returns true if two asmLines represent the same instruction.
func linesMatch(a, b asmLine) bool {
return a.isCode == b.isCode && a.isLabel == b.isLabel && a.isComment == b.isComment && a.text == b.text
}
func countCodeLines(lines []asmLine) int {
n := 0
for _, l := range lines {
if l.isCode {
n++
}
}
return n
}