Source file src/simd/archsimd/_gen/simdgen/sve_imm.go

     1  // Copyright 2026 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package main
     6  
     7  import (
     8  	"fmt"
     9  	"slices"
    10  	"strings"
    11  )
    12  
    13  // sveImmRanges maps the ISA's description of an SVE immediate, as the loader
    14  // passes it on in ImmDesc, to the immediate's range for an operation on
    15  // esize-bit elements. The ISA states the range only in prose, and some ranges
    16  // depend on the element width ("in the range 0 to number of bits per element
    17  // minus 1"), so each description an operation uses is entered here by hand.
    18  var sveImmRanges = map[string]func(esize int) (min, max int){
    19  	// LSL (immediate).
    20  	`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 },
    21  }
    22  
    23  // resolveSVEImmRanges sets the range of every SVE immediate in ops from
    24  // sveImmRanges. It fails on an immediate whose description has no entry, and
    25  // on an immediate of an exported API with a nonzero minimum, which the
    26  // intrinsics' range check cannot enforce.
    27  func resolveSVEImmRanges(ops []Operation) error {
    28  	if !CurrentArch().isSVE() {
    29  		return nil
    30  	}
    31  	var errs []string
    32  	for i := range ops {
    33  		op := &ops[i]
    34  		for j := range op.In {
    35  			in := &op.In[j]
    36  			if in.Class != "immediate" || in.ImmDesc == nil {
    37  				continue
    38  			}
    39  			r, ok := sveImmRanges[*in.ImmDesc]
    40  			if !ok {
    41  				errs = append(errs, fmt.Sprintf("%s %s: no entry in sveImmRanges for %q", op.Go, op.Asm, *in.ImmDesc))
    42  				continue
    43  			}
    44  			lo, hi := r(sveImmElemBits(*op))
    45  			if lo != 0 && (op.NoTypes == nil || *op.NoTypes != "true") {
    46  				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))
    47  				continue
    48  			}
    49  			in.ImmMin, in.ImmMax = &lo, &hi
    50  		}
    51  	}
    52  	if len(errs) > 0 {
    53  		slices.Sort(errs)
    54  		return fmt.Errorf("simdgen: SVE immediates:\n\t%s", strings.Join(slices.Compact(errs), "\n\t"))
    55  	}
    56  	return nil
    57  }
    58  
    59  // sveImmElemBits returns the element width an SVE immediate's range is stated
    60  // in terms of: that of the operation's first vector operand.
    61  func sveImmElemBits(op Operation) int {
    62  	for _, o := range append(slices.Clone(op.In), op.Out...) {
    63  		if o.Class == "vreg" && o.ElemBits != nil {
    64  			return *o.ElemBits
    65  		}
    66  	}
    67  	return 0
    68  }
    69  

View as plain text