1 | /******************************************************************************* |
2 | * Copyright 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_JIT_CODEGEN_OPERAND_HPP |
18 | #define GPU_JIT_CODEGEN_OPERAND_HPP |
19 | |
20 | #include "gpu/jit/codegen/ngen_helpers.hpp" |
21 | #include "gpu/jit/codegen/reg_buf.hpp" |
22 | #include "gpu/jit/ngen/ngen.hpp" |
23 | |
24 | namespace dnnl { |
25 | namespace impl { |
26 | namespace gpu { |
27 | namespace jit { |
28 | |
29 | enum class ngen_operand_kind_t { |
30 | invalid, |
31 | immediate, |
32 | reg_buf_data, |
33 | flag_register |
34 | }; |
35 | |
36 | // Wrapper to generalize ngen::FlagRegister, ngen::RegData, reg_buf_data_t and |
37 | // ngen::Immediate operands. |
38 | class ngen_operand_t { |
39 | public: |
40 | ngen_operand_t() : kind_(ngen_operand_kind_t::invalid) {} |
41 | |
42 | ngen_operand_t(const ngen::FlagRegister &flag) |
43 | : kind_(ngen_operand_kind_t::flag_register) |
44 | , ptr_(new ngen::FlagRegister(flag), |
45 | destroy<ngen_operand_kind_t::flag_register>) {} |
46 | |
47 | ngen_operand_t(const reg_buf_data_t ®_buf_data) |
48 | : kind_(ngen_operand_kind_t::reg_buf_data) |
49 | , ptr_(new reg_buf_data_t(reg_buf_data), |
50 | destroy<ngen_operand_kind_t::reg_buf_data>) {} |
51 | |
52 | ngen_operand_t(const ngen::Immediate &imm) |
53 | : kind_(ngen_operand_kind_t::immediate) |
54 | , ptr_(new ngen::Immediate(imm), |
55 | destroy<ngen_operand_kind_t::immediate>) {} |
56 | |
57 | template <typename T> |
58 | ngen_operand_t(const T &other, const ngen::InstructionModifier &mod) |
59 | : ngen_operand_t(other) { |
60 | mod_ = mod; |
61 | } |
62 | |
63 | const ngen::Immediate &immediate() const { |
64 | ir_assert(is_immediate()); |
65 | return *(const ngen::Immediate *)ptr_.get(); |
66 | } |
67 | |
68 | const reg_buf_data_t ®_buf_data() const { |
69 | ir_assert(is_reg_buf_data()); |
70 | return *(const reg_buf_data_t *)ptr_.get(); |
71 | } |
72 | |
73 | ngen::RegData reg_data() const { |
74 | auto &rd = reg_buf_data().reg_data(); |
75 | return is_negated_ ? -rd : rd; |
76 | } |
77 | |
78 | const ngen::FlagRegister &flag_register() const { |
79 | ir_assert(is_flag_register()); |
80 | return *(const ngen::FlagRegister *)ptr_.get(); |
81 | } |
82 | |
83 | ngen::InstructionModifier flag_register_mod() const { |
84 | ngen::InstructionModifier mod; |
85 | mod |= flag_register(); |
86 | return !is_negated() ? mod : ~mod; |
87 | } |
88 | |
89 | const ngen::InstructionModifier &mod() const { return mod_; } |
90 | |
91 | bool is_invalid() const { return kind_ == ngen_operand_kind_t::invalid; } |
92 | |
93 | bool is_immediate() const { |
94 | return kind_ == ngen_operand_kind_t::immediate; |
95 | } |
96 | |
97 | bool is_reg_buf_data() const { |
98 | return kind_ == ngen_operand_kind_t::reg_buf_data; |
99 | } |
100 | |
101 | bool is_reg_data() const { return is_reg_buf_data(); } |
102 | |
103 | bool is_flag_register() const { |
104 | return kind_ == ngen_operand_kind_t::flag_register; |
105 | } |
106 | |
107 | bool is_negated() const { return is_negated_; } |
108 | |
109 | ngen::DataType type() const { |
110 | if (is_immediate()) return immediate().getType(); |
111 | if (is_reg_buf_data()) return reg_buf_data().type(); |
112 | ir_error_not_expected(); |
113 | return ngen::DataType::invalid; |
114 | } |
115 | |
116 | ngen_operand_t operator-() const { |
117 | if (is_immediate()) return ngen_operand_t(ngen_negate(immediate())); |
118 | if (is_reg_buf_data() || is_flag_register()) { |
119 | auto ret = *this; |
120 | ret.is_negated_ = !ret.is_negated_; |
121 | return ret; |
122 | } |
123 | ir_error_not_expected(); |
124 | return ngen_operand_t(); |
125 | } |
126 | |
127 | ngen_operand_t reinterpret(const type_t &new_type) const { |
128 | ir_assert(new_type.is_scalar()); |
129 | return ngen_operand_t( |
130 | reg_buf_data().reinterpret(to_ngen(new_type)), mod_); |
131 | } |
132 | |
133 | // Creates an operand with the requested register region based on the |
134 | // existing region. off - offset in elements of the region data type. |
135 | ngen_operand_t sub_reg_data(int off, int exec_size) const { |
136 | int off_bytes = off * ngen::getBytes(reg_buf_data().type()) |
137 | * reg_buf_data().hs(); |
138 | auto rd = reg_buf_data().format(off_bytes, ngen::DataType::invalid, |
139 | exec_size, reg_buf_data().hs()); |
140 | return ngen_operand_t(rd, exec_size); |
141 | } |
142 | |
143 | bool operator==(const ngen_operand_t &other) const { |
144 | if (kind_ != other.kind_) return false; |
145 | if (mod_.getAll() != other.mod_.getAll()) return false; |
146 | switch (kind_) { |
147 | case ngen_operand_kind_t::immediate: { |
148 | auto &this_imm = immediate(); |
149 | auto &other_imm = other.immediate(); |
150 | return (this_imm.getType() == other_imm.getType()) |
151 | && (uint64_t(this_imm) == uint64_t(other_imm)); |
152 | } |
153 | case ngen_operand_kind_t::flag_register: |
154 | return flag_register() == other.flag_register(); |
155 | case ngen_operand_kind_t::reg_buf_data: |
156 | return reg_buf_data() == other.reg_buf_data(); |
157 | default: ir_error_not_expected(); |
158 | } |
159 | return false; |
160 | } |
161 | |
162 | private: |
163 | template <ngen_operand_kind_t kind> |
164 | static void destroy(void *ptr) { |
165 | if (!ptr) return; |
166 | |
167 | switch (kind) { |
168 | case ngen_operand_kind_t::immediate: |
169 | delete (ngen::Immediate *)ptr; |
170 | break; |
171 | case ngen_operand_kind_t::reg_buf_data: |
172 | delete (reg_buf_data_t *)ptr; |
173 | break; |
174 | case ngen_operand_kind_t::flag_register: |
175 | delete (ngen::FlagRegister *)ptr; |
176 | break; |
177 | default: ir_error_not_expected(); |
178 | } |
179 | } |
180 | |
181 | ngen_operand_kind_t kind_; |
182 | std::shared_ptr<void> ptr_; |
183 | ngen::InstructionModifier mod_; |
184 | |
185 | // Whether the operand is negated. Applicable to flag registers and |
186 | // register data operands only. Negation of immediate operands is directly |
187 | // supported through nGEN API. |
188 | bool is_negated_ = false; |
189 | }; |
190 | |
191 | template <typename T> |
192 | T to_cpp(ngen::HW hw, const ngen_operand_t &op) { |
193 | ir_assert(op.is_immediate()); |
194 | return to_cpp<T>(op.immediate()); |
195 | } |
196 | |
197 | } // namespace jit |
198 | } // namespace gpu |
199 | } // namespace impl |
200 | } // namespace dnnl |
201 | |
202 | #endif |
203 | |