[libre-riscv-dev] spike-sv non-default element widths

Jacob Lifshay programmerjake at gmail.com
Wed Oct 17 20:47:12 BST 2018


On Wed, Oct 17, 2018, 05:06 Luke Kenneth Casson Leighton <lkcl at lkcl.net>
wrote:

> https://libre-riscv.org/simple_v_extension/specification/#elwidth
>
> new section in specification on element widths, including pseudo-code.
> comments / thoughts appreciated, am slowly working towards getting
> this implemented.
>
Note that how you've written the reg_t union with pointers in it, using the
pointers like arrays won't achieve your intended effect, they will instead
reinterpret the value of the register as the memory address at which to
load/store when (I assume) reading/writing from/to the registers. You can
use arrays, but that won't work for larger-than-xlen values as that makes
the compiler insert padding for alignment purposes. You could do something
like:

https://gcc.godbolt.org/z/j9D4fo

// assuming the host is little endian
constexpr unsigned register_count = 128;
uint_XLEN_t regs[register_count];
template <typename T>
T read_helper(unsigned reg, unsigned index)
{
    assert(index + reg * (XLEN / 8) < register_count * (XLEN / 8));
    T retval;
    // memcpy is optimized into a load instruction with alignment of
min(alignof(uint_XLEN_t), alignof(T))
    memcpy(&retval, reinterpret_cast<char *>(&regs[reg]) + index *
sizeof(T), sizeof(T));
    return retval;
}
// enable_if_t is to prevent template type deduction to help catch errors
as arithmetic often returns a different type than you started with (eg. u8
+ u8 -> int)
template <typename T>
void write_helper(unsigned reg, unsigned index, std::enable_if_t<true, T>
value)
{
    assert(index + reg * (XLEN / 8) < register_count * (XLEN / 8));
    // memcpy is optimized into a store instruction with alignment of
min(alignof(uint_XLEN_t), alignof(T))
    memcpy(reinterpret_cast<char *>(&regs[reg]) + index * sizeof(T),
&value, sizeof(T));
}
void add_vectorized_unpredicated_u16(unsigned rd, unsigned rs1, unsigned
rs2, unsigned vl)
{
    typedef uint16_t T;
    for(unsigned i = 0; i < vl; i++)
    {
        write_helper<T>(rd, i, read_helper<T>(rs1, i) + read_helper<T>(rs2,
i));
    }
}
// ...
void add_vectorized_unpredicated_u128(unsigned rd, unsigned rs1, unsigned
rs2, unsigned vl)
{
    typedef uint128_t T;
    for(unsigned i = 0; i < vl; i++)
    {
        write_helper<T>(rd, i, read_helper<T>(rs1, i) + read_helper<T>(rs2,
i));
    }
}

Jacob Lifshay

>


More information about the libre-riscv-dev mailing list