1 | /******************************************************************************* |
2 | * Copyright 2019-2022 Intel Corporation |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at |
7 | * |
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | * |
10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. |
15 | *******************************************************************************/ |
16 | |
17 | #ifndef GPU_COMPUTE_KERNEL_CTX_HPP |
18 | #define GPU_COMPUTE_KERNEL_CTX_HPP |
19 | |
20 | #include <cassert> |
21 | #ifdef DEBUG_PRINT |
22 | #include <iostream> |
23 | #endif |
24 | #include <map> |
25 | #include <set> |
26 | #include <sstream> |
27 | #include <string> |
28 | #include <type_traits> |
29 | |
30 | #include "common/bit_cast.hpp" |
31 | #include "common/primitive_attr.hpp" |
32 | #include "gpu/gpu_primitive_attr.hpp" |
33 | |
34 | namespace dnnl { |
35 | namespace impl { |
36 | namespace gpu { |
37 | namespace compute { |
38 | |
39 | class kernel_ctx_t { |
40 | public: |
41 | kernel_ctx_t(const primitive_attr_t *attr = nullptr) { |
42 | set_default_options(attr); |
43 | } |
44 | |
45 | std::string options() const { |
46 | std::ostringstream oss; |
47 | for (auto &opt : option_set_) |
48 | oss << " " << opt; |
49 | |
50 | for (auto &int_var : int_var_map_) |
51 | oss << " -D" << int_var.first << "=" << int_var.second; |
52 | |
53 | for (auto &float_var : float_var_map_) { |
54 | oss << " -D" << float_var.first << "=as_float(0x" << std::hex |
55 | << utils::bit_cast<uint32_t>(float_var.second) << ")" ; |
56 | } |
57 | return oss.str(); |
58 | } |
59 | |
60 | void define_int(const char *variable, int64_t value) { |
61 | int_var_map_.insert({variable, value}); |
62 | } |
63 | |
64 | void define_int(const std::string &variable, int64_t value) { |
65 | define_int(variable.c_str(), value); |
66 | } |
67 | |
68 | // TODO: should be removed, any float values should be passed in |
69 | // kernel parameters |
70 | void define_float(const char *variable, float value) { |
71 | float_var_map_.insert({variable, value}); |
72 | } |
73 | |
74 | void add_option(const char *option) { option_set_.insert(option); } |
75 | void add_option(const std::string &option) { add_option(option.c_str()); } |
76 | |
77 | bool has_macro(const char *name) const { |
78 | std::string opt_start = std::string("-D" ) + name + "=" ; |
79 | for (auto &opt : option_set_) |
80 | if (opt.find(opt_start) != std::string::npos) return true; |
81 | |
82 | return int_var_map_.count(name) != 0 || float_var_map_.count(name) != 0; |
83 | } |
84 | bool has_macro(const std::string &name) const { |
85 | return has_macro(name.c_str()); |
86 | } |
87 | |
88 | void set_data_type(data_type_t dt) { |
89 | switch (dt) { |
90 | case data_type::bf16: define_int("DT_BF16" , 1); break; |
91 | case data_type::f16: define_int("DT_F16" , 1); break; |
92 | case data_type::f32: define_int("DT_F32" , 1); break; |
93 | case data_type::f64: define_int("DT_F64" , 1); break; |
94 | case data_type::s8: define_int("DT_S8" , 1); break; |
95 | case data_type::u8: define_int("DT_U8" , 1); break; |
96 | case data_type::s32: define_int("DT_S32" , 1); break; |
97 | default: assert(!"unknown data type" ); break; |
98 | } |
99 | } |
100 | |
101 | void print_options() const { |
102 | #ifdef DEBUG_PRINT |
103 | std::cout << "OPT:\n" << options() << std::endl; |
104 | #endif |
105 | } |
106 | |
107 | template <typename T> |
108 | T get_scalar(const std::string &s) const { |
109 | UNUSED(s); |
110 | static_assert(!std::is_same<T, T>::value, "not expected" ); |
111 | return {}; |
112 | } |
113 | |
114 | std::string data_type() const { |
115 | if (int_var_map_.count("DT_F16" ) != 0) return "f16" ; |
116 | |
117 | if (int_var_map_.count("DT_F32" ) != 0) return "f32" ; |
118 | |
119 | if (int_var_map_.count("DT_F64" ) != 0) return "f64" ; |
120 | |
121 | if (int_var_map_.count("DT_S8" ) != 0) return "s8" ; |
122 | |
123 | return "" ; |
124 | } |
125 | |
126 | private: |
127 | void set_default_options(const primitive_attr_t *attr) { |
128 | // By default fp32 division and sqrt are not IEEE-compliant |
129 | add_option("-cl-fp32-correctly-rounded-divide-sqrt" ); |
130 | |
131 | if (attr && attr->gpu_attr_) { |
132 | auto *gpu_attr = utils::downcast<gpu_primitive_attr_t *>( |
133 | attr->gpu_attr_.get()); |
134 | if (gpu_attr->threads_per_eu() == 4) { |
135 | add_option("-cl-intel-256-GRF-per-thread" ); |
136 | } |
137 | } |
138 | } |
139 | |
140 | std::map<std::string, int64_t> int_var_map_; |
141 | std::map<std::string, float> float_var_map_; |
142 | std::set<std::string> option_set_; |
143 | }; |
144 | |
145 | template <> |
146 | inline int64_t kernel_ctx_t::get_scalar(const std::string &name) const { |
147 | assert(int_var_map_.count(name) != 0 && "not expected" ); |
148 | return int_var_map_.at(name); |
149 | } |
150 | |
151 | } // namespace compute |
152 | } // namespace gpu |
153 | } // namespace impl |
154 | } // namespace dnnl |
155 | |
156 | #endif // GPU_COMPUTE_KERNEL_CTX_HPP |
157 | |