golang.org/x/arch@v0.17.0/loong64/loong64asm/inst.go (about) 1 // Copyright 2024 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 loong64asm 6 7 import ( 8 "fmt" 9 "strings" 10 ) 11 12 // An Inst is a single instruction. 13 type Inst struct { 14 Op Op // Opcode mnemonic 15 Enc uint32 // Raw encoding bits. 16 Args Args // Instruction arguments, in Loong64 manual order. 17 } 18 19 func (i Inst) String() string { 20 var op string = i.Op.String() 21 var args []string 22 23 for _, arg := range i.Args { 24 if arg == nil { 25 break 26 } 27 args = append(args, arg.String()) 28 } 29 30 switch i.Op { 31 case OR: 32 if i.Args[2].(Reg) == R0 { 33 op = "move" 34 args = args[0:2] 35 } 36 37 case ANDI: 38 if i.Args[0].(Reg) == R0 && i.Args[1].(Reg) == R0 { 39 return "nop" 40 } 41 42 case JIRL: 43 if i.Args[0].(Reg) == R0 && i.Args[1].(Reg) == R1 && i.Args[2].(OffsetSimm).Imm == 0 { 44 return "ret" 45 } else if i.Args[0].(Reg) == R0 && i.Args[2].(OffsetSimm).Imm == 0 { 46 return "jr " + args[1] 47 } 48 49 case BLT: 50 if i.Args[0].(Reg) == R0 { 51 op = "bgtz" 52 args = args[1:] 53 } else if i.Args[1].(Reg) == R0 { 54 op = "bltz" 55 args = append(args[:1], args[2:]...) 56 } 57 58 case BGE: 59 if i.Args[0].(Reg) == R0 { 60 op = "blez" 61 args = args[1:] 62 } else if i.Args[1].(Reg) == R0 { 63 op = "bgez" 64 args = append(args[:1], args[2:]...) 65 } 66 } 67 68 if len(args) == 0 { 69 return op 70 } else { 71 return op + " " + strings.Join(args, ", ") 72 } 73 } 74 75 // An Op is an Loong64 opcode. 76 type Op uint16 77 78 // NOTE: The actual Op values are defined in tables.go. 79 // They are chosen to simplify instruction decoding and 80 // are not a dense packing from 0 to N, although the 81 // density is high, probably at least 90%. 82 func (op Op) String() string { 83 if (op >= Op(len(opstr))) || (opstr[op] == "") { 84 return fmt.Sprintf("Op(%d)", int(op)) 85 } 86 87 return opstr[op] 88 } 89 90 // An Args holds the instruction arguments. 91 // If an instruction has fewer than 5 arguments, 92 // the final elements in the array are nil. 93 type Args [5]Arg 94 95 // An Arg is a single instruction argument 96 type Arg interface { 97 String() string 98 } 99 100 // A Reg is a single register. 101 // The zero value denotes R0, not the absence of a register. 102 type Reg uint16 103 104 const ( 105 // General-purpose register 106 R0 Reg = iota 107 R1 108 R2 109 R3 110 R4 111 R5 112 R6 113 R7 114 R8 115 R9 116 R10 117 R11 118 R12 119 R13 120 R14 121 R15 122 R16 123 R17 124 R18 125 R19 126 R20 127 R21 128 R22 129 R23 130 R24 131 R25 132 R26 133 R27 134 R28 135 R29 136 R30 137 R31 138 139 // Float point register 140 F0 141 F1 142 F2 143 F3 144 F4 145 F5 146 F6 147 F7 148 F8 149 F9 150 F10 151 F11 152 F12 153 F13 154 F14 155 F15 156 F16 157 F17 158 F18 159 F19 160 F20 161 F21 162 F22 163 F23 164 F24 165 F25 166 F26 167 F27 168 F28 169 F29 170 F30 171 F31 172 ) 173 174 func (r Reg) String() string { 175 switch { 176 case r == R0: 177 return "$zero" 178 179 case r == R1: 180 return "$ra" 181 182 case r == R2: 183 return "$tp" 184 185 case r == R3: 186 return "$sp" 187 188 case (r >= R4) && (r <= R11): 189 return fmt.Sprintf("$a%d", int(r-R4)) 190 191 case (r >= R12) && (r <= R20): 192 return fmt.Sprintf("$t%d", int(r-R12)) 193 194 case r == R21: 195 return "$r21" 196 197 case r == R22: 198 return "$fp" 199 200 case (r >= R23) && (r <= R31): 201 return fmt.Sprintf("$s%d", int(r-R23)) 202 203 case (r >= F0) && (r <= F7): 204 return fmt.Sprintf("$fa%d", int(r-F0)) 205 206 case (r >= F8) && (r <= F23): 207 return fmt.Sprintf("$ft%d", int(r-F8)) 208 209 case (r >= F24) && (r <= F31): 210 return fmt.Sprintf("$fs%d", int(r-F24)) 211 212 default: 213 return fmt.Sprintf("Unknown(%d)", int(r)) 214 } 215 } 216 217 // float control status register 218 type Fcsr uint8 219 220 const ( 221 FCSR0 Fcsr = iota 222 FCSR1 223 FCSR2 224 FCSR3 225 ) 226 227 func (f Fcsr) String() string { 228 return fmt.Sprintf("$fcsr%d", uint8(f)) 229 } 230 231 // float condition flags register 232 type Fcc uint8 233 234 const ( 235 FCC0 Fcc = iota 236 FCC1 237 FCC2 238 FCC3 239 FCC4 240 FCC5 241 FCC6 242 FCC7 243 ) 244 245 func (f Fcc) String() string { 246 return fmt.Sprintf("$fcc%d", uint8(f)) 247 } 248 249 // An Imm is an integer constant. 250 type Uimm struct { 251 Imm uint32 252 Decimal bool 253 } 254 255 func (i Uimm) String() string { 256 if i.Decimal == true { 257 return fmt.Sprintf("%d", i.Imm) 258 } else { 259 return fmt.Sprintf("%#x", i.Imm) 260 } 261 } 262 263 type Simm16 struct { 264 Imm int16 265 Width uint8 266 } 267 268 func (si Simm16) String() string { 269 return fmt.Sprintf("%d", int32(si.Imm)) 270 } 271 272 type Simm32 struct { 273 Imm int32 274 Width uint8 275 } 276 277 func (si Simm32) String() string { 278 return fmt.Sprintf("%d", int32(si.Imm)) 279 } 280 281 type OffsetSimm struct { 282 Imm int32 283 Width uint8 284 } 285 286 func (o OffsetSimm) String() string { 287 return fmt.Sprintf("%d", int32(o.Imm)) 288 } 289 290 type SaSimm int16 291 292 func (s SaSimm) String() string { 293 return fmt.Sprintf("%#x", int(s)) 294 } 295 296 type CodeSimm int16 297 298 func (c CodeSimm) String() string { 299 return fmt.Sprintf("%#x", int(c)) 300 }