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
24namespace dnnl {
25namespace impl {
26namespace gpu {
27namespace jit {
28
29enum 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.
38class ngen_operand_t {
39public:
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 &reg_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 &reg_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
162private:
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
191template <typename T>
192T 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