| // Copyright 2026 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 ( | |
| "fmt" | |
| "slices" | |
| "strings" | |
| ) | |
| // sveImmRanges maps the ISA's description of an SVE immediate, as the loader | |
| // passes it on in ImmDesc, to the immediate's range for an operation on | |
| // esize-bit elements. The ISA states the range only in prose, and some ranges | |
| // depend on the element width ("in the range 0 to number of bits per element | |
| // minus 1"), so each description an operation uses is entered here by hand. | |
| var sveImmRanges = map[string]func(esize int) (min, max int){ | |
| // LSL (immediate). | |
| `Is the immediate shift amount, in the range 0 to number of bits per element minus 1, encoded in "tszh:tszl:imm3".`: func(esize int) (int, int) { return 0, esize - 1 }, | |
| } | |
| // resolveSVEImmRanges sets the range of every SVE immediate in ops from | |
| // sveImmRanges. It fails on an immediate whose description has no entry, and | |
| // on an immediate of an exported API with a nonzero minimum, which the | |
| // intrinsics' range check cannot enforce. | |
| func resolveSVEImmRanges(ops []Operation) error { | |
| if !CurrentArch().isSVE() { | |
| return nil | |
| } | |
| var errs []string | |
| for i := range ops { | |
| op := &ops[i] | |
| for j := range op.In { | |
| in := &op.In[j] | |
| if in.Class != "immediate" || in.ImmDesc == nil { | |
| continue | |
| } | |
| r, ok := sveImmRanges[*in.ImmDesc] | |
| if !ok { | |
| errs = append(errs, fmt.Sprintf("%s %s: no entry in sveImmRanges for %q", op.Go, op.Asm, *in.ImmDesc)) | |
| continue | |
| } | |
| lo, hi := r(sveImmElemBits(*op)) | |
| if lo != 0 && (op.NoTypes == nil || *op.NoTypes != "true") { | |
| errs = append(errs, fmt.Sprintf("%s %s: immediate range %d to %d does not start at 0, which an API's range check cannot enforce", op.Go, op.Asm, lo, hi)) | |
| continue | |
| } | |
| in.ImmMin, in.ImmMax = &lo, &hi | |
| } | |
| } | |
| if len(errs) > 0 { | |
| slices.Sort(errs) | |
| return fmt.Errorf("simdgen: SVE immediates:\n\t%s", strings.Join(slices.Compact(errs), "\n\t")) | |
| } | |
| return nil | |
| } | |
| // sveImmElemBits returns the element width an SVE immediate's range is stated | |
| // in terms of: that of the operation's first vector operand. | |
| func sveImmElemBits(op Operation) int { | |
| for _, o := range append(slices.Clone(op.In), op.Out...) { | |
| if o.Class == "vreg" && o.ElemBits != nil { | |
| return *o.ElemBits | |
| } | |
| } | |
| return 0 | |
| } |