#ifndef GPU_AMD_MIOPEN_SOFTMAX_IMPL_HPP
#define GPU_AMD_MIOPEN_SOFTMAX_IMPL_HPP
#include "gpu/amd/sycl_hip_utils.hpp"
#include "miopen/miopen.h"
namespace dnnl {
namespace impl {
namespace gpu {
namespace amd {
constexpr int miopen_softmax_max_ndims = 4;
struct miopen_softmax_impl_base_t {
enum io { src = 0, dst, d_src, d_dst, NUM_IO };
int strides[NUM_IO][DNNL_MAX_NDIMS];
miopenDataType_t data_type;
miopenSoftmaxAlgorithm_t alg_kind;
miopenSoftmaxMode_t mode = miopenSoftmaxMode_t::MIOPEN_SOFTMAX_MODE_CHANNEL;
float alpha = 1.0f;
float beta = 0.0f;
virtual ~miopen_softmax_impl_base_t() {}
virtual status_t init(const softmax_pd_t *pd) = 0;
virtual void execute(miopenHandle_t handle, void **x, int size) const = 0;
status_t convert_alg_kind(bool is_log_softmax,
miopenSoftmaxAlgorithm_t *miopen_alg_kind) const {
if (is_log_softmax) {
*miopen_alg_kind = miopenSoftmaxAlgorithm_t::MIOPEN_SOFTMAX_LOG;
} else {
*miopen_alg_kind
= miopenSoftmaxAlgorithm_t::MIOPEN_SOFTMAX_ACCURATE;
}
return status::success;
}
};
struct miopen_softmax_fwd_impl_t : public miopen_softmax_impl_base_t {
int dims[NUM_IO][DNNL_MAX_NDIMS];
miopenTensorDescriptor_t tensor_desc;
status_t init(const softmax_pd_t *pd) override {
if (pd->has_zero_dim_memory()) return status::success;
if (pd->ndims() > miopen_softmax_max_ndims) {
return status::invalid_arguments;
}
convert_dims(pd->src_md()->padded_dims, dims[src], pd->ndims());
convert_dims(pd->src_md()->format_desc.blocking.strides, strides[src],
pd->ndims());
convert_dims(pd->dst_md()->format_desc.blocking.strides, strides[dst],
pd->ndims());
convert_alg_kind(pd->is_logsoftmax(), &alg_kind);
assert(pd->src_md()->data_type == pd->dst_md()->data_type);
CHECK(convert_data_type(pd->src_md(), &data_type));
CHECK(create_and_set_tensor_descriptor(&tensor_desc, data_type,
miopen_softmax_max_ndims, dims[src], strides[src]));
return status::success;
}
void execute(miopenHandle_t handle, void **x, int size) const override {
assert(size == 2);
MIOPEN_EXECUTE_FUNC(miopenSoftmaxForward_V2, handle, &alpha,
tensor_desc, x[0], &beta, tensor_desc, x[1], alg_kind, mode);
}
~miopen_softmax_fwd_impl_t() {
MIOPEN_EXECUTE_FUNC_V(miopenDestroyTensorDescriptor, tensor_desc);
}
};
struct miopen_softmax_bwd_impl_t : public miopen_softmax_impl_base_t {
int dims[NUM_IO][DNNL_MAX_NDIMS];
miopenTensorDescriptor_t tensor_dst_desc;
miopenTensorDescriptor_t tensor_diff_desc;
status_t init(const softmax_pd_t *pd) override {
if (pd->has_zero_dim_memory()) return status::success;
if (pd->ndims() > miopen_softmax_max_ndims) {
return status::invalid_arguments;
}
convert_dims(pd->dst_md()->padded_dims, dims[dst], pd->ndims());
convert_dims(pd->diff_src_md()->padded_dims, dims[d_src], pd->ndims());
convert_alg_kind(pd->is_logsoftmax(), &alg_kind);
assert(pd->diff_dst_md()->data_type == pd->dst_md()->data_type);
assert(pd->diff_dst_md()->data_type == pd->diff_src_md()->data_type);
CHECK(convert_data_type(pd->dst_md(), &data_type));
convert_dims(pd->dst_md()->format_desc.blocking.strides, strides[dst],
pd->ndims());
convert_dims(pd->diff_src_md()->format_desc.blocking.strides,
strides[d_src], pd->ndims());
convert_dims(pd->diff_dst_md()->format_desc.blocking.strides,
strides[d_dst], pd->ndims());
CHECK(create_and_set_tensor_descriptor(&tensor_dst_desc, data_type,
miopen_softmax_max_ndims, dims[dst], strides[dst]));
CHECK(create_and_set_tensor_descriptor(&tensor_diff_desc, data_type,
miopen_softmax_max_ndims, dims[d_src], strides[d_src]));
return status::success;
}
void execute(miopenHandle_t handle, void **x, int size) const override {
assert(size == 3);
MIOPEN_EXECUTE_FUNC(miopenSoftmaxBackward_V2, handle, &alpha,
tensor_dst_desc, x[0], tensor_diff_desc, x[1], &beta,
tensor_diff_desc, x[2], alg_kind, mode);
}
~miopen_softmax_bwd_impl_t() {
MIOPEN_EXECUTE_FUNC_V(miopenDestroyTensorDescriptor, tensor_dst_desc);
MIOPEN_EXECUTE_FUNC_V(miopenDestroyTensorDescriptor, tensor_diff_desc);
}
};
} } } }
#endif