...

Source file src/pkg/cmd/internal/obj/x86/evex.go

     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		"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	//	"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	}
   383	

View as plain text