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 5package x86 6 7import ( 8 "cmd/internal/obj" 9 "errors" 10 "fmt" 11 "strings" 12) 13 14// evexBits stores EVEX prefix info that is used during instruction encoding. 15type 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. 24func 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. 33func (evex evexBits) P() byte { return (evex.b1 & evexP) >> 0 } 34 35// L returns EVEX.L'L value. 36func (evex evexBits) L() byte { return (evex.b1 & evexL) >> 2 } 37 38// M returns EVEX.mm value. 39func (evex evexBits) M() byte { return (evex.b1 & evexM) >> 4 } 40 41// W returns EVEX.W value. 42func (evex evexBits) W() byte { return (evex.b1 & evexW) >> 7 } 43 44// BroadcastEnabled reports whether BCST suffix is permitted. 45func (evex evexBits) BroadcastEnabled() bool { 46 return evex.b2&evexBcst != 0 47} 48 49// ZeroingEnabled reports whether Z suffix is permitted. 50func (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. 56func (evex evexBits) RoundingEnabled() bool { 57 return (evex.b2&evexRounding)>>1 != 0 58} 59 60// SaeEnabled reports whether SAE suffix is permitted. 61func (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. 68func (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. 102const ( 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. 153func 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. 164func 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} 176type 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). 185const ( 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. 194func newEVEXSuffix() evexSuffix { 195 return evexSuffix{rounding: rcUnset} 196} 197 198// evexSuffixMap maps obj.X86suffix to its decoded version. 199// Filled during init(). 200var evexSuffixMap [255]evexSuffix 201 202func 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. 231func 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. 242func 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. 249func 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. 258func 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) 281func 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. 325var 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. 352type opSuffix uint8 353 354// badOpSuffix is used to represent all invalid suffix combinations. 355const 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. 361func 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. 372func (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. 381func (suffix opSuffix) String() string { 382 return opSuffixTable[suffix] 383} 384