From ce0e803ab9fcee7e5adc99d262dde6f6c1f41842 Mon Sep 17 00:00:00 2001 From: David Chase Date: Fri, 8 Aug 2025 16:49:17 -0400 Subject: [PATCH] [dev.simd] cmd/compile: keep track of multiple rule file names in ssa/_gen This was a long-standing "we need to fix this" for simd work, this fixes it. I expect that simd peephole rule files will be coming soon and there will be more errors and we will be happier to have this. Change-Id: Iefffc43e3e2110939f8d406f6e5da7e9e2d55bd9 Reviewed-on: https://go-review.googlesource.com/c/go/+/694455 Reviewed-by: Cherry Mui LUCI-TryBot-Result: Go LUCI --- .../compile/internal/ssa/_gen/multiscanner.go | 117 ++++++++++++++++++ src/cmd/compile/internal/ssa/_gen/rulegen.go | 18 +-- 2 files changed, 128 insertions(+), 7 deletions(-) create mode 100644 src/cmd/compile/internal/ssa/_gen/multiscanner.go diff --git a/src/cmd/compile/internal/ssa/_gen/multiscanner.go b/src/cmd/compile/internal/ssa/_gen/multiscanner.go new file mode 100644 index 0000000000..1c7520cade --- /dev/null +++ b/src/cmd/compile/internal/ssa/_gen/multiscanner.go @@ -0,0 +1,117 @@ +// Copyright 2025 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "bufio" + "io" +) + +// NamedScanner is a simple struct to pair a name with a Scanner. +type NamedScanner struct { + Name string + Scanner *bufio.Scanner +} + +// NamedReader is a simple struct to pair a name with a Reader, +// which will be converted to a Scanner using bufio.NewScanner. +type NamedReader struct { + Name string + Reader io.Reader +} + +// MultiScanner scans over multiple bufio.Scanners as if they were a single stream. +// It also keeps track of the name of the current scanner and the line number. +type MultiScanner struct { + scanners []NamedScanner + scannerIdx int + line int + totalLine int + err error +} + +// NewMultiScanner creates a new MultiScanner from slice of NamedScanners. +func NewMultiScanner(scanners []NamedScanner) *MultiScanner { + return &MultiScanner{ + scanners: scanners, + scannerIdx: -1, // Start before the first scanner + } +} + +// MultiScannerFromReaders creates a new MultiScanner from a slice of NamedReaders. +func MultiScannerFromReaders(readers []NamedReader) *MultiScanner { + var scanners []NamedScanner + for _, r := range readers { + scanners = append(scanners, NamedScanner{ + Name: r.Name, + Scanner: bufio.NewScanner(r.Reader), + }) + } + return NewMultiScanner(scanners) +} + +// Scan advances the scanner to the next token, which will then be +// available through the Text method. It returns false when the scan stops, +// either by reaching the end of the input or an error. +// After Scan returns false, the Err method will return any error that +// occurred during scanning, except that if it was io.EOF, Err +// will return nil. +func (ms *MultiScanner) Scan() bool { + if ms.scannerIdx == -1 { + ms.scannerIdx = 0 + } + + for ms.scannerIdx < len(ms.scanners) { + current := ms.scanners[ms.scannerIdx] + if current.Scanner.Scan() { + ms.line++ + ms.totalLine++ + return true + } + if err := current.Scanner.Err(); err != nil { + ms.err = err + return false + } + // Move to the next scanner + ms.scannerIdx++ + ms.line = 0 + } + + return false +} + +// Text returns the most recent token generated by a call to Scan. +func (ms *MultiScanner) Text() string { + if ms.scannerIdx < 0 || ms.scannerIdx >= len(ms.scanners) { + return "" + } + return ms.scanners[ms.scannerIdx].Scanner.Text() +} + +// Err returns the first non-EOF error that was encountered by the MultiScanner. +func (ms *MultiScanner) Err() error { + return ms.err +} + +// Name returns the name of the current scanner. +func (ms *MultiScanner) Name() string { + if ms.scannerIdx < 0 { + return "" + } + if ms.scannerIdx >= len(ms.scanners) { + return "" + } + return ms.scanners[ms.scannerIdx].Name +} + +// Line returns the current line number within the current scanner. +func (ms *MultiScanner) Line() int { + return ms.line +} + +// TotalLine returns the total number of lines scanned across all scanners. +func (ms *MultiScanner) TotalLine() int { + return ms.totalLine +} diff --git a/src/cmd/compile/internal/ssa/_gen/rulegen.go b/src/cmd/compile/internal/ssa/_gen/rulegen.go index 57fd2b0594..d4ca1aef22 100644 --- a/src/cmd/compile/internal/ssa/_gen/rulegen.go +++ b/src/cmd/compile/internal/ssa/_gen/rulegen.go @@ -94,9 +94,11 @@ func genSplitLoadRules(arch arch) { genRulesSuffix(arch, "splitload") } func genLateLowerRules(arch arch) { genRulesSuffix(arch, "latelower") } func genRulesSuffix(arch arch, suff string) { + var readers []NamedReader // Open input file. var text io.Reader - text, err := os.Open(arch.name + suff + ".rules") + name := arch.name + suff + ".rules" + text, err := os.Open(name) if err != nil { if suff == "" { // All architectures must have a plain rules file. @@ -105,12 +107,14 @@ func genRulesSuffix(arch arch, suff string) { // Some architectures have bonus rules files that others don't share. That's fine. return } + readers = append(readers, NamedReader{name, text}) // Check for file of SIMD rules to add if suff == "" { - simdtext, err := os.Open("simd" + arch.name + ".rules") + simdname := "simd" + arch.name + ".rules" + simdtext, err := os.Open(simdname) if err == nil { - text = io.MultiReader(text, simdtext) + readers = append(readers, NamedReader{simdname, simdtext}) } } @@ -119,12 +123,12 @@ func genRulesSuffix(arch arch, suff string) { oprules := map[string][]Rule{} // read rule file - scanner := bufio.NewScanner(text) + scanner := MultiScannerFromReaders(readers) rule := "" var lineno int var ruleLineno int // line number of "=>" for scanner.Scan() { - lineno++ + lineno = scanner.Line() line := scanner.Text() if i := strings.Index(line, "//"); i >= 0 { // Remove comments. Note that this isn't string safe, so @@ -151,7 +155,7 @@ func genRulesSuffix(arch arch, suff string) { break // continuing the line can't help, and it will only make errors worse } - loc := fmt.Sprintf("%s%s.rules:%d", arch.name, suff, ruleLineno) + loc := fmt.Sprintf("%s:%d", scanner.Name(), ruleLineno) for _, rule2 := range expandOr(rule) { r := Rule{Rule: rule2, Loc: loc} if rawop := strings.Split(rule2, " ")[0][1:]; isBlock(rawop, arch) { @@ -171,7 +175,7 @@ func genRulesSuffix(arch arch, suff string) { log.Fatalf("scanner failed: %v\n", err) } if balance(rule) != 0 { - log.Fatalf("%s.rules:%d: unbalanced rule: %v\n", arch.name, lineno, rule) + log.Fatalf("%s:%d: unbalanced rule: %v\n", scanner.Name(), lineno, rule) } // Order all the ops. -- 2.52.0