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 xeddata 6 7 import ( 8 "errors" 9 "strings" 10 ) 11 12 // OperandVisibility describes operand visibility in XED terms. 13 type OperandVisibility int 14 15 const ( 16 // VisExplicit is a default operand visibility. 17 // Explicit operand is "real" kind of operands that 18 // is shown in syntax and can be specified by the programmer. 19 VisExplicit OperandVisibility = iota 20 21 // VisImplicit is for fixed arg (like EAX); usually shown in syntax. 22 VisImplicit 23 24 // VisSuppressed is like VisImplicit, but not shown in syntax. 25 // In some very rare exceptions, they are also shown in syntax string. 26 VisSuppressed 27 28 // VisEcond is encoder-only conditions. Can be ignored. 29 VisEcond 30 ) 31 32 // Operand holds data that is encoded inside 33 // instruction's "OPERANDS" field. 34 // 35 // Use NewOperand function to decode operand fields into Operand object. 36 type Operand struct { 37 // Name is an ID with optional nonterminal name part. 38 // 39 // Possible values: "REG0=GPRv_B", "REG1", "MEM0", ... 40 // 41 // If nonterminal part is present, name 42 // can be split into LHS and RHS with NonTerminalName method. 43 Name string 44 45 // Action describes argument types. 46 // 47 // Possible values: "r", "w", "rw", "cr", "cw", "crw". 48 // Optional "c" prefix represents conditional access. 49 Action string 50 51 // Width descriptor. It can express simple width like "w" (word, 16bit) 52 // or meta-width like "v", which corresponds to {16, 32, 64} bits. 53 // 54 // Possible values: "", "q", "ds", "dq", ... 55 // Optional. 56 Width string 57 58 // Xtype holds XED-specific type information. 59 // 60 // Possible values: "", "f64", "i32", ... 61 // Optional. 62 Xtype string 63 64 // Attributes serves as container for all other properties. 65 // 66 // Possible values: 67 // EVEX.b context { 68 // TXT=ZEROSTR - zeroing 69 // TXT=SAESTR - suppress all exceptions 70 // TXT=ROUNDC - rounding 71 // TXT=BCASTSTR - broadcasting 72 // } 73 // MULTISOURCE4 - 4FMA multi-register operand. 74 // 75 // Optional. For most operands, it's nil. 76 Attributes map[string]bool 77 78 // Visibility tells if operand is explicit, implicit or suspended. 79 Visibility OperandVisibility 80 } 81 82 var xedVisibilities = map[string]OperandVisibility{ 83 "EXPL": VisExplicit, 84 "IMPL": VisImplicit, 85 "SUPP": VisSuppressed, 86 "ECOND": VisEcond, 87 } 88 89 // NewOperand decodes operand string. 90 // 91 // See "$XED/pysrc/opnds.py" to learn about fields format 92 // and valid combinations. 93 // 94 // Requires database with xtypes and widths info. 95 func NewOperand(db *Database, s string) (*Operand, error) { 96 if db.widths == nil { 97 return nil, errors.New("Database.widths is nil") 98 } 99 100 fields := strings.Split(s, ":") 101 switch len(fields) { 102 case 0: 103 return nil, errors.New("empty operand fields string") 104 case 1: 105 return &Operand{Name: fields[0]}, nil 106 } 107 var op Operand 108 109 // First two fields are fixed. 110 op.Name = fields[0] 111 op.Action = fields[1] 112 113 // Optional fields. 114 for _, f := range fields[2:] { 115 if db.widths[f] != nil && op.Width == "" { 116 op.Width = f 117 } else if vis, ok := xedVisibilities[f]; ok { 118 op.Visibility = vis 119 } else if xtype := db.xtypes[f]; xtype != nil { 120 op.Xtype = f 121 } else { 122 if op.Attributes == nil { 123 op.Attributes = make(map[string]bool) 124 } 125 op.Attributes[f] = true 126 } 127 } 128 129 return &op, nil 130 } 131 132 // NonterminalName returns true if op.Name consist 133 // of LHS and RHS parts. 134 // 135 // RHS is non-terminal name lookup function expression. 136 // Example: "REG0=GPRv()" has "GPRv()" name lookup function. 137 func (op *Operand) NonterminalName() bool { 138 return strings.Contains(op.Name, "=") 139 } 140 141 // NameLHS returns left hand side part of the non-terminal name. 142 // Example: NameLHS("REG0=GPRv()") => "REG0". 143 func (op *Operand) NameLHS() string { 144 return strings.Split(op.Name, "=")[0] 145 } 146 147 // NameRHS returns right hand side part of the non-terminal name. 148 // Example: NameLHS("REG0=GPRv()") => "GPRv()". 149 func (op *Operand) NameRHS() string { 150 return strings.Split(op.Name, "=")[1] 151 } 152 153 // IsVisible returns true for operands that are usually 154 // shown in syntax strings. 155 func (op *Operand) IsVisible() bool { 156 return op.Visibility == VisExplicit || 157 op.Visibility == VisImplicit 158 } 159