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