delve/vendor/golang.org/x/arch/riscv64/riscv64asm/gnu.go
2024-10-11 12:34:25 -07:00

329 lines
6.6 KiB
Go

// Copyright 2024 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package riscv64asm
import (
"strings"
)
// GNUSyntax returns the GNU assembler syntax for the instruction, as defined by GNU binutils.
// This form typically matches the syntax defined in the RISC-V Instruction Set Manual. See
// https://github.com/riscv/riscv-isa-manual/releases/download/Ratified-IMAFDQC/riscv-spec-20191213.pdf
func GNUSyntax(inst Inst) string {
op := strings.ToLower(inst.Op.String())
var args []string
for _, a := range inst.Args {
if a == nil {
break
}
args = append(args, strings.ToLower(a.String()))
}
switch inst.Op {
case ADDI, ADDIW, ANDI, ORI, SLLI, SLLIW, SRAI, SRAIW, SRLI, SRLIW, XORI:
if inst.Op == ADDI {
if inst.Args[1].(Reg) == X0 && inst.Args[0].(Reg) != X0 {
op = "li"
args[1] = args[2]
args = args[:len(args)-1]
break
}
if inst.Args[2].(Simm).Imm == 0 {
if inst.Args[0].(Reg) == X0 && inst.Args[1].(Reg) == X0 {
op = "nop"
args = nil
} else {
op = "mv"
args = args[:len(args)-1]
}
}
}
if inst.Op == ADDIW && inst.Args[2].(Simm).Imm == 0 {
op = "sext.w"
args = args[:len(args)-1]
}
if inst.Op == XORI && inst.Args[2].(Simm).String() == "-1" {
op = "not"
args = args[:len(args)-1]
}
case ADD:
if inst.Args[1].(Reg) == X0 {
op = "mv"
args[1] = args[2]
args = args[:len(args)-1]
}
case BEQ:
if inst.Args[1].(Reg) == X0 {
op = "beqz"
args[1] = args[2]
args = args[:len(args)-1]
}
case BGE:
if inst.Args[1].(Reg) == X0 {
op = "bgez"
args[1] = args[2]
args = args[:len(args)-1]
} else if inst.Args[0].(Reg) == X0 {
op = "blez"
args[0], args[1] = args[1], args[2]
args = args[:len(args)-1]
}
case BLT:
if inst.Args[1].(Reg) == X0 {
op = "bltz"
args[1] = args[2]
args = args[:len(args)-1]
} else if inst.Args[0].(Reg) == X0 {
op = "bgtz"
args[0], args[1] = args[1], args[2]
args = args[:len(args)-1]
}
case BNE:
if inst.Args[1].(Reg) == X0 {
op = "bnez"
args[1] = args[2]
args = args[:len(args)-1]
}
case CSRRC:
if inst.Args[0].(Reg) == X0 {
op = "csrc"
args[0], args[1] = args[1], args[2]
args = args[:len(args)-1]
}
case CSRRCI:
if inst.Args[0].(Reg) == X0 {
op = "csrci"
args[0], args[1] = args[1], args[2]
args = args[:len(args)-1]
}
case CSRRS:
if inst.Args[2].(Reg) == X0 {
switch inst.Args[1].(CSR) {
case FCSR:
op = "frcsr"
args = args[:len(args)-2]
case FFLAGS:
op = "frflags"
args = args[:len(args)-2]
case FRM:
op = "frrm"
args = args[:len(args)-2]
// rdcycleh, rdinstreth and rdtimeh are RV-32 only instructions.
// So not included there.
case CYCLE:
op = "rdcycle"
args = args[:len(args)-2]
case INSTRET:
op = "rdinstret"
args = args[:len(args)-2]
case TIME:
op = "rdtime"
args = args[:len(args)-2]
default:
op = "csrr"
args = args[:len(args)-1]
}
} else if inst.Args[0].(Reg) == X0 {
op = "csrs"
args[0], args[1] = args[1], args[2]
args = args[:len(args)-1]
}
case CSRRSI:
if inst.Args[0].(Reg) == X0 {
op = "csrsi"
args[0], args[1] = args[1], args[2]
args = args[:len(args)-1]
}
case CSRRW:
switch inst.Args[1].(CSR) {
case FCSR:
op = "fscsr"
if inst.Args[0].(Reg) == X0 {
args[0] = args[2]
args = args[:len(args)-2]
} else {
args[1] = args[2]
args = args[:len(args)-1]
}
case FFLAGS:
op = "fsflags"
if inst.Args[0].(Reg) == X0 {
args[0] = args[2]
args = args[:len(args)-2]
} else {
args[1] = args[2]
args = args[:len(args)-1]
}
case FRM:
op = "fsrm"
if inst.Args[0].(Reg) == X0 {
args[0] = args[2]
args = args[:len(args)-2]
} else {
args[1] = args[2]
args = args[:len(args)-1]
}
case CYCLE:
if inst.Args[0].(Reg) == X0 && inst.Args[2].(Reg) == X0 {
op = "unimp"
args = nil
}
default:
if inst.Args[0].(Reg) == X0 {
op = "csrw"
args[0], args[1] = args[1], args[2]
args = args[:len(args)-1]
}
}
case CSRRWI:
if inst.Args[0].(Reg) == X0 {
op = "csrwi"
args[0], args[1] = args[1], args[2]
args = args[:len(args)-1]
}
// When both pred and succ equals to iorw, the GNU objdump will omit them.
case FENCE:
if inst.Args[0].(MemOrder).String() == "iorw" &&
inst.Args[1].(MemOrder).String() == "iorw" {
args = nil
}
case FSGNJX_D:
if inst.Args[1].(Reg) == inst.Args[2].(Reg) {
op = "fabs.d"
args = args[:len(args)-1]
}
case FSGNJX_S:
if inst.Args[1].(Reg) == inst.Args[2].(Reg) {
op = "fabs.s"
args = args[:len(args)-1]
}
case FSGNJ_D:
if inst.Args[1].(Reg) == inst.Args[2].(Reg) {
op = "fmv.d"
args = args[:len(args)-1]
}
case FSGNJ_S:
if inst.Args[1].(Reg) == inst.Args[2].(Reg) {
op = "fmv.s"
args = args[:len(args)-1]
}
case FSGNJN_D:
if inst.Args[1].(Reg) == inst.Args[2].(Reg) {
op = "fneg.d"
args = args[:len(args)-1]
}
case FSGNJN_S:
if inst.Args[1].(Reg) == inst.Args[2].(Reg) {
op = "fneg.s"
args = args[:len(args)-1]
}
case JAL:
if inst.Args[0].(Reg) == X0 {
op = "j"
args[0] = args[1]
args = args[:len(args)-1]
} else if inst.Args[0].(Reg) == X1 {
op = "jal"
args[0] = args[1]
args = args[:len(args)-1]
}
case JALR:
if inst.Args[0].(Reg) == X1 && inst.Args[1].(RegOffset).Ofs.Imm == 0 {
args[0] = inst.Args[1].(RegOffset).OfsReg.String()
args = args[:len(args)-1]
}
if inst.Args[0].(Reg) == X0 {
if inst.Args[1].(RegOffset).OfsReg == X1 && inst.Args[1].(RegOffset).Ofs.Imm == 0 {
op = "ret"
args = nil
} else if inst.Args[1].(RegOffset).Ofs.Imm == 0 {
op = "jr"
args[0] = inst.Args[1].(RegOffset).OfsReg.String()
args = args[:len(args)-1]
} else {
op = "jr"
args[0] = inst.Args[1].(RegOffset).String()
args = args[:len(args)-1]
}
}
case SLTIU:
if inst.Args[2].(Simm).String() == "1" {
op = "seqz"
args = args[:len(args)-1]
}
case SLT:
if inst.Args[1].(Reg) == X0 {
op = "sgtz"
args[1] = args[2]
args = args[:len(args)-1]
} else if inst.Args[2].(Reg) == X0 {
op = "sltz"
args = args[:len(args)-1]
}
case SLTU:
if inst.Args[1].(Reg) == X0 {
op = "snez"
args[1] = args[2]
args = args[:len(args)-1]
}
case SUB:
if inst.Args[1].(Reg) == X0 {
op = "neg"
args[1] = args[2]
args = args[:len(args)-1]
}
case SUBW:
if inst.Args[1].(Reg) == X0 {
op = "negw"
args[1] = args[2]
args = args[:len(args)-1]
}
}
if args != nil {
op += " " + strings.Join(args, ",")
}
return op
}