1 // runtime.cc -- runtime functions called by generated code
2 
3 // Copyright 2011 The Go Authors. All rights reserved.
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file.
6 
7 #include "go-system.h"
8 
9 #include "gogo.h"
10 #include "types.h"
11 #include "expressions.h"
12 #include "runtime.h"
13 
14 // The frontend generates calls to various runtime functions.  They
15 // are implemented in libgo/runtime.  This is how the runtime
16 // functions are represented in the frontend.  Note that there is
17 // currently nothing which ensures that the compiler's understanding
18 // of the runtime function matches the actual implementation in
19 // libgo/runtime.
20 
21 // Parameter and result types used by runtime functions.
22 
23 enum Runtime_function_type
24 {
25   // General indicator that value is not used.
26   RFT_VOID,
27   // Go untyped bool, C type _Bool.
28   RFT_BOOL,
29   // Go type *bool, C type _Bool*.
30   RFT_BOOLPTR,
31   // Go type int, C type intgo.
32   RFT_INT,
33   // Go type uint, C type uintgo.
34   RFT_UINT,
35   // Go type uint8, C type uint8_t.
36   RFT_UINT8,
37   // Go type uint16, C type uint16_t.
38   RFT_UINT16,
39   // Go type int32, C type int32_t.
40   RFT_INT32,
41   // Go type uint32, C type uint32_t.
42   RFT_UINT32,
43   // Go type int64, C type int64_t.
44   RFT_INT64,
45   // Go type uint64, C type uint64_t.
46   RFT_UINT64,
47   // Go type uintptr, C type uintptr_t.
48   RFT_UINTPTR,
49   // Go type rune, C type int32_t.
50   RFT_RUNE,
51   // Go type float64, C type double.
52   RFT_FLOAT64,
53   // Go type complex64, C type __complex float.
54   RFT_COMPLEX64,
55   // Go type complex128, C type __complex double.
56   RFT_COMPLEX128,
57   // Go type string, C type struct __go_string.
58   RFT_STRING,
59   // Go type unsafe.Pointer, C type "void *".
60   RFT_POINTER,
61   // Go type []any, C type struct __go_open_array.
62   RFT_SLICE,
63   // Go type map[any]any, C type struct __go_map *.
64   RFT_MAP,
65   // Go type chan any, C type struct __go_channel *.
66   RFT_CHAN,
67   // Go type non-empty interface, C type struct __go_interface.
68   RFT_IFACE,
69   // Go type interface{}, C type struct __go_empty_interface.
70   RFT_EFACE,
71   // Pointer to Go type descriptor.
72   RFT_TYPE,
73   // [2]string.
74   RFT_ARRAY2STRING,
75   // [3]string.
76   RFT_ARRAY3STRING,
77   // [4]string.
78   RFT_ARRAY4STRING,
79   // [5]string.
80   RFT_ARRAY5STRING,
81 
82   NUMBER_OF_RUNTIME_FUNCTION_TYPES
83 };
84 
85 // The Type structures for the runtime function types.
86 
87 static Type* runtime_function_types[NUMBER_OF_RUNTIME_FUNCTION_TYPES];
88 
89 // Get the Type for a Runtime_function_type code.
90 
91 static Type*
runtime_function_type(Runtime_function_type bft)92 runtime_function_type(Runtime_function_type bft)
93 {
94   go_assert(bft < NUMBER_OF_RUNTIME_FUNCTION_TYPES);
95   Type* any = Type::make_pointer_type(Type::make_void_type());
96   if (runtime_function_types[bft] == NULL)
97     {
98       const Location bloc = Linemap::predeclared_location();
99       Type* t;
100       switch (bft)
101 	{
102 	default:
103 	case RFT_VOID:
104 	  go_unreachable();
105 
106 	case RFT_BOOL:
107 	  t = Type::make_boolean_type();
108 	  break;
109 
110 	case RFT_BOOLPTR:
111 	  t = Type::make_pointer_type(Type::lookup_bool_type());
112 	  break;
113 
114 	case RFT_INT:
115 	  t = Type::lookup_integer_type("int");
116 	  break;
117 
118 	case RFT_UINT:
119 	  t = Type::lookup_integer_type("uint");
120 	  break;
121 
122 	case RFT_UINT8:
123 	  t = Type::lookup_integer_type("uint8");
124 	  break;
125 
126 	case RFT_UINT16:
127 	  t = Type::lookup_integer_type("uint16");
128 	  break;
129 
130 	case RFT_INT32:
131 	  t = Type::lookup_integer_type("int32");
132 	  break;
133 
134 	case RFT_UINT32:
135 	  t = Type::lookup_integer_type("uint32");
136 	  break;
137 
138 	case RFT_INT64:
139 	  t = Type::lookup_integer_type("int64");
140 	  break;
141 
142 	case RFT_UINT64:
143 	  t = Type::lookup_integer_type("uint64");
144 	  break;
145 
146 	case RFT_RUNE:
147 	  t = Type::lookup_integer_type("int32");
148 	  break;
149 
150 	case RFT_UINTPTR:
151 	  t = Type::lookup_integer_type("uintptr");
152 	  break;
153 
154 	case RFT_FLOAT64:
155 	  t = Type::lookup_float_type("float64");
156 	  break;
157 
158 	case RFT_COMPLEX64:
159 	  t = Type::lookup_complex_type("complex64");
160 	  break;
161 
162 	case RFT_COMPLEX128:
163 	  t = Type::lookup_complex_type("complex128");
164 	  break;
165 
166 	case RFT_STRING:
167 	  t = Type::lookup_string_type();
168 	  break;
169 
170 	case RFT_POINTER:
171 	  t = Type::make_pointer_type(Type::make_void_type());
172 	  break;
173 
174 	case RFT_SLICE:
175 	  t = Type::make_array_type(any, NULL);
176 	  break;
177 
178 	case RFT_MAP:
179 	  t = Type::make_map_type(any, any, bloc);
180 	  break;
181 
182 	case RFT_CHAN:
183 	  t = Type::make_channel_type(true, true, any);
184 	  break;
185 
186 	case RFT_IFACE:
187 	  {
188 	    Typed_identifier_list* methods = new Typed_identifier_list();
189 	    Type* mtype = Type::make_function_type(NULL, NULL, NULL, bloc);
190 	    methods->push_back(Typed_identifier("x", mtype, bloc));
191 	    Interface_type* it = Type::make_interface_type(methods, bloc);
192 	    it->finalize_methods();
193 	    t = it;
194 	  }
195 	  break;
196 
197 	case RFT_EFACE:
198 	  t = Type::make_empty_interface_type(bloc);
199 	  break;
200 
201 	case RFT_TYPE:
202 	  t = Type::make_type_descriptor_ptr_type();
203 	  break;
204 
205 	case RFT_ARRAY2STRING:
206 	  {
207 	    Array_type* at =
208 	      Type::make_array_type(Type::make_string_type(),
209 				    Expression::make_integer_ul(2, NULL,
210 								bloc));
211 	    at->set_is_array_incomparable();
212 	    t = at;
213 	  }
214 	  break;
215 
216 	case RFT_ARRAY3STRING:
217 	  {
218 	    Array_type* at =
219 	      Type::make_array_type(Type::make_string_type(),
220 				    Expression::make_integer_ul(3, NULL,
221 								bloc));
222 	    at->set_is_array_incomparable();
223 	    t = at;
224 	  }
225 	  break;
226 
227 	case RFT_ARRAY4STRING:
228 	  {
229 	    Array_type* at =
230 	      Type::make_array_type(Type::make_string_type(),
231 				    Expression::make_integer_ul(4, NULL,
232 								bloc));
233 	    at->set_is_array_incomparable();
234 	    t = at;
235 	  }
236 	  break;
237 
238 	case RFT_ARRAY5STRING:
239 	  {
240 	    Array_type* at =
241 	      Type::make_array_type(Type::make_string_type(),
242 				    Expression::make_integer_ul(5, NULL,
243 								bloc));
244 	    at->set_is_array_incomparable();
245 	    t = at;
246 	  }
247 	  break;
248 	}
249 
250       runtime_function_types[bft] = t;
251     }
252 
253   return runtime_function_types[bft];
254 }
255 
256 // Convert an expression to the type to pass to a runtime function.
257 
258 static Expression*
convert_to_runtime_function_type(Runtime_function_type bft,Expression * e,Location loc)259 convert_to_runtime_function_type(Runtime_function_type bft, Expression* e,
260 				 Location loc)
261 {
262   switch (bft)
263     {
264     default:
265     case RFT_VOID:
266       go_unreachable();
267 
268     case RFT_BOOL:
269     case RFT_BOOLPTR:
270     case RFT_INT:
271     case RFT_UINT:
272     case RFT_UINT8:
273     case RFT_UINT16:
274     case RFT_INT32:
275     case RFT_UINT32:
276     case RFT_INT64:
277     case RFT_UINT64:
278     case RFT_UINTPTR:
279     case RFT_RUNE:
280     case RFT_FLOAT64:
281     case RFT_COMPLEX64:
282     case RFT_COMPLEX128:
283     case RFT_STRING:
284     case RFT_POINTER:
285       {
286 	Type* t = runtime_function_type(bft);
287 	if (!Type::are_identical(t, e->type(), true, NULL))
288 	  e = Expression::make_cast(t, e, loc);
289 	return e;
290       }
291 
292     case RFT_SLICE:
293     case RFT_MAP:
294     case RFT_CHAN:
295     case RFT_IFACE:
296     case RFT_EFACE:
297     case RFT_ARRAY2STRING:
298     case RFT_ARRAY3STRING:
299     case RFT_ARRAY4STRING:
300     case RFT_ARRAY5STRING:
301       return Expression::make_unsafe_cast(runtime_function_type(bft), e, loc);
302 
303     case RFT_TYPE:
304       go_assert(e->type() == Type::make_type_descriptor_ptr_type());
305       return e;
306     }
307 }
308 
309 // Convert all the types used for runtime functions to the backend
310 // representation.
311 
312 void
convert_types(Gogo * gogo)313 Runtime::convert_types(Gogo* gogo)
314 {
315   for (int i = 0; i < static_cast<int>(NUMBER_OF_RUNTIME_FUNCTION_TYPES); ++i)
316     {
317       Type* t = runtime_function_types[i];
318       if (t != NULL && t->named_type() != NULL)
319 	{
320 	  bool r = t->verify();
321 	  go_assert(r);
322 	  t->named_type()->convert(gogo);
323 	}
324     }
325 }
326 
327 // The type used to define a runtime function.
328 
329 struct Runtime_function
330 {
331   // Function name.
332   const char* name;
333   // Parameter types.  Never more than 6, as it happens.  RFT_VOID if
334   // not used.
335   Runtime_function_type parameter_types[6];
336   // Result types.  Never more than 2, as it happens.  RFT_VOID if not
337   // used.
338   Runtime_function_type result_types[2];
339 };
340 
341 static const Runtime_function runtime_functions[] =
342 {
343 
344 #define DEF_GO_RUNTIME(CODE, NAME, PARAMS, RESULTS) { NAME, PARAMS, RESULTS } ,
345 
346 #include "runtime.def"
347 
348 #undef DEF_GO_RUNTIME
349 
350 };
351 
352 static Named_object*
353 runtime_function_declarations[Runtime::NUMBER_OF_FUNCTIONS];
354 
355 // Get the declaration of a runtime function.
356 
357 Named_object*
runtime_declaration(Function code)358 Runtime::runtime_declaration(Function code)
359 {
360   go_assert(code < Runtime::NUMBER_OF_FUNCTIONS);
361   if (runtime_function_declarations[code] == NULL)
362     {
363       const Runtime_function* pb = &runtime_functions[code];
364 
365       Location bloc = Linemap::predeclared_location();
366 
367       Typed_identifier_list* param_types = NULL;
368       if (pb->parameter_types[0] != RFT_VOID)
369 	{
370 	  param_types = new Typed_identifier_list();
371 	  for (unsigned int i = 0;
372 	       i < (sizeof(pb->parameter_types)
373 		    / sizeof (pb->parameter_types[0]));
374 	       i++)
375 	    {
376 	      if (pb->parameter_types[i] == RFT_VOID)
377 		break;
378 	      Type* t = runtime_function_type(pb->parameter_types[i]);
379 	      param_types->push_back(Typed_identifier("", t, bloc));
380 	    }
381 	}
382 
383       Typed_identifier_list* result_types = NULL;
384       if (pb->result_types[0] != RFT_VOID)
385 	{
386 	  result_types = new Typed_identifier_list();
387 	  for (unsigned int i = 0;
388 	       i < sizeof(pb->result_types) / sizeof(pb->result_types[0]);
389 	       i++)
390 	    {
391 	      if (pb->result_types[i] == RFT_VOID)
392 		break;
393 	      Type* t = runtime_function_type(pb->result_types[i]);
394 	      result_types->push_back(Typed_identifier("", t, bloc));
395 	    }
396 	}
397 
398       Function_type* fntype = Type::make_function_type(NULL, param_types,
399 						       result_types, bloc);
400       const char* n = pb->name;
401       const char* n1 = strchr(n, '.');
402       if (n1 != NULL)
403 	n = n1 + 1;
404       Named_object* no = Named_object::make_function_declaration(n, NULL,
405 								 fntype, bloc);
406       no->func_declaration_value()->set_asm_name(pb->name);
407 
408       runtime_function_declarations[code] = no;
409     }
410 
411   return runtime_function_declarations[code];
412 }
413 
414 // Make a call to a runtime function.
415 
416 Call_expression*
make_call(Runtime::Function code,Location loc,int param_count,...)417 Runtime::make_call(Runtime::Function code, Location loc,
418 		   int param_count, ...)
419 {
420   go_assert(code < Runtime::NUMBER_OF_FUNCTIONS);
421 
422   const Runtime_function* pb = &runtime_functions[code];
423 
424   go_assert(static_cast<size_t>(param_count)
425 	     <= sizeof(pb->parameter_types) / sizeof(pb->parameter_types[0]));
426 
427   Named_object* no = runtime_declaration(code);
428   Expression* func = Expression::make_func_reference(no, NULL, loc);
429 
430   Expression_list* args = new Expression_list();
431   args->reserve(param_count);
432 
433   va_list ap;
434   va_start(ap, param_count);
435   for (int i = 0; i < param_count; ++i)
436     {
437       Expression* e = va_arg(ap, Expression*);
438       Runtime_function_type rft = pb->parameter_types[i];
439       args->push_back(convert_to_runtime_function_type(rft, e, loc));
440     }
441   va_end(ap);
442 
443   return Expression::make_call(func, args, false, loc);
444 }
445 
446 // Get the runtime code for a named builtin function.  This is used as a helper
447 // when creating function references for call expressions.  Every reference to
448 // a builtin runtime function should have the associated runtime code.  If the
449 // name is ambiguous and can refer to many runtime codes, return
450 // NUMBER_OF_FUNCTIONS.
451 
452 Runtime::Function
name_to_code(const std::string & name)453 Runtime::name_to_code(const std::string& name)
454 {
455   Function code = Runtime::NUMBER_OF_FUNCTIONS;
456 
457   // Look through the known names for a match.
458   for (size_t i = 0; i < Runtime::NUMBER_OF_FUNCTIONS; i++)
459     {
460       const char* runtime_function_name = runtime_functions[i].name;
461       if (strcmp(runtime_function_name, name.c_str()) == 0)
462         code = static_cast<Runtime::Function>(i);
463       // The names in the table have "runtime." prefix. We may be
464       // called with a name without the prefix. Try matching
465       // without the prefix as well.
466       if (strncmp(runtime_function_name, "runtime.", 8) == 0
467           && strcmp(runtime_function_name + 8, name.c_str()) == 0)
468         code = static_cast<Runtime::Function>(i);
469     }
470   return code;
471 }
472