github.com/bir3/gocompiler@v0.9.2202/src/xvendor/golang.org/x/arch/arm/armasm/inst.go (about) 1 // Copyright 2014 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 armasm 6 7 import ( 8 "bytes" 9 "fmt" 10 ) 11 12 // A Mode is an instruction execution mode. 13 type Mode int 14 15 const ( 16 _ Mode = iota 17 ModeARM 18 ModeThumb 19 ) 20 21 func (m Mode) String() string { 22 switch m { 23 case ModeARM: 24 return "ARM" 25 case ModeThumb: 26 return "Thumb" 27 } 28 return fmt.Sprintf("Mode(%d)", int(m)) 29 } 30 31 // An Op is an ARM opcode. 32 type Op uint16 33 34 // NOTE: The actual Op values are defined in tables.go. 35 // They are chosen to simplify instruction decoding and 36 // are not a dense packing from 0 to N, although the 37 // density is high, probably at least 90%. 38 39 func (op Op) String() string { 40 if op >= Op(len(opstr)) || opstr[op] == "" { 41 return fmt.Sprintf("Op(%d)", int(op)) 42 } 43 return opstr[op] 44 } 45 46 // An Inst is a single instruction. 47 type Inst struct { 48 Op Op // Opcode mnemonic 49 Enc uint32 // Raw encoding bits. 50 Len int // Length of encoding in bytes. 51 Args Args // Instruction arguments, in ARM manual order. 52 } 53 54 func (i Inst) String() string { 55 var buf bytes.Buffer 56 buf.WriteString(i.Op.String()) 57 for j, arg := range i.Args { 58 if arg == nil { 59 break 60 } 61 if j == 0 { 62 buf.WriteString(" ") 63 } else { 64 buf.WriteString(", ") 65 } 66 buf.WriteString(arg.String()) 67 } 68 return buf.String() 69 } 70 71 // An Args holds the instruction arguments. 72 // If an instruction has fewer than 4 arguments, 73 // the final elements in the array are nil. 74 type Args [4]Arg 75 76 // An Arg is a single instruction argument, one of these types: 77 // Endian, Imm, Mem, PCRel, Reg, RegList, RegShift, RegShiftReg. 78 type Arg interface { 79 IsArg() 80 String() string 81 } 82 83 type Float32Imm float32 84 85 func (Float32Imm) IsArg() {} 86 87 func (f Float32Imm) String() string { 88 return fmt.Sprintf("#%v", float32(f)) 89 } 90 91 type Float64Imm float32 92 93 func (Float64Imm) IsArg() {} 94 95 func (f Float64Imm) String() string { 96 return fmt.Sprintf("#%v", float64(f)) 97 } 98 99 // An Imm is an integer constant. 100 type Imm uint32 101 102 func (Imm) IsArg() {} 103 104 func (i Imm) String() string { 105 return fmt.Sprintf("#%#x", uint32(i)) 106 } 107 108 // An ImmAlt is an alternate encoding of an integer constant. 109 type ImmAlt struct { 110 Val uint8 111 Rot uint8 112 } 113 114 func (ImmAlt) IsArg() {} 115 116 func (i ImmAlt) Imm() Imm { 117 v := uint32(i.Val) 118 r := uint(i.Rot) 119 return Imm(v>>r | v<<(32-r)) 120 } 121 122 func (i ImmAlt) String() string { 123 return fmt.Sprintf("#%#x, %d", i.Val, i.Rot) 124 } 125 126 // A Label is a text (code) address. 127 type Label uint32 128 129 func (Label) IsArg() {} 130 131 func (i Label) String() string { 132 return fmt.Sprintf("%#x", uint32(i)) 133 } 134 135 // A Reg is a single register. 136 // The zero value denotes R0, not the absence of a register. 137 type Reg uint8 138 139 const ( 140 R0 Reg = iota 141 R1 142 R2 143 R3 144 R4 145 R5 146 R6 147 R7 148 R8 149 R9 150 R10 151 R11 152 R12 153 R13 154 R14 155 R15 156 157 S0 158 S1 159 S2 160 S3 161 S4 162 S5 163 S6 164 S7 165 S8 166 S9 167 S10 168 S11 169 S12 170 S13 171 S14 172 S15 173 S16 174 S17 175 S18 176 S19 177 S20 178 S21 179 S22 180 S23 181 S24 182 S25 183 S26 184 S27 185 S28 186 S29 187 S30 188 S31 189 190 D0 191 D1 192 D2 193 D3 194 D4 195 D5 196 D6 197 D7 198 D8 199 D9 200 D10 201 D11 202 D12 203 D13 204 D14 205 D15 206 D16 207 D17 208 D18 209 D19 210 D20 211 D21 212 D22 213 D23 214 D24 215 D25 216 D26 217 D27 218 D28 219 D29 220 D30 221 D31 222 223 APSR 224 APSR_nzcv 225 FPSCR 226 227 SP = R13 228 LR = R14 229 PC = R15 230 ) 231 232 func (Reg) IsArg() {} 233 234 func (r Reg) String() string { 235 switch r { 236 case APSR: 237 return "APSR" 238 case APSR_nzcv: 239 return "APSR_nzcv" 240 case FPSCR: 241 return "FPSCR" 242 case SP: 243 return "SP" 244 case PC: 245 return "PC" 246 case LR: 247 return "LR" 248 } 249 if R0 <= r && r <= R15 { 250 return fmt.Sprintf("R%d", int(r-R0)) 251 } 252 if S0 <= r && r <= S31 { 253 return fmt.Sprintf("S%d", int(r-S0)) 254 } 255 if D0 <= r && r <= D31 { 256 return fmt.Sprintf("D%d", int(r-D0)) 257 } 258 return fmt.Sprintf("Reg(%d)", int(r)) 259 } 260 261 // A RegX represents a fraction of a multi-value register. 262 // The Index field specifies the index number, 263 // but the size of the fraction is not specified. 264 // It must be inferred from the instruction and the register type. 265 // For example, in a VMOV instruction, RegX{D5, 1} represents 266 // the top 32 bits of the 64-bit D5 register. 267 type RegX struct { 268 Reg Reg 269 Index int 270 } 271 272 func (RegX) IsArg() {} 273 274 func (r RegX) String() string { 275 return fmt.Sprintf("%s[%d]", r.Reg, r.Index) 276 } 277 278 // A RegList is a register list. 279 // Bits at indexes x = 0 through 15 indicate whether the corresponding Rx register is in the list. 280 type RegList uint16 281 282 func (RegList) IsArg() {} 283 284 func (r RegList) String() string { 285 var buf bytes.Buffer 286 fmt.Fprintf(&buf, "{") 287 sep := "" 288 for i := 0; i < 16; i++ { 289 if r&(1<<uint(i)) != 0 { 290 fmt.Fprintf(&buf, "%s%s", sep, Reg(i).String()) 291 sep = "," 292 } 293 } 294 fmt.Fprintf(&buf, "}") 295 return buf.String() 296 } 297 298 // An Endian is the argument to the SETEND instruction. 299 type Endian uint8 300 301 const ( 302 LittleEndian Endian = 0 303 BigEndian Endian = 1 304 ) 305 306 func (Endian) IsArg() {} 307 308 func (e Endian) String() string { 309 if e != 0 { 310 return "BE" 311 } 312 return "LE" 313 } 314 315 // A Shift describes an ARM shift operation. 316 type Shift uint8 317 318 const ( 319 ShiftLeft Shift = 0 // left shift 320 ShiftRight Shift = 1 // logical (unsigned) right shift 321 ShiftRightSigned Shift = 2 // arithmetic (signed) right shift 322 RotateRight Shift = 3 // right rotate 323 RotateRightExt Shift = 4 // right rotate through carry (Count will always be 1) 324 ) 325 326 var shiftName = [...]string{ 327 "LSL", "LSR", "ASR", "ROR", "RRX", 328 } 329 330 func (s Shift) String() string { 331 if s < 5 { 332 return shiftName[s] 333 } 334 return fmt.Sprintf("Shift(%d)", int(s)) 335 } 336 337 // A RegShift is a register shifted by a constant. 338 type RegShift struct { 339 Reg Reg 340 Shift Shift 341 Count uint8 342 } 343 344 func (RegShift) IsArg() {} 345 346 func (r RegShift) String() string { 347 return fmt.Sprintf("%s %s #%d", r.Reg, r.Shift, r.Count) 348 } 349 350 // A RegShiftReg is a register shifted by a register. 351 type RegShiftReg struct { 352 Reg Reg 353 Shift Shift 354 RegCount Reg 355 } 356 357 func (RegShiftReg) IsArg() {} 358 359 func (r RegShiftReg) String() string { 360 return fmt.Sprintf("%s %s %s", r.Reg, r.Shift, r.RegCount) 361 } 362 363 // A PCRel describes a memory address (usually a code label) 364 // as a distance relative to the program counter. 365 // TODO(rsc): Define which program counter (PC+4? PC+8? PC?). 366 type PCRel int32 367 368 func (PCRel) IsArg() {} 369 370 func (r PCRel) String() string { 371 return fmt.Sprintf("PC%+#x", int32(r)) 372 } 373 374 // An AddrMode is an ARM addressing mode. 375 type AddrMode uint8 376 377 const ( 378 _ AddrMode = iota 379 AddrPostIndex // [R], X – use address R, set R = R + X 380 AddrPreIndex // [R, X]! – use address R + X, set R = R + X 381 AddrOffset // [R, X] – use address R + X 382 AddrLDM // R – [R] but formats as R, for LDM/STM only 383 AddrLDM_WB // R! - [R], X where X is instruction-specific amount, for LDM/STM only 384 ) 385 386 // A Mem is a memory reference made up of a base R and index expression X. 387 // The effective memory address is R or R+X depending on AddrMode. 388 // The index expression is X = Sign*(Index Shift Count) + Offset, 389 // but in any instruction either Sign = 0 or Offset = 0. 390 type Mem struct { 391 Base Reg 392 Mode AddrMode 393 Sign int8 394 Index Reg 395 Shift Shift 396 Count uint8 397 Offset int16 398 } 399 400 func (Mem) IsArg() {} 401 402 func (m Mem) String() string { 403 R := m.Base.String() 404 X := "" 405 if m.Sign != 0 { 406 X = "+" 407 if m.Sign < 0 { 408 X = "-" 409 } 410 X += m.Index.String() 411 if m.Shift != ShiftLeft || m.Count != 0 { 412 X += fmt.Sprintf(", %s #%d", m.Shift, m.Count) 413 } 414 } else { 415 X = fmt.Sprintf("#%d", m.Offset) 416 } 417 418 switch m.Mode { 419 case AddrOffset: 420 if X == "#0" { 421 return fmt.Sprintf("[%s]", R) 422 } 423 return fmt.Sprintf("[%s, %s]", R, X) 424 case AddrPreIndex: 425 return fmt.Sprintf("[%s, %s]!", R, X) 426 case AddrPostIndex: 427 return fmt.Sprintf("[%s], %s", R, X) 428 case AddrLDM: 429 if X == "#0" { 430 return R 431 } 432 case AddrLDM_WB: 433 if X == "#0" { 434 return R + "!" 435 } 436 } 437 return fmt.Sprintf("[%s Mode(%d) %s]", R, int(m.Mode), X) 438 }