feat(cli): add --map flag to diff for comparing differently-named

functions
This commit is contained in:
2026-08-05 20:20:47 +02:00
parent ad6e3360df
commit ece0d3f127
2 changed files with 41 additions and 6 deletions
+6
View File
@@ -9,6 +9,12 @@ and this project adheres to [Conventional Commits](https://www.conventionalcommi
Unreleased changes on the `development` branch.
### Added
- **`gasm diff --map`** — compare functions whose names differ between files
(e.g. `--map wideCopyAVX2=wideCopyAVX512` pairs AVX2 and AVX-512 variants
regardless of suffix). Unmapped functions fall back to the original name match.
## [0.29.0] — 2026-08-05
RISC-V GOOBJ emission, YMM vector register display, named buffer allocation
+35 -6
View File
@@ -542,7 +542,11 @@ Compare the machine code produced by assembling two files.
Shows which functions differ and the byte-level differences.
Useful for verifying that two implementations produce identical code,
or for tracking encoding changes between Go assembler versions.
Use --map to compare functions whose names differ between the files,
e.g. --map wideCopyAVX2=wideCopyAVX512 pairs the two regardless of suffix.
`)
mapSpec := fs.String("map", "", "comma-separated old=new pairs to match functions with different names")
fs.Parse(args)
if fs.NArg() != 2 {
fmt.Fprintln(os.Stderr, "usage: gasm diff <file1.s> <file2.s>")
@@ -550,6 +554,19 @@ or for tracking encoding changes between Go assembler versions.
}
path1, path2 := fs.Arg(0), fs.Arg(1)
// Parse the name mapping (file1 name → file2 name).
nameMap := make(map[string]string)
if *mapSpec != "" {
for _, pair := range strings.Split(*mapSpec, ",") {
old, new, ok := strings.Cut(pair, "=")
if !ok || old == "" || new == "" {
fmt.Fprintf(os.Stderr, "gasm diff: invalid --map pair %q (expected old=new)\n", pair)
return 2
}
nameMap[old] = new
}
}
// Assemble both files.
img1, err := assembleFile(path1)
if err != nil {
@@ -562,7 +579,7 @@ or for tracking encoding changes between Go assembler versions.
return 1
}
// Compare functions by name.
// Compare functions by name, honouring the --map overrides.
funcs1 := make(map[string][]byte)
for _, fn := range img1.Funcs {
funcs1[fn.Name] = img1.Code[fn.Offset : fn.Offset+fn.Size]
@@ -572,25 +589,37 @@ or for tracking encoding changes between Go assembler versions.
funcs2[fn.Name] = img2.Code[fn.Offset : fn.Offset+fn.Size]
}
// Find common functions and compare.
// Track which file2 functions were consumed (by direct match or via --map)
// so the "only in file2" pass skips them.
matched2 := make(map[string]bool)
diffs := 0
for name, code1 := range funcs1 {
code2, ok := funcs2[name]
target := name
if mapped, ok := nameMap[name]; ok {
target = mapped
}
code2, ok := funcs2[target]
if !ok {
fmt.Printf("%s: only in %s\n", name, path1)
diffs++
continue
}
matched2[target] = true
label := name
if target != name {
label = name + " → " + target
}
if !bytes.Equal(code1, code2) {
fmt.Printf("%s: DIFFERS (%d vs %d bytes)\n", name, len(code1), len(code2))
fmt.Printf("%s: DIFFERS (%d vs %d bytes)\n", label, len(code1), len(code2))
printByteDiff(code1, code2)
diffs++
} else {
fmt.Printf("%s: identical (%d bytes)\n", name, len(code1))
fmt.Printf("%s: identical (%d bytes)\n", label, len(code1))
}
}
for name := range funcs2 {
if _, ok := funcs1[name]; !ok {
if !matched2[name] {
fmt.Printf("%s: only in %s\n", name, path2)
diffs++
}