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
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
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/>. */
24 #include "brig-code-entry-handler.h"
26 #include "gimple-expr.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
;
42 brig_cvt_inst_handler::round (const BrigBase
*base
) const
44 const BrigInstCvt
*inst
= (const BrigInstCvt
*) base
;
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
)
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 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
));
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
)
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. */
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
);
110 input
= convert_to_integer (unsigned_int_type
, input
);
114 input
= build_h2f_conversion (input
);
116 /* Flush the float operand to zero if indicated with 'ftz'. */
117 if (FTZ
&& SCALAR_FLOAT_TYPE_P (src_type
))
119 tree casted_input
= build_resize_convert_view (src_type
, input
);
120 input
= flush_to_zero (src_is_fp16
) (*this, casted_input
);
123 tree conversion_result
= NULL_TREE
;
124 if (brig_inst
->type
== BRIG_TYPE_B1
)
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
))
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));
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)
146 unsigned_int_type
= gccbrig_tree_type_for_hsa_type (BRIG_TYPE_U16
);
147 and_mask
= build_int_cst (unsigned_int_type
, 0x7FFF);
149 else if (conv_src_size
== 4)
151 unsigned_int_type
= gccbrig_tree_type_for_hsa_type (BRIG_TYPE_U32
);
152 and_mask
= build_int_cst (unsigned_int_type
, 0x7FFFFFFF);
154 else if (conv_src_size
== 8)
156 unsigned_int_type
= gccbrig_tree_type_for_hsa_type (BRIG_TYPE_U64
);
157 and_mask
= build_int_cst (unsigned_int_type
, 0x7FFFFFFFFFFFFFFF);
161 tree casted_input
= build_resize_convert_view (unsigned_int_type
,
164 = build2 (BIT_AND_EXPR
, unsigned_int_type
, casted_input
, and_mask
);
166 = build2 (NE_EXPR
, TREE_TYPE (masked_input
), masked_input
,
167 build_int_cst (unsigned_int_type
, 0));
169 /* The result from the comparison is a boolean, convert it to such. */
171 = convert_to_integer (gccbrig_tree_type_for_hsa_type (BRIG_TYPE_B1
),
174 else if (dest_is_fp16
)
176 tree casted_input
= build_resize_convert_view (src_type
, input
);
178 = convert_to_real (brig_to_generic::s_fp32_type
, casted_input
);
180 conversion_result
= flush_to_zero (true) (*this, conversion_result
);
181 conversion_result
= build_f2h_conversion (conversion_result
);
183 else if (SCALAR_FLOAT_TYPE_P (dest_type
))
185 tree casted_input
= build_resize_convert_view (src_type
, input
);
186 conversion_result
= convert_to_real (dest_type
, casted_input
);
188 else if (INTEGRAL_TYPE_P (dest_type
) && INTEGRAL_TYPE_P (src_type
))
190 conversion_result
= extend_int (input
, dest_type
, src_type
);
192 else if (INTEGRAL_TYPE_P (dest_type
) && SCALAR_FLOAT_TYPE_P (src_type
))
195 if (cvt_inst
->round
== BRIG_ROUND_INTEGER_ZERO_SAT
)
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
205 tree builtin
= NULL_TREE
;
206 BrigType16_t src_arith_type
208 ? (BrigType16_t
) BRIG_TYPE_F32
: cvt_inst
->sourceType
;
209 #define DEF_HSAIL_CVT_ZEROI_SAT_BUILTIN(ENUM, HSAIL_DST_TYPE, HSAIL_SRC_TYPE, \
211 if (brig_inst->type == HSAIL_DST_TYPE \
212 && src_arith_type == HSAIL_SRC_TYPE) \
213 builtin = builtin_decl_explicit (ENUM); \
215 #include "brig-builtins.def"
218 tree casted_input
= build_resize_convert_view (src_type
, input
);
220 = call_builtin (builtin
, 1, dest_type
, src_type
, casted_input
);
224 tree casted_input
= build_resize_convert_view (src_type
, input
);
226 /* Perform the float to int conversion. */
227 conversion_result
= convert_to_integer (dest_type
, casted_input
);
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
);
237 size_t dst_reg_size
= int_size_in_bytes (TREE_TYPE (output
));
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
)))
246 gcc_assert (!VECTOR_TYPE_P (casted_output
));
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
,
252 casted_output
= build1 (CONVERT_EXPR
, resized_int_type
, casted_output
);
256 = build_resize_convert_view (TREE_TYPE (output
), casted_output
);
257 tree assign
= build2 (MODIFY_EXPR
, TREE_TYPE (output
), output
, casted_output
);
259 m_parent
.m_cf
->append_statement (assign
);
261 return base
->byteCount
;