1
2
3
4
5 package loong64asm
6
7 import (
8 "fmt"
9 "strings"
10 )
11
12
13
14
15
16
17
18
19
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
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) {
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
205
206
207
208
209
210
211 switch a := arg.(type) {
212 case Reg:
213 regenum := uint16(a)
214 regno := uint16(a) & 0x1f
215
216 if regenum >= uint16(R0) && regenum <= uint16(R31) {
217 return fmt.Sprintf("R%d", regno)
218 } else {
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
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 }
542
View as plain text