Browse Source

Merge pull request #2103 from riscv-software-src/fix-func-decl

fix: move vectorUnit_t::elt defintion to the header
pull/2107/head
Andrew Waterman 10 months ago
committed by GitHub
parent
commit
9b136d0210
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 84
      riscv/vector_unit.cc
  2. 69
      riscv/vector_unit.h

84
riscv/vector_unit.cc

@ -89,87 +89,7 @@ reg_t vectorUnit_t::vectorUnit_t::set_vl(int rd, int rs1, reg_t reqVL, reg_t new
return vl->read();
}
template<class T> T& vectorUnit_t::elt(reg_t vReg, reg_t n, bool UNUSED is_write) {
assert(vsew != 0);
assert((VLEN >> 3)/sizeof(T) > 0);
reg_t elts_per_reg = (VLEN >> 3) / (sizeof(T));
vReg += n / elts_per_reg;
n = n % elts_per_reg;
#ifdef WORDS_BIGENDIAN
// "V" spec 0.7.1 requires lower indices to map to lower significant
// bits when changing SEW, thus we need to index from the end on BE.
n ^= elts_per_reg - 1;
#endif
if (unlikely(p->get_log_commits_enabled() && is_write))
void vectorUnit_t::log_elt_write_if_needed(reg_t vReg) const {
if (unlikely(p->get_log_commits_enabled()))
p->get_state()->log_reg_write[((vReg) << 4) | 2] = {0, 0};
T *regStart = (T*)((char*)reg_file + vReg * (VLEN >> 3));
return regStart[n];
}
// The logic differences between 'elt()' and 'elt_group()' come from
// the fact that, while 'elt()' requires that the element is fully
// contained in a single vector register, the element group may span
// multiple registers in a single register group (LMUL>1).
//
// Notes:
// - We do NOT check that a single element - i.e., the T in the element
// group type std::array<T, N> - fits within a single register, or that
// T is smaller or equal to VSEW. Implementations of the instructions
// sometimes use a different T than what the specification suggests.
// Instructon implementations should 'require()' what the specification
// dictates.
// - We do NOT check that 'vReg' is a valid register group, or that
// 'n+1' element groups fit in the register group 'vReg'. It is
// the responsibility of the caller to validate those preconditions.
template<typename EG> EG&
vectorUnit_t::elt_group(reg_t vReg, reg_t n, bool UNUSED is_write) {
#ifdef WORDS_BIGENDIAN
fputs("vectorUnit_t::elt_group is not compatible with WORDS_BIGENDIAN setup.\n",
stderr);
abort();
#endif
using T = typename EG::value_type;
constexpr std::size_t N = std::tuple_size<EG>::value;
assert(N > 0);
assert(vsew != 0);
constexpr reg_t elt_group_size = N * sizeof(T);
const reg_t reg_group_size = (VLEN >> 3) * vflmul;
assert(((n + 1) * elt_group_size) <= reg_group_size);
const reg_t start_byte = n * elt_group_size;
const reg_t bytes_per_reg = VLEN >> 3;
// Inclusive first/last register indices.
const reg_t reg_first = vReg + start_byte / bytes_per_reg;
const reg_t reg_last = vReg + (start_byte + elt_group_size - 1) / bytes_per_reg;
// Element groups per register groups
for (reg_t vidx = reg_first; vidx <= reg_last; ++vidx) {
if (unlikely(p->get_log_commits_enabled() && is_write)) {
p->get_state()->log_reg_write[(vidx << 4) | 2] = {0, 0};
}
}
return *(EG*)((char*)reg_file + vReg * (VLEN >> 3) + start_byte);
}
template signed char& vectorUnit_t::elt<signed char>(reg_t, reg_t, bool);
template short& vectorUnit_t::elt<short>(reg_t, reg_t, bool);
template int& vectorUnit_t::elt<int>(reg_t, reg_t, bool);
template long& vectorUnit_t::elt<long>(reg_t, reg_t, bool);
template long long& vectorUnit_t::elt<long long>(reg_t, reg_t, bool);
template uint8_t& vectorUnit_t::elt<uint8_t>(reg_t, reg_t, bool);
template uint16_t& vectorUnit_t::elt<uint16_t>(reg_t, reg_t, bool);
template uint32_t& vectorUnit_t::elt<uint32_t>(reg_t, reg_t, bool);
template uint64_t& vectorUnit_t::elt<uint64_t>(reg_t, reg_t, bool);
template float16_t& vectorUnit_t::elt<float16_t>(reg_t, reg_t, bool);
template float32_t& vectorUnit_t::elt<float32_t>(reg_t, reg_t, bool);
template float64_t& vectorUnit_t::elt<float64_t>(reg_t, reg_t, bool);
template EGU32x4_t& vectorUnit_t::elt_group<EGU32x4_t>(reg_t, reg_t, bool);
template EGU32x8_t& vectorUnit_t::elt_group<EGU32x8_t>(reg_t, reg_t, bool);
template EGU64x4_t& vectorUnit_t::elt_group<EGU64x4_t>(reg_t, reg_t, bool);
template EGU8x16_t& vectorUnit_t::elt_group<EGU8x16_t>(reg_t, reg_t, bool);

69
riscv/vector_unit.h

@ -103,10 +103,71 @@ public:
bool vstart_alu = false;
// vector element for various SEW
template<class T> T& elt(reg_t vReg, reg_t n, bool is_write = false);
template<typename T> T& elt(reg_t vReg, reg_t n, bool is_write = false) {
assert(vsew != 0);
assert((VLEN >> 3)/sizeof(T) > 0);
reg_t elts_per_reg = (VLEN >> 3) / (sizeof(T));
vReg += n / elts_per_reg;
n = n % elts_per_reg;
#ifdef WORDS_BIGENDIAN
// "V" spec 0.7.1 requires lower indices to map to lower significant
// bits when changing SEW, thus we need to index from the end on BE.
n ^= elts_per_reg - 1;
#endif
if (is_write)
log_elt_write_if_needed(vReg);
T *regStart = (T*)((char*)reg_file + vReg * (VLEN >> 3));
return regStart[n];
}
// vector element group access, where EG is a std::array<T, N>.
// The logic differences between 'elt()' and 'elt_group()' come from
// the fact that, while 'elt()' requires that the element is fully
// contained in a single vector register, the element group may span
// multiple registers in a single register group (LMUL>1).
//
// Notes:
// - We do NOT check that a single element - i.e., the T in the element
// group type std::array<T, N> - fits within a single register, or that
// T is smaller or equal to VSEW. Implementations of the instructions
// sometimes use a different T than what the specification suggests.
// Instructon implementations should 'require()' what the specification
// dictates.
// - We do NOT check that 'vReg' is a valid register group, or that
// 'n+1' element groups fit in the register group 'vReg'. It is
// the responsibility of the caller to validate those preconditions.
template<typename EG> EG&
elt_group(reg_t vReg, reg_t n, bool is_write = false);
elt_group(reg_t vReg, reg_t n, bool is_write = false) {
#ifdef WORDS_BIGENDIAN
fputs("vectorUnit_t::elt_group is not compatible with WORDS_BIGENDIAN setup.\n",
stderr);
abort();
#endif
using T = typename EG::value_type;
constexpr std::size_t N = std::tuple_size<EG>::value;
assert(N > 0);
assert(vsew != 0);
constexpr reg_t elt_group_size = N * sizeof(T);
const reg_t reg_group_size = (VLEN >> 3) * vflmul;
assert(((n + 1) * elt_group_size) <= reg_group_size);
const reg_t start_byte = n * elt_group_size;
const reg_t bytes_per_reg = VLEN >> 3;
// Inclusive first/last register indices.
const reg_t reg_first = vReg + start_byte / bytes_per_reg;
const reg_t reg_last = vReg + (start_byte + elt_group_size - 1) / bytes_per_reg;
// Element groups per register groups
for (reg_t vidx = reg_first; vidx <= reg_last; ++vidx)
if (is_write)
log_elt_write_if_needed(vidx);
return *(EG*)((char*)reg_file + vReg * (VLEN >> 3) + start_byte);
}
bool mask_elt(reg_t vReg, reg_t n)
{
@ -119,6 +180,10 @@ public:
e = (e & ~(1U << (n % 8))) | (value << (n % 8));
}
private:
void log_elt_write_if_needed(reg_t vReg) const;
public:
void reset();

Loading…
Cancel
Save