xref: /netbsd-src/external/gpl3/gcc.old/dist/gcc/brig/brigfrontend/brig-cvt-inst-handler.cc (revision 4f645668ed707e1f969c546666f8c8e45e6f8888)
1 /* brig-cvt-inst-handler.cc -- brig cvt (convert) instruction handling
2    Copyright (C) 2016-2019 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   if (m_parent.m_cf->is_id_val (input))
87     {
88       input = m_parent.m_cf->id_val (input);
89       src_type = TREE_TYPE (input);
90     }
91 
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));
95 
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)
101     {
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.  */
106 	{
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 ();
115 	}
116       input = convert_to_integer (unsigned_int_type, input);
117     }
118 
119   if (src_is_fp16)
120     input = build_h2f_conversion (input);
121 
122   /* Flush the float operand to zero if indicated with 'ftz'.  */
123   if (FTZ && SCALAR_FLOAT_TYPE_P (src_type))
124     {
125       tree casted_input = build_resize_convert_view (src_type, input);
126       input = flush_to_zero (src_is_fp16) (*this, casted_input);
127     }
128 
129   tree conversion_result = NULL_TREE;
130   if (brig_inst->type == BRIG_TYPE_B1)
131     {
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))
135 	{
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));
139 	}
140       else
141 	{
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)
151 	    {
152 	      unsigned_int_type = gccbrig_tree_type_for_hsa_type (BRIG_TYPE_U16);
153 	      and_mask = build_int_cst (unsigned_int_type, 0x7FFF);
154 	    }
155 	  else if (conv_src_size == 4)
156 	    {
157 	      unsigned_int_type = gccbrig_tree_type_for_hsa_type (BRIG_TYPE_U32);
158 	      and_mask = build_int_cst (unsigned_int_type, 0x7FFFFFFF);
159 	    }
160 	  else if (conv_src_size == 8)
161 	    {
162 	      unsigned_int_type = gccbrig_tree_type_for_hsa_type (BRIG_TYPE_U64);
163 	      and_mask = build_int_cst (unsigned_int_type, 0x7FFFFFFFFFFFFFFF);
164 	    }
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));
174 	}
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);
179     }
180   else if (dest_is_fp16)
181     {
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);
188     }
189   else if (SCALAR_FLOAT_TYPE_P (dest_type))
190     {
191       tree casted_input = build_resize_convert_view (src_type, input);
192       conversion_result = convert_to_real (dest_type, casted_input);
193     }
194   else if (INTEGRAL_TYPE_P (dest_type) && INTEGRAL_TYPE_P (src_type))
195     {
196       conversion_result = extend_int (input, dest_type, src_type);
197     }
198   else if (INTEGRAL_TYPE_P (dest_type) && SCALAR_FLOAT_TYPE_P (src_type))
199     {
200 
201       if (cvt_inst->round == BRIG_ROUND_INTEGER_ZERO_SAT)
202 	{
203 
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
210 
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 ();
223 
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);
227 	}
228       else
229 	{
230 	  tree casted_input = build_resize_convert_view (src_type, input);
231 
232 	  /* Perform the float to int conversion.  */
233 	  conversion_result = convert_to_integer (dest_type, casted_input);
234 	}
235     }
236   else
237     {
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);
241     }
242 
243   size_t dst_reg_size = int_size_in_bytes (TREE_TYPE (output));
244 
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)))
251     {
252       gcc_assert (!VECTOR_TYPE_P (casted_output));
253 
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);
259     }
260 
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);
264 
265   m_parent.m_cf->append_statement (assign);
266 
267   return base->byteCount;
268 }
269