| // Copyright 2025 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 |
| |
| // This file contains some utility functions that can be used to decode |
| // vector instructions into both gnu and plan9 assembly. |
| |
| func implicitMask(instOp Op) bool { |
| switch instOp { |
| case VADC_VIM, VADC_VVM, VADC_VXM, VFMERGE_VFM, VMADC_VIM, VMADC_VVM, |
| VMADC_VXM, VMERGE_VIM, VMERGE_VVM, VMERGE_VXM, VMSBC_VVM, VMSBC_VXM, |
| VSBC_VVM, VSBC_VXM: |
| return true |
| |
| default: |
| return false |
| } |
| } |
| |
| func imaOrFma(instOp Op) bool { |
| switch instOp { |
| case VFMACC_VF, VFMACC_VV, VFMADD_VF, VFMADD_VV, VFMSAC_VF, VFMSAC_VV, |
| VFMSUB_VF, VFMSUB_VV, VFNMACC_VF, VFNMACC_VV, VFNMADD_VF, VFNMADD_VV, |
| VFNMSAC_VF, VFNMSAC_VV, VFNMSUB_VF, VFNMSUB_VV, VFWMACC_VF, VFWMACC_VV, |
| VFWMSAC_VF, VFWMSAC_VV, VFWNMACC_VF, VFWNMACC_VV, VFWNMSAC_VF, |
| VFWNMSAC_VV, VMACC_VV, VMACC_VX, VMADD_VV, VMADD_VX, VNMSAC_VV, |
| VNMSAC_VX, VNMSUB_VV, VNMSUB_VX, VWMACCSU_VV, VWMACCSU_VX, VWMACCUS_VX, |
| VWMACCU_VV, VWMACCU_VX, VWMACC_VV, VWMACC_VX: |
| return true |
| |
| default: |
| return false |
| } |
| } |
| |
| func pseudoRVVLoad(instOp Op) string { |
| switch instOp { |
| case VL1RE8_V: |
| return "VL1R.V" |
| |
| case VL2RE8_V: |
| return "VL2R.V" |
| |
| case VL4RE8_V: |
| return "VL4R.V" |
| |
| case VL8RE8_V: |
| return "VL8R.V" |
| } |
| |
| return "" |
| } |
| |
| func pseudoRVVArith(instOp Op, rawArgs []Arg, args []string) (string, []string) { |
| var op string |
| |
| switch instOp { |
| case VRSUB_VX: |
| if v, ok := rawArgs[1].(Reg); ok && v == X0 { |
| op = "VNEG.V" |
| args = append(args[:1], args[2:]...) |
| } |
| |
| case VWADD_VX: |
| if v, ok := rawArgs[1].(Reg); ok && v == X0 { |
| op = "VWCVT.X.X.V" |
| args = append(args[:1], args[2:]...) |
| } |
| |
| case VWADDU_VX: |
| if v, ok := rawArgs[1].(Reg); ok && v == X0 { |
| op = "VWCVTU.X.X.V" |
| args = append(args[:1], args[2:]...) |
| } |
| |
| case VXOR_VI: |
| if v, ok := rawArgs[1].(Simm); ok && v.Imm == -1 { |
| op = "VNOT.V" |
| args = append(args[:1], args[2:]...) |
| } |
| |
| case VNSRL_WX: |
| if v, ok := rawArgs[1].(Reg); ok && v == X0 { |
| op = "VNCVT.X.X.W" |
| args = append(args[:1], args[2:]...) |
| } |
| |
| case VFSGNJN_VV: |
| vs2, ok1 := rawArgs[0].(Reg) |
| vs1, ok2 := rawArgs[1].(Reg) |
| if ok1 && ok2 && vs1 == vs2 { |
| op = "VFNEG.V" |
| args = args[1:] |
| } |
| |
| case VFSGNJX_VV: |
| vs2, ok1 := rawArgs[0].(Reg) |
| vs1, ok2 := rawArgs[1].(Reg) |
| if ok1 && ok2 && vs1 == vs2 { |
| op = "VFABS.V" |
| args = args[1:] |
| } |
| |
| case VMAND_MM: |
| vs2, ok1 := rawArgs[0].(Reg) |
| vs1, ok2 := rawArgs[1].(Reg) |
| if ok1 && ok2 && vs1 == vs2 { |
| op = "VMMV.M" |
| args = args[1:] |
| } |
| |
| case VMXOR_MM: |
| vs2, ok1 := rawArgs[0].(Reg) |
| vs1, ok2 := rawArgs[1].(Reg) |
| vd, ok3 := rawArgs[2].(Reg) |
| if ok1 && ok2 && ok3 && vs1 == vs2 && vd == vs1 { |
| op = "VMCLR.M" |
| args = args[2:] |
| } |
| |
| case VMXNOR_MM: |
| vs2, ok1 := rawArgs[0].(Reg) |
| vs1, ok2 := rawArgs[1].(Reg) |
| vd, ok3 := rawArgs[2].(Reg) |
| if ok1 && ok2 && ok3 && vs1 == vs2 && vd == vs1 { |
| op = "VMSET.M" |
| args = args[2:] |
| } |
| |
| case VMNAND_MM: |
| vs2, ok1 := rawArgs[0].(Reg) |
| vs1, ok2 := rawArgs[1].(Reg) |
| if ok1 && ok2 && vs1 == vs2 { |
| op = "VMNOT.M" |
| args = args[1:] |
| } |
| } |
| |
| return op, args |
| } |