PR rtl-optimization/88470
[official-gcc.git] / gcc / brig / brigfrontend / brig-cvt-inst-handler.cc
blob3b8c9ea01df54d29a7f1e28ff1e75f70f75eace1
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.
6 This file is part of GCC.
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.
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.
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/>. */
22 #include <sstream>
24 #include "brig-code-entry-handler.h"
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"
34 const BrigAluModifier8_t *
35 brig_cvt_inst_handler::modifier (const BrigBase *base) const
37 const BrigInstCvt *inst = (const BrigInstCvt *) base;
38 return &inst->modifier;
41 const BrigRound8_t *
42 brig_cvt_inst_handler::round (const BrigBase *base) const
44 const BrigInstCvt *inst = (const BrigInstCvt *) base;
45 return &inst->round;
48 size_t
49 brig_cvt_inst_handler::generate (const BrigBase *base)
51 /* In cvt instructions there can be at least four data types involved:
53 - the input register type
54 - the output register type
55 - the conversion source type
56 - the conversion destination type
59 const BrigInstBase *brig_inst
60 = (const BrigInstBase *) &((const BrigInstBasic *) base)->base;
61 const BrigInstCvt *cvt_inst = (const BrigInstCvt *) base;
63 const BrigAluModifier8_t *inst_modifier = modifier (base);
64 const bool FTZ = inst_modifier != NULL && (*inst_modifier) & BRIG_ALU_FTZ;
66 /* The conversion source type. */
67 tree src_type = get_tree_expr_type_for_hsa_type (cvt_inst->sourceType);
69 bool src_is_fp16 = cvt_inst->sourceType == BRIG_TYPE_F16;
71 /* The conversion destination type. */
72 tree dest_type = gccbrig_tree_type_for_hsa_type (brig_inst->type);
74 bool dest_is_fp16 = brig_inst->type == BRIG_TYPE_F16;
76 if (!dest_type || !src_type)
78 gcc_unreachable ();
79 return base->byteCount;
82 tree_stl_vec operands = build_operands (*brig_inst);
83 tree &input = operands.at (1);
84 tree &output = operands.at (0);
86 if (m_parent.m_cf->is_id_val (input))
88 input = m_parent.m_cf->id_val (input);
89 src_type = TREE_TYPE (input);
92 size_t conv_src_size = int_size_in_bytes (src_type);
93 size_t conv_dst_size = int_size_in_bytes (dest_type);
94 size_t src_reg_size = int_size_in_bytes (TREE_TYPE (input));
96 /* The input register can be of different type&size than the
97 conversion input size. First cast the input to the conversion
98 input type. These casts are always bitcasts which can be
99 expressed as casts between different unsigned integers. */
100 if (src_reg_size != conv_src_size)
102 tree unsigned_int_type = NULL_TREE;
103 if (INTEGRAL_TYPE_P (src_type))
104 unsigned_int_type = unsigned_type_for (src_type);
105 else /* Find a matching size int type for the REAL type. */
107 if (conv_src_size == 2)
108 unsigned_int_type = gccbrig_tree_type_for_hsa_type (BRIG_TYPE_U16);
109 else if (conv_src_size == 4)
110 unsigned_int_type = gccbrig_tree_type_for_hsa_type (BRIG_TYPE_U32);
111 else if (conv_src_size == 8)
112 unsigned_int_type = gccbrig_tree_type_for_hsa_type (BRIG_TYPE_U64);
113 else
114 gcc_unreachable ();
116 input = convert_to_integer (unsigned_int_type, input);
119 if (src_is_fp16)
120 input = build_h2f_conversion (input);
122 /* Flush the float operand to zero if indicated with 'ftz'. */
123 if (FTZ && SCALAR_FLOAT_TYPE_P (src_type))
125 tree casted_input = build_resize_convert_view (src_type, input);
126 input = flush_to_zero (src_is_fp16) (*this, casted_input);
129 tree conversion_result = NULL_TREE;
130 if (brig_inst->type == BRIG_TYPE_B1)
132 /* When the destination is b1, cvt does a 'ztest' operation which is
133 defined as a != 0 for integers and similarly (!= 0.0f) for floats. */
134 if (INTEGRAL_TYPE_P (src_type))
136 /* Generate an integer not equal operation. */
137 conversion_result = build2 (NE_EXPR, TREE_TYPE (input), input,
138 build_int_cst (TREE_TYPE (input), 0));
140 else
142 /* For REAL source types, ztest returns 1 if the value is not +- 0.0f.
143 We can perform this check with an integer comparison after
144 masking away the sign bit from a correct position. This is safer
145 than using absf because of exceptions in case of a NaN
146 input (NaN exceptions are not generated with cvt). */
147 tree unsigned_int_type = NULL_TREE;
148 /* Bit battern with all but the upper bit 1. */
149 tree and_mask = NULL_TREE;
150 if (conv_src_size == 2)
152 unsigned_int_type = gccbrig_tree_type_for_hsa_type (BRIG_TYPE_U16);
153 and_mask = build_int_cst (unsigned_int_type, 0x7FFF);
155 else if (conv_src_size == 4)
157 unsigned_int_type = gccbrig_tree_type_for_hsa_type (BRIG_TYPE_U32);
158 and_mask = build_int_cst (unsigned_int_type, 0x7FFFFFFF);
160 else if (conv_src_size == 8)
162 unsigned_int_type = gccbrig_tree_type_for_hsa_type (BRIG_TYPE_U64);
163 and_mask = build_int_cst (unsigned_int_type, 0x7FFFFFFFFFFFFFFF);
165 else
166 gcc_unreachable ();
167 tree casted_input = build_resize_convert_view (unsigned_int_type,
168 input);
169 tree masked_input
170 = build2 (BIT_AND_EXPR, unsigned_int_type, casted_input, and_mask);
171 conversion_result
172 = build2 (NE_EXPR, TREE_TYPE (masked_input), masked_input,
173 build_int_cst (unsigned_int_type, 0));
175 /* The result from the comparison is a boolean, convert it to such. */
176 conversion_result
177 = convert_to_integer (gccbrig_tree_type_for_hsa_type (BRIG_TYPE_B1),
178 conversion_result);
180 else if (dest_is_fp16)
182 tree casted_input = build_resize_convert_view (src_type, input);
183 conversion_result
184 = convert_to_real (brig_to_generic::s_fp32_type, casted_input);
185 if (FTZ)
186 conversion_result = flush_to_zero (true) (*this, conversion_result);
187 conversion_result = build_f2h_conversion (conversion_result);
189 else if (SCALAR_FLOAT_TYPE_P (dest_type))
191 tree casted_input = build_resize_convert_view (src_type, input);
192 conversion_result = convert_to_real (dest_type, casted_input);
194 else if (INTEGRAL_TYPE_P (dest_type) && INTEGRAL_TYPE_P (src_type))
196 conversion_result = extend_int (input, dest_type, src_type);
198 else if (INTEGRAL_TYPE_P (dest_type) && SCALAR_FLOAT_TYPE_P (src_type))
201 if (cvt_inst->round == BRIG_ROUND_INTEGER_ZERO_SAT)
204 /* Use builtins for the saturating conversions. */
205 #undef DEF_HSAIL_SAT_BUILTIN
206 #undef DEF_HSAIL_BUILTIN
207 #undef DEF_HSAIL_ATOMIC_BUILTIN
208 #undef DEF_HSAIL_INTR_BUILTIN
209 #undef DEF_HSAIL_CVT_ZEROI_SAT_BUILTIN
211 tree builtin = NULL_TREE;
212 BrigType16_t src_arith_type
213 = src_is_fp16
214 ? (BrigType16_t) BRIG_TYPE_F32 : cvt_inst->sourceType;
215 #define DEF_HSAIL_CVT_ZEROI_SAT_BUILTIN(ENUM, HSAIL_DST_TYPE, HSAIL_SRC_TYPE, \
216 NAME, TYPE, ATTRS) \
217 if (brig_inst->type == HSAIL_DST_TYPE \
218 && src_arith_type == HSAIL_SRC_TYPE) \
219 builtin = builtin_decl_explicit (ENUM); \
220 else
221 #include "brig-builtins.def"
222 gcc_unreachable ();
224 tree casted_input = build_resize_convert_view (src_type, input);
225 conversion_result
226 = call_builtin (builtin, 1, dest_type, src_type, casted_input);
228 else
230 tree casted_input = build_resize_convert_view (src_type, input);
232 /* Perform the float to int conversion. */
233 conversion_result = convert_to_integer (dest_type, casted_input);
236 else
238 /* Just use CONVERT_EXPR and hope for the best. */
239 tree casted_input = build_resize_convert_view (dest_type, input);
240 conversion_result = build1 (CONVERT_EXPR, dest_type, casted_input);
243 size_t dst_reg_size = int_size_in_bytes (TREE_TYPE (output));
245 /* The output register can be of different type&size than the
246 conversion output size. Only need to handle signed integers, rest
247 is handled by reinterpret_cast. */
248 tree casted_output = conversion_result;
249 if (dst_reg_size > conv_dst_size &&
250 INTEGRAL_TYPE_P (TREE_TYPE (casted_output)))
252 gcc_assert (!VECTOR_TYPE_P (casted_output));
254 bool unsignedp = TYPE_UNSIGNED (TREE_TYPE (casted_output));
255 tree resized_int_type
256 = build_nonstandard_integer_type (dst_reg_size * BITS_PER_UNIT,
257 unsignedp);
258 casted_output = build1 (CONVERT_EXPR, resized_int_type, casted_output);
261 casted_output
262 = build_resize_convert_view (TREE_TYPE (output), casted_output);
263 tree assign = build2 (MODIFY_EXPR, TREE_TYPE (output), output, casted_output);
265 m_parent.m_cf->append_statement (assign);
267 return base->byteCount;