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