diff --git a/asm/riscv_assemble.go b/asm/riscv_assemble.go index ecfe8ff..9d9c59d 100644 --- a/asm/riscv_assemble.go +++ b/asm/riscv_assemble.go @@ -3560,7 +3560,28 @@ func rvcCB(funct3, rs1 uint32, off int32) uint16 { // the vector mnemonics. func encodeRISCVVector(mnem string, ops []*ast.Operand) ([]byte, bool, error) { reg := regFromOperand + // The general vector load and store families: unit, constant-stride and + // indexed, with and without segments, the fault-only-first loads and the + // whole-register moves. riscvIsVecLS parses the mnemonic. + if riscvIsVecLS(mnem) { + return encodeRISCVVecLS(mnem, ops) + } switch mnem { + case "VSETVL": + // INSTR rs2, rs1, rd: the register form of the configuration + // setting. The toolchain writes funct7 0x40 above the standard + // fields, its own disambiguator against the immediate forms. + if len(ops) != 3 { + return nil, true, fmt.Errorf("%s expects 3 operands, got %d", mnem, len(ops)) + } + rs2 := reg(ops[0]) + rs1 := reg(ops[1]) + rd := reg(ops[2]) + if rs1 < 0 || rs2 < 0 || rd < 0 { + return nil, true, fmt.Errorf("%s: invalid register", mnem) + } + return wordLE(riscvRType(riscvEnc{0x57, 0x7, 0x40}, rd, rs1, rs2)), true, nil + case "VSETVLI", "VSETIVLI": // INSTR avl, vsew, vlmul, vta, vma, rd. if len(ops) != 6 { @@ -3616,60 +3637,6 @@ func encodeRISCVVector(mnem string, ops []*ast.Operand) ([]byte, bool, error) { ivli := mnem == "VSETIVLI" || isImmOperand(ops[0]) return wordLE(riscvVSetEnc(ivli, avl, riscvVType(vsew, vlmul, vta, vma), rd)), true, nil - case "VLE8V": - // Unit-stride load: INSTR (base), vd. - if len(ops) != 2 { - return nil, true, fmt.Errorf("%s expects 2 operands, got %d", mnem, len(ops)) - } - rs1, ok := riscvVecMem(ops[0]) - if !ok { - return nil, true, fmt.Errorf("%s: invalid memory operand", mnem) - } - vd := reg(ops[1]) - if vd < 0 { - return nil, true, fmt.Errorf("%s: invalid vector register", mnem) - } - return wordLE(riscvVLSType(0x07, 0, 0, 0, 0, rs1, vd)), true, nil - - case "VSE8V", "VSE32V": - // Unit-stride store: INSTR vs3, (base). - if len(ops) != 2 { - return nil, true, fmt.Errorf("%s expects 2 operands, got %d", mnem, len(ops)) - } - vs3 := reg(ops[0]) - rs1, ok := riscvVecMem(ops[1]) - if !ok { - return nil, true, fmt.Errorf("%s: invalid memory operand", mnem) - } - if vs3 < 0 { - return nil, true, fmt.Errorf("%s: invalid vector register", mnem) - } - width := 0 - if mnem == "VSE32V" { - width = 6 - } - return wordLE(riscvVLSType(0x27, 0, 0, width, 0, rs1, vs3)), true, nil - - case "VLSSEG4E32V", "VLSSEG8E32V": - // Constant-stride segmented load: INSTR (base), stride, vd. - if len(ops) != 3 { - return nil, true, fmt.Errorf("%s expects 3 operands, got %d", mnem, len(ops)) - } - rs1, ok := riscvVecMem(ops[0]) - if !ok { - return nil, true, fmt.Errorf("%s: invalid memory operand", mnem) - } - rs2 := reg(ops[1]) - vd := reg(ops[2]) - if rs2 < 0 || vd < 0 { - return nil, true, fmt.Errorf("%s: invalid register operand", mnem) - } - nf := 3 // 4 fields - if mnem == "VLSSEG8E32V" { - nf = 7 // 8 fields - } - return wordLE(riscvVLSType(0x07, nf, 2, 6, int32(rs2), rs1, vd)), true, nil - case "VADDVV", "VXORVV", "VMSNEVV": // Vector-vector: INSTR vs1, vs2, vd. if len(ops) != 3 { @@ -3781,6 +3748,230 @@ func riscvVecMem(op *ast.Operand) (rs1 int, ok bool) { return rs1, rs1 >= 0 } +// riscvVecLS is one parsed vector load/store mnemonic: the direction, the +// field counts and the fixed rs2 content (0 for plain forms, the +// fault-only-first marker, the mask pair's 11 or the whole-register marker). +type riscvVecLS struct { + load bool // true for the VL families, false for the VS families + nf int // segment count minus one + mop int // 0 unit, 1 indexed-ux, 2 constant-stride, 3 indexed-ox + width int // 0 = 8-bit, 5 = 16-bit, 6 = 32-bit, 7 = 64-bit + ff bool // fault-only-first: the fixed rs2 field carries 16 + rs2f int // fixed rs2 field: the whole-register and mask markers +} + +// riscvVecWidths maps the width segment of a vector load/store name onto the +// instruction's width field. +var riscvVecWidths = map[string]int{"8": 0, "16": 5, "32": 6, "64": 7} + +// riscvParseVecLS parses a vector load/store mnemonic into its fields. The +// families the toolchain spells: the unit, constant-stride and indexed +// accesses (VLE8V, VLSE8V, VLUXEI8V, VLOXEI8V and the stores), each with its +// segment variants (VLSEG2E8V, VLSSEG2E8V, VLUXSEG2EI8V, ...), the +// fault-only-first loads (VLE8FFV, VLSEG2E8FFV), the whole-register moves +// (VL1RV, VL2RE64V, VS8RV) and the bit-mask pair (VLMV, VSMV). +func riscvParseVecLS(m string) (riscvVecLS, bool) { + // The whole-register spellings and the mask pair: exact names. + whole := func(load bool, nf, rs2f int) (riscvVecLS, bool) { + return riscvVecLS{load: load, nf: nf, rs2f: rs2f}, true + } + switch m { + case "VLMV": + return whole(true, 0, 11) + case "VSMV": + return whole(false, 0, 11) + case "VL1RV": + return whole(true, 0, 8) + case "VS1RV": + return whole(false, 0, 8) + case "VL2RV": + return whole(true, 1, 8) + case "VS2RV": + return whole(false, 1, 8) + case "VL4RV": + return whole(true, 3, 8) + case "VS4RV": + return whole(false, 3, 8) + case "VL8RV": + return whole(true, 7, 8) + case "VS8RV": + return whole(false, 7, 8) + } + // VL{n}RE{w}V: the whole-register loads with an explicit width; the + // encoding is the width-less spelling's with the width field filled. + if len(m) >= 7 && m[1] == 'L' && m[2] >= '1' && m[2] <= '8' && m[3:5] == "RE" && strings.HasSuffix(m, "V") { + n := int(m[2] - '0') + w, ok := riscvParseVecLSWidth(m[5 : len(m)-1]) + if !ok { + return riscvVecLS{}, false + } + rs2f := 8 + return riscvVecLS{load: true, nf: n - 1, width: w, rs2f: rs2f}, true + } + if len(m) < 4 || m[0] != 'V' || (m[1] != 'L' && m[1] != 'S') { + return riscvVecLS{}, false + } + v := riscvVecLS{load: m[1] == 'L'} + rest := m[2:] + // The segment families carry the count: SEGE, SSEGE, UXSEGEI, + // OXSEGEI. + for _, fam := range []struct { + prefix string + mop int + ei bool + }{ + {"SSEG", 2, false}, + {"UXSEG", 1, true}, + {"OXSEG", 3, true}, + {"SEG", 0, false}, + } { + if !strings.HasPrefix(rest, fam.prefix) { + continue + } + tail := rest[len(fam.prefix):] + if len(tail) < 3 || tail[0] < '2' || tail[0] > '8' || tail[1] != 'E' { + return riscvVecLS{}, false + } + v.nf = int(tail[0] - '0') + v.nf-- // the field is the count minus one + tail = tail[2:] + if fam.ei { + if !strings.HasPrefix(tail, "I") { + return riscvVecLS{}, false + } + tail = tail[1:] + } + v.mop = fam.mop + rest = tail + break + } + if v.nf == 0 { + // The flat families: SEV, UXEIV, OXEIV, EV. + switch { + case strings.HasPrefix(rest, "SE"): + v.mop = 2 + rest = rest[2:] + case strings.HasPrefix(rest, "UXEI"): + v.mop = 1 + rest = rest[4:] + case strings.HasPrefix(rest, "OXEI"): + v.mop = 3 + rest = rest[4:] + case strings.HasPrefix(rest, "E"): + rest = rest[1:] + default: + return riscvVecLS{}, false + } + } + // The tail: V, or FFV on the fault-only-first loads. + ff := false + if strings.HasSuffix(rest, "FFV") { + ff = v.load + rest = rest[:len(rest)-3] + } else if strings.HasSuffix(rest, "V") { + rest = rest[:len(rest)-1] + } else { + return riscvVecLS{}, false + } + w, ok := riscvParseVecLSWidth(rest) + if !ok { + return riscvVecLS{}, false + } + v.width = w + v.ff = ff + if ff { + v.rs2f = 16 + } + return v, true +} + +// riscvParseVecLSWidth parses a vector width segment ("8", "16", "32", "64") +// onto its width field. The second result reports whether the text is a +// width the families carry. +func riscvParseVecLSWidth(s string) (int, bool) { + w, ok := riscvVecWidths[s] + return w, ok +} + +// riscvIsVecLS reports whether m is one of the vector load/store mnemonics +// encodeRISCVVecLS handles. +func riscvIsVecLS(m string) bool { + _, ok := riscvParseVecLS(m) + return ok +} + +// encodeRISCVVecLS encodes one vector load or store. The operand shapes are +// the toolchain's: (base), vd for the unit loads; (base), rs2|vs2 [, V0], vd +// for the stride, indexed and segment forms with their optional V0 mask; +// stores mirror them with vs3 first and (base) last. +func encodeRISCVVecLS(mnem string, ops []*ast.Operand) ([]byte, bool, error) { + v, ok := riscvParseVecLS(mnem) + if !ok { + return nil, true, fmt.Errorf("unsupported vector load/store %q", mnem) + } + op := uint32(0x27) + if v.load { + op = 0x07 + } + strided := v.mop == 2 + indexed := v.mop == 1 || v.mop == 3 + whole := v.rs2f == 2 || v.rs2f == 8 + + // Split the operands: the memory end fixes one operand, the register end + // the other, and a V0 beside the register end is the mask. + memIdx, regIdx := 0, len(ops)-1 + if !v.load { + memIdx, regIdx = len(ops)-1, 0 + } + rs1, ok := riscvVecMem(ops[memIdx]) + if !ok { + return nil, true, fmt.Errorf("%s: invalid memory operand", mnem) + } + vd := regFromOperand(ops[regIdx]) + if vd < 0 { + kind := "vd" + if !v.load { + kind = "vs1" + } + return nil, true, fmt.Errorf("%s: expected vector register in %s position", mnem, kind) + } + rs2 := v.rs2f + masked := false + for _, mid := range ops[min(memIdx, regIdx)+1 : max(memIdx, regIdx)] { + // The mask operand is the vector register V0: name-checked, so an + // integer X0 in the stride position is not mistaken for it. + if regFromOperand(mid) == 0 && strings.HasPrefix(strings.ToUpper(mid.Raw), "V") { + masked = true + continue + } + if !strided && !indexed { + return nil, true, fmt.Errorf("%s: too many operands for instruction", mnem) + } + if rs2 != v.rs2f { + return nil, true, fmt.Errorf("%s: too many operands for instruction", mnem) + } + rs2 = regFromOperand(mid) + if rs2 < 0 { + return nil, true, fmt.Errorf("%s: invalid register operand", mnem) + } + if indexed && strings.HasPrefix(strings.ToUpper(mid.Raw), "X") { + return nil, true, fmt.Errorf("%s: expected vector register in vs2 position", mnem) + } + if strided && !strings.HasPrefix(strings.ToUpper(mid.Raw), "X") { + return nil, true, fmt.Errorf("%s: expected integer register in rs2 position", mnem) + } + } + if masked && whole { + return nil, true, fmt.Errorf("%s: too many operands for instruction", mnem) + } + word := uint32(v.nf&7)<<29 | uint32(v.mop&3)<<26 | uint32(rs2&0x1F)<<20 | + uint32(rs1&0x1F)<<15 | uint32(v.width&7)<<12 | uint32(vd&0x1F)<<7 | op + if !masked { + word |= 1 << 25 + } + return wordLE(word), true, nil +} + // Instruction type classifiers. func isRTypeInstr(m string) bool { switch m { diff --git a/asm/riscv_vector_test.go b/asm/riscv_vector_test.go new file mode 100644 index 0000000..8b8ce9a --- /dev/null +++ b/asm/riscv_vector_test.go @@ -0,0 +1,660 @@ +// Copyright (c) 2026 Petr Balvín (https://petrbalvin.org) +// SPDX-License-Identifier: BSD-3-Clause + +package asm + +import ( + "os" + "path/filepath" + "testing" +) + +// TestRISCVVectorLS_Differential proves the vector load/store families and +// the configuration settings against the toolchain: the "V" extension's +// memory section of the toolchain's own testdata (unit, constant-stride and +// indexed accesses with their segments, the fault-only-first loads, the +// whole-register moves and the mask pair, every masked and unmasked form) +// assembled by gasm and by go tool asm must agree word for word. +func TestRISCVVectorLS_Differential(t *testing.T) { + src := `#include "textflag.h" + +TEXT ·vecls(SB), NOSPLIT, $0 + + VSETVLI X10, E8, M1, TU, MU, X12 + VSETVLI X10, E16, M1, TU, MU, X12 + VSETVLI X10, E32, M1, TU, MU, X12 + VSETVLI X10, E64, M1, TU, MU, X12 + VSETVLI X10, E32, M1, TU, MA, X12 + VSETVLI X10, E32, M1, TA, MA, X12 + VSETVLI X10, E32, M2, TA, MA, X12 + VSETVLI X10, E32, M4, TA, MA, X12 + VSETVLI X10, E32, M8, TA, MA, X12 + VSETVLI X10, E32, MF8, TA, MA, X12 + VSETVLI X10, E32, MF4, TA, MA, X12 + VSETVLI X10, E32, MF2, TA, MA, X12 + VSETVLI X10, E32, M1, TA, MA, X12 + VSETVLI $15, E32, M1, TA, MA, X12 + VSETIVLI $0, E32, M1, TA, MA, X12 + VSETIVLI $15, E32, M1, TA, MA, X12 + VSETIVLI $31, E32, M1, TA, MA, X12 + VSETVL X10, X11, X12 + + VLE8V (X10), V3 + VLE8V (X10), V0, V3 + VLE16V (X10), V3 + VLE16V (X10), V0, V3 + VLE32V (X10), V3 + VLE32V (X10), V0, V3 + VLE64V (X10), V3 + VLE64V (X10), V0, V3 + VSE8V V3, (X10) + VSE8V V3, V0, (X10) + VSE16V V3, (X10) + VSE16V V3, V0, (X10) + VSE32V V3, (X10) + VSE32V V3, V0, (X10) + VSE64V V3, (X10) + VSE64V V3, V0, (X10) + VLMV (X10), V3 + VSMV V3, (X10) + + VLSE8V (X10), X11, V3 + VLSE8V (X10), X11, V0, V3 + VLSE16V (X10), X11, V3 + VLSE16V (X10), X11, V0, V3 + VLSE32V (X10), X11, V3 + VLSE32V (X10), X11, V0, V3 + VLSE64V (X10), X11, V3 + VLSE64V (X10), X11, V0, V3 + VSSE8V V3, X11, (X10) + VSSE8V V3, X11, V0, (X10) + VSSE16V V3, X11, (X10) + VSSE16V V3, X11, V0, (X10) + VSSE32V V3, X11, (X10) + VSSE32V V3, X11, V0, (X10) + VSSE64V V3, X11, (X10) + VSSE64V V3, X11, V0, (X10) + + VLUXEI8V (X10), V2, V3 + VLUXEI8V (X10), V2, V0, V3 + VLUXEI16V (X10), V2, V3 + VLUXEI16V (X10), V2, V0, V3 + VLUXEI32V (X10), V2, V3 + VLUXEI32V (X10), V2, V0, V3 + VLUXEI64V (X10), V2, V3 + VLUXEI64V (X10), V2, V0, V3 + VLOXEI8V (X10), V2, V3 + VLOXEI8V (X10), V2, V0, V3 + VLOXEI16V (X10), V2, V3 + VLOXEI16V (X10), V2, V0, V3 + VLOXEI32V (X10), V2, V3 + VLOXEI32V (X10), V2, V0, V3 + VLOXEI64V (X10), V2, V3 + VLOXEI64V (X10), V2, V0, V3 + VSUXEI8V V3, V2, (X10) + VSUXEI8V V3, V2, V0, (X10) + VSUXEI16V V3, V2, (X10) + VSUXEI16V V3, V2, V0, (X10) + VSUXEI32V V3, V2, (X10) + VSUXEI32V V3, V2, V0, (X10) + VSUXEI64V V3, V2, (X10) + VSUXEI64V V3, V2, V0, (X10) + VSOXEI8V V3, V2, (X10) + VSOXEI8V V3, V2, V0, (X10) + VSOXEI16V V3, V2, (X10) + VSOXEI16V V3, V2, V0, (X10) + VSOXEI32V V3, V2, (X10) + VSOXEI32V V3, V2, V0, (X10) + VSOXEI64V V3, V2, (X10) + VSOXEI64V V3, V2, V0, (X10) + + VLE8FFV (X10), V8 + VLE16FFV (X10), V8 + VLE32FFV (X10), V8 + VLE64FFV (X10), V8 + VLE8FFV (X10), V0, V8 + VLE16FFV (X10), V0, V8 + VLE32FFV (X10), V0, V8 + VLE64FFV (X10), V0, V8 + + VLSEG2E8V (X10), V8 + VLSEG2E16V (X10), V8 + VLSEG2E32V (X10), V8 + VLSEG2E64V (X10), V8 + VLSEG2E8V (X10), V0, V8 + VLSEG2E16V (X10), V0, V8 + VLSEG2E32V (X10), V0, V8 + VLSEG2E64V (X10), V0, V8 + VLSEG3E8V (X10), V8 + VLSEG3E16V (X10), V8 + VLSEG3E32V (X10), V8 + VLSEG3E64V (X10), V8 + VLSEG3E8V (X10), V0, V8 + VLSEG3E16V (X10), V0, V8 + VLSEG3E32V (X10), V0, V8 + VLSEG3E64V (X10), V0, V8 + VLSEG4E8V (X10), V8 + VLSEG4E16V (X10), V8 + VLSEG4E32V (X10), V8 + VLSEG4E64V (X10), V8 + VLSEG4E8V (X10), V0, V8 + VLSEG4E16V (X10), V0, V8 + VLSEG4E32V (X10), V0, V8 + VLSEG4E64V (X10), V0, V8 + VLSEG5E8V (X10), V8 + VLSEG5E16V (X10), V8 + VLSEG5E32V (X10), V8 + VLSEG5E64V (X10), V8 + VLSEG5E8V (X10), V0, V8 + VLSEG5E16V (X10), V0, V8 + VLSEG5E32V (X10), V0, V8 + VLSEG5E64V (X10), V0, V8 + VLSEG6E8V (X10), V8 + VLSEG6E16V (X10), V8 + VLSEG6E32V (X10), V8 + VLSEG6E64V (X10), V8 + VLSEG6E8V (X10), V0, V8 + VLSEG6E16V (X10), V0, V8 + VLSEG6E32V (X10), V0, V8 + VLSEG6E64V (X10), V0, V8 + VLSEG7E8V (X10), V8 + VLSEG7E16V (X10), V8 + VLSEG7E32V (X10), V8 + VLSEG7E64V (X10), V8 + VLSEG7E8V (X10), V0, V8 + VLSEG7E16V (X10), V0, V8 + VLSEG7E32V (X10), V0, V8 + VLSEG7E64V (X10), V0, V8 + VLSEG8E8V (X10), V8 + VLSEG8E16V (X10), V8 + VLSEG8E32V (X10), V8 + VLSEG8E64V (X10), V8 + VLSEG8E8V (X10), V0, V8 + VLSEG8E16V (X10), V0, V8 + VLSEG8E32V (X10), V0, V8 + VLSEG8E64V (X10), V0, V8 + VSSEG2E8V V24, (X10) + VSSEG2E16V V24, (X10) + VSSEG2E32V V24, (X10) + VSSEG2E64V V24, (X10) + VSSEG2E8V V24, V0, (X10) + VSSEG2E16V V24, V0, (X10) + VSSEG2E32V V24, V0, (X10) + VSSEG2E64V V24, V0, (X10) + VSSEG3E8V V24, (X10) + VSSEG3E16V V24, (X10) + VSSEG3E32V V24, (X10) + VSSEG3E64V V24, (X10) + VSSEG3E8V V24, V0, (X10) + VSSEG3E16V V24, V0, (X10) + VSSEG3E32V V24, V0, (X10) + VSSEG3E64V V24, V0, (X10) + VSSEG4E8V V24, (X10) + VSSEG4E16V V24, (X10) + VSSEG4E32V V24, (X10) + VSSEG4E64V V24, (X10) + VSSEG4E8V V24, V0, (X10) + VSSEG4E16V V24, V0, (X10) + VSSEG4E32V V24, V0, (X10) + VSSEG4E64V V24, V0, (X10) + VSSEG5E8V V24, (X10) + VSSEG5E16V V24, (X10) + VSSEG5E32V V24, (X10) + VSSEG5E64V V24, (X10) + VSSEG5E8V V24, V0, (X10) + VSSEG5E16V V24, V0, (X10) + VSSEG5E32V V24, V0, (X10) + VSSEG5E64V V24, V0, (X10) + VSSEG6E8V V24, (X10) + VSSEG6E16V V24, (X10) + VSSEG6E32V V24, (X10) + VSSEG6E64V V24, (X10) + VSSEG6E8V V24, V0, (X10) + VSSEG6E16V V24, V0, (X10) + VSSEG6E32V V24, V0, (X10) + VSSEG6E64V V24, V0, (X10) + VSSEG7E8V V24, (X10) + VSSEG7E16V V24, (X10) + VSSEG7E32V V24, (X10) + VSSEG7E64V V24, (X10) + VSSEG7E8V V24, V0, (X10) + VSSEG7E16V V24, V0, (X10) + VSSEG7E32V V24, V0, (X10) + VSSEG7E64V V24, V0, (X10) + VSSEG8E8V V24, (X10) + VSSEG8E16V V24, (X10) + VSSEG8E32V V24, (X10) + VSSEG8E64V V24, (X10) + VSSEG8E8V V24, V0, (X10) + VSSEG8E16V V24, V0, (X10) + VSSEG8E32V V24, V0, (X10) + VSSEG8E64V V24, V0, (X10) + VLSEG2E8FFV (X10), V8 + VLSEG2E16FFV (X10), V8 + VLSEG2E32FFV (X10), V8 + VLSEG2E64FFV (X10), V8 + VLSEG2E8FFV (X10), V0, V8 + VLSEG2E16FFV (X10), V0, V8 + VLSEG2E32FFV (X10), V0, V8 + VLSEG2E64FFV (X10), V0, V8 + VLSEG3E8FFV (X10), V8 + VLSEG3E16FFV (X10), V8 + VLSEG3E32FFV (X10), V8 + VLSEG3E64FFV (X10), V8 + VLSEG3E8FFV (X10), V0, V8 + VLSEG3E16FFV (X10), V0, V8 + VLSEG3E32FFV (X10), V0, V8 + VLSEG3E64FFV (X10), V0, V8 + VLSEG4E8FFV (X10), V8 + VLSEG4E16FFV (X10), V8 + VLSEG4E32FFV (X10), V8 + VLSEG4E64FFV (X10), V8 + VLSEG4E8FFV (X10), V0, V8 + VLSEG4E16FFV (X10), V0, V8 + VLSEG4E32FFV (X10), V0, V8 + VLSEG4E64FFV (X10), V0, V8 + VLSEG5E8FFV (X10), V8 + VLSEG5E16FFV (X10), V8 + VLSEG5E32FFV (X10), V8 + VLSEG5E64FFV (X10), V8 + VLSEG5E8FFV (X10), V0, V8 + VLSEG5E16FFV (X10), V0, V8 + VLSEG5E32FFV (X10), V0, V8 + VLSEG5E64FFV (X10), V0, V8 + VLSEG6E8FFV (X10), V8 + VLSEG6E16FFV (X10), V8 + VLSEG6E32FFV (X10), V8 + VLSEG6E64FFV (X10), V8 + VLSEG6E8FFV (X10), V0, V8 + VLSEG6E16FFV (X10), V0, V8 + VLSEG6E32FFV (X10), V0, V8 + VLSEG6E64FFV (X10), V0, V8 + VLSEG7E8FFV (X10), V8 + VLSEG7E16FFV (X10), V8 + VLSEG7E32FFV (X10), V8 + VLSEG7E64FFV (X10), V8 + VLSEG7E8FFV (X10), V0, V8 + VLSEG7E16FFV (X10), V0, V8 + VLSEG7E32FFV (X10), V0, V8 + VLSEG7E64FFV (X10), V0, V8 + VLSEG8E8FFV (X10), V8 + VLSEG8E16FFV (X10), V8 + VLSEG8E32FFV (X10), V8 + VLSEG8E64FFV (X10), V8 + VLSEG8E8FFV (X10), V0, V8 + VLSEG8E16FFV (X10), V0, V8 + VLSEG8E32FFV (X10), V0, V8 + VLSEG8E64FFV (X10), V0, V8 + + VLSSEG2E8V (X10), X11, V8 + VLSSEG2E16V (X10), X11, V8 + VLSSEG2E32V (X10), X11, V8 + VLSSEG2E64V (X10), X11, V8 + VLSSEG2E8V (X10), X11, V0, V8 + VLSSEG2E16V (X10), X11, V0, V8 + VLSSEG2E32V (X10), X11, V0, V8 + VLSSEG2E64V (X10), X11, V0, V8 + VLSSEG3E8V (X10), X11, V8 + VLSSEG3E16V (X10), X11, V8 + VLSSEG3E32V (X10), X11, V8 + VLSSEG3E64V (X10), X11, V8 + VLSSEG3E8V (X10), X11, V0, V8 + VLSSEG3E16V (X10), X11, V0, V8 + VLSSEG3E32V (X10), X11, V0, V8 + VLSSEG3E64V (X10), X11, V0, V8 + VLSSEG4E8V (X10), X11, V8 + VLSSEG4E16V (X10), X11, V8 + VLSSEG4E32V (X10), X11, V8 + VLSSEG4E64V (X10), X11, V8 + VLSSEG4E8V (X10), X11, V0, V8 + VLSSEG4E16V (X10), X11, V0, V8 + VLSSEG4E32V (X10), X11, V0, V8 + VLSSEG4E64V (X10), X11, V0, V8 + VLSSEG5E8V (X10), X11, V8 + VLSSEG5E16V (X10), X11, V8 + VLSSEG5E32V (X10), X11, V8 + VLSSEG5E64V (X10), X11, V8 + VLSSEG5E8V (X10), X11, V0, V8 + VLSSEG5E16V (X10), X11, V0, V8 + VLSSEG5E32V (X10), X11, V0, V8 + VLSSEG5E64V (X10), X11, V0, V8 + VLSSEG6E8V (X10), X11, V8 + VLSSEG6E16V (X10), X11, V8 + VLSSEG6E32V (X10), X11, V8 + VLSSEG6E64V (X10), X11, V8 + VLSSEG6E8V (X10), X11, V0, V8 + VLSSEG6E16V (X10), X11, V0, V8 + VLSSEG6E32V (X10), X11, V0, V8 + VLSSEG6E64V (X10), X11, V0, V8 + VLSSEG7E8V (X10), X11, V8 + VLSSEG7E16V (X10), X11, V8 + VLSSEG7E32V (X10), X11, V8 + VLSSEG7E64V (X10), X11, V8 + VLSSEG7E8V (X10), X11, V0, V8 + VLSSEG7E16V (X10), X11, V0, V8 + VLSSEG7E32V (X10), X11, V0, V8 + VLSSEG7E64V (X10), X11, V0, V8 + VLSSEG8E8V (X10), X11, V8 + VLSSEG8E16V (X10), X11, V8 + VLSSEG8E32V (X10), X11, V8 + VLSSEG8E64V (X10), X11, V8 + VLSSEG8E8V (X10), X11, V0, V8 + VLSSEG8E16V (X10), X11, V0, V8 + VLSSEG8E32V (X10), X11, V0, V8 + VLSSEG8E64V (X10), X11, V0, V8 + VSSSEG2E8V V24, X11, (X10) + VSSSEG2E16V V24, X11, (X10) + VSSSEG2E32V V24, X11, (X10) + VSSSEG2E64V V24, X11, (X10) + VSSSEG2E8V V24, X11, V0, (X10) + VSSSEG2E16V V24, X11, V0, (X10) + VSSSEG2E32V V24, X11, V0, (X10) + VSSSEG2E64V V24, X11, V0, (X10) + VSSSEG3E8V V24, X11, (X10) + VSSSEG3E16V V24, X11, (X10) + VSSSEG3E32V V24, X11, (X10) + VSSSEG3E64V V24, X11, (X10) + VSSSEG3E8V V24, X11, V0, (X10) + VSSSEG3E16V V24, X11, V0, (X10) + VSSSEG3E32V V24, X11, V0, (X10) + VSSSEG3E64V V24, X11, V0, (X10) + VSSSEG4E8V V24, X11, (X10) + VSSSEG4E16V V24, X11, (X10) + VSSSEG4E32V V24, X11, (X10) + VSSSEG4E64V V24, X11, (X10) + VSSSEG4E8V V24, X11, V0, (X10) + VSSSEG4E16V V24, X11, V0, (X10) + VSSSEG4E32V V24, X11, V0, (X10) + VSSSEG4E64V V24, X11, V0, (X10) + VSSSEG5E8V V24, X11, (X10) + VSSSEG5E16V V24, X11, (X10) + VSSSEG5E32V V24, X11, (X10) + VSSSEG5E64V V24, X11, (X10) + VSSSEG5E8V V24, X11, V0, (X10) + VSSSEG5E16V V24, X11, V0, (X10) + VSSSEG5E32V V24, X11, V0, (X10) + VSSSEG5E64V V24, X11, V0, (X10) + VSSSEG6E8V V24, X11, (X10) + VSSSEG6E16V V24, X11, (X10) + VSSSEG6E32V V24, X11, (X10) + VSSSEG6E64V V24, X11, (X10) + VSSSEG6E8V V24, X11, V0, (X10) + VSSSEG6E16V V24, X11, V0, (X10) + VSSSEG6E32V V24, X11, V0, (X10) + VSSSEG6E64V V24, X11, V0, (X10) + VSSSEG7E8V V24, X11, (X10) + VSSSEG7E16V V24, X11, (X10) + VSSSEG7E32V V24, X11, (X10) + VSSSEG7E64V V24, X11, (X10) + VSSSEG7E8V V24, X11, V0, (X10) + VSSSEG7E16V V24, X11, V0, (X10) + VSSSEG7E32V V24, X11, V0, (X10) + VSSSEG7E64V V24, X11, V0, (X10) + VSSSEG8E8V V24, X11, (X10) + VSSSEG8E16V V24, X11, (X10) + VSSSEG8E32V V24, X11, (X10) + VSSSEG8E64V V24, X11, (X10) + VSSSEG8E8V V24, X11, V0, (X10) + VSSSEG8E16V V24, X11, V0, (X10) + VSSSEG8E32V V24, X11, V0, (X10) + VSSSEG8E64V V24, X11, V0, (X10) + + VLUXSEG2EI8V (X10), V4, V8 + VLUXSEG2EI16V (X10), V4, V8 + VLUXSEG2EI32V (X10), V4, V8 + VLUXSEG2EI64V (X10), V4, V8 + VLUXSEG2EI8V (X10), V4, V0, V8 + VLUXSEG2EI16V (X10), V4, V0, V8 + VLUXSEG2EI32V (X10), V4, V0, V8 + VLUXSEG2EI64V (X10), V4, V0, V8 + VLUXSEG3EI8V (X10), V4, V8 + VLUXSEG3EI16V (X10), V4, V8 + VLUXSEG3EI32V (X10), V4, V8 + VLUXSEG3EI64V (X10), V4, V8 + VLUXSEG3EI8V (X10), V4, V0, V8 + VLUXSEG3EI16V (X10), V4, V0, V8 + VLUXSEG3EI32V (X10), V4, V0, V8 + VLUXSEG3EI64V (X10), V4, V0, V8 + VLUXSEG4EI8V (X10), V4, V8 + VLUXSEG4EI16V (X10), V4, V8 + VLUXSEG4EI32V (X10), V4, V8 + VLUXSEG4EI64V (X10), V4, V8 + VLUXSEG4EI8V (X10), V4, V0, V8 + VLUXSEG4EI16V (X10), V4, V0, V8 + VLUXSEG4EI32V (X10), V4, V0, V8 + VLUXSEG4EI64V (X10), V4, V0, V8 + VLUXSEG5EI8V (X10), V4, V8 + VLUXSEG5EI16V (X10), V4, V8 + VLUXSEG5EI32V (X10), V4, V8 + VLUXSEG5EI64V (X10), V4, V8 + VLUXSEG5EI8V (X10), V4, V0, V8 + VLUXSEG5EI16V (X10), V4, V0, V8 + VLUXSEG5EI32V (X10), V4, V0, V8 + VLUXSEG5EI64V (X10), V4, V0, V8 + VLUXSEG6EI8V (X10), V4, V8 + VLUXSEG6EI16V (X10), V4, V8 + VLUXSEG6EI32V (X10), V4, V8 + VLUXSEG6EI64V (X10), V4, V8 + VLUXSEG6EI8V (X10), V4, V0, V8 + VLUXSEG6EI16V (X10), V4, V0, V8 + VLUXSEG6EI32V (X10), V4, V0, V8 + VLUXSEG6EI64V (X10), V4, V0, V8 + VLOXSEG6EI8V (X10), V4, V8 + VLOXSEG6EI16V (X10), V4, V8 + VLOXSEG6EI32V (X10), V4, V8 + VLOXSEG6EI64V (X10), V4, V8 + VLOXSEG6EI8V (X10), V4, V0, V8 + VLOXSEG6EI16V (X10), V4, V0, V8 + VLOXSEG6EI32V (X10), V4, V0, V8 + VLOXSEG6EI64V (X10), V4, V0, V8 + VLUXSEG7EI8V (X10), V4, V8 + VLUXSEG7EI16V (X10), V4, V8 + VLUXSEG7EI32V (X10), V4, V8 + VLUXSEG7EI64V (X10), V4, V8 + VLUXSEG7EI8V (X10), V4, V0, V8 + VLUXSEG7EI16V (X10), V4, V0, V8 + VLUXSEG7EI32V (X10), V4, V0, V8 + VLUXSEG7EI64V (X10), V4, V0, V8 + VLUXSEG8EI8V (X10), V4, V8 + VLUXSEG8EI16V (X10), V4, V8 + VLUXSEG8EI32V (X10), V4, V8 + VLUXSEG8EI64V (X10), V4, V8 + VLUXSEG8EI8V (X10), V4, V0, V8 + VLUXSEG8EI16V (X10), V4, V0, V8 + VLUXSEG8EI32V (X10), V4, V0, V8 + VLUXSEG8EI64V (X10), V4, V0, V8 + VSUXSEG2EI8V V24, V4, (X10) + VSUXSEG2EI16V V24, V4, (X10) + VSUXSEG2EI32V V24, V4, (X10) + VSUXSEG2EI64V V24, V4, (X10) + VSUXSEG2EI8V V24, V4, V0, (X10) + VSUXSEG2EI16V V24, V4, V0, (X10) + VSUXSEG2EI32V V24, V4, V0, (X10) + VSUXSEG2EI64V V24, V4, V0, (X10) + VSUXSEG3EI8V V24, V4, (X10) + VSUXSEG3EI16V V24, V4, (X10) + VSUXSEG3EI32V V24, V4, (X10) + VSUXSEG3EI64V V24, V4, (X10) + VSUXSEG3EI8V V24, V4, V0, (X10) + VSUXSEG3EI16V V24, V4, V0, (X10) + VSUXSEG3EI32V V24, V4, V0, (X10) + VSUXSEG3EI64V V24, V4, V0, (X10) + VSUXSEG4EI8V V24, V4, (X10) + VSUXSEG4EI16V V24, V4, (X10) + VSUXSEG4EI32V V24, V4, (X10) + VSUXSEG4EI64V V24, V4, (X10) + VSUXSEG4EI8V V24, V4, V0, (X10) + VSUXSEG4EI16V V24, V4, V0, (X10) + VSUXSEG4EI32V V24, V4, V0, (X10) + VSUXSEG4EI64V V24, V4, V0, (X10) + VSUXSEG5EI8V V24, V4, (X10) + VSUXSEG5EI16V V24, V4, (X10) + VSUXSEG5EI32V V24, V4, (X10) + VSUXSEG5EI64V V24, V4, (X10) + VSUXSEG5EI8V V24, V4, V0, (X10) + VSUXSEG5EI16V V24, V4, V0, (X10) + VSUXSEG5EI32V V24, V4, V0, (X10) + VSUXSEG5EI64V V24, V4, V0, (X10) + VSUXSEG6EI8V V24, V4, (X10) + VSUXSEG6EI16V V24, V4, (X10) + VSUXSEG6EI32V V24, V4, (X10) + VSUXSEG6EI64V V24, V4, (X10) + VSUXSEG6EI8V V24, V4, V0, (X10) + VSUXSEG6EI16V V24, V4, V0, (X10) + VSUXSEG6EI32V V24, V4, V0, (X10) + VSUXSEG6EI64V V24, V4, V0, (X10) + VSUXSEG7EI8V V24, V4, (X10) + VSUXSEG7EI16V V24, V4, (X10) + VSUXSEG7EI32V V24, V4, (X10) + VSUXSEG7EI64V V24, V4, (X10) + VSUXSEG7EI8V V24, V4, V0, (X10) + VSUXSEG7EI16V V24, V4, V0, (X10) + VSUXSEG7EI32V V24, V4, V0, (X10) + VSUXSEG7EI64V V24, V4, V0, (X10) + VSUXSEG8EI8V V24, V4, (X10) + VSUXSEG8EI16V V24, V4, (X10) + VSUXSEG8EI32V V24, V4, (X10) + VSUXSEG8EI64V V24, V4, (X10) + VSUXSEG8EI8V V24, V4, V0, (X10) + VSUXSEG8EI16V V24, V4, V0, (X10) + VSUXSEG8EI32V V24, V4, V0, (X10) + VSUXSEG8EI64V V24, V4, V0, (X10) + VLOXSEG2EI8V (X10), V4, V8 + VLOXSEG2EI16V (X10), V4, V8 + VLOXSEG2EI32V (X10), V4, V8 + VLOXSEG2EI64V (X10), V4, V8 + VLOXSEG2EI8V (X10), V4, V0, V8 + VLOXSEG2EI16V (X10), V4, V0, V8 + VLOXSEG2EI32V (X10), V4, V0, V8 + VLOXSEG2EI64V (X10), V4, V0, V8 + VLOXSEG3EI8V (X10), V4, V8 + VLOXSEG3EI16V (X10), V4, V8 + VLOXSEG3EI32V (X10), V4, V8 + VLOXSEG3EI64V (X10), V4, V8 + VLOXSEG3EI8V (X10), V4, V0, V8 + VLOXSEG3EI16V (X10), V4, V0, V8 + VLOXSEG3EI32V (X10), V4, V0, V8 + VLOXSEG3EI64V (X10), V4, V0, V8 + VLOXSEG4EI8V (X10), V4, V8 + VLOXSEG4EI16V (X10), V4, V8 + VLOXSEG4EI32V (X10), V4, V8 + VLOXSEG4EI64V (X10), V4, V8 + VLOXSEG4EI8V (X10), V4, V0, V8 + VLOXSEG4EI16V (X10), V4, V0, V8 + VLOXSEG4EI32V (X10), V4, V0, V8 + VLOXSEG4EI64V (X10), V4, V0, V8 + VLOXSEG5EI8V (X10), V4, V8 + VLOXSEG5EI16V (X10), V4, V8 + VLOXSEG5EI32V (X10), V4, V8 + VLOXSEG5EI64V (X10), V4, V8 + VLOXSEG5EI8V (X10), V4, V0, V8 + VLOXSEG5EI16V (X10), V4, V0, V8 + VLOXSEG5EI32V (X10), V4, V0, V8 + VLOXSEG5EI64V (X10), V4, V0, V8 + VLOXSEG7EI8V (X10), V4, V8 + VLOXSEG7EI16V (X10), V4, V8 + VLOXSEG7EI32V (X10), V4, V8 + VLOXSEG7EI64V (X10), V4, V8 + VLOXSEG7EI8V (X10), V4, V0, V8 + VLOXSEG7EI16V (X10), V4, V0, V8 + VLOXSEG7EI32V (X10), V4, V0, V8 + VLOXSEG7EI64V (X10), V4, V0, V8 + VLOXSEG8EI8V (X10), V4, V8 + VLOXSEG8EI16V (X10), V4, V8 + VLOXSEG8EI32V (X10), V4, V8 + VLOXSEG8EI64V (X10), V4, V8 + VLOXSEG8EI8V (X10), V4, V0, V8 + VLOXSEG8EI16V (X10), V4, V0, V8 + VLOXSEG8EI32V (X10), V4, V0, V8 + VLOXSEG8EI64V (X10), V4, V0, V8 + VSOXSEG2EI8V V24, V4, (X10) + VSOXSEG2EI16V V24, V4, (X10) + VSOXSEG2EI32V V24, V4, (X10) + VSOXSEG2EI64V V24, V4, (X10) + VSOXSEG2EI8V V24, V4, V0, (X10) + VSOXSEG2EI16V V24, V4, V0, (X10) + VSOXSEG2EI32V V24, V4, V0, (X10) + VSOXSEG2EI64V V24, V4, V0, (X10) + VSOXSEG3EI8V V24, V4, (X10) + VSOXSEG3EI16V V24, V4, (X10) + VSOXSEG3EI32V V24, V4, (X10) + VSOXSEG3EI64V V24, V4, (X10) + VSOXSEG3EI8V V24, V4, V0, (X10) + VSOXSEG3EI16V V24, V4, V0, (X10) + VSOXSEG3EI32V V24, V4, V0, (X10) + VSOXSEG3EI64V V24, V4, V0, (X10) + VSOXSEG4EI8V V24, V4, (X10) + VSOXSEG4EI16V V24, V4, (X10) + VSOXSEG4EI32V V24, V4, (X10) + VSOXSEG4EI64V V24, V4, (X10) + VSOXSEG4EI8V V24, V4, V0, (X10) + VSOXSEG4EI16V V24, V4, V0, (X10) + VSOXSEG4EI32V V24, V4, V0, (X10) + VSOXSEG4EI64V V24, V4, V0, (X10) + VSOXSEG5EI8V V24, V4, (X10) + VSOXSEG5EI16V V24, V4, (X10) + VSOXSEG5EI32V V24, V4, (X10) + VSOXSEG5EI64V V24, V4, (X10) + VSOXSEG5EI8V V24, V4, V0, (X10) + VSOXSEG5EI16V V24, V4, V0, (X10) + VSOXSEG5EI32V V24, V4, V0, (X10) + VSOXSEG5EI64V V24, V4, V0, (X10) + VSOXSEG6EI8V V24, V4, (X10) + VSOXSEG6EI16V V24, V4, (X10) + VSOXSEG6EI32V V24, V4, (X10) + VSOXSEG6EI64V V24, V4, (X10) + VSOXSEG6EI8V V24, V4, V0, (X10) + VSOXSEG6EI16V V24, V4, V0, (X10) + VSOXSEG6EI32V V24, V4, V0, (X10) + VSOXSEG6EI64V V24, V4, V0, (X10) + VSOXSEG7EI8V V24, V4, (X10) + VSOXSEG7EI16V V24, V4, (X10) + VSOXSEG7EI32V V24, V4, (X10) + VSOXSEG7EI64V V24, V4, (X10) + VSOXSEG7EI8V V24, V4, V0, (X10) + VSOXSEG7EI16V V24, V4, V0, (X10) + VSOXSEG7EI32V V24, V4, V0, (X10) + VSOXSEG7EI64V V24, V4, V0, (X10) + VSOXSEG8EI8V V24, V4, (X10) + VSOXSEG8EI16V V24, V4, (X10) + VSOXSEG8EI32V V24, V4, (X10) + VSOXSEG8EI64V V24, V4, (X10) + VSOXSEG8EI8V V24, V4, V0, (X10) + VSOXSEG8EI16V V24, V4, V0, (X10) + VSOXSEG8EI32V V24, V4, V0, (X10) + VSOXSEG8EI64V V24, V4, V0, (X10) + + VL1RV (X10), V3 + VL1RE8V (X10), V3 + VL1RE16V (X10), V3 + VL1RE32V (X10), V3 + VL1RE64V (X10), V3 + VL2RV (X10), V2 + VL2RE8V (X10), V2 + VL2RE16V (X10), V2 + VL2RE32V (X10), V2 + VL2RE64V (X10), V2 + VL4RV (X10), V4 + VL4RE8V (X10), V4 + VL4RE16V (X10), V4 + VL4RE32V (X10), V4 + VL4RE64V (X10), V4 + VL8RV (X10), V8 + VL8RE8V (X10), V8 + VL8RE16V (X10), V8 + VL8RE32V (X10), V8 + VL8RE64V (X10), V8 + VS1RV V3, (X11) + VS2RV V2, (X11) + VS4RV V4, (X11) + VS8RV V8, (X11) + + RET +` + dir := t.TempDir() + path := filepath.Join(dir, "vecls_riscv64.s") + if err := os.WriteFile(path, []byte(src), 0o644); err != nil { + t.Fatal(err) + } + assertRISCVDifferential(t, path, src, "vecls") +}