xref: /netbsd-src/external/gpl3/gcc.old/dist/gcc/brig/brigfrontend/brig-atomic-inst-handler.cc (revision 4c3eb207d36f67d31994830c0a694161fc1ca39b)
1 /* brig-atomic-inst-handler.cc -- brig atomic instruction handling
2    Copyright (C) 2016-2020 Free Software Foundation, Inc.
3 
4    Contributed by Pekka Jaaskelainen <pekka.jaaskelainen@parmance.com>
5    for General Processor Tech.
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 #include "brig-util.h"
26 #include "fold-const.h"
27 #include "diagnostic.h"
28 #include "tree-pretty-print.h"
29 #include "print-tree.h"
30 #include "convert.h"
31 #include "langhooks.h"
32 #include "gimple-expr.h"
33 #include "stringpool.h"
34 #include "brig-builtins.h"
35 
brig_atomic_inst_handler(brig_to_generic & parent)36 brig_atomic_inst_handler::brig_atomic_inst_handler (brig_to_generic &parent)
37   : brig_code_entry_handler (parent)
38 {
39 }
40 
41 size_t
generate_tree(const BrigInstBase & inst,BrigAtomicOperation8_t atomic_opcode)42 brig_atomic_inst_handler::generate_tree (const BrigInstBase &inst,
43 					 BrigAtomicOperation8_t atomic_opcode)
44 {
45   tree_stl_vec operands = build_operands (inst);
46   const int first_input
47     = gccbrig_hsa_opcode_op_output_p (inst.opcode, 0) ? 1 : 0;
48 
49   tree instr_type = gccbrig_tree_type_for_hsa_type (inst.type);
50 
51   /* Utilize the atomic data types (from C++11 support) for implementing
52      atomic operations.  */
53 
54   tree atomic_type = build_qualified_type (instr_type, TYPE_QUAL_ATOMIC);
55 
56   gcc_assert (atomic_type != NULL_TREE);
57 
58   tree signal_handle = operands[first_input];
59   tree atomic_ptype = build_pointer_type (atomic_type);
60   tree casted_to_ptr = convert_to_pointer (atomic_ptype, signal_handle);
61 
62   tree src0 = NULL_TREE;
63   if (atomic_opcode != BRIG_ATOMIC_LD)
64     src0 = operands[first_input + 1];
65 
66   tree instr_expr = NULL_TREE;
67 
68   tree ptype = build_pointer_type (instr_type);
69   tree ptr = convert_to_pointer (ptype, operands[first_input]);
70 
71   if (atomic_opcode == BRIG_ATOMIC_ST)
72     {
73       tree mem_ref = build2 (MEM_REF, atomic_type, casted_to_ptr,
74 			     build_int_cst (atomic_ptype, 0));
75       instr_expr = build2 (MODIFY_EXPR, atomic_type, mem_ref, src0);
76     }
77   else if (atomic_opcode == BRIG_ATOMIC_LD
78 	   || (atomic_opcode >= BRIG_ATOMIC_WAIT_EQ
79 	       && atomic_opcode <= BRIG_ATOMIC_WAITTIMEOUT_GTE))
80     {
81       tree mem_ref = build2 (MEM_REF, atomic_type, casted_to_ptr,
82 			     build_int_cst (atomic_ptype, 0));
83       /* signal_wait* instructions can return spuriously before the
84 	 condition becomes true.  Therefore it's legal to return
85 	 right away.  TODO: builtin calls which can be
86 	 implemented with a power efficient sleep-wait.  */
87       instr_expr = mem_ref;
88     }
89   else if (atomic_opcode == BRIG_ATOMIC_CAS)
90     {
91       /* Special case for CAS due to the two args.  */
92       tree built_in = NULL_TREE;
93       switch (gccbrig_hsa_type_bit_size (inst.type))
94 	{
95 	case 32:
96 	  built_in
97 	    = builtin_decl_explicit (BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_4);
98 	  break;
99 	case 64:
100 	  built_in
101 	    = builtin_decl_explicit (BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_8);
102 	  break;
103 	default:
104 	  gcc_unreachable ();
105 	}
106 
107       tree src1 = operands[first_input + 2];
108 
109       tree src0_type
110 	= TREE_VALUE (TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (built_in))));
111 
112       tree src1_type = TREE_VALUE
113 	(TREE_CHAIN (TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (built_in)))));
114 
115       instr_expr = call_builtin (built_in, 3, instr_type, ptype, ptr,
116 				 src0_type, src0, src1_type, src1);
117     }
118   else
119     {
120       tree built_in = NULL_TREE;
121       /* The rest of the builtins have the same number of parameters.
122 	 Generate a big if..else that finds the correct builtin
123 	 automagically from the def file.  */
124 #undef DEF_HSAIL_SAT_BUILTIN
125 #undef DEF_HSAIL_BUILTIN
126 #undef DEF_HSAIL_ATOMIC_BUILTIN
127 #undef DEF_HSAIL_INTR_BUILTIN
128 #undef DEF_HSAIL_CVT_ZEROI_SAT_BUILTIN
129 
130 #define DEF_HSAIL_ATOMIC_BUILTIN(ENUM, ATOMIC_OPCODE, HSAIL_TYPE,	\
131 				 NAME, TYPE, ATTRS)			\
132       if (atomic_opcode == ATOMIC_OPCODE && inst.type == HSAIL_TYPE)	\
133 	built_in = builtin_decl_explicit (ENUM);			\
134       else
135 #include "brig-builtins.def"
136       switch (atomic_opcode)
137 	{
138 	case BRIG_ATOMIC_ADD:
139 	  switch (gccbrig_hsa_type_bit_size (inst.type))
140 	    {
141 	    case 32:
142 	      built_in
143 		= builtin_decl_explicit (BUILT_IN_SYNC_FETCH_AND_ADD_4);
144 	      break;
145 	    case 64:
146 	      built_in
147 		= builtin_decl_explicit (BUILT_IN_SYNC_FETCH_AND_ADD_8);
148 	      break;
149 	    default:
150 	      gcc_unreachable ();
151 	    }
152 	  break;
153 	case BRIG_ATOMIC_SUB:
154 	  switch (gccbrig_hsa_type_bit_size (inst.type))
155 	    {
156 	    case 32:
157 	      built_in
158 		= builtin_decl_explicit (BUILT_IN_SYNC_FETCH_AND_SUB_4);
159 	      break;
160 	    case 64:
161 	      built_in
162 		= builtin_decl_explicit (BUILT_IN_SYNC_FETCH_AND_SUB_8);
163 	      break;
164 	    default:
165 	      gcc_unreachable ();
166 	    }
167 	  break;
168 	case BRIG_ATOMIC_AND:
169 	  switch (gccbrig_hsa_type_bit_size (inst.type))
170 	    {
171 	    case 32:
172 	      built_in
173 		= builtin_decl_explicit (BUILT_IN_SYNC_FETCH_AND_AND_4);
174 	      break;
175 	    case 64:
176 	      built_in
177 		= builtin_decl_explicit (BUILT_IN_SYNC_FETCH_AND_AND_8);
178 	      break;
179 	    default:
180 	      gcc_unreachable ();
181 	    }
182 	  break;
183 	case BRIG_ATOMIC_XOR:
184 	  switch (gccbrig_hsa_type_bit_size (inst.type))
185 	    {
186 	    case 32:
187 	      built_in
188 		= builtin_decl_explicit (BUILT_IN_SYNC_FETCH_AND_XOR_4);
189 	      break;
190 	    case 64:
191 	      built_in
192 		= builtin_decl_explicit (BUILT_IN_SYNC_FETCH_AND_XOR_8);
193 	      break;
194 	    default:
195 	      gcc_unreachable ();
196 	    }
197 	  break;
198 	case BRIG_ATOMIC_OR:
199 	  switch (gccbrig_hsa_type_bit_size (inst.type))
200 	    {
201 	    case 32:
202 	      built_in
203 		= builtin_decl_explicit (BUILT_IN_SYNC_FETCH_AND_OR_4);
204 	      break;
205 	    case 64:
206 	      built_in
207 		= builtin_decl_explicit (BUILT_IN_SYNC_FETCH_AND_OR_8);
208 	      break;
209 	    default:
210 	      gcc_unreachable ();
211 	    }
212 	  break;
213 	case BRIG_ATOMIC_EXCH:
214 	  switch (gccbrig_hsa_type_bit_size (inst.type))
215 	    {
216 	    case 32:
217 	      built_in
218 		= builtin_decl_explicit (BUILT_IN_SYNC_LOCK_TEST_AND_SET_4);
219 	      break;
220 	    case 64:
221 	      built_in
222 		= builtin_decl_explicit (BUILT_IN_SYNC_LOCK_TEST_AND_SET_8);
223 	      break;
224 	    default:
225 	      gcc_unreachable ();
226 	    }
227 	  break;
228 	default:
229 	  gcc_unreachable ();
230 	};
231 
232       gcc_assert (built_in != NULL_TREE);
233       tree arg0_type
234 	= TREE_VALUE (TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (built_in))));
235 
236       instr_expr = call_builtin (built_in, 2, instr_type, ptr_type_node,
237 				 ptr, arg0_type, src0);
238 
239       /* We need a temp variable for the result, because otherwise
240 	 the gimplifier drops a necessary (unsigned to signed) cast in
241 	 the output assignment and fails a check later.  */
242       tree tmp_var = create_tmp_var (arg0_type, "builtin_out");
243       tree tmp_assign
244 	= build2 (MODIFY_EXPR, TREE_TYPE (tmp_var), tmp_var, instr_expr);
245       m_parent.m_cf->append_statement (tmp_assign);
246       instr_expr = tmp_var;
247     }
248 
249   if (first_input > 0)
250     build_output_assignment (inst, operands[0], instr_expr);
251   else
252     m_parent.m_cf->append_statement (instr_expr);
253 
254   return inst.base.byteCount;
255 }
256 
257 size_t
operator ()(const BrigBase * base)258 brig_atomic_inst_handler::operator () (const BrigBase *base)
259 {
260   const BrigInstAtomic *inst = (const BrigInstAtomic *) base;
261   BrigAtomicOperation8_t atomic_opcode;
262   atomic_opcode = inst->atomicOperation;
263 
264   return generate_tree (inst->base, atomic_opcode);
265 }
266