Why RISC-V v-extension requires m-extension as a support? How is this function achieved?Where can I find its implementation?

I recently tried to implement my own lightweight compiler based on llvm. I only need to use integer instructions and some instructions in the v extension, but I found that the compilation process will report an error without the m extension.

My code generates multiplication instructions in compilation because of addressing operations.

I was hoping to make a modification so that the v extension can be independent of the m extension, and the addition can be used instead of the multiplication operation when there is no m extension, but I find that I can’t find out how this process is implemented.

I used Compiler Explorer for simulation to generate the following code to illustrate the multiply instruction I encountered.

#include "riscv_vector.h"

int square(int num) {
    volatile vint8m1_t a8, b8, c8;
    volatile vint32m8_t a32, b32, c32;
    c8 = vadd_vv_i8m1(a8,b8,1);
    c32 = vadd_vv_i32m8(a32,b32,1);
    return num * num;
}
        addi    sp, sp, -16
        sw      ra, 12(sp)                      # 4-byte Folded Spill
        sw      s0, 8(sp)                       # 4-byte Folded Spill
        addi    s0, sp, 16
        csrr    a1, vlenb
        li      a2, 28
        mul     a1, a1, a2
        sub     sp, sp, a1
        sw      a0, -16(s0)
        csrr    a0, vlenb
        sub     a0, s0, a0
        addi    a0, a0, -16
        vl1r.v  v8, (a0)
        csrr    a0, vlenb
        slli    a0, a0, 1
        sub     a0, s0, a0
        addi    a0, a0, -16
        vl1r.v  v9, (a0)
        vsetivli        zero, 1, e8, m1, ta, ma
        vadd.vv v8, v8, v9
        csrr    a0, vlenb
        slli    a1, a0, 1
        add     a0, a1, a0
        sub     a0, s0, a0
        addi    a0, a0, -16
        vs1r.v  v8, (a0)
        csrr    a0, vlenb
        li      a1, 12
        **mul     a0, a0, a1**
        sub     a0, s0, a0
        addi    a0, a0, -16
        vl8re32.v       v8, (a0)
        csrr    a0, vlenb
        li      a1, 20
        mul     a0, a0, a1
        sub     a0, s0, a0
        addi    a0, a0, -16
        vl8re32.v       v16, (a0)
        vsetivli        zero, 1, e32, m8, ta, ma
        vadd.vv v8, v8, v16
        csrr    a0, vlenb
        li      a1, 28
        mul     a0, a0, a1
        sub     a0, s0, a0
        addi    a0, a0, -16
        vs8r.v  v8, (a0)
        lw      a0, -16(s0)
        mul     a0, a0, a0
        addi    sp, s0, -16
        lw      ra, 12(sp)                      # 4-byte Folded Reload
        lw      s0, 8(sp)                       # 4-byte Folded Reload
        addi    sp, sp, 16
        ret

I really hope someone can give me an answer, thank you very much for your help!

The error message is:

error: M- or Zmmul-extension must be enabled to calculate the vscaled size/offset.

Because vectors are an unknown length, allocating stack space for them requires reading that length and multiplying by an appropriate count; in this case, 3 lots of 1 for your vint8m1_ts and 3 lots of 8 for your vint32m8_ts, rounded up to an even number for alignment reasons (I assume).

This error comes from RISCVInstrInfo::getVLENFactoredAmount. As far as I can tell that’s the only dependency on M/Zmmul, and is only used when RVV vectors are stored on the stack. There’s no reason you couldn’t fix that code to inline a bunch of shifts and adds for the non-M/Zmmul case, it’s just going to perform poorly and a core that supports V but not Zmmul doesn’t really make much sense to me. You can’t make a libcall though without extreme care since the generated code needs to work in a prologue.