adds mask_mask logical instructions
This commit is contained in:
parent
63889b02e7
commit
c1277b6528
@ -494,6 +494,9 @@ if(vector != null) {%>
|
|||||||
throw new std::runtime_error("Unsupported sew bit value");
|
throw new std::runtime_error("Unsupported sew bit value");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
void mask_mask_op(uint8_t* V, unsigned funct6, unsigned funct3, uint64_t vl, uint64_t vstart, unsigned vd, unsigned vs2, unsigned vs1){
|
||||||
|
return softvector::mask_mask_op<${vlen}>(V, funct6, funct3, vl, vstart, vd, vs2, vs1);
|
||||||
|
}
|
||||||
<%}%>
|
<%}%>
|
||||||
uint64_t fetch_count{0};
|
uint64_t fetch_count{0};
|
||||||
uint64_t tval{0};
|
uint64_t tval{0};
|
||||||
|
@ -100,6 +100,8 @@ bool sat_vector_imm_op(uint8_t* V, unsigned funct6, unsigned funct3, uint64_t vl
|
|||||||
template <unsigned VLEN, typename dest_elem_t, typename src_elem_t = dest_elem_t>
|
template <unsigned VLEN, typename dest_elem_t, typename src_elem_t = dest_elem_t>
|
||||||
void vector_red_op(uint8_t* V, unsigned funct6, unsigned funct3, uint64_t vl, uint64_t vstart, vtype_t vtype, bool vm, unsigned vd,
|
void vector_red_op(uint8_t* V, unsigned funct6, unsigned funct3, uint64_t vl, uint64_t vstart, vtype_t vtype, bool vm, unsigned vd,
|
||||||
unsigned vs2, unsigned vs1);
|
unsigned vs2, unsigned vs1);
|
||||||
|
template <unsigned VLEN>
|
||||||
|
void mask_mask_op(uint8_t* V, unsigned funct6, unsigned funct3, uint64_t vl, uint64_t vstart, unsigned vd, unsigned vs2, unsigned vs1);
|
||||||
} // namespace softvector
|
} // namespace softvector
|
||||||
#include "vm/vector_functions.hpp"
|
#include "vm/vector_functions.hpp"
|
||||||
#endif /* _VM_VECTOR_FUNCTIONS_H_ */
|
#endif /* _VM_VECTOR_FUNCTIONS_H_ */
|
||||||
|
@ -155,14 +155,6 @@ std::function<dest_elem_t(dest_elem_t, src2_elem_t, src1_elem_t)> get_funct(unsi
|
|||||||
// case 0b001110: // VSLID1EUP
|
// case 0b001110: // VSLID1EUP
|
||||||
// case 0b001111: // VSLIDE1DOWN
|
// case 0b001111: // VSLIDE1DOWN
|
||||||
// case 0b010111: // VCOMPRESS
|
// case 0b010111: // VCOMPRESS
|
||||||
// case 0b011000: // VMANDN
|
|
||||||
// case 0b011001: // VMAND
|
|
||||||
// case 0b011010: // VMOR
|
|
||||||
// case 0b011011: // VMXOR
|
|
||||||
// case 0b011100: // VMORN
|
|
||||||
// case 0b011101: // VMNAND
|
|
||||||
// case 0b011110: // VMNOR
|
|
||||||
// case 0b011111: // VMXNOR
|
|
||||||
case 0b100000: // VDIVU
|
case 0b100000: // VDIVU
|
||||||
return [](dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) -> dest_elem_t {
|
return [](dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) -> dest_elem_t {
|
||||||
if(vs1 == 0)
|
if(vs1 == 0)
|
||||||
@ -380,34 +372,58 @@ void vector_imm_op(uint8_t* V, unsigned funct6, unsigned funct3, uint64_t vl, ui
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
template <typename elem_t> std::function<bool(elem_t, elem_t)> get_mask_funct(unsigned funct) {
|
template <typename elem_t> std::function<bool(elem_t, elem_t)> get_mask_funct(unsigned funct6, unsigned funct3) {
|
||||||
switch(funct) {
|
if(funct3 == OPIVV || funct3 == OPIVX || funct3 == OPIVI)
|
||||||
case 0b011000: // VMSEQ
|
switch(funct6) {
|
||||||
return [](elem_t vs2, elem_t vs1) { return vs2 == vs1; };
|
case 0b011000: // VMSEQ
|
||||||
case 0b011001: // VMSNE
|
return [](elem_t vs2, elem_t vs1) { return vs2 == vs1; };
|
||||||
return [](elem_t vs2, elem_t vs1) { return vs2 != vs1; };
|
case 0b011001: // VMSNE
|
||||||
case 0b011010: // VMSLTU
|
return [](elem_t vs2, elem_t vs1) { return vs2 != vs1; };
|
||||||
return [](elem_t vs2, elem_t vs1) { return vs2 < vs1; };
|
case 0b011010: // VMSLTU
|
||||||
case 0b011011: // VMSLT
|
return [](elem_t vs2, elem_t vs1) { return vs2 < vs1; };
|
||||||
return [](elem_t vs2, elem_t vs1) {
|
case 0b011011: // VMSLT
|
||||||
return static_cast<std::make_signed_t<elem_t>>(vs2) < static_cast<std::make_signed_t<elem_t>>(vs1);
|
return [](elem_t vs2, elem_t vs1) {
|
||||||
};
|
return static_cast<std::make_signed_t<elem_t>>(vs2) < static_cast<std::make_signed_t<elem_t>>(vs1);
|
||||||
case 0b011100: // VMSLEU
|
};
|
||||||
return [](elem_t vs2, elem_t vs1) { return vs2 <= vs1; };
|
case 0b011100: // VMSLEU
|
||||||
case 0b011101: // VMSLE
|
return [](elem_t vs2, elem_t vs1) { return vs2 <= vs1; };
|
||||||
return [](elem_t vs2, elem_t vs1) {
|
case 0b011101: // VMSLE
|
||||||
return static_cast<std::make_signed_t<elem_t>>(vs2) <= static_cast<std::make_signed_t<elem_t>>(vs1);
|
return [](elem_t vs2, elem_t vs1) {
|
||||||
};
|
return static_cast<std::make_signed_t<elem_t>>(vs2) <= static_cast<std::make_signed_t<elem_t>>(vs1);
|
||||||
case 0b011110: // VMSGTU
|
};
|
||||||
return [](elem_t vs2, elem_t vs1) { return vs2 > vs1; };
|
case 0b011110: // VMSGTU
|
||||||
case 0b011111: // VMSGT
|
return [](elem_t vs2, elem_t vs1) { return vs2 > vs1; };
|
||||||
return [](elem_t vs2, elem_t vs1) {
|
case 0b011111: // VMSGT
|
||||||
return static_cast<std::make_signed_t<elem_t>>(vs2) > static_cast<std::make_signed_t<elem_t>>(vs1);
|
return [](elem_t vs2, elem_t vs1) {
|
||||||
};
|
return static_cast<std::make_signed_t<elem_t>>(vs2) > static_cast<std::make_signed_t<elem_t>>(vs1);
|
||||||
|
};
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new std::runtime_error("Unknown funct in get_mask_funct");
|
throw new std::runtime_error("Unknown funct6 in get_mask_funct");
|
||||||
}
|
}
|
||||||
|
else if(funct3 == OPMVV || funct3 == OPMVX)
|
||||||
|
switch(funct6) {
|
||||||
|
case 0b011000: // VMANDN
|
||||||
|
return [](elem_t vs2, elem_t vs1) { return vs2 & !vs1; };
|
||||||
|
case 0b011001: // VMAND
|
||||||
|
return [](elem_t vs2, elem_t vs1) { return vs2 & vs1; };
|
||||||
|
case 0b011010: // VMOR
|
||||||
|
return [](elem_t vs2, elem_t vs1) { return vs2 | vs1; };
|
||||||
|
case 0b011011: // VMXOR
|
||||||
|
return [](elem_t vs2, elem_t vs1) { return vs2 ^ vs1; };
|
||||||
|
case 0b011100: // VMORN
|
||||||
|
return [](elem_t vs2, elem_t vs1) { return vs2 | !vs1; };
|
||||||
|
case 0b011101: // VMNAND
|
||||||
|
return [](elem_t vs2, elem_t vs1) { return !(vs2 & vs1); };
|
||||||
|
case 0b011110: // VMNOR
|
||||||
|
return [](elem_t vs2, elem_t vs1) { return !(vs2 | vs1); };
|
||||||
|
case 0b011111: // VMXNOR
|
||||||
|
return [](elem_t vs2, elem_t vs1) { return !(vs2 ^ vs1); };
|
||||||
|
default:
|
||||||
|
throw new std::runtime_error("Unknown funct6 in get_mask_funct");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw new std::runtime_error("Unknown funct3 in get_mask_funct");
|
||||||
}
|
}
|
||||||
template <unsigned VLEN, typename elem_t>
|
template <unsigned VLEN, typename elem_t>
|
||||||
void mask_vector_vector_op(uint8_t* V, unsigned funct6, unsigned funct3, uint64_t vl, uint64_t vstart, vtype_t vtype, bool vm, unsigned vd,
|
void mask_vector_vector_op(uint8_t* V, unsigned funct6, unsigned funct3, uint64_t vl, uint64_t vstart, vtype_t vtype, bool vm, unsigned vd,
|
||||||
@ -417,7 +433,7 @@ void mask_vector_vector_op(uint8_t* V, unsigned funct6, unsigned funct3, uint64_
|
|||||||
auto vs1_view = get_vreg<VLEN, elem_t>(V, vs1, elem_count);
|
auto vs1_view = get_vreg<VLEN, elem_t>(V, vs1, elem_count);
|
||||||
auto vs2_view = get_vreg<VLEN, elem_t>(V, vs2, elem_count);
|
auto vs2_view = get_vreg<VLEN, elem_t>(V, vs2, elem_count);
|
||||||
vmask_view vd_mask_view = read_vmask<VLEN>(V, elem_count, vd);
|
vmask_view vd_mask_view = read_vmask<VLEN>(V, elem_count, vd);
|
||||||
auto fn = get_mask_funct<elem_t>(funct6);
|
auto fn = get_mask_funct<elem_t>(funct6, funct3);
|
||||||
// elements w/ index smaller than vstart are in the prestart and get skipped
|
// elements w/ index smaller than vstart are in the prestart and get skipped
|
||||||
// body is from vstart to min(elem_count, vl)
|
// body is from vstart to min(elem_count, vl)
|
||||||
for(unsigned idx = vstart; idx < std::min(elem_count, vl); idx++) {
|
for(unsigned idx = vstart; idx < std::min(elem_count, vl); idx++) {
|
||||||
@ -449,7 +465,7 @@ void mask_vector_imm_op(uint8_t* V, unsigned funct6, unsigned funct3, uint64_t v
|
|||||||
vmask_view mask_reg = read_vmask<VLEN>(V, elem_count);
|
vmask_view mask_reg = read_vmask<VLEN>(V, elem_count);
|
||||||
auto vs2_view = get_vreg<VLEN, elem_t>(V, vs2, elem_count);
|
auto vs2_view = get_vreg<VLEN, elem_t>(V, vs2, elem_count);
|
||||||
vmask_view vd_mask_view = read_vmask<VLEN>(V, elem_count, vd);
|
vmask_view vd_mask_view = read_vmask<VLEN>(V, elem_count, vd);
|
||||||
auto fn = get_mask_funct<elem_t>(funct6);
|
auto fn = get_mask_funct<elem_t>(funct6, funct3);
|
||||||
// elements w/ index smaller than vstart are in the prestart and get skipped
|
// elements w/ index smaller than vstart are in the prestart and get skipped
|
||||||
// body is from vstart to min(elem_count, vl)
|
// body is from vstart to min(elem_count, vl)
|
||||||
for(unsigned idx = vstart; idx < std::min(elem_count, vl); idx++) {
|
for(unsigned idx = vstart; idx < std::min(elem_count, vl); idx++) {
|
||||||
@ -866,4 +882,28 @@ void vector_red_op(uint8_t* V, unsigned funct6, unsigned funct3, uint64_t vl, ui
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
template <unsigned VLEN>
|
||||||
|
void mask_mask_op(uint8_t* V, unsigned funct6, unsigned funct3, uint64_t vl, uint64_t vstart, unsigned vd, unsigned vs2, unsigned vs1) {
|
||||||
|
uint64_t elem_count = VLEN;
|
||||||
|
auto vs1_view = read_vmask<VLEN>(V, elem_count, vs1);
|
||||||
|
auto vs2_view = read_vmask<VLEN>(V, elem_count, vs2);
|
||||||
|
auto vd_view = read_vmask<VLEN>(V, elem_count, vd);
|
||||||
|
auto fn = get_mask_funct<unsigned>(funct6, funct3); // could be bool, but would break the make_signed_t in get_mask_funct
|
||||||
|
for(unsigned idx = vstart; idx < std::min(vl, elem_count); idx++) {
|
||||||
|
unsigned new_bit_value = fn(vs2_view[idx], vs1_view[idx]);
|
||||||
|
uint8_t* cur_mask_byte_addr = vd_view.start + idx / 8;
|
||||||
|
unsigned cur_bit = idx % 8;
|
||||||
|
*cur_mask_byte_addr = *cur_mask_byte_addr & ~(1U << cur_bit) | static_cast<unsigned>(new_bit_value) << cur_bit;
|
||||||
|
}
|
||||||
|
// the tail is all elements of the destination register beyond the first one
|
||||||
|
for(unsigned idx = 1; idx < VLEN; idx++) {
|
||||||
|
// always tail agnostic
|
||||||
|
// this is a nop, placeholder for vta behavior
|
||||||
|
unsigned new_bit_value = vd_view[idx];
|
||||||
|
uint8_t* cur_mask_byte_addr = vd_view.start + idx / 8;
|
||||||
|
unsigned cur_bit = idx % 8;
|
||||||
|
*cur_mask_byte_addr = *cur_mask_byte_addr & ~(1U << cur_bit) | static_cast<unsigned>(new_bit_value) << cur_bit;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
} // namespace softvector
|
} // namespace softvector
|
Loading…
x
Reference in New Issue
Block a user