Commit a4f8d30b authored by Paul's avatar Paul
Browse files

Merge branch 'develop' into layout-nhwc

parents d12efcd2 a8d86615
#include <migraphx/gpu/driver/action.hpp>
#include <migraphx/gpu/driver/perf.hpp>
#include <migraphx/gpu/compile_pointwise.hpp>
#include <migraphx/gpu/context.hpp>
namespace migraphx {
inline namespace MIGRAPHX_INLINE_NS {
namespace gpu {
namespace driver {
struct compile_pointwise : action<compile_pointwise>
{
static void apply(const parser& p, const value& v)
{
context ctx;
auto inputs = p.parse_shapes(v.at("inputs"));
auto op = gpu::compile_pointwise(ctx, inputs, v.at("lambda").to<std::string>());
double t = time_op(ctx, op, inputs, p.get(v, "iterations", 100));
std::cout << op << ": " << t << "ms" << std::endl;
}
};
} // namespace driver
} // namespace gpu
} // namespace MIGRAPHX_INLINE_NS
} // namespace migraphx
#ifndef MIGRAPHX_GUARD_GPU_DRIVER_ACTION_HPP
#define MIGRAPHX_GUARD_GPU_DRIVER_ACTION_HPP
#include <migraphx/config.hpp>
#include <migraphx/auto_register.hpp>
#include <migraphx/type_name.hpp>
#include <migraphx/gpu/driver/parser.hpp>
namespace migraphx {
inline namespace MIGRAPHX_INLINE_NS {
namespace gpu {
namespace driver {
using action_function = std::function<void(const parser&, const value&)>;
action_function get_action(const std::string& name);
void register_action(const std::string& name, const action_function& a);
struct auto_register_action
{
template <class T>
static void apply()
{
auto name = get_type_name<T>();
register_action(name.substr(name.rfind("::") + 2),
[](auto&&... xs) { T::apply(std::forward<decltype(xs)>(xs)...); });
}
};
template <class T>
using action = auto_register<auto_register_action, T>;
} // namespace driver
} // namespace gpu
} // namespace MIGRAPHX_INLINE_NS
} // namespace migraphx
#endif // MIGRAPHX_GUARD_GPU_DRIVER_ACTION_HPP
#ifndef MIGRAPHX_GUARD_GPU_DRIVER_PARSER_HPP
#define MIGRAPHX_GUARD_GPU_DRIVER_PARSER_HPP
#include <migraphx/value.hpp>
#include <migraphx/shape.hpp>
#include <unordered_map>
#include <functional>
#include <vector>
#include <string>
namespace migraphx {
inline namespace MIGRAPHX_INLINE_NS {
namespace gpu {
namespace driver {
[[noreturn]] void error(const std::string& msg);
struct parser
{
parser() = default;
template <class T>
T get(const value& v, const std::string& key, const T& default_value) const
{
return v.get(key, settings.get(key, default_value));
}
shape parse_shape(const value& v) const;
std::vector<shape> parse_shapes(const value& v) const;
void load_settings(const value& v);
static void process(const value& v);
private:
value settings = value::object{};
};
} // namespace driver
} // namespace gpu
} // namespace MIGRAPHX_INLINE_NS
} // namespace migraphx
#endif // MIGRAPHX_GUARD_GPU_DRIVER_PARSER_HPP
#ifndef MIGRAPHX_GUARD_GPU_DRIVER_PERF_HPP
#define MIGRAPHX_GUARD_GPU_DRIVER_PERF_HPP
#include <migraphx/config.hpp>
#include <migraphx/gpu/context.hpp>
#include <migraphx/operation.hpp>
namespace migraphx {
inline namespace MIGRAPHX_INLINE_NS {
namespace gpu {
namespace driver {
double time_op(context& ctx, operation op, const std::vector<shape>& inputs, int n = 100);
} // namespace driver
} // namespace gpu
} // namespace MIGRAPHX_INLINE_NS
} // namespace migraphx
#endif // MIGRAPHX_GUARD_GPU_DRIVER_PERF_HPP
#include <migraphx/gpu/driver/parser.hpp>
#include <migraphx/json.hpp>
#include <migraphx/convert_to_json.hpp>
#include <migraphx/file_buffer.hpp>
using namespace migraphx; // NOLINT
using namespace migraphx::gpu; // NOLINT
using namespace migraphx::gpu::driver; // NOLINT
int main(int argc, char const* argv[])
{
std::vector<std::string> args(argv, argv + argc);
if(args.size() < 2)
{
std::cout << "Usage: gpu-driver <input-file>" << std::endl;
std::abort();
}
auto v = from_json_string(convert_to_json(read_string(args[1])));
parser::process(v);
}
#include <migraphx/gpu/driver/parser.hpp>
#include <migraphx/gpu/driver/action.hpp>
namespace migraphx {
inline namespace MIGRAPHX_INLINE_NS {
namespace gpu {
namespace driver {
[[noreturn]] void error(const std::string& msg)
{
std::cout << msg << std::endl;
std::abort();
}
shape parser::parse_shape(const value& v) const
{
auto lens = get(v, "lens", std::vector<std::size_t>{});
auto strides = get(v, "strides", std::vector<std::size_t>{});
auto type = shape::parse_type(get<std::string>(v, "type", "float"));
if(strides.empty())
return shape{type, lens};
else
return shape{type, lens, strides};
}
std::vector<shape> parser::parse_shapes(const value& v) const
{
std::vector<shape> result;
std::transform(
v.begin(), v.end(), std::back_inserter(result), [&](auto&& x) { return parse_shape(x); });
return result;
}
void parser::load_settings(const value& v)
{
if(v.contains("settings"))
settings = v.at("settings");
}
void parser::process(const value& v)
{
if(not v.is_object())
error("Input is not an object");
parser p{};
p.load_settings(v);
for(auto&& pp : v)
{
if(pp.get_key() == "settings")
continue;
get_action(pp.get_key())(p, pp.without_key());
}
}
} // namespace driver
} // namespace gpu
} // namespace MIGRAPHX_INLINE_NS
} // namespace migraphx
#include <migraphx/gpu/driver/perf.hpp>
#include <migraphx/context.hpp>
#include <migraphx/generate.hpp>
#include <migraphx/time.hpp>
#include <migraphx/gpu/hip.hpp>
namespace migraphx {
inline namespace MIGRAPHX_INLINE_NS {
namespace gpu {
namespace driver {
std::vector<argument> generate_arguments(const std::vector<shape>& shapes, unsigned long seed = 0)
{
std::vector<argument> args;
std::transform(shapes.begin(), shapes.end(), std::back_inserter(args), [&](auto& s) {
return to_gpu(generate_argument(s, seed++));
});
return args;
}
using milliseconds = std::chrono::duration<double, std::milli>;
double time_op(context& ctx, operation op, const std::vector<shape>& inputs, int n)
{
// TODO: Use std::ref
migraphx::context gctx = ctx;
auto output = op.compute_shape(inputs);
op.finalize(gctx, output, inputs);
auto args = generate_arguments(inputs);
auto run = [&] {
op.compute(gctx, output, args);
gctx.finish();
};
run();
auto r = range(n);
double t = std::accumulate(
r.begin(), r.end(), double{0.0}, [&](auto x, auto) { return x + time<milliseconds>(run); });
return t / n;
}
} // namespace driver
} // namespace gpu
} // namespace MIGRAPHX_INLINE_NS
} // namespace migraphx
#include <migraphx/gpu/driver/action.hpp>
#include <migraphx/gpu/driver/perf.hpp>
#include <migraphx/gpu/context.hpp>
#include <migraphx/make_op.hpp>
namespace migraphx {
inline namespace MIGRAPHX_INLINE_NS {
namespace gpu {
namespace driver {
struct run_op : action<run_op>
{
static void apply(const parser& p, const value& v)
{
context ctx;
auto inputs = p.parse_shapes(v.at("inputs"));
auto name = v.at("name").to<std::string>();
if(not contains(name, "::"))
name = "gpu::" + name;
auto op = make_op(name);
double t = time_op(ctx, op, inputs);
std::cout << op << ": " << t << "ms" << std::endl;
}
};
} // namespace driver
} // namespace gpu
} // namespace MIGRAPHX_INLINE_NS
} // namespace migraphx
...@@ -51,6 +51,7 @@ struct code_object_op ...@@ -51,6 +51,7 @@ struct code_object_op
os << "symbol_name=" << op.symbol_name << ","; os << "symbol_name=" << op.symbol_name << ",";
os << "global=" << op.global << ","; os << "global=" << op.global << ",";
os << "local=" << op.local << ","; os << "local=" << op.local << ",";
os << "]";
return os; return os;
} }
}; };
......
...@@ -16,6 +16,7 @@ struct hip_compile_options ...@@ -16,6 +16,7 @@ struct hip_compile_options
shape output; shape output;
std::string kernel_name = "kernel"; std::string kernel_name = "kernel";
std::string params = ""; std::string params = "";
std::vector<shape> reduced_inputs = {};
}; };
operation compile_hip_code_object(const std::string& content, hip_compile_options options); operation compile_hip_code_object(const std::string& content, hip_compile_options options);
......
#ifndef MIGRAPHX_GUARD_GPU_COMPILE_POINTWISE_HPP
#define MIGRAPHX_GUARD_GPU_COMPILE_POINTWISE_HPP
#include <migraphx/config.hpp>
#include <migraphx/operation.hpp>
namespace migraphx {
inline namespace MIGRAPHX_INLINE_NS {
namespace gpu {
struct context;
operation
compile_pointwise(context& ctx, const std::vector<shape>& inputs, const std::string& lambda);
} // namespace gpu
} // namespace MIGRAPHX_INLINE_NS
} // namespace migraphx
#endif // MIGRAPHX_GUARD_GPU_COMPILE_POINTWISE_HPP
#ifndef MIGRAPHX_GUARD_RTGLIB_DEVICE_SCATTER_HPP
#define MIGRAPHX_GUARD_RTGLIB_DEVICE_SCATTER_HPP
#include <migraphx/argument.hpp>
#include <migraphx/config.hpp>
#include <hip/hip_runtime_api.h>
namespace migraphx {
inline namespace MIGRAPHX_INLINE_NS {
namespace gpu {
namespace device {
argument scatter(
hipStream_t stream, argument result, argument arg0, argument arg1, argument arg2, int64_t axis);
} // namespace device
} // namespace gpu
} // namespace MIGRAPHX_INLINE_NS
} // namespace migraphx
#endif
#ifndef MIGRAPHX_GUARD_RTGLIB_SCATTER_HPP
#define MIGRAPHX_GUARD_RTGLIB_SCATTER_HPP
#include <migraphx/argument.hpp>
#include <migraphx/reflect.hpp>
#include <migraphx/op/scatter.hpp>
#include <migraphx/gpu/miopen.hpp>
namespace migraphx {
inline namespace MIGRAPHX_INLINE_NS {
namespace gpu {
struct context;
struct hip_scatter
{
op::scatter op;
template <class Self, class F>
static auto reflect(Self& self, F f)
{
return migraphx::reflect(self.op, f);
}
std::string name() const { return "gpu::scatter"; }
shape compute_shape(std::vector<shape> inputs) const;
argument
compute(context& ctx, const shape& output_shape, const std::vector<argument>& args) const;
std::ptrdiff_t output_alias(const std::vector<shape>& shapes) const
{
return shapes.size() - 1;
}
};
} // namespace gpu
} // namespace MIGRAPHX_INLINE_NS
} // namespace migraphx
#endif
...@@ -43,6 +43,59 @@ constexpr bool is_sorted(Iterator first, Iterator last, Compare comp) ...@@ -43,6 +43,59 @@ constexpr bool is_sorted(Iterator first, Iterator last, Compare comp)
return is_sorted_until(first, last, comp) == last; return is_sorted_until(first, last, comp) == last;
} }
template <class Iterator, class F>
constexpr F for_each(Iterator first, Iterator last, F f)
{
for(; first != last; ++first)
{
f(*first);
}
return f;
}
template <class Iterator, class Predicate>
constexpr Iterator find_if(Iterator first, Iterator last, Predicate p)
{
for(; first != last; ++first)
{
if(p(*first))
{
return first;
}
}
return last;
}
template <class Iterator, class T>
constexpr Iterator find(Iterator first, Iterator last, const T& value)
{
return find_if(first, last, [&](const auto& x) { return x == value; });
}
template <class Iterator1, class Iterator2>
constexpr Iterator1 search(Iterator1 first, Iterator1 last, Iterator2 s_first, Iterator2 s_last)
{
for(;; ++first)
{
Iterator1 it = first;
for(Iterator2 s_it = s_first;; ++it, ++s_it)
{
if(s_it == s_last)
{
return first;
}
if(it == last)
{
return last;
}
if(!(*it == *s_it))
{
break;
}
}
}
}
} // namespace migraphx } // namespace migraphx
#endif #endif
...@@ -2,56 +2,25 @@ ...@@ -2,56 +2,25 @@
#define MIGRAPHX_GUARD_KERNELS_ARGS_HPP #define MIGRAPHX_GUARD_KERNELS_ARGS_HPP
#include <migraphx/kernels/types.hpp> #include <migraphx/kernels/types.hpp>
#include <migraphx/kernels/functional.hpp>
namespace migraphx { namespace migraphx {
template <std::size_t N>
struct arg
{
};
template <std::size_t...>
struct seq
{
using type = seq;
};
template <class, class>
struct merge_seq;
template <std::size_t... Xs, std::size_t... Ys>
struct merge_seq<seq<Xs...>, seq<Ys...>> : seq<Xs..., (sizeof...(Xs) + Ys)...>
{
};
template <std::size_t N>
struct gens : merge_seq<typename gens<N / 2>::type, typename gens<N - N / 2>::type>
{
};
template <>
struct gens<0> : seq<>
{
};
template <>
struct gens<1> : seq<0>
{
};
// Use template specialization since ADL is broken on hcc // Use template specialization since ADL is broken on hcc
template <std::size_t> template <index_int>
struct make_tensor; struct make_tensor;
template <class F, std::size_t... Ns, class... Ts> template <class F, index_int... Ns, class... Ts>
__device__ auto make_tensors_impl(F f, seq<Ns...>, Ts*... xs) __device__ auto make_tensors_impl(F f, detail::seq<Ns...>, Ts*... xs)
{ {
f(make_tensor<Ns>::apply(xs)...); return f(make_tensor<Ns>::apply(xs)...);
} }
template <class... Ts> inline __device__ auto make_tensors()
__device__ auto make_tensors(Ts*... xs)
{ {
return [=](auto f) { make_tensors_impl(f, gens<sizeof...(Ts)>{}, xs...); }; return [](auto*... xs) {
return [=](auto f) { return make_tensors_impl(f, detail::gens<sizeof...(xs)>{}, xs...); };
};
} }
} // namespace migraphx } // namespace migraphx
......
...@@ -2,7 +2,8 @@ ...@@ -2,7 +2,8 @@
#define MIGRAPHX_GUARD_AMDMIGRAPHX_KERNELS_ARRAY_HPP #define MIGRAPHX_GUARD_AMDMIGRAPHX_KERNELS_ARRAY_HPP
#include <migraphx/kernels/types.hpp> #include <migraphx/kernels/types.hpp>
#include <type_traits> #include <migraphx/kernels/integral_constant.hpp>
#include <migraphx/kernels/debug.hpp>
namespace migraphx { namespace migraphx {
...@@ -41,8 +42,16 @@ template <class T, index_int N> ...@@ -41,8 +42,16 @@ template <class T, index_int N>
struct array struct array
{ {
T d[N]; T d[N];
constexpr T& operator[](index_int i) { return d[i]; } constexpr T& operator[](index_int i)
constexpr const T& operator[](index_int i) const { return d[i]; } {
MIGRAPHX_ASSERT(i < N);
return d[i];
}
constexpr const T& operator[](index_int i) const
{
MIGRAPHX_ASSERT(i < N);
return d[i];
}
constexpr T& front() { return d[0]; } constexpr T& front() { return d[0]; }
constexpr const T& front() const { return d[0]; } constexpr const T& front() const { return d[0]; }
...@@ -53,7 +62,7 @@ struct array ...@@ -53,7 +62,7 @@ struct array
constexpr T* data() { return d; } constexpr T* data() { return d; }
constexpr const T* data() const { return d; } constexpr const T* data() const { return d; }
constexpr std::integral_constant<index_int, N> size() const { return {}; } constexpr index_constant<N> size() const { return {}; }
constexpr T* begin() { return d; } constexpr T* begin() { return d; }
constexpr const T* begin() const { return d; } constexpr const T* begin() const { return d; }
...@@ -142,6 +151,18 @@ struct array ...@@ -142,6 +151,18 @@ struct array
result[0] += overflow; result[0] += overflow;
return result; return result;
} }
template <class Stream>
friend constexpr const Stream& operator<<(const Stream& ss, const array& a)
{
for(index_int i = 0; i < N; i++)
{
if(i > 0)
ss << ", ";
ss << a[i];
}
return ss;
}
}; };
template <class T, T... xs> template <class T, T... xs>
...@@ -151,6 +172,18 @@ struct integral_const_array : array<T, sizeof...(xs)> ...@@ -151,6 +172,18 @@ struct integral_const_array : array<T, sizeof...(xs)>
MIGRAPHX_DEVICE_CONSTEXPR integral_const_array() : base_array({xs...}) {} MIGRAPHX_DEVICE_CONSTEXPR integral_const_array() : base_array({xs...}) {}
}; };
template <class T, T... xs, class F>
constexpr auto transform(integral_const_array<T, xs...>, F f)
{
return integral_const_array<T, f(xs)...>{};
}
template <class T, T... xs, class U, U... ys, class F>
constexpr auto transform(integral_const_array<T, xs...>, integral_const_array<U, ys...>, F f)
{
return integral_const_array<T, f(xs, ys)...>{};
}
template <index_int... Ns> template <index_int... Ns>
using index_ints = integral_const_array<index_int, Ns...>; using index_ints = integral_const_array<index_int, Ns...>;
......
#ifndef MIGRAPHX_GUARD_KERNELS_DEBUG_HPP
#define MIGRAPHX_GUARD_KERNELS_DEBUG_HPP
#include <hip/hip_runtime.h>
namespace migraphx {
inline __host__ __device__ void
assert_fail(const char* assertion, const char* file, unsigned int line, const char* function)
{
printf("%s:%u: %s: assertion '%s' failed.\n", file, line, function, assertion);
abort();
}
#ifdef MIGRAPHX_DEBUG
#define MIGRAPHX_ASSERT(cond) \
((cond) ? void(0) : [](auto... xs) { \
assert_fail(xs...); \
}(#cond, __FILE__, __LINE__, __PRETTY_FUNCTION__))
#else
#define MIGRAPHX_ASSERT(cond)
#endif
} // namespace migraphx
#endif // MIGRAPHX_GUARD_KERNELS_DEBUG_HPP
#ifndef MIGRAPHX_GUARD_KERNELS_FUNCTIONAL_HPP
#define MIGRAPHX_GUARD_KERNELS_FUNCTIONAL_HPP
#include <migraphx/kernels/array.hpp>
namespace migraphx {
struct swallow
{
template <class... Ts>
constexpr swallow(Ts&&...)
{
}
};
template <index_int>
using ignore = swallow;
namespace detail {
template <class R>
struct eval_helper
{
R result;
template <class F, class... Ts>
constexpr eval_helper(const F& f, Ts&&... xs) : result(f(static_cast<Ts>(xs)...))
{
}
};
template <>
struct eval_helper<void>
{
int result;
template <class F, class... Ts>
constexpr eval_helper(const F& f, Ts&&... xs) : result((f(static_cast<Ts>(xs)...), 0))
{
}
};
template <index_int...>
struct seq
{
using type = seq;
};
template <class, class>
struct merge_seq;
template <index_int... Xs, index_int... Ys>
struct merge_seq<seq<Xs...>, seq<Ys...>> : seq<Xs..., (sizeof...(Xs) + Ys)...>
{
};
template <index_int N>
struct gens : merge_seq<typename gens<N / 2>::type, typename gens<N - N / 2>::type>
{
};
template <>
struct gens<0> : seq<>
{
};
template <>
struct gens<1> : seq<0>
{
};
template <class F, index_int... Ns>
constexpr auto sequence_c_impl(F&& f, seq<Ns...>)
{
return f(index_constant<Ns>{}...);
}
template <index_int... N>
constexpr auto args_at(seq<N...>)
{
return [](ignore<N>..., auto x, auto...) { return x; };
}
} // namespace detail
template <class T>
constexpr auto always(T x)
{
return [=](auto&&...) { return x; };
}
template <index_int N, class F>
constexpr auto sequence_c(F&& f)
{
return detail::sequence_c_impl(f, detail::gens<N>{});
}
template <class IntegerConstant, class F>
constexpr auto sequence(IntegerConstant ic, F&& f)
{
return sequence_c<ic>(f);
}
template <class F, class G>
constexpr auto by(F f, G g)
{
return [=](auto... xs) {
return detail::eval_helper<decltype(g(f(xs)...))>{g, f(xs)...}.result;
};
}
template <class F>
constexpr auto by(F f)
{
return by([=](auto x) { return (f(x), 0); }, always(0));
}
template <class F, class... Ts>
constexpr void each_args(F f, Ts&&... xs)
{
swallow{(f(std::forward<Ts>(xs)), 0)...};
}
template <class F>
constexpr void each_args(F)
{
}
template <class... Ts>
auto pack(Ts... xs)
{
return [=](auto f) { return f(xs...); };
}
template <index_int N>
constexpr auto arg_c()
{
return [](auto... xs) { return detail::args_at(detail::gens<N>{})(xs...); };
}
template <class IntegralConstant>
constexpr auto arg(IntegralConstant ic)
{
return arg_c<ic>();
}
inline constexpr auto rotate_last()
{
return [](auto... xs) {
return [=](auto&& f) {
return sequence_c<sizeof...(xs)>([&](auto... is) {
constexpr auto size = sizeof...(is);
return f(arg_c<(is + size - 1) % size>()(xs...)...);
});
};
};
}
template <class F>
constexpr auto transform_args(F f)
{
return [=](auto... xs) {
return [=](auto g) { return f(xs...)([&](auto... ys) { return g(ys...); }); };
};
}
template <class F, class... Fs>
constexpr auto transform_args(F f, Fs... fs)
{
return [=](auto... xs) { return transform_args(f)(xs...)(transform_args(fs...)); };
}
#define MIGRAPHX_LIFT(...) \
([](auto&&... xs) { return (__VA_ARGS__)(static_cast<decltype(xs)>(xs)...); })
} // namespace migraphx
#endif // MIGRAPHX_GUARD_KERNELS_FUNCTIONAL_HPP
...@@ -12,9 +12,43 @@ struct index ...@@ -12,9 +12,43 @@ struct index
index_int local = 0; index_int local = 0;
index_int group = 0; index_int group = 0;
__device__ index_int nglobal() const { return blockDim.x * gridDim.x; } // NOLINT __device__ index_int nglobal() const
{
#ifdef MIGRAPHX_NGLOBAL
return MIGRAPHX_NGLOBAL;
#else
return blockDim.x * gridDim.x;
#endif
}
__device__ index_int nlocal() const { return blockDim.x; } // NOLINT __device__ index_int nlocal() const
{
#ifdef MIGRAPHX_NLOCAL
return MIGRAPHX_NLOCAL;
#else
return blockDim.x;
#endif
}
template <class F>
__device__ void global_stride(index_int n, F f) const
{
const auto stride = nglobal();
for(index_int i = global; i < n; i += stride)
{
f(i);
}
}
template <class F>
__device__ void local_stride(index_int n, F f) const
{
const auto stride = nlocal();
for(index_int i = local; i < n; i += stride)
{
f(i);
}
}
}; };
inline __device__ index make_index() inline __device__ index make_index()
......
#ifndef MIGRAPHX_GUARD_KERNELS_INTEGRAL_CONSTANT_HPP
#define MIGRAPHX_GUARD_KERNELS_INTEGRAL_CONSTANT_HPP
#include <migraphx/kernels/types.hpp>
namespace migraphx {
template <class T, T v>
struct integral_constant
{
static constexpr T value = v;
using value_type = T;
using type = integral_constant;
constexpr operator value_type() const noexcept { return value; }
constexpr value_type operator()() const noexcept { return value; }
};
#define MIGRAPHX_INTEGRAL_CONSTANT_BINARY_OP(op) \
template <class T, T v, class U, U w> \
constexpr inline integral_constant<decltype(v op w), (v op w)> operator op( \
integral_constant<T, v>, integral_constant<U, w>) noexcept \
{ \
return {}; \
}
#define MIGRAPHX_INTEGRAL_CONSTANT_UNARY_OP(op) \
template <class T, T v> \
constexpr inline integral_constant<decltype(op v), (op v)> operator op( \
integral_constant<T, v>) noexcept \
{ \
return {}; \
}
MIGRAPHX_INTEGRAL_CONSTANT_BINARY_OP(+)
MIGRAPHX_INTEGRAL_CONSTANT_BINARY_OP(-)
MIGRAPHX_INTEGRAL_CONSTANT_BINARY_OP(*)
MIGRAPHX_INTEGRAL_CONSTANT_BINARY_OP(/)
MIGRAPHX_INTEGRAL_CONSTANT_BINARY_OP(%)
MIGRAPHX_INTEGRAL_CONSTANT_BINARY_OP(>>)
MIGRAPHX_INTEGRAL_CONSTANT_BINARY_OP(<<)
MIGRAPHX_INTEGRAL_CONSTANT_BINARY_OP(>)
MIGRAPHX_INTEGRAL_CONSTANT_BINARY_OP(<)
MIGRAPHX_INTEGRAL_CONSTANT_BINARY_OP(<=)
MIGRAPHX_INTEGRAL_CONSTANT_BINARY_OP(>=)
MIGRAPHX_INTEGRAL_CONSTANT_BINARY_OP(==)
MIGRAPHX_INTEGRAL_CONSTANT_BINARY_OP(!=)
MIGRAPHX_INTEGRAL_CONSTANT_BINARY_OP(&)
MIGRAPHX_INTEGRAL_CONSTANT_BINARY_OP (^)
MIGRAPHX_INTEGRAL_CONSTANT_BINARY_OP(|)
MIGRAPHX_INTEGRAL_CONSTANT_BINARY_OP(&&)
MIGRAPHX_INTEGRAL_CONSTANT_BINARY_OP(||)
MIGRAPHX_INTEGRAL_CONSTANT_UNARY_OP(!)
MIGRAPHX_INTEGRAL_CONSTANT_UNARY_OP(~)
MIGRAPHX_INTEGRAL_CONSTANT_UNARY_OP(+)
MIGRAPHX_INTEGRAL_CONSTANT_UNARY_OP(-)
template <bool B>
using bool_constant = integral_constant<bool, B>;
using true_type = bool_constant<true>;
using false_type = bool_constant<false>;
template <index_int N>
using index_constant = integral_constant<index_int, N>;
template <auto v>
static constexpr auto _c = integral_constant<decltype(v), v>{};
} // namespace migraphx
#endif // MIGRAPHX_GUARD_KERNELS_INTEGRAL_CONSTANT_HPP
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment