evex.go (9505B)
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/twitchyliquid64/golang-asm/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 // "RU_SAE.Z" => {rounding: 3, zeroing: true} 172 // "Z" => {zeroing: true} 173 // "BCST" => {broadcast: true} 174 // "SAE.Z" => {sae: true, zeroing: true} 175 type evexSuffix struct { 176 rounding byte 177 sae bool 178 zeroing bool 179 broadcast bool 180 } 181 182 // Rounding control values. 183 // Match exact value for EVEX.L'L field (with exception of rcUnset). 184 const ( 185 rcRNSAE = 0 // Round towards nearest 186 rcRDSAE = 1 // Round towards -Inf 187 rcRUSAE = 2 // Round towards +Inf 188 rcRZSAE = 3 // Round towards zero 189 rcUnset = 4 190 ) 191 192 // newEVEXSuffix returns proper zero value for evexSuffix. 193 func newEVEXSuffix() evexSuffix { 194 return evexSuffix{rounding: rcUnset} 195 } 196 197 // evexSuffixMap maps obj.X86suffix to its decoded version. 198 // Filled during init(). 199 var evexSuffixMap [255]evexSuffix 200 201 func init() { 202 // Decode all valid suffixes for later use. 203 for i := range opSuffixTable { 204 suffix := newEVEXSuffix() 205 parts := strings.Split(opSuffixTable[i], ".") 206 for j := range parts { 207 switch parts[j] { 208 case "Z": 209 suffix.zeroing = true 210 case "BCST": 211 suffix.broadcast = true 212 case "SAE": 213 suffix.sae = true 214 215 case "RN_SAE": 216 suffix.rounding = rcRNSAE 217 case "RD_SAE": 218 suffix.rounding = rcRDSAE 219 case "RU_SAE": 220 suffix.rounding = rcRUSAE 221 case "RZ_SAE": 222 suffix.rounding = rcRZSAE 223 } 224 } 225 evexSuffixMap[i] = suffix 226 } 227 } 228 229 // toDisp8 tries to convert disp to proper 8-bit displacement value. 230 func toDisp8(disp int32, p *obj.Prog, asmbuf *AsmBuf) (disp8 byte, ok bool) { 231 if asmbuf.evexflag { 232 bcst := evexSuffixMap[p.Scond].broadcast 233 elemSize := asmbuf.evex.DispMultiplier(bcst) 234 return compressedDisp8(disp, elemSize) 235 } 236 return byte(disp), disp >= -128 && disp < 128 237 } 238 239 // EncodeRegisterRange packs [reg0-reg1] list into 64-bit value that 240 // is intended to be stored inside obj.Addr.Offset with TYPE_REGLIST. 241 func EncodeRegisterRange(reg0, reg1 int16) int64 { 242 return (int64(reg0) << 0) | 243 (int64(reg1) << 16) | 244 obj.RegListX86Lo 245 } 246 247 // decodeRegisterRange unpacks [reg0-reg1] list from 64-bit value created by EncodeRegisterRange. 248 func decodeRegisterRange(list int64) (reg0, reg1 int) { 249 return int((list >> 0) & 0xFFFF), 250 int((list >> 16) & 0xFFFF) 251 } 252 253 // ParseSuffix handles the special suffix for the 386/AMD64. 254 // Suffix bits are stored into p.Scond. 255 // 256 // Leading "." in cond is ignored. 257 func ParseSuffix(p *obj.Prog, cond string) error { 258 cond = strings.TrimPrefix(cond, ".") 259 260 suffix := newOpSuffix(cond) 261 if !suffix.IsValid() { 262 return inferSuffixError(cond) 263 } 264 265 p.Scond = uint8(suffix) 266 return nil 267 } 268 269 // inferSuffixError returns non-nil error that describes what could be 270 // the cause of suffix parse failure. 271 // 272 // At the point this function is executed there is already assembly error, 273 // so we can burn some clocks to construct good error message. 274 // 275 // Reported issues: 276 // - duplicated suffixes 277 // - illegal rounding/SAE+broadcast combinations 278 // - unknown suffixes 279 // - misplaced suffix (e.g. wrong Z suffix position) 280 func inferSuffixError(cond string) error { 281 suffixSet := make(map[string]bool) // Set for duplicates detection. 282 unknownSet := make(map[string]bool) // Set of unknown suffixes. 283 hasBcst := false 284 hasRoundSae := false 285 var msg []string // Error message parts 286 287 suffixes := strings.Split(cond, ".") 288 for i, suffix := range suffixes { 289 switch suffix { 290 case "Z": 291 if i != len(suffixes)-1 { 292 msg = append(msg, "Z suffix should be the last") 293 } 294 case "BCST": 295 hasBcst = true 296 case "SAE", "RN_SAE", "RZ_SAE", "RD_SAE", "RU_SAE": 297 hasRoundSae = true 298 default: 299 if !unknownSet[suffix] { 300 msg = append(msg, fmt.Sprintf("unknown suffix %q", suffix)) 301 } 302 unknownSet[suffix] = true 303 } 304 305 if suffixSet[suffix] { 306 msg = append(msg, fmt.Sprintf("duplicate suffix %q", suffix)) 307 } 308 suffixSet[suffix] = true 309 } 310 311 if hasBcst && hasRoundSae { 312 msg = append(msg, "can't combine rounding/SAE and broadcast") 313 } 314 315 if len(msg) == 0 { 316 return errors.New("bad suffix combination") 317 } 318 return errors.New(strings.Join(msg, "; ")) 319 } 320 321 // opSuffixTable is a complete list of possible opcode suffix combinations. 322 // It "maps" uint8 suffix bits to their string representation. 323 // With the exception of first and last elements, order is not important. 324 var opSuffixTable = [...]string{ 325 "", // Map empty suffix to empty string. 326 327 "Z", 328 329 "SAE", 330 "SAE.Z", 331 332 "RN_SAE", 333 "RZ_SAE", 334 "RD_SAE", 335 "RU_SAE", 336 "RN_SAE.Z", 337 "RZ_SAE.Z", 338 "RD_SAE.Z", 339 "RU_SAE.Z", 340 341 "BCST", 342 "BCST.Z", 343 344 "<bad suffix>", 345 } 346 347 // opSuffix represents instruction opcode suffix. 348 // Compound (multi-part) suffixes expressed with single opSuffix value. 349 // 350 // uint8 type is used to fit obj.Prog.Scond. 351 type opSuffix uint8 352 353 // badOpSuffix is used to represent all invalid suffix combinations. 354 const badOpSuffix = opSuffix(len(opSuffixTable) - 1) 355 356 // newOpSuffix returns opSuffix object that matches suffixes string. 357 // 358 // If no matching suffix is found, special "invalid" suffix is returned. 359 // Use IsValid method to check against this case. 360 func newOpSuffix(suffixes string) opSuffix { 361 for i := range opSuffixTable { 362 if opSuffixTable[i] == suffixes { 363 return opSuffix(i) 364 } 365 } 366 return badOpSuffix 367 } 368 369 // IsValid reports whether suffix is valid. 370 // Empty suffixes are valid. 371 func (suffix opSuffix) IsValid() bool { 372 return suffix != badOpSuffix 373 } 374 375 // String returns suffix printed representation. 376 // 377 // It matches the string that was used to create suffix with NewX86Suffix() 378 // for valid suffixes. 379 // For all invalid suffixes, special marker is returned. 380 func (suffix opSuffix) String() string { 381 return opSuffixTable[suffix] 382 }