Source file src/simd/archsimd/_gen/simdgen/types/operation.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 types
     6  
     7  import (
     8  	"fmt"
     9  	"simd/archsimd/_gen/specgen/specexpr"
    10  	"simd/archsimd/_gen/unify"
    11  )
    12  
    13  // RawOperation is the unifier representation of an [Operation]. It is
    14  // translated into a more parsed form after unifier decoding.
    15  type RawOperation struct {
    16  	Go string // Base Go method name
    17  
    18  	GOARCH       string  // GOARCH for this definition
    19  	Asm          string  // Assembly mnemonic
    20  	Arrangement  *string // optional Arrangement for ARM64 SIMD operations (e.g., "4S", "2D")
    21  	OperandOrder *string // optional Operand order for better Go declarations
    22  	// Optional tag to indicate this operation is paired with special generic->machine ssa lowering rules.
    23  	// Should be paired with special templates in gen_simdrules.go
    24  	SpecialLower *string
    25  	// HiHalfAsm is the assembly mnemonic for the hi-half "2" variant of this operation,
    26  	// specified in go_arm64.yaml (e.g., "VSHRN2", "VUMULL2").
    27  	// When non-nil, simdgen generates the "2" variant machine op and folding rules.
    28  	HiHalfAsm *string
    29  
    30  	In              []Operand // Parameters
    31  	InVariant       []Operand // Optional parameters
    32  	Out             []Operand // Results
    33  	MemFeatures     *string   // The memory operand feature this operation supports
    34  	MemFeaturesData *string   // Additional data associated with MemFeatures
    35  	Commutative     bool      // Commutativity
    36  	CPUFeature      string    // CPUID/Has* feature name
    37  	Zeroing         *bool     // nil => use asm suffix ".Z"; false => do not use asm suffix ".Z"
    38  	Documentation   *string   // Documentation will be appended to the stubs comments.
    39  	AddDoc          *string   // Additional doc to be appended.
    40  	// ConstMask is a hack to reduce the size of defs the user writes for const-immediate
    41  	// If present, it will be copied to [In[0].Const].
    42  	ConstImm *string
    43  	// NameAndSizeCheck is used to check [BWDQ] maps to (8|16|32|64) elemBits.
    44  	NameAndSizeCheck *bool
    45  	// If non-nil, all generation in gen_simdTypes.go and gen_intrinsics will be skipped.
    46  	NoTypes *string
    47  	// If non-nil, all generation in gen_simdGenericOps and gen_simdrules will be skipped.
    48  	NoGenericOps *string
    49  	// If non-nil, this string will be attached to the machine ssa op name.  E.g. "const"
    50  	SSAVariant *string
    51  	// If true, do not emit method declarations, generic ops, or intrinsics for masked variants
    52  	// DO emit the architecture-specific opcodes and optimizations.
    53  	HideMaskMethods *bool
    54  	// UnpredCPUFeature is set when an SVE operation's unpredicated encoding
    55  	// needs a higher feature level than the operation itself: the CPUFeature
    56  	// field is the floor its predicated sibling provides, and the lowering may
    57  	// use the unpredicated encoding only in blocks where the ssa cpufeatures
    58  	// analysis proves this level (e.g. integer MUL: CPUFeature "SVE",
    59  	// UnpredCPUFeature "SVE2").
    60  	UnpredCPUFeature *string
    61  	// WidthAgnostic marks an SVE bitwise operation whose unpredicated encoding
    62  	// is written .D but computes the same bits under any element view. The
    63  	// loader emits one def per element width so every Go type gets the API;
    64  	// the unpredicated machine op collapses back to the single .D instruction
    65  	// (see machineOpName), while the per-<T> predicated forms stay per width.
    66  	WidthAgnostic *bool
    67  }
    68  
    69  // MaxVectorBits is the maximum vector length in bits Go currently supports (256
    70  // bits / 32 bytes). It is used where a concrete upper bound is required for
    71  // scalable SVE vectors (e.g., SSA vector types and buffer allocations).
    72  const MaxVectorBits = 256
    73  
    74  type Operand struct {
    75  	Class string // One of "mask", "immediate", "vreg", "greg", and "mem"
    76  
    77  	Go     *string // Go type of this operand
    78  	AsmPos int     // Position of this operand in the assembly instruction
    79  
    80  	Base     *string    // Base Go type ("int", "uint", "float")
    81  	ElemBits *int       // Element bit width (omitted for greg)
    82  	Bits     VectorSize // Total bit width, or scalable
    83  
    84  	Const *string // Optional constant value for immediates.
    85  	// Optional immediate arg offsets. If this field is non-nil,
    86  	// This operand will be an immediate operand:
    87  	// The compiler will right-shift the user-passed value by ImmOffset and set it as the AuxInt
    88  	// field of the operation.
    89  	ImmOffset *string
    90  	ImmMax    *int    // optional maximum immediate, also highest case in immediate jump table
    91  	Name      *string // optional name in the Go intrinsic declaration
    92  	Lanes     *int    // Omitted for scalable
    93  	// TreatLikeAScalarOfSize means only the lower $TreatLikeAScalarOfSize bits of the vector
    94  	// is used, so at the API level we can make it just a scalar value of this size; Then we
    95  	// can overwrite it to a vector of the right size during intrinsics stage.
    96  	TreatLikeAScalarOfSize *int
    97  	// If non-nil, it means the [Class] field is overwritten here, right now this is used to
    98  	// overwrite the results of AVX2 compares to masks.
    99  	OverwriteClass *string
   100  	// If non-nil, it means the [Base] field is overwritten here. This field exist solely
   101  	// because Intel's XED data is inconsistent. e.g. VANDNP[SD] marks its operand int.
   102  	OverwriteBase *string
   103  	// If non-nil, it means the [ElementBits] field is overwritten. This field exist solely
   104  	// because Intel's XED data is inconsistent. e.g. AVX512 VPMADDUBSW marks its operand
   105  	// elemBits 16, which should be 8.
   106  	OverwriteElementBits *int
   107  	// For greg only, specifically VPEXTR[BW], their results are specified by Intel as 32 bits,
   108  	// but they really are 8/16 bits.
   109  	OverwriteBits *int
   110  	// FixedReg is the name of the fixed registers
   111  	FixedReg *string
   112  	// If non-nil, marks this vreg as a register list operand (for TBL/TBX).
   113  	// Currently only list number 0 is supported (we might need to teach regalloc handle register lists
   114  	// to support more than one register in the list).
   115  	ListNumber *int
   116  	// RegName is the assembly template's register symbol for this operand, e.g.
   117  	// "Zdn", "Zn", "Pg" (SVE only). Comparing it across operands is how the
   118  	// shape of an instruction is recognised: an input naming the same register
   119  	// as the destination is written in place.
   120  	RegName *string
   121  	// PredRegName is the symbol this operand has in each of the operation's
   122  	// predicated encodings, indexed to match InVariant (SVE only). It is nil
   123  	// for an operation with no predicated encoding, and for every other target.
   124  	PredRegName *[]string
   125  	// Predication is the SVE governing-predicate qualifier, "M" (merging) or
   126  	// "Z" (zeroing). It is set on mask operands of predicated encodings and
   127  	// decides whether the generated machine op is the merging or the zeroing
   128  	// form (see sveMaskSuffix).
   129  	Predication *string
   130  	// Governing marks the SVE governing predicate among an instruction's
   131  	// operands — the one that selects which lanes the instruction acts on, as
   132  	// opposed to a predicate it merely reads as data (SEL's <Pv>, the <Pn>/<Pm>
   133  	// of a predicate-logical op).
   134  	//
   135  	// It is set only where the instruction has no unpredicated encoding, since
   136  	// otherwise that encoding carries the operation and its predicated sibling's
   137  	// predicate becomes an InVariant instead. So a governing predicate here is
   138  	// always one the Go API hides: the generated method, generic op and
   139  	// intrinsic omit it, and the lowering synthesizes an all-true predicate in
   140  	// its place, which is how predicated-only instructions (ZCMPGT) expose an
   141  	// unpredicated API. See #79781.
   142  	//
   143  	// This is independent of [Operand.Predication]: a governing predicate need
   144  	// not carry a qualifier (SADDV <Dd>, <Pg>, <Zn>.<T> has no lanes to merge
   145  	// into), and a qualified predicate need not be governing in this sense (the
   146  	// InVariant of a paired operation is a real operand a peephole supplies).
   147  	Governing *bool
   148  }
   149  
   150  // VectorSize is a unifier value that is either a number or the string "scalable".
   151  type VectorSize struct {
   152  	Scalable bool
   153  	NRaw     int // Only meaningful if !Scalable
   154  }
   155  
   156  // N returns vs.NRaw, or panics if vs.Scalable.
   157  func (vs VectorSize) N() int {
   158  	if vs.Scalable {
   159  		panic("cannot get bit width of scalable type")
   160  	}
   161  	return vs.NRaw
   162  }
   163  
   164  func (vs VectorSize) Num() specexpr.Num {
   165  	if vs.Scalable {
   166  		return specexpr.VW()
   167  	}
   168  	return specexpr.Int(vs.NRaw)
   169  }
   170  
   171  func (vs VectorSize) String() string {
   172  	if vs.Scalable {
   173  		return "scalable"
   174  	}
   175  	return fmt.Sprint(vs.N())
   176  }
   177  
   178  // IsGoverning reports whether this operand is the SVE governing predicate, and
   179  // so is dropped from the API and filled with an all-true predicate at lowering.
   180  func (o *Operand) IsGoverning() bool {
   181  	return o.Governing != nil && *o.Governing
   182  }
   183  
   184  func (o Operand) OpName(s string) string {
   185  	if n := o.Name; n != nil {
   186  		return *n
   187  	}
   188  	if o.Class == "mask" {
   189  		return "mask"
   190  	}
   191  	return s
   192  }
   193  
   194  func (o Operand) OpNameAndType(s string) string {
   195  	return o.OpName(s) + " " + *o.Go
   196  }
   197  
   198  func (vs *VectorSize) DecodeUnified(v *unify.Value) error {
   199  	var n int
   200  	if err := v.Decode(&n); err == nil {
   201  		*vs = VectorSize{false, n}
   202  		return nil
   203  	}
   204  
   205  	var s string
   206  	if err := v.Decode(&s); err == nil && s == "scalable" {
   207  		*vs = VectorSize{true, -1}
   208  		return nil
   209  	}
   210  
   211  	return fmt.Errorf("bits must be an integer or \"scalable\"")
   212  }
   213  

View as plain text