]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/brig/brigfrontend/brig-cvt-inst-handler.cc
Update copyright years.
[thirdparty/gcc.git] / gcc / brig / brigfrontend / brig-cvt-inst-handler.cc
1 /* brig-cvt-inst-handler.cc -- brig cvt (convert) instruction handling
2 Copyright (C) 2016-2018 Free Software Foundation, Inc.
3 Contributed by Pekka Jaaskelainen <pekka.jaaskelainen@parmance.com>
4 for General Processor Tech.
5
6 This file is part of GCC.
7
8 GCC is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 3, or (at your option) any later
11 version.
12
13 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING3. If not see
20 <http://www.gnu.org/licenses/>. */
21
22 #include <sstream>
23
24 #include "brig-code-entry-handler.h"
25
26 #include "gimple-expr.h"
27 #include "errors.h"
28 #include "convert.h"
29 #include "tree-pretty-print.h"
30 #include "print-tree.h"
31 #include "diagnostic-core.h"
32 #include "brig-util.h"
33
34 const BrigAluModifier8_t *
35 brig_cvt_inst_handler::modifier (const BrigBase *base) const
36 {
37 const BrigInstCvt *inst = (const BrigInstCvt *) base;
38 return &inst->modifier;
39 }
40
41 const BrigRound8_t *
42 brig_cvt_inst_handler::round (const BrigBase *base) const
43 {
44 const BrigInstCvt *inst = (const BrigInstCvt *) base;
45 return &inst->round;
46 }
47
48 size_t
49 brig_cvt_inst_handler::generate (const BrigBase *base)
50 {
51 /* In cvt instructions there can be at least four data types involved:
52
53 - the input register type
54 - the output register type
55 - the conversion source type
56 - the conversion destination type
57 */
58
59 const BrigInstBase *brig_inst
60 = (const BrigInstBase *) &((const BrigInstBasic *) base)->base;
61 const BrigInstCvt *cvt_inst = (const BrigInstCvt *) base;
62
63 const BrigAluModifier8_t *inst_modifier = modifier (base);
64 const bool FTZ = inst_modifier != NULL && (*inst_modifier) & BRIG_ALU_FTZ;
65
66 /* The conversion source type. */
67 tree src_type = get_tree_expr_type_for_hsa_type (cvt_inst->sourceType);
68
69 bool src_is_fp16 = cvt_inst->sourceType == BRIG_TYPE_F16;
70
71 /* The conversion destination type. */
72 tree dest_type = gccbrig_tree_type_for_hsa_type (brig_inst->type);
73
74 bool dest_is_fp16 = brig_inst->type == BRIG_TYPE_F16;
75
76 if (!dest_type || !src_type)
77 {
78 gcc_unreachable ();
79 return base->byteCount;
80 }
81
82 tree_stl_vec operands = build_operands (*brig_inst);
83 tree &input = operands.at (1);
84 tree &output = operands.at (0);
85
86 size_t conv_src_size = int_size_in_bytes (src_type);
87 size_t conv_dst_size = int_size_in_bytes (dest_type);
88 size_t src_reg_size = int_size_in_bytes (TREE_TYPE (input));
89
90 /* The input register can be of different type&size than the
91 conversion input size. First cast the input to the conversion
92 input type. These casts are always bitcasts which can be
93 expressed as casts between different unsigned integers. */
94 if (src_reg_size != conv_src_size)
95 {
96 tree unsigned_int_type = NULL_TREE;
97 if (INTEGRAL_TYPE_P (src_type))
98 unsigned_int_type = unsigned_type_for (src_type);
99 else /* Find a matching size int type for the REAL type. */
100 {
101 if (conv_src_size == 2)
102 unsigned_int_type = gccbrig_tree_type_for_hsa_type (BRIG_TYPE_U16);
103 else if (conv_src_size == 4)
104 unsigned_int_type = gccbrig_tree_type_for_hsa_type (BRIG_TYPE_U32);
105 else if (conv_src_size == 8)
106 unsigned_int_type = gccbrig_tree_type_for_hsa_type (BRIG_TYPE_U64);
107 else
108 gcc_unreachable ();
109 }
110 input = convert_to_integer (unsigned_int_type, input);
111 }
112
113 if (src_is_fp16)
114 input = build_h2f_conversion (input);
115
116 /* Flush the float operand to zero if indicated with 'ftz'. */
117 if (FTZ && SCALAR_FLOAT_TYPE_P (src_type))
118 {
119 tree casted_input = build_resize_convert_view (src_type, input);
120 input = flush_to_zero (src_is_fp16) (*this, casted_input);
121 }
122
123 tree conversion_result = NULL_TREE;
124 if (brig_inst->type == BRIG_TYPE_B1)
125 {
126 /* When the destination is b1, cvt does a 'ztest' operation which is
127 defined as a != 0 for integers and similarly (!= 0.0f) for floats. */
128 if (INTEGRAL_TYPE_P (src_type))
129 {
130 /* Generate an integer not equal operation. */
131 conversion_result = build2 (NE_EXPR, TREE_TYPE (input), input,
132 build_int_cst (TREE_TYPE (input), 0));
133 }
134 else
135 {
136 /* For REAL source types, ztest returns 1 if the value is not +- 0.0f.
137 We can perform this check with an integer comparison after
138 masking away the sign bit from a correct position. This is safer
139 than using absf because of exceptions in case of a NaN
140 input (NaN exceptions are not generated with cvt). */
141 tree unsigned_int_type = NULL_TREE;
142 /* Bit battern with all but the upper bit 1. */
143 tree and_mask = NULL_TREE;
144 if (conv_src_size == 2)
145 {
146 unsigned_int_type = gccbrig_tree_type_for_hsa_type (BRIG_TYPE_U16);
147 and_mask = build_int_cst (unsigned_int_type, 0x7FFF);
148 }
149 else if (conv_src_size == 4)
150 {
151 unsigned_int_type = gccbrig_tree_type_for_hsa_type (BRIG_TYPE_U32);
152 and_mask = build_int_cst (unsigned_int_type, 0x7FFFFFFF);
153 }
154 else if (conv_src_size == 8)
155 {
156 unsigned_int_type = gccbrig_tree_type_for_hsa_type (BRIG_TYPE_U64);
157 and_mask = build_int_cst (unsigned_int_type, 0x7FFFFFFFFFFFFFFF);
158 }
159 else
160 gcc_unreachable ();
161 tree casted_input = build_resize_convert_view (unsigned_int_type,
162 input);
163 tree masked_input
164 = build2 (BIT_AND_EXPR, unsigned_int_type, casted_input, and_mask);
165 conversion_result
166 = build2 (NE_EXPR, TREE_TYPE (masked_input), masked_input,
167 build_int_cst (unsigned_int_type, 0));
168 }
169 /* The result from the comparison is a boolean, convert it to such. */
170 conversion_result
171 = convert_to_integer (gccbrig_tree_type_for_hsa_type (BRIG_TYPE_B1),
172 conversion_result);
173 }
174 else if (dest_is_fp16)
175 {
176 tree casted_input = build_resize_convert_view (src_type, input);
177 conversion_result
178 = convert_to_real (brig_to_generic::s_fp32_type, casted_input);
179 if (FTZ)
180 conversion_result = flush_to_zero (true) (*this, conversion_result);
181 conversion_result = build_f2h_conversion (conversion_result);
182 }
183 else if (SCALAR_FLOAT_TYPE_P (dest_type))
184 {
185 tree casted_input = build_resize_convert_view (src_type, input);
186 conversion_result = convert_to_real (dest_type, casted_input);
187 }
188 else if (INTEGRAL_TYPE_P (dest_type) && INTEGRAL_TYPE_P (src_type))
189 {
190 conversion_result = extend_int (input, dest_type, src_type);
191 }
192 else if (INTEGRAL_TYPE_P (dest_type) && SCALAR_FLOAT_TYPE_P (src_type))
193 {
194
195 if (cvt_inst->round == BRIG_ROUND_INTEGER_ZERO_SAT)
196 {
197
198 /* Use builtins for the saturating conversions. */
199 #undef DEF_HSAIL_SAT_BUILTIN
200 #undef DEF_HSAIL_BUILTIN
201 #undef DEF_HSAIL_ATOMIC_BUILTIN
202 #undef DEF_HSAIL_INTR_BUILTIN
203 #undef DEF_HSAIL_CVT_ZEROI_SAT_BUILTIN
204
205 tree builtin = NULL_TREE;
206 BrigType16_t src_arith_type
207 = src_is_fp16
208 ? (BrigType16_t) BRIG_TYPE_F32 : cvt_inst->sourceType;
209 #define DEF_HSAIL_CVT_ZEROI_SAT_BUILTIN(ENUM, HSAIL_DST_TYPE, HSAIL_SRC_TYPE, \
210 NAME, TYPE, ATTRS) \
211 if (brig_inst->type == HSAIL_DST_TYPE \
212 && src_arith_type == HSAIL_SRC_TYPE) \
213 builtin = builtin_decl_explicit (ENUM); \
214 else
215 #include "brig-builtins.def"
216 gcc_unreachable ();
217
218 tree casted_input = build_resize_convert_view (src_type, input);
219 conversion_result
220 = call_builtin (builtin, 1, dest_type, src_type, casted_input);
221 }
222 else
223 {
224 tree casted_input = build_resize_convert_view (src_type, input);
225
226 /* Perform the float to int conversion. */
227 conversion_result = convert_to_integer (dest_type, casted_input);
228 }
229 }
230 else
231 {
232 /* Just use CONVERT_EXPR and hope for the best. */
233 tree casted_input = build_resize_convert_view (dest_type, input);
234 conversion_result = build1 (CONVERT_EXPR, dest_type, casted_input);
235 }
236
237 size_t dst_reg_size = int_size_in_bytes (TREE_TYPE (output));
238
239 /* The output register can be of different type&size than the
240 conversion output size. Only need to handle signed integers, rest
241 is handled by reinterpret_cast. */
242 tree casted_output = conversion_result;
243 if (dst_reg_size > conv_dst_size &&
244 INTEGRAL_TYPE_P (TREE_TYPE (casted_output)))
245 {
246 gcc_assert (!VECTOR_TYPE_P (casted_output));
247
248 bool unsignedp = TYPE_UNSIGNED (TREE_TYPE (casted_output));
249 tree resized_int_type
250 = build_nonstandard_integer_type (dst_reg_size * BITS_PER_UNIT,
251 unsignedp);
252 casted_output = build1 (CONVERT_EXPR, resized_int_type, casted_output);
253 }
254
255 casted_output
256 = build_resize_convert_view (TREE_TYPE (output), casted_output);
257 tree assign = build2 (MODIFY_EXPR, TREE_TYPE (output), output, casted_output);
258
259 m_parent.m_cf->append_statement (assign);
260
261 return base->byteCount;
262 }