Source file src/cmd/internal/obj/arm64/inst.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 arm64 6 7 import ( 8 "cmd/internal/obj" 9 "fmt" 10 "iter" 11 ) 12 13 // instEncoder represents an instruction encoder. 14 type instEncoder struct { 15 goOp obj.As // Go opcode mnemonic 16 fixedBits uint32 // Known bits 17 args []operand // Operands, in Go order 18 } 19 20 type varBits struct { 21 // The low and high bit index in the binary encoding, exclusive on hi 22 lo, hi int 23 encoded bool // If true then its value is already encoded 24 bits uint32 25 } 26 27 // component is the component of an binary encoding. 28 // e.g. for operand <Zda>.<T>, <T>'s encoding function might be described as: 29 // 30 // For the "Byte and halfword" variant: is the size specifier, 31 // sz <T> 32 // 0 B 33 // 1 H 34 // bit range mappings: 35 // sz: [22:23) 36 // 37 // Then sz is the component of the binary encoding. 38 type component uint16 39 40 type elemEncoder struct { 41 fn func(uint32) (uint32, bool) 42 // comp is the component of the binary encoding. 43 comp component 44 } 45 46 // operand is the operand type of an instruction. 47 type operand struct { 48 class AClass // Operand class, register, constant, memory operation etc. 49 // The elements that this operand includes, this only includes the encoding-related parts 50 // They are represented as a list of pointers to the encoding functions. 51 // The first returned value is the encoded binary, the second is the ok signal. 52 // The encoding functions return the ok signal for deduplication purposes: 53 // For example: 54 // SDOT <Zda>.<T>, <Zn>.<Tb>, <Zm>.<Tb> 55 // SDOT <Zda>.H, <Zn>.B, <Zm>.B 56 // SDOT <Zda>.S, <Zn>.H, <Zm>.H 57 // 58 // <T> and <Tb> are specified in the encoding text, that there is a constraint "T = 4*Tb". 59 // We don't know this fact by looking at the encoding format solely, without this information 60 // the first encoding domain entails the other 2. And at instruction matching phase we simply 61 // cannot deduplicate them. So we defer this deduplication to the encoding phase. 62 // We need the ok signal with [elemEncoder.comp] field to deduplicate them. 63 elemEncoders []elemEncoder 64 } 65 66 // opsInProg returns an iterator over the operands ([Addr]) of p 67 func opsInProg(p *obj.Prog) iter.Seq[*obj.Addr] { 68 return func(yield func(*obj.Addr) bool) { 69 // Go order: From, Reg, RestArgs..., To 70 // For SVE, Reg is unused as it's so common that registers have arrangements. 71 if p.From.Type != obj.TYPE_NONE { 72 if !yield(&p.From) { 73 return 74 } 75 } 76 for j := range p.RestArgs { 77 if !yield(&p.RestArgs[j].Addr) { 78 return 79 } 80 } 81 if p.To.Type != obj.TYPE_NONE { 82 if !yield(&p.To) { 83 return 84 } 85 } 86 } 87 } 88 89 // aclass returns the AClass of an Addr. 90 func aclass(a *obj.Addr) AClass { 91 if a.Type == obj.TYPE_REG { 92 if a.Reg >= REG_Z0 && a.Reg <= REG_Z31 { 93 return AC_ZREG 94 } 95 if a.Reg >= REG_P0 && a.Reg <= REG_P15 { 96 return AC_PREG 97 } 98 if a.Reg >= REG_ARNG && a.Reg < REG_ELEM { 99 return AC_ARNG 100 } 101 if a.Reg >= REG_ZARNG && a.Reg < REG_PARNGZM { 102 return AC_ARNG 103 } 104 if a.Reg >= REG_PARNGZM && a.Reg < REG_PARNGZM_END { 105 switch (a.Reg >> 5) & 15 { 106 case PRED_M, PRED_Z: 107 return AC_PREGZM 108 default: 109 return AC_ARNG 110 } 111 } 112 } 113 panic("unknown AClass") 114 } 115 116 // addrComponent returns the binary (component) of the stored element in a at index, for operand 117 // of type aclass. 118 // 119 // For example, for operand of type AC_ARNG, it has 2 permissible components (identified by index) 120 // 0. register: <reg> 121 // 1. arrangement: <T> 122 // 123 // They are stored in a.Reg as: 124 // 125 // reg | (arrangement << 5) 126 // 127 // More details are in the comments in the switch cases of this function. 128 func addrComponent(a *obj.Addr, acl AClass, index int) uint32 { 129 switch acl { 130 // AClass: AC_ARNG, AC_PREG, AC_PREGZ, AC_PREGM, AC_ZREG 131 // GNU mnemonic: <reg>.<T> Or <reg>/<T> (T is M or Z) 132 // Go mnemonic: 133 // reg.<T> 134 // Encoding: 135 // Type = TYPE_REG 136 // Reg = reg | (arrangement or predication << 5) 137 case AC_ARNG, AC_PREG, AC_PREGZM, AC_ZREG: 138 switch index { 139 case 0: 140 return uint32(a.Reg & 31) 141 case 1: 142 return uint32((a.Reg >> 5) & 15) 143 default: 144 panic(fmt.Errorf("unknown elm index at %d in AClass %d", index, acl)) 145 } 146 } 147 // TODO: handle more AClasses. 148 panic(fmt.Errorf("unknown AClass %d", acl)) 149 } 150 151 // tryEncode tries to encode p with i, it returns the encoded binary and ok signal. 152 func (i *instEncoder) tryEncode(p *obj.Prog) (uint32, bool) { 153 bin := i.fixedBits 154 // Some elements are encoded in the same component, they need to be equal. 155 // For example { <Zn1>.<Tb>-<Zn2>.<Tb> }. 156 // The 2 instances of <Tb> must encode to the same value. 157 encoded := map[component]uint32{} 158 opIdx := 0 159 for addr := range opsInProg(p) { 160 if opIdx >= len(i.args) { 161 return 0, false 162 } 163 op := i.args[opIdx] 164 opIdx++ 165 acl := aclass(addr) 166 if acl != op.class { 167 return 0, false 168 } 169 for i, enc := range op.elemEncoders { 170 val := addrComponent(addr, acl, i) 171 if b, ok := enc.fn(val); ok { 172 bin |= b 173 if _, ok := encoded[enc.comp]; ok && b != encoded[enc.comp] { 174 return 0, false 175 } 176 if enc.comp != enc_NIL { 177 encoded[enc.comp] = b 178 } 179 } else { 180 return 0, false 181 } 182 } 183 } 184 if opIdx != len(i.args) { 185 return 0, false 186 } 187 return bin, true 188 } 189