github.com/bir3/gocompiler@v0.9.2202/src/cmd/internal/obj/x86/evex.go (about) 1 // Copyright 2018 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 x86 6 7 import ( 8 "github.com/bir3/gocompiler/src/cmd/internal/obj" 9 "errors" 10 "fmt" 11 "strings" 12 ) 13 14 // evexBits stores EVEX prefix info that is used during instruction encoding. 15 type evexBits struct { 16 b1 byte // [W1mmLLpp] 17 b2 byte // [NNNbbZRS] 18 19 // Associated instruction opcode. 20 opcode byte 21 } 22 23 // newEVEXBits creates evexBits object from enc bytes at z position. 24 func newEVEXBits(z int, enc *opBytes) evexBits { 25 return evexBits{ 26 b1: enc[z+0], 27 b2: enc[z+1], 28 opcode: enc[z+2], 29 } 30 } 31 32 // P returns EVEX.pp value. 33 func (evex evexBits) P() byte { return (evex.b1 & evexP) >> 0 } 34 35 // L returns EVEX.L'L value. 36 func (evex evexBits) L() byte { return (evex.b1 & evexL) >> 2 } 37 38 // M returns EVEX.mm value. 39 func (evex evexBits) M() byte { return (evex.b1 & evexM) >> 4 } 40 41 // W returns EVEX.W value. 42 func (evex evexBits) W() byte { return (evex.b1 & evexW) >> 7 } 43 44 // BroadcastEnabled reports whether BCST suffix is permitted. 45 func (evex evexBits) BroadcastEnabled() bool { 46 return evex.b2&evexBcst != 0 47 } 48 49 // ZeroingEnabled reports whether Z suffix is permitted. 50 func (evex evexBits) ZeroingEnabled() bool { 51 return (evex.b2&evexZeroing)>>2 != 0 52 } 53 54 // RoundingEnabled reports whether RN_SAE, RZ_SAE, RD_SAE and RU_SAE suffixes 55 // are permitted. 56 func (evex evexBits) RoundingEnabled() bool { 57 return (evex.b2&evexRounding)>>1 != 0 58 } 59 60 // SaeEnabled reports whether SAE suffix is permitted. 61 func (evex evexBits) SaeEnabled() bool { 62 return (evex.b2&evexSae)>>0 != 0 63 } 64 65 // DispMultiplier returns displacement multiplier that is calculated 66 // based on tuple type, EVEX.W and input size. 67 // If embedded broadcast is used, bcst should be true. 68 func (evex evexBits) DispMultiplier(bcst bool) int32 { 69 if bcst { 70 switch evex.b2 & evexBcst { 71 case evexBcstN4: 72 return 4 73 case evexBcstN8: 74 return 8 75 } 76 return 1 77 } 78 79 switch evex.b2 & evexN { 80 case evexN1: 81 return 1 82 case evexN2: 83 return 2 84 case evexN4: 85 return 4 86 case evexN8: 87 return 8 88 case evexN16: 89 return 16 90 case evexN32: 91 return 32 92 case evexN64: 93 return 64 94 case evexN128: 95 return 128 96 } 97 return 1 98 } 99 100 // EVEX is described by using 2-byte sequence. 101 // See evexBits for more details. 102 const ( 103 evexW = 0x80 // b1[W... ....] 104 evexWIG = 0 << 7 105 evexW0 = 0 << 7 106 evexW1 = 1 << 7 107 108 evexM = 0x30 // b2[..mm ...] 109 evex0F = 1 << 4 110 evex0F38 = 2 << 4 111 evex0F3A = 3 << 4 112 113 evexL = 0x0C // b1[.... LL..] 114 evexLIG = 0 << 2 115 evex128 = 0 << 2 116 evex256 = 1 << 2 117 evex512 = 2 << 2 118 119 evexP = 0x03 // b1[.... ..pp] 120 evex66 = 1 << 0 121 evexF3 = 2 << 0 122 evexF2 = 3 << 0 123 124 // Precalculated Disp8 N value. 125 // N acts like a multiplier for 8bit displacement. 126 // Note that some N are not used, but their bits are reserved. 127 evexN = 0xE0 // b2[NNN. ....] 128 evexN1 = 0 << 5 129 evexN2 = 1 << 5 130 evexN4 = 2 << 5 131 evexN8 = 3 << 5 132 evexN16 = 4 << 5 133 evexN32 = 5 << 5 134 evexN64 = 6 << 5 135 evexN128 = 7 << 5 136 137 // Disp8 for broadcasts. 138 evexBcst = 0x18 // b2[...b b...] 139 evexBcstN4 = 1 << 3 140 evexBcstN8 = 2 << 3 141 142 // Flags that permit certain AVX512 features. 143 // It's semantically illegal to combine evexZeroing and evexSae. 144 evexZeroing = 0x4 // b2[.... .Z..] 145 evexZeroingEnabled = 1 << 2 146 evexRounding = 0x2 // b2[.... ..R.] 147 evexRoundingEnabled = 1 << 1 148 evexSae = 0x1 // b2[.... ...S] 149 evexSaeEnabled = 1 << 0 150 ) 151 152 // compressedDisp8 calculates EVEX compressed displacement, if applicable. 153 func compressedDisp8(disp, elemSize int32) (disp8 byte, ok bool) { 154 if disp%elemSize == 0 { 155 v := disp / elemSize 156 if v >= -128 && v <= 127 { 157 return byte(v), true 158 } 159 } 160 return 0, false 161 } 162 163 // evexZcase reports whether given Z-case belongs to EVEX group. 164 func evexZcase(zcase uint8) bool { 165 return zcase > Zevex_first && zcase < Zevex_last 166 } 167 168 // evexSuffixBits carries instruction EVEX suffix set flags. 169 // 170 // Examples: 171 // 172 // "RU_SAE.Z" => {rounding: 3, zeroing: true} 173 // "Z" => {zeroing: true} 174 // "BCST" => {broadcast: true} 175 // "SAE.Z" => {sae: true, zeroing: true} 176 type evexSuffix struct { 177 rounding byte 178 sae bool 179 zeroing bool 180 broadcast bool 181 } 182 183 // Rounding control values. 184 // Match exact value for EVEX.L'L field (with exception of rcUnset). 185 const ( 186 rcRNSAE = 0 // Round towards nearest 187 rcRDSAE = 1 // Round towards -Inf 188 rcRUSAE = 2 // Round towards +Inf 189 rcRZSAE = 3 // Round towards zero 190 rcUnset = 4 191 ) 192 193 // newEVEXSuffix returns proper zero value for evexSuffix. 194 func newEVEXSuffix() evexSuffix { 195 return evexSuffix{rounding: rcUnset} 196 } 197 198 // evexSuffixMap maps obj.X86suffix to its decoded version. 199 // Filled during init(). 200 var evexSuffixMap [255]evexSuffix 201 202 func init() { 203 // Decode all valid suffixes for later use. 204 for i := range opSuffixTable { 205 suffix := newEVEXSuffix() 206 parts := strings.Split(opSuffixTable[i], ".") 207 for j := range parts { 208 switch parts[j] { 209 case "Z": 210 suffix.zeroing = true 211 case "BCST": 212 suffix.broadcast = true 213 case "SAE": 214 suffix.sae = true 215 216 case "RN_SAE": 217 suffix.rounding = rcRNSAE 218 case "RD_SAE": 219 suffix.rounding = rcRDSAE 220 case "RU_SAE": 221 suffix.rounding = rcRUSAE 222 case "RZ_SAE": 223 suffix.rounding = rcRZSAE 224 } 225 } 226 evexSuffixMap[i] = suffix 227 } 228 } 229 230 // toDisp8 tries to convert disp to proper 8-bit displacement value. 231 func toDisp8(disp int32, p *obj.Prog, asmbuf *AsmBuf) (disp8 byte, ok bool) { 232 if asmbuf.evexflag { 233 bcst := evexSuffixMap[p.Scond].broadcast 234 elemSize := asmbuf.evex.DispMultiplier(bcst) 235 return compressedDisp8(disp, elemSize) 236 } 237 return byte(disp), disp >= -128 && disp < 128 238 } 239 240 // EncodeRegisterRange packs [reg0-reg1] list into 64-bit value that 241 // is intended to be stored inside obj.Addr.Offset with TYPE_REGLIST. 242 func EncodeRegisterRange(reg0, reg1 int16) int64 { 243 return (int64(reg0) << 0) | 244 (int64(reg1) << 16) | 245 obj.RegListX86Lo 246 } 247 248 // decodeRegisterRange unpacks [reg0-reg1] list from 64-bit value created by EncodeRegisterRange. 249 func decodeRegisterRange(list int64) (reg0, reg1 int) { 250 return int((list >> 0) & 0xFFFF), 251 int((list >> 16) & 0xFFFF) 252 } 253 254 // ParseSuffix handles the special suffix for the 386/AMD64. 255 // Suffix bits are stored into p.Scond. 256 // 257 // Leading "." in cond is ignored. 258 func ParseSuffix(p *obj.Prog, cond string) error { 259 cond = strings.TrimPrefix(cond, ".") 260 261 suffix := newOpSuffix(cond) 262 if !suffix.IsValid() { 263 return inferSuffixError(cond) 264 } 265 266 p.Scond = uint8(suffix) 267 return nil 268 } 269 270 // inferSuffixError returns non-nil error that describes what could be 271 // the cause of suffix parse failure. 272 // 273 // At the point this function is executed there is already assembly error, 274 // so we can burn some clocks to construct good error message. 275 // 276 // Reported issues: 277 // - duplicated suffixes 278 // - illegal rounding/SAE+broadcast combinations 279 // - unknown suffixes 280 // - misplaced suffix (e.g. wrong Z suffix position) 281 func inferSuffixError(cond string) error { 282 suffixSet := make(map[string]bool) // Set for duplicates detection. 283 unknownSet := make(map[string]bool) // Set of unknown suffixes. 284 hasBcst := false 285 hasRoundSae := false 286 var msg []string // Error message parts 287 288 suffixes := strings.Split(cond, ".") 289 for i, suffix := range suffixes { 290 switch suffix { 291 case "Z": 292 if i != len(suffixes)-1 { 293 msg = append(msg, "Z suffix should be the last") 294 } 295 case "BCST": 296 hasBcst = true 297 case "SAE", "RN_SAE", "RZ_SAE", "RD_SAE", "RU_SAE": 298 hasRoundSae = true 299 default: 300 if !unknownSet[suffix] { 301 msg = append(msg, fmt.Sprintf("unknown suffix %q", suffix)) 302 } 303 unknownSet[suffix] = true 304 } 305 306 if suffixSet[suffix] { 307 msg = append(msg, fmt.Sprintf("duplicate suffix %q", suffix)) 308 } 309 suffixSet[suffix] = true 310 } 311 312 if hasBcst && hasRoundSae { 313 msg = append(msg, "can't combine rounding/SAE and broadcast") 314 } 315 316 if len(msg) == 0 { 317 return errors.New("bad suffix combination") 318 } 319 return errors.New(strings.Join(msg, "; ")) 320 } 321 322 // opSuffixTable is a complete list of possible opcode suffix combinations. 323 // It "maps" uint8 suffix bits to their string representation. 324 // With the exception of first and last elements, order is not important. 325 var opSuffixTable = [...]string{ 326 "", // Map empty suffix to empty string. 327 328 "Z", 329 330 "SAE", 331 "SAE.Z", 332 333 "RN_SAE", 334 "RZ_SAE", 335 "RD_SAE", 336 "RU_SAE", 337 "RN_SAE.Z", 338 "RZ_SAE.Z", 339 "RD_SAE.Z", 340 "RU_SAE.Z", 341 342 "BCST", 343 "BCST.Z", 344 345 "<bad suffix>", 346 } 347 348 // opSuffix represents instruction opcode suffix. 349 // Compound (multi-part) suffixes expressed with single opSuffix value. 350 // 351 // uint8 type is used to fit obj.Prog.Scond. 352 type opSuffix uint8 353 354 // badOpSuffix is used to represent all invalid suffix combinations. 355 const badOpSuffix = opSuffix(len(opSuffixTable) - 1) 356 357 // newOpSuffix returns opSuffix object that matches suffixes string. 358 // 359 // If no matching suffix is found, special "invalid" suffix is returned. 360 // Use IsValid method to check against this case. 361 func newOpSuffix(suffixes string) opSuffix { 362 for i := range opSuffixTable { 363 if opSuffixTable[i] == suffixes { 364 return opSuffix(i) 365 } 366 } 367 return badOpSuffix 368 } 369 370 // IsValid reports whether suffix is valid. 371 // Empty suffixes are valid. 372 func (suffix opSuffix) IsValid() bool { 373 return suffix != badOpSuffix 374 } 375 376 // String returns suffix printed representation. 377 // 378 // It matches the string that was used to create suffix with NewX86Suffix() 379 // for valid suffixes. 380 // For all invalid suffixes, special marker is returned. 381 func (suffix opSuffix) String() string { 382 return opSuffixTable[suffix] 383 }