golang.org/x/arch@v0.17.0/riscv64/riscv64asm/gnu.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 riscv64asm 6 7 import ( 8 "strings" 9 ) 10 11 // GNUSyntax returns the GNU assembler syntax for the instruction, as defined by GNU binutils. 12 // This form typically matches the syntax defined in the RISC-V Instruction Set Manual. See 13 // https://github.com/riscv/riscv-isa-manual/releases/download/Ratified-IMAFDQC/riscv-spec-20191213.pdf 14 func GNUSyntax(inst Inst) string { 15 op := strings.ToLower(inst.Op.String()) 16 var args []string 17 for _, a := range inst.Args { 18 if a == nil { 19 break 20 } 21 args = append(args, strings.ToLower(a.String())) 22 } 23 24 switch inst.Op { 25 case ADDI, ADDIW, ANDI, ORI, SLLI, SLLIW, SRAI, SRAIW, SRLI, SRLIW, XORI: 26 if inst.Op == ADDI { 27 if inst.Args[1].(Reg) == X0 && inst.Args[0].(Reg) != X0 { 28 op = "li" 29 args[1] = args[2] 30 args = args[:len(args)-1] 31 break 32 } 33 34 if inst.Args[2].(Simm).Imm == 0 { 35 if inst.Args[0].(Reg) == X0 && inst.Args[1].(Reg) == X0 { 36 op = "nop" 37 args = nil 38 } else { 39 op = "mv" 40 args = args[:len(args)-1] 41 } 42 } 43 } 44 45 if inst.Op == ANDI && inst.Args[2].(Simm).Imm == 255 { 46 op = "zext.b" 47 args = args[:len(args)-1] 48 } 49 50 if inst.Op == ADDIW && inst.Args[2].(Simm).Imm == 0 { 51 op = "sext.w" 52 args = args[:len(args)-1] 53 } 54 55 if inst.Op == XORI && inst.Args[2].(Simm).String() == "-1" { 56 op = "not" 57 args = args[:len(args)-1] 58 } 59 60 case ADD: 61 if inst.Args[1].(Reg) == X0 { 62 op = "mv" 63 args[1] = args[2] 64 args = args[:len(args)-1] 65 } 66 67 case BEQ: 68 if inst.Args[1].(Reg) == X0 { 69 op = "beqz" 70 args[1] = args[2] 71 args = args[:len(args)-1] 72 } 73 74 case BGE: 75 if inst.Args[1].(Reg) == X0 { 76 op = "bgez" 77 args[1] = args[2] 78 args = args[:len(args)-1] 79 } else if inst.Args[0].(Reg) == X0 { 80 op = "blez" 81 args[0], args[1] = args[1], args[2] 82 args = args[:len(args)-1] 83 } 84 85 case BLT: 86 if inst.Args[1].(Reg) == X0 { 87 op = "bltz" 88 args[1] = args[2] 89 args = args[:len(args)-1] 90 } else if inst.Args[0].(Reg) == X0 { 91 op = "bgtz" 92 args[0], args[1] = args[1], args[2] 93 args = args[:len(args)-1] 94 } 95 96 case BNE: 97 if inst.Args[1].(Reg) == X0 { 98 op = "bnez" 99 args[1] = args[2] 100 args = args[:len(args)-1] 101 } 102 103 case CSRRC: 104 if inst.Args[0].(Reg) == X0 { 105 op = "csrc" 106 args[0], args[1] = args[1], args[2] 107 args = args[:len(args)-1] 108 } 109 110 case CSRRCI: 111 if inst.Args[0].(Reg) == X0 { 112 op = "csrci" 113 args[0], args[1] = args[1], args[2] 114 args = args[:len(args)-1] 115 } 116 117 case CSRRS: 118 if inst.Args[2].(Reg) == X0 { 119 switch inst.Args[1].(CSR) { 120 case FCSR: 121 op = "frcsr" 122 args = args[:len(args)-2] 123 124 case FFLAGS: 125 op = "frflags" 126 args = args[:len(args)-2] 127 128 case FRM: 129 op = "frrm" 130 args = args[:len(args)-2] 131 132 // rdcycleh, rdinstreth and rdtimeh are RV-32 only instructions. 133 // So not included there. 134 case CYCLE: 135 op = "rdcycle" 136 args = args[:len(args)-2] 137 138 case INSTRET: 139 op = "rdinstret" 140 args = args[:len(args)-2] 141 142 case TIME: 143 op = "rdtime" 144 args = args[:len(args)-2] 145 146 default: 147 op = "csrr" 148 args = args[:len(args)-1] 149 } 150 } else if inst.Args[0].(Reg) == X0 { 151 op = "csrs" 152 args[0], args[1] = args[1], args[2] 153 args = args[:len(args)-1] 154 } 155 156 case CSRRSI: 157 if inst.Args[0].(Reg) == X0 { 158 op = "csrsi" 159 args[0], args[1] = args[1], args[2] 160 args = args[:len(args)-1] 161 } 162 163 case CSRRW: 164 switch inst.Args[1].(CSR) { 165 case FCSR: 166 op = "fscsr" 167 if inst.Args[0].(Reg) == X0 { 168 args[0] = args[2] 169 args = args[:len(args)-2] 170 } else { 171 args[1] = args[2] 172 args = args[:len(args)-1] 173 } 174 175 case FFLAGS: 176 op = "fsflags" 177 if inst.Args[0].(Reg) == X0 { 178 args[0] = args[2] 179 args = args[:len(args)-2] 180 } else { 181 args[1] = args[2] 182 args = args[:len(args)-1] 183 } 184 185 case FRM: 186 op = "fsrm" 187 if inst.Args[0].(Reg) == X0 { 188 args[0] = args[2] 189 args = args[:len(args)-2] 190 } else { 191 args[1] = args[2] 192 args = args[:len(args)-1] 193 } 194 195 case CYCLE: 196 if inst.Args[0].(Reg) == X0 && inst.Args[2].(Reg) == X0 { 197 op = "unimp" 198 args = nil 199 } 200 201 default: 202 if inst.Args[0].(Reg) == X0 { 203 op = "csrw" 204 args[0], args[1] = args[1], args[2] 205 args = args[:len(args)-1] 206 } 207 } 208 209 case CSRRWI: 210 if inst.Args[0].(Reg) == X0 { 211 op = "csrwi" 212 args[0], args[1] = args[1], args[2] 213 args = args[:len(args)-1] 214 } 215 216 // When both pred and succ equals to iorw, the GNU objdump will omit them. 217 case FENCE: 218 if inst.Args[0].(MemOrder).String() == "iorw" && 219 inst.Args[1].(MemOrder).String() == "iorw" { 220 args = nil 221 } 222 223 case FSGNJX_D: 224 if inst.Args[1].(Reg) == inst.Args[2].(Reg) { 225 op = "fabs.d" 226 args = args[:len(args)-1] 227 } 228 229 case FSGNJX_S: 230 if inst.Args[1].(Reg) == inst.Args[2].(Reg) { 231 op = "fabs.s" 232 args = args[:len(args)-1] 233 } 234 235 case FSGNJ_D: 236 if inst.Args[1].(Reg) == inst.Args[2].(Reg) { 237 op = "fmv.d" 238 args = args[:len(args)-1] 239 } 240 241 case FSGNJ_S: 242 if inst.Args[1].(Reg) == inst.Args[2].(Reg) { 243 op = "fmv.s" 244 args = args[:len(args)-1] 245 } 246 247 case FSGNJN_D: 248 if inst.Args[1].(Reg) == inst.Args[2].(Reg) { 249 op = "fneg.d" 250 args = args[:len(args)-1] 251 } 252 253 case FSGNJN_S: 254 if inst.Args[1].(Reg) == inst.Args[2].(Reg) { 255 op = "fneg.s" 256 args = args[:len(args)-1] 257 } 258 259 case JAL: 260 if inst.Args[0].(Reg) == X0 { 261 op = "j" 262 args[0] = args[1] 263 args = args[:len(args)-1] 264 } else if inst.Args[0].(Reg) == X1 { 265 op = "jal" 266 args[0] = args[1] 267 args = args[:len(args)-1] 268 } 269 270 case JALR: 271 if inst.Args[0].(Reg) == X1 && inst.Args[1].(RegOffset).Ofs.Imm == 0 { 272 args[0] = inst.Args[1].(RegOffset).OfsReg.String() 273 args = args[:len(args)-1] 274 } 275 276 if inst.Args[0].(Reg) == X0 { 277 if inst.Args[1].(RegOffset).OfsReg == X1 && inst.Args[1].(RegOffset).Ofs.Imm == 0 { 278 op = "ret" 279 args = nil 280 } else if inst.Args[1].(RegOffset).Ofs.Imm == 0 { 281 op = "jr" 282 args[0] = inst.Args[1].(RegOffset).OfsReg.String() 283 args = args[:len(args)-1] 284 } else { 285 op = "jr" 286 args[0] = inst.Args[1].(RegOffset).String() 287 args = args[:len(args)-1] 288 } 289 } 290 291 case SLTIU: 292 if inst.Args[2].(Simm).String() == "1" { 293 op = "seqz" 294 args = args[:len(args)-1] 295 } 296 297 case SLT: 298 if inst.Args[1].(Reg) == X0 { 299 op = "sgtz" 300 args[1] = args[2] 301 args = args[:len(args)-1] 302 } else if inst.Args[2].(Reg) == X0 { 303 op = "sltz" 304 args = args[:len(args)-1] 305 } 306 307 case SLTU: 308 if inst.Args[1].(Reg) == X0 { 309 op = "snez" 310 args[1] = args[2] 311 args = args[:len(args)-1] 312 } 313 314 case SUB: 315 if inst.Args[1].(Reg) == X0 { 316 op = "neg" 317 args[1] = args[2] 318 args = args[:len(args)-1] 319 } 320 321 case SUBW: 322 if inst.Args[1].(Reg) == X0 { 323 op = "negw" 324 args[1] = args[2] 325 args = args[:len(args)-1] 326 } 327 } 328 329 if args != nil { 330 op += " " + strings.Join(args, ",") 331 } 332 return op 333 }