329 lines
6.6 KiB
Go
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
|
|
}
|