1 /* brig-cmp-inst-handler.cc -- brig cmp 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 "brig-code-entry-handler.h"
23 #include "diagnostic.h"
24 #include "tree-pretty-print.h"
25 #include "print-tree.h"
26 #include "brig-util.h"
27 #include "convert.h"
28
29 size_t
operator ()(const BrigBase * base)30 brig_cmp_inst_handler::operator () (const BrigBase *base)
31 {
32 const BrigInstBase *inst_base = (const BrigInstBase *) base;
33 const BrigInstCmp *inst = (const BrigInstCmp *) base;
34
35 tree cmp_type = get_tree_expr_type_for_hsa_type (inst->sourceType);
36
37 /* The destination type to convert the comparison result to. */
38 tree dest_type = gccbrig_tree_type_for_hsa_type (inst_base->type);
39
40 const bool is_fp16_dest
41 = (inst_base->type & BRIG_TYPE_BASE_MASK) == BRIG_TYPE_F16;
42 const bool is_boolean_dest
43 = (inst_base->type & BRIG_TYPE_BASE_MASK) == BRIG_TYPE_B1;
44
45 bool is_int_cmp = VECTOR_TYPE_P (cmp_type)
46 ? INTEGRAL_TYPE_P (TREE_TYPE (cmp_type))
47 : INTEGRAL_TYPE_P (cmp_type);
48
49 /* The type for the GENERIC comparison. It should match the
50 input operand width for vector comparisons, a boolean
51 otherwise. */
52 tree result_type = get_comparison_result_type (cmp_type);
53
54 /* Save the result as a boolean and extend/convert it to the
55 wanted destination type. */
56 tree expr = NULL_TREE;
57
58 std::vector<tree> operands = build_operands (*inst_base);
59
60 switch (inst->compare)
61 {
62 case BRIG_COMPARE_SEQ:
63 case BRIG_COMPARE_EQ:
64 expr = build2 (EQ_EXPR, result_type, operands[1], operands[2]);
65 break;
66 case BRIG_COMPARE_SNE:
67 case BRIG_COMPARE_NE:
68 expr = build2 (NE_EXPR, result_type, operands[1], operands[2]);
69
70 if (!is_int_cmp)
71 expr = build2 (BIT_AND_EXPR, TREE_TYPE (expr),
72 expr,
73 build2 (ORDERED_EXPR, result_type, operands[1],
74 operands[2]));
75 break;
76 case BRIG_COMPARE_SLT:
77 case BRIG_COMPARE_LT:
78 expr = build2 (LT_EXPR, result_type, operands[1], operands[2]);
79 break;
80 case BRIG_COMPARE_SLE:
81 case BRIG_COMPARE_LE:
82 expr = build2 (LE_EXPR, result_type, operands[1], operands[2]);
83 break;
84 case BRIG_COMPARE_SGT:
85 case BRIG_COMPARE_GT:
86 expr = build2 (GT_EXPR, result_type, operands[1], operands[2]);
87 break;
88 case BRIG_COMPARE_SGE:
89 case BRIG_COMPARE_GE:
90 expr = build2 (GE_EXPR, result_type, operands[1], operands[2]);
91 break;
92 case BRIG_COMPARE_SEQU:
93 case BRIG_COMPARE_EQU:
94 expr = build2 (UNEQ_EXPR, result_type, operands[1], operands[2]);
95 break;
96 case BRIG_COMPARE_SNEU:
97 case BRIG_COMPARE_NEU:
98 expr = build2 (NE_EXPR, result_type, operands[1], operands[2]);
99 break;
100 case BRIG_COMPARE_SLTU:
101 case BRIG_COMPARE_LTU:
102 expr = build2 (UNLT_EXPR, result_type, operands[1], operands[2]);
103 break;
104 case BRIG_COMPARE_SLEU:
105 case BRIG_COMPARE_LEU:
106 expr = build2 (UNLE_EXPR, result_type, operands[1], operands[2]);
107 break;
108 case BRIG_COMPARE_SGTU:
109 case BRIG_COMPARE_GTU:
110 expr = build2 (UNGT_EXPR, result_type, operands[1], operands[2]);
111 break;
112 case BRIG_COMPARE_SGEU:
113 case BRIG_COMPARE_GEU:
114 expr = build2 (UNGE_EXPR, result_type, operands[1], operands[2]);
115 break;
116 case BRIG_COMPARE_SNUM:
117 case BRIG_COMPARE_NUM:
118 expr = build2 (ORDERED_EXPR, result_type, operands[1], operands[2]);
119 break;
120 case BRIG_COMPARE_SNAN:
121 case BRIG_COMPARE_NAN:
122 expr = build2 (UNORDERED_EXPR, result_type, operands[1], operands[2]);
123 break;
124 default:
125 break;
126 }
127
128 if (expr == NULL_TREE)
129 gcc_unreachable ();
130
131 if (is_fp16_dest)
132 {
133 expr = convert_to_real (brig_to_generic::s_fp32_type, expr);
134 }
135 else if (VECTOR_TYPE_P (dest_type) && ANY_INTEGRAL_TYPE_P (dest_type)
136 && !is_boolean_dest
137 && (inst->sourceType & BRIG_TYPE_BASE_MASK) != BRIG_TYPE_F16)
138 {
139 /* In later gcc versions, the output of comparison is not
140 all ones for vectors like still in 4.9.1. We need to use
141 an additional VEC_COND_EXPR to produce the all ones 'true' value
142 required by HSA.
143 VEC_COND_EXPR <a == b, { -1, -1, -1, -1 }, { 0, 0, 0, 0 }>; */
144
145 tree all_ones
146 = build_vector_from_val (dest_type,
147 build_minus_one_cst (TREE_TYPE (dest_type)));
148 tree all_zeroes
149 = build_vector_from_val (dest_type,
150 build_zero_cst (TREE_TYPE (dest_type)));
151 expr = build3 (VEC_COND_EXPR, dest_type, expr, all_ones, all_zeroes);
152 }
153 else if (INTEGRAL_TYPE_P (dest_type) && !is_boolean_dest)
154 {
155 /* We need to produce the all-ones pattern for the width of the whole
156 resulting integer type. Use back and forth shifts for propagating
157 the lower 1. */
158 tree signed_type = signed_type_for (dest_type);
159 tree signed_result = convert_to_integer (signed_type, expr);
160
161 size_t result_width = int_size_in_bytes (dest_type) * BITS_PER_UNIT;
162
163 tree shift_amount_cst
164 = build_int_cstu (signed_type, result_width - 1);
165
166 tree shift_left_result
167 = build2 (LSHIFT_EXPR, signed_type, signed_result, shift_amount_cst);
168
169 expr = build2 (RSHIFT_EXPR, signed_type, shift_left_result,
170 shift_amount_cst);
171 }
172 else if (SCALAR_FLOAT_TYPE_P (dest_type))
173 {
174 expr = convert_to_real (dest_type, expr);
175 }
176 else if (VECTOR_TYPE_P (dest_type)
177 && (inst->sourceType & BRIG_TYPE_BASE_MASK) == BRIG_TYPE_F16)
178 {
179 /* Because F16 comparison is emulated as an F32 comparison with S32
180 results, we must now truncate the result vector to S16s so it
181 fits to the destination register. We can build the target vector
182 type from the f16 storage type (unsigned ints). */
183 expr = add_temp_var ("wide_cmp_result", expr);
184 tree_stl_vec wide_elements;
185 tree_stl_vec shrunk_elements;
186 unpack (expr, wide_elements);
187 for (size_t i = 0; i < wide_elements.size (); ++i)
188 {
189 tree wide = wide_elements.at (i);
190 shrunk_elements.push_back
191 (convert_to_integer (short_integer_type_node, wide));
192 }
193 expr = pack (shrunk_elements);
194 }
195 build_output_assignment (*inst_base, operands[0], expr);
196
197 return base->byteCount;
198 }
199