podman
382 строки · 9.3 Кб
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 x866
7import (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.
15type evexBits struct {16b1 byte // [W1mmLLpp]17b2 byte // [NNNbbZRS]18
19// Associated instruction opcode.20opcode byte21}
22
23// newEVEXBits creates evexBits object from enc bytes at z position.
24func newEVEXBits(z int, enc *opBytes) evexBits {25return evexBits{26b1: enc[z+0],27b2: enc[z+1],28opcode: 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 {46return evex.b2&evexBcst != 047}
48
49// ZeroingEnabled reports whether Z suffix is permitted.
50func (evex evexBits) ZeroingEnabled() bool {51return (evex.b2&evexZeroing)>>2 != 052}
53
54// RoundingEnabled reports whether RN_SAE, RZ_SAE, RD_SAE and RU_SAE suffixes
55// are permitted.
56func (evex evexBits) RoundingEnabled() bool {57return (evex.b2&evexRounding)>>1 != 058}
59
60// SaeEnabled reports whether SAE suffix is permitted.
61func (evex evexBits) SaeEnabled() bool {62return (evex.b2&evexSae)>>0 != 063}
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 {69if bcst {70switch evex.b2 & evexBcst {71case evexBcstN4:72return 473case evexBcstN8:74return 875}76return 177}78
79switch evex.b2 & evexN {80case evexN1:81return 182case evexN2:83return 284case evexN4:85return 486case evexN8:87return 888case evexN16:89return 1690case evexN32:91return 3292case evexN64:93return 6494case evexN128:95return 12896}97return 198}
99
100// EVEX is described by using 2-byte sequence.
101// See evexBits for more details.
102const (103evexW = 0x80 // b1[W... ....]104evexWIG = 0 << 7105evexW0 = 0 << 7106evexW1 = 1 << 7107
108evexM = 0x30 // b2[..mm ...]109evex0F = 1 << 4110evex0F38 = 2 << 4111evex0F3A = 3 << 4112
113evexL = 0x0C // b1[.... LL..]114evexLIG = 0 << 2115evex128 = 0 << 2116evex256 = 1 << 2117evex512 = 2 << 2118
119evexP = 0x03 // b1[.... ..pp]120evex66 = 1 << 0121evexF3 = 2 << 0122evexF2 = 3 << 0123
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.127evexN = 0xE0 // b2[NNN. ....]128evexN1 = 0 << 5129evexN2 = 1 << 5130evexN4 = 2 << 5131evexN8 = 3 << 5132evexN16 = 4 << 5133evexN32 = 5 << 5134evexN64 = 6 << 5135evexN128 = 7 << 5136
137// Disp8 for broadcasts.138evexBcst = 0x18 // b2[...b b...]139evexBcstN4 = 1 << 3140evexBcstN8 = 2 << 3141
142// Flags that permit certain AVX512 features.143// It's semantically illegal to combine evexZeroing and evexSae.144evexZeroing = 0x4 // b2[.... .Z..]145evexZeroingEnabled = 1 << 2146evexRounding = 0x2 // b2[.... ..R.]147evexRoundingEnabled = 1 << 1148evexSae = 0x1 // b2[.... ...S]149evexSaeEnabled = 1 << 0150)
151
152// compressedDisp8 calculates EVEX compressed displacement, if applicable.
153func compressedDisp8(disp, elemSize int32) (disp8 byte, ok bool) {154if disp%elemSize == 0 {155v := disp / elemSize156if v >= -128 && v <= 127 {157return byte(v), true158}159}160return 0, false161}
162
163// evexZcase reports whether given Z-case belongs to EVEX group.
164func evexZcase(zcase uint8) bool {165return zcase > Zevex_first && zcase < Zevex_last166}
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}
175type evexSuffix struct {176rounding byte177sae bool178zeroing bool179broadcast bool180}
181
182// Rounding control values.
183// Match exact value for EVEX.L'L field (with exception of rcUnset).
184const (185rcRNSAE = 0 // Round towards nearest186rcRDSAE = 1 // Round towards -Inf187rcRUSAE = 2 // Round towards +Inf188rcRZSAE = 3 // Round towards zero189rcUnset = 4190)
191
192// newEVEXSuffix returns proper zero value for evexSuffix.
193func newEVEXSuffix() evexSuffix {194return evexSuffix{rounding: rcUnset}195}
196
197// evexSuffixMap maps obj.X86suffix to its decoded version.
198// Filled during init().
199var evexSuffixMap [255]evexSuffix200
201func init() {202// Decode all valid suffixes for later use.203for i := range opSuffixTable {204suffix := newEVEXSuffix()205parts := strings.Split(opSuffixTable[i], ".")206for j := range parts {207switch parts[j] {208case "Z":209suffix.zeroing = true210case "BCST":211suffix.broadcast = true212case "SAE":213suffix.sae = true214
215case "RN_SAE":216suffix.rounding = rcRNSAE217case "RD_SAE":218suffix.rounding = rcRDSAE219case "RU_SAE":220suffix.rounding = rcRUSAE221case "RZ_SAE":222suffix.rounding = rcRZSAE223}224}225evexSuffixMap[i] = suffix226}227}
228
229// toDisp8 tries to convert disp to proper 8-bit displacement value.
230func toDisp8(disp int32, p *obj.Prog, asmbuf *AsmBuf) (disp8 byte, ok bool) {231if asmbuf.evexflag {232bcst := evexSuffixMap[p.Scond].broadcast233elemSize := asmbuf.evex.DispMultiplier(bcst)234return compressedDisp8(disp, elemSize)235}236return byte(disp), disp >= -128 && disp < 128237}
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.
241func EncodeRegisterRange(reg0, reg1 int16) int64 {242return (int64(reg0) << 0) |243(int64(reg1) << 16) |244obj.RegListX86Lo245}
246
247// decodeRegisterRange unpacks [reg0-reg1] list from 64-bit value created by EncodeRegisterRange.
248func decodeRegisterRange(list int64) (reg0, reg1 int) {249return int((list >> 0) & 0xFFFF),250int((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.
257func ParseSuffix(p *obj.Prog, cond string) error {258cond = strings.TrimPrefix(cond, ".")259
260suffix := newOpSuffix(cond)261if !suffix.IsValid() {262return inferSuffixError(cond)263}264
265p.Scond = uint8(suffix)266return nil267}
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)
280func inferSuffixError(cond string) error {281suffixSet := make(map[string]bool) // Set for duplicates detection.282unknownSet := make(map[string]bool) // Set of unknown suffixes.283hasBcst := false284hasRoundSae := false285var msg []string // Error message parts286
287suffixes := strings.Split(cond, ".")288for i, suffix := range suffixes {289switch suffix {290case "Z":291if i != len(suffixes)-1 {292msg = append(msg, "Z suffix should be the last")293}294case "BCST":295hasBcst = true296case "SAE", "RN_SAE", "RZ_SAE", "RD_SAE", "RU_SAE":297hasRoundSae = true298default:299if !unknownSet[suffix] {300msg = append(msg, fmt.Sprintf("unknown suffix %q", suffix))301}302unknownSet[suffix] = true303}304
305if suffixSet[suffix] {306msg = append(msg, fmt.Sprintf("duplicate suffix %q", suffix))307}308suffixSet[suffix] = true309}310
311if hasBcst && hasRoundSae {312msg = append(msg, "can't combine rounding/SAE and broadcast")313}314
315if len(msg) == 0 {316return errors.New("bad suffix combination")317}318return 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.
324var 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.
351type opSuffix uint8352
353// badOpSuffix is used to represent all invalid suffix combinations.
354const 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.
360func newOpSuffix(suffixes string) opSuffix {361for i := range opSuffixTable {362if opSuffixTable[i] == suffixes {363return opSuffix(i)364}365}366return badOpSuffix367}
368
369// IsValid reports whether suffix is valid.
370// Empty suffixes are valid.
371func (suffix opSuffix) IsValid() bool {372return suffix != badOpSuffix373}
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.
380func (suffix opSuffix) String() string {381return opSuffixTable[suffix]382}
383