#include "dsl/ir/send.hpp"
#include "dsl/ir/ir.hpp"
GEMMSTONE_NAMESPACE_START
namespace dsl {
namespace ir {
stmt_t send_t::create_offset_store(const expr_t &header_buf,
const expr_t &mem_buf, const expr_t &_mem_off,
bool is_signed_offset) const {
dsl_assert(is_var(mem_buf));
int header_off = 0;
int unit_size = 1;
if (!is_lsc && is_block() && is_slm()) {
header_off = 2 * address_type().size();
unit_size = type.base().size();
}
expr_t mem_off = _mem_off;
if (unit_size != 1) mem_off /= unit_size;
expr_t header_sub_buf = header_buf[header_off];
expr_t off;
if (is_a64()) {
off = cast(mem_buf, address_type());
if (mem_off.type().elems() > 1) {
off = shuffle_t::make_broadcast(off, mem_off.type().elems());
}
off += mem_off;
} else {
off = std::move(mem_off);
}
off = cast(off, address_type(is_signed_offset, off.type().elems()));
return store_t::make(header_sub_buf, 0, off);
}
bool send_t::is_supported() const {
int max_access_size
= (is_2d() && !is_store_2d()) ? 32 * grf_size() : 8 * grf_size();
if (access_size() > max_access_size) return false;
if (is_block() && slots != 1) return false;
if (is_block() && !one_of(type.elems(), {1, 2, 4, 8, 16})) return false;
if (type.is_oword() && !is_slm() && type.elems() > 8) return false;
if (is_slm() && type.is_hword()) return false;
if (is_slm() && !is_block()) return false;
if (is_slm() && !is_load() && !is_store()) return false;
if (is_store() && type.is_hword() && !is_xe_hpc_plus()) return false;
if (is_store() && is_block() && is_xe_hpc_plus()
&& type.size() % grf_size() != 0)
return false;
if (type.is_dword() && type.elems() != 1) return false;
if (type.is_qword() && type.elems() != 1) return false;
if (is_prefetch() && !type.is_hword()) return false;
if (is_prefetch() && type.elems() > 8) return false;
if (is_atomic() && !(type.is_dword() || type.is_qword())) return false;
if (is_atomic() && !is_xe_hpc_plus() && is_a64() && slots > 8) return false;
if (is_scattered() && !is_atomic() && !type.is_byte() && !type.is_qword())
return false;
if (type.is_byte() && type.elems() > 4) return false;
if (is_scattered() && !is_atomic() && !one_of(type.elems(), {1, 2, 4, 8}))
return false;
return true;
}
std::vector<func_t> send_t::get_all(const hw_t &hw, send_op_t op,
send_address_t address, const type_t &mem_type, bool zero_out,
send_cache_hint_t cache_hint) {
std::vector<func_t> filtered;
for (int slots : {1, 2, 4, 8, 16}) {
for (int elems : {1, 2, 4, 8, 16}) {
for (auto &type : {type_t::byte(), type_t::dword(), type_t::qword(),
type_t::oword(), type_t::hword()}) {
if (op == send_op_t::atomic_fadd
&& type.size() != mem_type.size())
continue;
auto f = send_t::make(hw, op, address, type.with_elems(elems),
slots, zero_out, cache_hint);
if (!f.as<send_t>().is_supported()) continue;
filtered.push_back(f);
}
}
}
std::sort(filtered.begin(), filtered.end(),
[](const func_t &_a, const func_t &_b) {
auto &a = _a.as<send_t>();
auto &b = _b.as<send_t>();
size_t a_sz = a.access_size();
size_t b_sz = b.access_size();
if (a.is_block() != b.is_block()) return a.is_block();
if (a_sz == b_sz) return a.type.base().size() < b.type.base().size();
return a_sz > b_sz;
});
std::vector<func_t> ret;
for (size_t i = 0; i < filtered.size(); i++) {
if (i > 0) {
auto &s_prev = filtered[i - 1].as<send_t>();
auto &s_cur = filtered[i].as<send_t>();
if (s_prev.is_block() && s_cur.is_block()
&& (s_prev.type.size() == s_cur.type.size()))
continue;
}
ret.push_back(filtered[i]);
}
return ret;
}
} } GEMMSTONE_NAMESPACE_END