[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 <cherryyz@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
This commit is contained in:
David Chase
2025-08-08 16:49:17 -04:00
parent 38b76bf2a3
commit ce0e803ab9
2 changed files with 128 additions and 7 deletions

View File

@@ -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 "<before first>"
}
if ms.scannerIdx >= len(ms.scanners) {
return "<after last>"
}
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
}

View File

@@ -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.