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
23enum 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 int32, C type int32_t.
34  RFT_INT32,
35  // Go type int64, C type int64_t.
36  RFT_INT64,
37  // Go type uint64, C type uint64_t.
38  RFT_UINT64,
39  // Go type uintptr, C type uintptr_t.
40  RFT_UINTPTR,
41  // Go type rune, C type int32_t.
42  RFT_RUNE,
43  // Go type float64, C type double.
44  RFT_FLOAT64,
45  // Go type complex64, C type __complex float.
46  RFT_COMPLEX64,
47  // Go type complex128, C type __complex double.
48  RFT_COMPLEX128,
49  // Go type string, C type struct __go_string.
50  RFT_STRING,
51  // Go type unsafe.Pointer, C type "void *".
52  RFT_POINTER,
53  // Go type []any, C type struct __go_open_array.
54  RFT_SLICE,
55  // Go type map[any]any, C type struct __go_map *.
56  RFT_MAP,
57  // Pointer to map iteration type.
58  RFT_MAPITER,
59  // Go type chan any, C type struct __go_channel *.
60  RFT_CHAN,
61  // Go type non-empty interface, C type struct __go_interface.
62  RFT_IFACE,
63  // Go type interface{}, C type struct __go_empty_interface.
64  RFT_EFACE,
65  // Go type func(unsafe.Pointer), C type void (*) (void *).
66  RFT_FUNC_PTR,
67  // Pointer to Go type descriptor.
68  RFT_TYPE,
69  // Pointer to map descriptor.
70  RFT_MAPDESCRIPTOR,
71
72  NUMBER_OF_RUNTIME_FUNCTION_TYPES
73};
74
75// The Type structures for the runtime function types.
76
77static Type* runtime_function_types[NUMBER_OF_RUNTIME_FUNCTION_TYPES];
78
79// Get the Type for a Runtime_function_type code.
80
81static Type*
82runtime_function_type(Runtime_function_type bft)
83{
84  go_assert(bft < NUMBER_OF_RUNTIME_FUNCTION_TYPES);
85  Type* any = Type::make_pointer_type(Type::make_void_type());
86  if (runtime_function_types[bft] == NULL)
87    {
88      const Location bloc = Linemap::predeclared_location();
89      Type* t;
90      switch (bft)
91	{
92	default:
93	case RFT_VOID:
94	  go_unreachable();
95
96	case RFT_BOOL:
97	  t = Type::make_boolean_type();
98	  break;
99
100	case RFT_BOOLPTR:
101	  t = Type::make_pointer_type(Type::lookup_bool_type());
102	  break;
103
104	case RFT_INT:
105	  t = Type::lookup_integer_type("int");
106	  break;
107
108	case RFT_INT32:
109	  t = Type::lookup_integer_type("int32");
110	  break;
111
112	case RFT_INT64:
113	  t = Type::lookup_integer_type("int64");
114	  break;
115
116	case RFT_UINT64:
117	  t = Type::lookup_integer_type("uint64");
118	  break;
119
120	case RFT_RUNE:
121	  t = Type::lookup_integer_type("int32");
122	  break;
123
124	case RFT_UINTPTR:
125	  t = Type::lookup_integer_type("uintptr");
126	  break;
127
128	case RFT_FLOAT64:
129	  t = Type::lookup_float_type("float64");
130	  break;
131
132	case RFT_COMPLEX64:
133	  t = Type::lookup_complex_type("complex64");
134	  break;
135
136	case RFT_COMPLEX128:
137	  t = Type::lookup_complex_type("complex128");
138	  break;
139
140	case RFT_STRING:
141	  t = Type::lookup_string_type();
142	  break;
143
144	case RFT_POINTER:
145	  t = Type::make_pointer_type(Type::make_void_type());
146	  break;
147
148	case RFT_SLICE:
149	  t = Type::make_array_type(any, NULL);
150	  break;
151
152	case RFT_MAP:
153	  t = Type::make_map_type(any, any, bloc);
154	  break;
155
156	case RFT_MAPITER:
157	  t = Type::make_pointer_type(Runtime::map_iteration_type());
158	  break;
159
160	case RFT_CHAN:
161	  t = Type::make_channel_type(true, true, any);
162	  break;
163
164	case RFT_IFACE:
165	  {
166	    Typed_identifier_list* methods = new Typed_identifier_list();
167	    Type* mtype = Type::make_function_type(NULL, NULL, NULL, bloc);
168	    methods->push_back(Typed_identifier("x", mtype, bloc));
169	    Interface_type* it = Type::make_interface_type(methods, bloc);
170	    it->finalize_methods();
171	    t = it;
172	  }
173	  break;
174
175	case RFT_EFACE:
176	  t = Type::make_empty_interface_type(bloc);
177	  break;
178
179	case RFT_FUNC_PTR:
180	  {
181	    Typed_identifier_list* param_types = new Typed_identifier_list();
182	    Type* ptrtype = runtime_function_type(RFT_POINTER);
183	    param_types->push_back(Typed_identifier("", ptrtype, bloc));
184	    t = Type::make_function_type(NULL, param_types, NULL, bloc);
185	  }
186	  break;
187
188	case RFT_TYPE:
189	  t = Type::make_type_descriptor_ptr_type();
190	  break;
191
192	case RFT_MAPDESCRIPTOR:
193	  t = Type::make_pointer_type(Map_type::make_map_descriptor_type());
194	  break;
195	}
196
197      runtime_function_types[bft] = t;
198    }
199
200  return runtime_function_types[bft];
201}
202
203// Convert an expression to the type to pass to a runtime function.
204
205static Expression*
206convert_to_runtime_function_type(Runtime_function_type bft, Expression* e,
207				 Location loc)
208{
209  switch (bft)
210    {
211    default:
212    case RFT_VOID:
213      go_unreachable();
214
215    case RFT_BOOL:
216    case RFT_BOOLPTR:
217    case RFT_INT:
218    case RFT_INT32:
219    case RFT_INT64:
220    case RFT_UINT64:
221    case RFT_UINTPTR:
222    case RFT_RUNE:
223    case RFT_FLOAT64:
224    case RFT_COMPLEX64:
225    case RFT_COMPLEX128:
226    case RFT_STRING:
227    case RFT_POINTER:
228    case RFT_MAPITER:
229    case RFT_FUNC_PTR:
230      {
231	Type* t = runtime_function_type(bft);
232	if (!Type::are_identical(t, e->type(), true, NULL))
233	  e = Expression::make_cast(t, e, loc);
234	return e;
235      }
236
237    case RFT_SLICE:
238    case RFT_MAP:
239    case RFT_CHAN:
240    case RFT_IFACE:
241    case RFT_EFACE:
242      return Expression::make_unsafe_cast(runtime_function_type(bft), e, loc);
243
244    case RFT_TYPE:
245      go_assert(e->type() == Type::make_type_descriptor_ptr_type());
246      return e;
247
248    case RFT_MAPDESCRIPTOR:
249      go_assert(e->type()->points_to()
250		== Map_type::make_map_descriptor_type());
251      return e;
252    }
253}
254
255// Convert all the types used for runtime functions to the backend
256// representation.
257
258void
259Runtime::convert_types(Gogo* gogo)
260{
261  for (int i = 0; i < static_cast<int>(NUMBER_OF_RUNTIME_FUNCTION_TYPES); ++i)
262    {
263      Type* t = runtime_function_types[i];
264      if (t != NULL && t->named_type() != NULL)
265	{
266	  bool r = t->verify();
267	  go_assert(r);
268	  t->named_type()->convert(gogo);
269	}
270    }
271}
272
273// The type used to define a runtime function.
274
275struct Runtime_function
276{
277  // Function name.
278  const char* name;
279  // Parameter types.  Never more than 6, as it happens.  RFT_VOID if
280  // not used.
281  Runtime_function_type parameter_types[6];
282  // Result types.  Never more than 2, as it happens.  RFT_VOID if not
283  // used.
284  Runtime_function_type result_types[2];
285};
286
287static const Runtime_function runtime_functions[] =
288{
289
290#define DEF_GO_RUNTIME(CODE, NAME, PARAMS, RESULTS) { NAME, PARAMS, RESULTS } ,
291
292#include "runtime.def"
293
294#undef DEF_GO_RUNTIME
295
296};
297
298static Named_object*
299runtime_function_declarations[Runtime::NUMBER_OF_FUNCTIONS];
300
301// Get the declaration of a runtime function.
302
303Named_object*
304Runtime::runtime_declaration(Function code)
305{
306  go_assert(code < Runtime::NUMBER_OF_FUNCTIONS);
307  if (runtime_function_declarations[code] == NULL)
308    {
309      const Runtime_function* pb = &runtime_functions[code];
310
311      Location bloc = Linemap::predeclared_location();
312
313      Typed_identifier_list* param_types = NULL;
314      if (pb->parameter_types[0] != RFT_VOID)
315	{
316	  param_types = new Typed_identifier_list();
317	  for (unsigned int i = 0;
318	       i < (sizeof(pb->parameter_types)
319		    / sizeof (pb->parameter_types[0]));
320	       i++)
321	    {
322	      if (pb->parameter_types[i] == RFT_VOID)
323		break;
324	      Type* t = runtime_function_type(pb->parameter_types[i]);
325	      param_types->push_back(Typed_identifier("", t, bloc));
326	    }
327	}
328
329      Typed_identifier_list* result_types = NULL;
330      if (pb->result_types[0] != RFT_VOID)
331	{
332	  result_types = new Typed_identifier_list();
333	  for (unsigned int i = 0;
334	       i < sizeof(pb->result_types) / sizeof(pb->result_types[0]);
335	       i++)
336	    {
337	      if (pb->result_types[i] == RFT_VOID)
338		break;
339	      Type* t = runtime_function_type(pb->result_types[i]);
340	      result_types->push_back(Typed_identifier("", t, bloc));
341	    }
342	}
343
344      Function_type* fntype = Type::make_function_type(NULL, param_types,
345						       result_types, bloc);
346      const char* n = pb->name;
347      const char* n1 = strchr(n, '.');
348      if (n1 != NULL)
349	n = n1 + 1;
350      Named_object* no = Named_object::make_function_declaration(n, NULL,
351								 fntype, bloc);
352      no->func_declaration_value()->set_asm_name(pb->name);
353
354      runtime_function_declarations[code] = no;
355    }
356
357  return runtime_function_declarations[code];
358}
359
360// Make a call to a runtime function.
361
362Call_expression*
363Runtime::make_call(Runtime::Function code, Location loc,
364		   int param_count, ...)
365{
366  go_assert(code < Runtime::NUMBER_OF_FUNCTIONS);
367
368  const Runtime_function* pb = &runtime_functions[code];
369
370  go_assert(static_cast<size_t>(param_count)
371	     <= sizeof(pb->parameter_types) / sizeof(pb->parameter_types[0]));
372
373  Named_object* no = runtime_declaration(code);
374  Expression* func = Expression::make_func_reference(no, NULL, loc);
375
376  Expression_list* args = new Expression_list();
377  args->reserve(param_count);
378
379  va_list ap;
380  va_start(ap, param_count);
381  for (int i = 0; i < param_count; ++i)
382    {
383      Expression* e = va_arg(ap, Expression*);
384      Runtime_function_type rft = pb->parameter_types[i];
385      args->push_back(convert_to_runtime_function_type(rft, e, loc));
386    }
387  va_end(ap);
388
389  return Expression::make_call(func, args, false, loc);
390}
391
392// The type we use for a map iteration.  This is really a struct which
393// is four pointers long.  This must match the runtime struct
394// __go_hash_iter.
395
396Type*
397Runtime::map_iteration_type()
398{
399  const unsigned long map_iteration_size = 4;
400  Expression* iexpr =
401    Expression::make_integer_ul(map_iteration_size, NULL,
402				Linemap::predeclared_location());
403  return Type::make_array_type(runtime_function_type(RFT_POINTER), iexpr);
404}
405