golang.org/x/arch@v0.17.0/loong64/loong64asm/plan9x.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 // GoSyntax returns the Go assembler syntax for the instruction. 13 // The syntax was originally defined by Plan 9. 14 // The pc is the program counter of the instruction, used for 15 // expanding PC-relative addresses into absolute ones. 16 // The symname function queries the symbol table for the program 17 // being disassembled. Given a target address it returns the name 18 // and base address of the symbol containing the target, if any; 19 // otherwise it returns "", 0. 20 func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64)) string { 21 if symname == nil { 22 symname = func(uint64) (string, uint64) { return "", 0 } 23 } 24 if inst.Op == 0 && inst.Enc == 0 { 25 return "WORD $0" 26 } else if inst.Op == 0 { 27 return "?" 28 } 29 30 var args []string 31 for _, a := range inst.Args { 32 if a == nil { 33 break 34 } 35 args = append(args, plan9Arg(&inst, pc, symname, a)) 36 } 37 38 var op string = plan9OpMap[inst.Op] 39 if op == "" { 40 op = "Unknown " + inst.Op.String() 41 } 42 43 switch inst.Op { 44 case BSTRPICK_W, BSTRPICK_D, BSTRINS_W, BSTRINS_D: 45 msbw, lsbw := inst.Args[2].(Uimm), inst.Args[3].(Uimm) 46 if inst.Op == BSTRPICK_D && msbw.Imm == 15 && lsbw.Imm == 0 { 47 op = "MOVHU" 48 args = append(args[1:2], args[0:1]...) 49 } else { 50 args[0], args[2], args[3] = args[2], args[3], args[0] 51 } 52 53 case BCNEZ, BCEQZ: 54 args = args[1:2] 55 56 case BEQ, BNE: 57 rj := inst.Args[0].(Reg) 58 rd := inst.Args[1].(Reg) 59 if rj == rd && inst.Op == BEQ { 60 op = "JMP" 61 args = args[2:] 62 } else if rj == R0 { 63 args = args[1:] 64 } else if rd == R0 { 65 args = append(args[:1], args[2:]...) 66 } 67 68 case BEQZ, BNEZ: 69 if inst.Args[0].(Reg) == R0 && inst.Op == BEQ { 70 op = "JMP" 71 args = args[1:] 72 } 73 74 case BLT, BLTU, BGE, BGEU: 75 rj := inst.Args[0].(Reg) 76 rd := inst.Args[1].(Reg) 77 if rj == rd && (inst.Op == BGE || inst.Op == BGEU) { 78 op = "JMP" 79 args = args[2:] 80 } else if rj == R0 { 81 switch inst.Op { 82 case BGE: 83 op = "BLEZ" 84 case BLT: 85 op = "BGTZ" 86 } 87 args = args[1:] 88 } else if rd == R0 { 89 if !strings.HasSuffix(op, "U") { 90 op += "Z" 91 } 92 args = append(args[:1], args[2:]...) 93 } 94 95 case JIRL: 96 rd := inst.Args[0].(Reg) 97 rj := inst.Args[1].(Reg) 98 regno := uint16(rj) & 31 99 off := inst.Args[2].(OffsetSimm).Imm 100 if rd == R0 && rj == R1 && off == 0 { 101 return fmt.Sprintf("RET") 102 } else if rd == R0 && off == 0 { 103 return fmt.Sprintf("JMP (R%d)", regno) 104 } else if rd == R0 { 105 return fmt.Sprintf("JMP %d(R%d)", off, regno) 106 } 107 return fmt.Sprintf("CALL (R%d)", regno) 108 109 case LD_B, LD_H, LD_W, LD_D, LD_BU, LD_HU, LD_WU, LL_W, LL_D, 110 ST_B, ST_H, ST_W, ST_D, SC_W, SC_D, FLD_S, FLD_D, FST_S, FST_D: 111 var off int32 112 switch a := inst.Args[2].(type) { 113 case Simm16: 114 off = signumConvInt32(int32(a.Imm), a.Width) 115 case Simm32: 116 off = signumConvInt32(int32(a.Imm), a.Width) >> 2 117 } 118 Iop := strings.ToUpper(inst.Op.String()) 119 if strings.HasPrefix(Iop, "L") || strings.HasPrefix(Iop, "FL") { 120 return fmt.Sprintf("%s %d(%s), %s", op, off, args[1], args[0]) 121 } 122 return fmt.Sprintf("%s %s, %d(%s)", op, args[0], off, args[1]) 123 124 case LDX_B, LDX_H, LDX_W, LDX_D, LDX_BU, LDX_HU, LDX_WU, FLDX_S, FLDX_D, 125 STX_B, STX_H, STX_W, STX_D, FSTX_S, FSTX_D: 126 Iop := strings.ToUpper(inst.Op.String()) 127 if strings.HasPrefix(Iop, "L") || strings.HasPrefix(Iop, "FL") { 128 return fmt.Sprintf("%s (%s)(%s), %s", op, args[1], args[2], args[0]) 129 } 130 return fmt.Sprintf("%s %s, (%s)(%s)", op, args[0], args[1], args[2]) 131 132 case AMADD_B, AMADD_D, AMADD_DB_B, AMADD_DB_D, AMADD_DB_H, AMADD_DB_W, AMADD_H, 133 AMADD_W, AMAND_D, AMAND_DB_D, AMAND_DB_W, AMAND_W, AMCAS_B, AMCAS_D, AMCAS_DB_B, 134 AMCAS_DB_D, AMCAS_DB_H, AMCAS_DB_W, AMCAS_H, AMCAS_W, AMMAX_D, AMMAX_DB_D, 135 AMMAX_DB_DU, AMMAX_DB_W, AMMAX_DB_WU, AMMAX_DU, AMMAX_W, AMMAX_WU, AMMIN_D, 136 AMMIN_DB_D, AMMIN_DB_DU, AMMIN_DB_W, AMMIN_DB_WU, AMMIN_DU, AMMIN_W, AMMIN_WU, 137 AMOR_D, AMOR_DB_D, AMOR_DB_W, AMOR_W, AMSWAP_B, AMSWAP_D, AMSWAP_DB_B, AMSWAP_DB_D, 138 AMSWAP_DB_H, AMSWAP_DB_W, AMSWAP_H, AMSWAP_W, AMXOR_D, AMXOR_DB_D, AMXOR_DB_W, AMXOR_W: 139 return fmt.Sprintf("%s %s, (%s), %s", op, args[1], args[2], args[0]) 140 141 default: 142 // Reverse args, placing dest last 143 for i, j := 0, len(args)-1; i < j; i, j = i+1, j-1 { 144 args[i], args[j] = args[j], args[i] 145 } 146 switch len(args) { // Special use cases 147 case 0, 1: 148 if inst.Op != B && inst.Op != BL { 149 return op 150 } 151 152 case 3: 153 switch a0 := inst.Args[0].(type) { 154 case Reg: 155 rj := inst.Args[1].(Reg) 156 if a0 == rj && a0 != R0 { 157 args = args[0:2] 158 } 159 } 160 switch inst.Op { 161 case SUB_W, SUB_D, ADDI_W, ADDI_D, ORI: 162 rj := inst.Args[1].(Reg) 163 if rj == R0 { 164 args = append(args[0:1], args[2:]...) 165 if inst.Op == SUB_W { 166 op = "NEGW" 167 } else if inst.Op == SUB_D { 168 op = "NEGV" 169 } else { 170 op = "MOVW" 171 } 172 } 173 174 case ANDI: 175 ui12 := inst.Args[2].(Uimm) 176 if ui12.Imm == uint32(0xff) { 177 op = "MOVBU" 178 args = args[1:] 179 } else if ui12.Imm == 0 && inst.Args[0].(Reg) == R0 && inst.Args[1].(Reg) == R0 { 180 return "NOOP" 181 } 182 183 case SLL_W, OR: 184 rk := inst.Args[2].(Reg) 185 if rk == R0 { 186 args = args[1:] 187 if inst.Op == SLL_W { 188 op = "MOVW" 189 } else { 190 op = "MOVV" 191 } 192 } 193 } 194 } 195 } 196 197 if args != nil { 198 op += " " + strings.Join(args, ", ") 199 } 200 return op 201 } 202 203 func plan9Arg(inst *Inst, pc uint64, symname func(uint64) (string, uint64), arg Arg) string { 204 // Reg: gpr[0, 31] and fpr[0, 31] 205 // Fcsr: fcsr[0, 3] 206 // Fcc: fcc[0, 7] 207 // Uimm: unsigned integer constant 208 // Simm16: si16 209 // Simm32: si32 210 // OffsetSimm: si32 211 switch a := arg.(type) { 212 case Reg: 213 regenum := uint16(a) 214 regno := uint16(a) & 0x1f 215 // General-purpose register 216 if regenum >= uint16(R0) && regenum <= uint16(R31) { 217 return fmt.Sprintf("R%d", regno) 218 } else { // Float point register 219 return fmt.Sprintf("F%d", regno) 220 } 221 222 case Fcsr: 223 regno := uint8(a) & 0x1f 224 return fmt.Sprintf("FCSR%d", regno) 225 226 case Fcc: 227 regno := uint8(a) & 0x1f 228 return fmt.Sprintf("FCC%d", regno) 229 230 case Uimm: 231 return fmt.Sprintf("$%d", a.Imm) 232 233 case Simm16: 234 si16 := signumConvInt32(int32(a.Imm), a.Width) 235 return fmt.Sprintf("$%d", si16) 236 237 case Simm32: 238 si32 := signumConvInt32(a.Imm, a.Width) 239 return fmt.Sprintf("$%d", si32) 240 241 case OffsetSimm: 242 offs := offsConvInt32(a.Imm, a.Width) 243 if inst.Op == B || inst.Op == BL { 244 addr := int64(pc) + int64(a.Imm) 245 if s, base := symname(uint64(addr)); s != "" && uint64(addr) == base { 246 return fmt.Sprintf("%s(SB)", s) 247 } 248 } 249 return fmt.Sprintf("%d(PC)", offs>>2) 250 251 case SaSimm: 252 return fmt.Sprintf("$%d", a) 253 254 case CodeSimm: 255 return fmt.Sprintf("$%d", a) 256 257 } 258 return strings.ToUpper(arg.String()) 259 } 260 261 func signumConvInt32(imm int32, width uint8) int32 { 262 active := uint32(1<<width) - 1 263 signum := uint32(imm) & active 264 if ((signum >> (width - 1)) & 0x1) == 1 { 265 signum |= ^active 266 } 267 return int32(signum) 268 } 269 270 func offsConvInt32(imm int32, width uint8) int32 { 271 relWidth := width + 2 272 return signumConvInt32(imm, relWidth) 273 } 274 275 var plan9OpMap = map[Op]string{ 276 ADD_W: "ADD", 277 ADD_D: "ADDV", 278 SUB_W: "SUB", 279 SUB_D: "SUBV", 280 ADDI_W: "ADD", 281 ADDI_D: "ADDV", 282 LU12I_W: "LU12IW", 283 LU32I_D: "LU32ID", 284 LU52I_D: "LU52ID", 285 SLT: "SGT", 286 SLTU: "SGTU", 287 SLTI: "SGT", 288 SLTUI: "SGTU", 289 PCADDU12I: "PCADDU12I", 290 PCALAU12I: "PCALAU12I", 291 AND: "AND", 292 OR: "OR", 293 NOR: "NOR", 294 XOR: "XOR", 295 ANDI: "AND", 296 ORI: "OR", 297 XORI: "XOR", 298 MUL_W: "MUL", 299 MULH_W: "MULH", 300 MULH_WU: "MULHU", 301 MUL_D: "MULV", 302 MULH_D: "MULHV", 303 MULH_DU: "MULHVU", 304 DIV_W: "DIV", 305 DIV_WU: "DIVU", 306 DIV_D: "DIVV", 307 DIV_DU: "DIVVU", 308 MOD_W: "REM", 309 MOD_WU: "REMU", 310 MOD_D: "REMV", 311 MOD_DU: "REMVU", 312 SLL_W: "SLL", 313 SRL_W: "SRL", 314 SRA_W: "SRA", 315 ROTR_W: "ROTR", 316 SLL_D: "SLLV", 317 SRL_D: "SRLV", 318 SRA_D: "SRAV", 319 ROTR_D: "ROTRV", 320 SLLI_W: "SLL", 321 SRLI_W: "SRL", 322 SRAI_W: "SRA", 323 ROTRI_W: "ROTR", 324 SLLI_D: "SLLV", 325 SRLI_D: "SRLV", 326 SRAI_D: "SRAV", 327 ROTRI_D: "ROTRV", 328 EXT_W_B: "?", 329 EXT_W_H: "?", 330 BITREV_W: "BITREVW", 331 BITREV_D: "BITREVV", 332 CLO_W: "CLOW", 333 CLO_D: "CLOV", 334 CLZ_W: "CLZW", 335 CLZ_D: "CLZV", 336 CTO_W: "CTOW", 337 CTO_D: "CTOV", 338 CTZ_W: "CTZW", 339 CTZ_D: "CTZV", 340 REVB_2H: "REVB2H", 341 REVB_2W: "REVB2W", 342 REVB_4H: "REVB4H", 343 REVB_D: "REVBV", 344 BSTRPICK_W: "BSTRPICKW", 345 BSTRPICK_D: "BSTRPICKV", 346 BSTRINS_W: "BSTRINSW", 347 BSTRINS_D: "BSTRINSV", 348 MASKEQZ: "MASKEQZ", 349 MASKNEZ: "MASKNEZ", 350 BCNEZ: "BFPT", 351 BCEQZ: "BFPF", 352 BEQ: "BEQ", 353 BNE: "BNE", 354 BEQZ: "BEQ", 355 BNEZ: "BNE", 356 BLT: "BLT", 357 BLTU: "BLTU", 358 BGE: "BGE", 359 BGEU: "BGEU", 360 B: "JMP", 361 BL: "CALL", 362 LD_B: "MOVB", 363 LD_H: "MOVH", 364 LD_W: "MOVW", 365 LD_D: "MOVV", 366 LD_BU: "MOVBU", 367 LD_HU: "MOVHU", 368 LD_WU: "MOVWU", 369 ST_B: "MOVB", 370 ST_H: "MOVH", 371 ST_W: "MOVW", 372 ST_D: "MOVV", 373 LDX_B: "MOVB", 374 LDX_BU: "MOVBU", 375 LDX_D: "MOVV", 376 LDX_H: "MOVH", 377 LDX_HU: "MOVHU", 378 LDX_W: "MOVW", 379 LDX_WU: "MOVWU", 380 STX_B: "MOVB", 381 STX_D: "MOVV", 382 STX_H: "MOVH", 383 STX_W: "MOVW", 384 AMADD_B: "AMADDB", 385 AMADD_D: "AMADDV", 386 AMADD_DB_B: "AMADDDBB", 387 AMADD_DB_D: "AMADDDBV", 388 AMADD_DB_H: "AMADDDBH", 389 AMADD_DB_W: "AMADDDBW", 390 AMADD_H: "AMADDH", 391 AMADD_W: "AMADDW", 392 AMAND_D: "AMANDV", 393 AMAND_DB_D: "AMANDDBV", 394 AMAND_DB_W: "AMANDDBW", 395 AMAND_W: "AMANDW", 396 AMCAS_B: "AMCASB", 397 AMCAS_D: "AMCASV", 398 AMCAS_DB_B: "AMCASDBB", 399 AMCAS_DB_D: "AMCASDBV", 400 AMCAS_DB_H: "AMCASDBH", 401 AMCAS_DB_W: "AMCASDBW", 402 AMCAS_H: "AMCASH", 403 AMCAS_W: "AMCASW", 404 AMMAX_D: "AMMAXV", 405 AMMAX_DB_D: "AMMAXDBV", 406 AMMAX_DB_DU: "AMMAXDBVU", 407 AMMAX_DB_W: "AMMAXDBW", 408 AMMAX_DB_WU: "AMMAXDBWU", 409 AMMAX_DU: "AMMAXVU", 410 AMMAX_W: "AMMAXW", 411 AMMAX_WU: "AMMAXWU", 412 AMMIN_D: "AMMINV", 413 AMMIN_DB_D: "AMMINDBV", 414 AMMIN_DB_DU: "AMMINDBVU", 415 AMMIN_DB_W: "AMMINDBW", 416 AMMIN_DB_WU: "AMMINDBWU", 417 AMMIN_DU: "AMMINVU", 418 AMMIN_W: "AMMINW", 419 AMMIN_WU: "AMMINWU", 420 AMOR_D: "AMORV", 421 AMOR_DB_D: "AMORDBV", 422 AMOR_DB_W: "AMORDBW", 423 AMOR_W: "AMORW", 424 AMSWAP_B: "AMSWAPB", 425 AMSWAP_D: "AMSWAPV", 426 AMSWAP_DB_B: "AMSWAPDBB", 427 AMSWAP_DB_D: "AMSWAPDBV", 428 AMSWAP_DB_H: "AMSWAPDBH", 429 AMSWAP_DB_W: "AMSWAPDBW", 430 AMSWAP_H: "AMSWAPH", 431 AMSWAP_W: "AMSWAPW", 432 AMXOR_D: "AMXORV", 433 AMXOR_DB_D: "AMXORDBV", 434 AMXOR_DB_W: "AMXORDBW", 435 AMXOR_W: "AMXORW", 436 LL_W: "LL", 437 LL_D: "LLV", 438 SC_W: "SC", 439 SC_D: "SCV", 440 CRCC_W_B_W: "CRCCWBW", 441 CRCC_W_D_W: "CRCCWVW", 442 CRCC_W_H_W: "CRCCWHW", 443 CRCC_W_W_W: "CRCCWWW", 444 CRC_W_B_W: "CRCWBW", 445 CRC_W_D_W: "CRCWVW", 446 CRC_W_H_W: "CRCWHW", 447 CRC_W_W_W: "CRCWWW", 448 DBAR: "DBAR", 449 SYSCALL: "SYSCALL", 450 BREAK: "BREAK", 451 RDTIMEL_W: "RDTIMELW", 452 RDTIMEH_W: "RDTIMEHW", 453 RDTIME_D: "RDTIMED", 454 CPUCFG: "CPUCFG", 455 456 // Floating-point instructions 457 FADD_S: "ADDF", 458 FADD_D: "ADDD", 459 FSUB_S: "SUBF", 460 FSUB_D: "SUBD", 461 FMUL_S: "MULF", 462 FMUL_D: "MULD", 463 FDIV_S: "DIVF", 464 FDIV_D: "DIVD", 465 FMSUB_S: "FMSUBF", 466 FMSUB_D: "FMSUBD", 467 FMADD_S: "FMADDF", 468 FMADD_D: "FMADDD", 469 FNMADD_S: "FNMADDF", 470 FNMADD_D: "FNMADDD", 471 FNMSUB_S: "FNMSUBF", 472 FNMSUB_D: "FNMSUBD", 473 FABS_S: "ABSF", 474 FABS_D: "ABSD", 475 FNEG_S: "NEGF", 476 FNEG_D: "NEGD", 477 FSQRT_S: "SQRTF", 478 FSQRT_D: "SQRTD", 479 FCOPYSIGN_S: "FCOPYSGF", 480 FCOPYSIGN_D: "FCOPYSGD", 481 FMAX_S: "FMAXF", 482 FMAX_D: "FMAXD", 483 FMIN_S: "FMINF", 484 FMIN_D: "FMIND", 485 FCLASS_S: "FCLASSF", 486 FCLASS_D: "FCLASSD", 487 FCMP_CEQ_S: "CMPEQF", 488 FCMP_CEQ_D: "CMPEQD", 489 FCMP_SLE_S: "CMPGEF", 490 FCMP_SLE_D: "CMPGED", 491 FCMP_SLT_S: "CMPGTF", 492 FCMP_SLT_D: "CMPGTD", 493 FCVT_D_S: "MOVFD", 494 FCVT_S_D: "MOVDF", 495 FFINT_S_W: "FFINTFW", 496 FFINT_S_L: "FFINTFV", 497 FFINT_D_W: "FFINTDW", 498 FFINT_D_L: "FFINTDV", 499 FTINTRM_L_D: "FTINTRMVD", 500 FTINTRM_L_S: "FTINTRMVF", 501 FTINTRM_W_D: "FTINTRMWD", 502 FTINTRM_W_S: "FTINTRMWF", 503 FTINTRNE_L_D: "FTINTRNEVD", 504 FTINTRNE_L_S: "FTINTRNEVF", 505 FTINTRNE_W_D: "FTINTRNEWD", 506 FTINTRNE_W_S: "FTINTRNEWF", 507 FTINTRP_L_D: "FTINTRPVD", 508 FTINTRP_L_S: "FTINTRPVF", 509 FTINTRP_W_D: "FTINTRPWD", 510 FTINTRP_W_S: "FTINTRPWF", 511 FTINTRZ_L_D: "FTINTRZVD", 512 FTINTRZ_L_S: "FTINTRZVF", 513 FTINTRZ_W_D: "FTINTRZWD", 514 FTINTRZ_W_S: "FTINTRZWF", 515 FTINT_L_D: "FTINTVD", 516 FTINT_L_S: "FTINTVF", 517 FTINT_W_D: "FTINTWD", 518 FTINT_W_S: "FTINTWF", 519 FRINT_S: "FRINTS", 520 FRINT_D: "FRINTD", 521 FMOV_S: "MOVF", 522 FMOV_D: "MOVD", 523 MOVGR2FR_W: "MOVW", 524 MOVGR2FR_D: "MOVV", 525 MOVFR2GR_S: "MOVW", 526 MOVFR2GR_D: "MOVV", 527 MOVGR2CF: "MOVV", 528 MOVCF2GR: "MOVV", 529 MOVFCSR2GR: "MOVV", 530 MOVGR2FCSR: "MOVV", 531 MOVFR2CF: "MOVV", 532 MOVCF2FR: "MOVV", 533 FLD_S: "MOVF", 534 FLD_D: "MOVD", 535 FST_S: "MOVF", 536 FST_D: "MOVD", 537 FLDX_S: "MOVF", 538 FLDX_D: "MOVD", 539 FSTX_S: "MOVF", 540 FSTX_D: "MOVD", 541 }