1//===- runtime.go - IR generation for runtime calls -----------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file implements IR generation for calls to the runtime library.
10//
11//===----------------------------------------------------------------------===//
12
13package irgen
14
15import (
16	"strconv"
17
18	"llvm.org/llgo/third_party/gotools/go/types"
19
20	"llvm.org/llvm/bindings/go/llvm"
21)
22
23type runtimeFnInfo struct {
24	fi *functionTypeInfo
25	fn llvm.Value
26}
27
28func (rfi *runtimeFnInfo) init(tm *llvmTypeMap, m llvm.Module, name string, args []types.Type, results []types.Type) {
29	rfi.fi = new(functionTypeInfo)
30	*rfi.fi = tm.getFunctionTypeInfo(args, results)
31	rfi.fn = rfi.fi.declare(m, name)
32}
33
34func (rfi *runtimeFnInfo) call(f *frame, args ...llvm.Value) []llvm.Value {
35	if f.unwindBlock.IsNil() {
36		return rfi.callOnly(f, args...)
37	} else {
38		return rfi.invoke(f, f.unwindBlock, args...)
39	}
40}
41
42func (rfi *runtimeFnInfo) callOnly(f *frame, args ...llvm.Value) []llvm.Value {
43	return rfi.fi.call(f.llvmtypes.ctx, f.allocaBuilder, f.builder, rfi.fn, llvm.Value{nil}, args)
44}
45
46func (rfi *runtimeFnInfo) invoke(f *frame, lpad llvm.BasicBlock, args ...llvm.Value) []llvm.Value {
47	contbb := llvm.AddBasicBlock(f.function, "")
48	return rfi.fi.invoke(f.llvmtypes.ctx, f.allocaBuilder, f.builder, rfi.fn, llvm.Value{nil}, args, contbb, lpad)
49}
50
51// runtimeInterface is a struct containing references to
52// runtime types and intrinsic function declarations.
53type runtimeInterface struct {
54	// LLVM intrinsics
55	memcpy,
56	memset,
57	returnaddress llvm.Value
58
59	// Exception handling support
60	gccgoPersonality   llvm.Value
61	gccgoExceptionType llvm.Type
62
63	// Runtime intrinsics
64	append,
65	assertInterface,
66	byteArrayToString,
67	canRecover,
68	chanCap,
69	chanLen,
70	chanrecv2,
71	checkDefer,
72	checkInterfaceType,
73	builtinClose,
74	convertInterface,
75	copy,
76	Defer,
77	deferredRecover,
78	emptyInterfaceCompare,
79	Go,
80	ifaceE2I2,
81	ifaceI2I2,
82	intArrayToString,
83	interfaceCompare,
84	intToString,
85	makeSlice,
86	mapdelete,
87	mapiter2,
88	mapiterinit,
89	mapiternext,
90	mapIndex,
91	mapLen,
92	New,
93	newChannel,
94	newMap,
95	newSelect,
96	panic,
97	printBool,
98	printComplex,
99	printDouble,
100	printEmptyInterface,
101	printInterface,
102	printInt64,
103	printNl,
104	printPointer,
105	printSlice,
106	printSpace,
107	printString,
108	printUint64,
109	receive,
110	recover,
111	registerGcRoots,
112	runtimeError,
113	selectdefault,
114	selectrecv2,
115	selectsend,
116	selectgo,
117	sendBig,
118	setDeferRetaddr,
119	strcmp,
120	stringiter2,
121	stringPlus,
122	stringSlice,
123	stringToByteArray,
124	stringToIntArray,
125	typeDescriptorsEqual,
126	undefer runtimeFnInfo
127}
128
129func newRuntimeInterface(module llvm.Module, tm *llvmTypeMap) (*runtimeInterface, error) {
130	var ri runtimeInterface
131
132	Bool := types.Typ[types.Bool]
133	Complex128 := types.Typ[types.Complex128]
134	Float64 := types.Typ[types.Float64]
135	Int32 := types.Typ[types.Int32]
136	Int64 := types.Typ[types.Int64]
137	Int := types.Typ[types.Int]
138	Rune := types.Typ[types.Rune]
139	String := types.Typ[types.String]
140	Uintptr := types.Typ[types.Uintptr]
141	UnsafePointer := types.Typ[types.UnsafePointer]
142
143	EmptyInterface := types.NewInterface(nil, nil)
144	ByteSlice := types.NewSlice(types.Typ[types.Byte])
145	IntSlice := types.NewSlice(types.Typ[types.Int])
146
147	AttrKind := llvm.AttributeKindID("nounwind")
148	NoUnwindAttr := module.Context().CreateEnumAttribute(AttrKind, 0)
149	AttrKind = llvm.AttributeKindID("noreturn")
150	NoReturnAttr := module.Context().CreateEnumAttribute(AttrKind, 0)
151
152	for _, rt := range [...]struct {
153		name      string
154		rfi       *runtimeFnInfo
155		args, res []types.Type
156		attrs     []llvm.Attribute
157	}{
158		{
159			name: "__go_append",
160			rfi:  &ri.append,
161			args: []types.Type{IntSlice, UnsafePointer, Uintptr, Uintptr},
162			res:  []types.Type{IntSlice},
163		},
164		{
165			name: "__go_assert_interface",
166			rfi:  &ri.assertInterface,
167			args: []types.Type{UnsafePointer, UnsafePointer},
168			res:  []types.Type{UnsafePointer},
169		},
170		{
171			name:  "__go_byte_array_to_string",
172			rfi:   &ri.byteArrayToString,
173			args:  []types.Type{UnsafePointer, Int},
174			res:   []types.Type{String},
175			attrs: []llvm.Attribute{NoUnwindAttr},
176		},
177		{
178			name: "__go_can_recover",
179			rfi:  &ri.canRecover,
180			args: []types.Type{UnsafePointer},
181			res:  []types.Type{Bool},
182		},
183		{
184			name: "__go_chan_cap",
185			rfi:  &ri.chanCap,
186			args: []types.Type{UnsafePointer},
187			res:  []types.Type{Int},
188		},
189		{
190			name: "__go_chan_len",
191			rfi:  &ri.chanLen,
192			args: []types.Type{UnsafePointer},
193			res:  []types.Type{Int},
194		},
195		{
196			name: "runtime.chanrecv2",
197			rfi:  &ri.chanrecv2,
198			args: []types.Type{UnsafePointer, UnsafePointer, UnsafePointer},
199			res:  []types.Type{Bool},
200		},
201		{
202			name: "__go_check_defer",
203			rfi:  &ri.checkDefer,
204			args: []types.Type{UnsafePointer},
205		},
206		{
207			name: "__go_check_interface_type",
208			rfi:  &ri.checkInterfaceType,
209			args: []types.Type{UnsafePointer, UnsafePointer, UnsafePointer},
210		},
211		{
212			name: "__go_builtin_close",
213			rfi:  &ri.builtinClose,
214			args: []types.Type{UnsafePointer},
215		},
216		{
217			name: "__go_convert_interface",
218			rfi:  &ri.convertInterface,
219			args: []types.Type{UnsafePointer, UnsafePointer},
220			res:  []types.Type{UnsafePointer},
221		},
222		{
223			name: "__go_copy",
224			rfi:  &ri.copy,
225			args: []types.Type{UnsafePointer, UnsafePointer, Uintptr},
226		},
227		{
228			name: "__go_defer",
229			rfi:  &ri.Defer,
230			args: []types.Type{UnsafePointer, UnsafePointer, UnsafePointer},
231		},
232		{
233			name: "__go_deferred_recover",
234			rfi:  &ri.deferredRecover,
235			res:  []types.Type{EmptyInterface},
236		},
237		{
238			name: "__go_empty_interface_compare",
239			rfi:  &ri.emptyInterfaceCompare,
240			args: []types.Type{EmptyInterface, EmptyInterface},
241			res:  []types.Type{Int},
242		},
243		{
244			name: "__go_go",
245			rfi:  &ri.Go,
246			args: []types.Type{UnsafePointer, UnsafePointer},
247		},
248		{
249			name: "runtime.ifaceE2I2",
250			rfi:  &ri.ifaceE2I2,
251			args: []types.Type{UnsafePointer, EmptyInterface},
252			res:  []types.Type{EmptyInterface, Bool},
253		},
254		{
255			name: "runtime.ifaceI2I2",
256			rfi:  &ri.ifaceI2I2,
257			args: []types.Type{UnsafePointer, EmptyInterface},
258			res:  []types.Type{EmptyInterface, Bool},
259		},
260		{
261			name: "__go_int_array_to_string",
262			rfi:  &ri.intArrayToString,
263			args: []types.Type{UnsafePointer, Int},
264			res:  []types.Type{String},
265		},
266		{
267			name: "__go_int_to_string",
268			rfi:  &ri.intToString,
269			args: []types.Type{Int},
270			res:  []types.Type{String},
271		},
272		{
273			name: "__go_interface_compare",
274			rfi:  &ri.interfaceCompare,
275			args: []types.Type{EmptyInterface, EmptyInterface},
276			res:  []types.Type{Int},
277		},
278		{
279			name: "__go_make_slice2",
280			rfi:  &ri.makeSlice,
281			args: []types.Type{UnsafePointer, Uintptr, Uintptr},
282			res:  []types.Type{IntSlice},
283		},
284		{
285			name: "runtime.mapdelete",
286			rfi:  &ri.mapdelete,
287			args: []types.Type{UnsafePointer, UnsafePointer},
288		},
289		{
290			name: "runtime.mapiter2",
291			rfi:  &ri.mapiter2,
292			args: []types.Type{UnsafePointer, UnsafePointer, UnsafePointer},
293		},
294		{
295			name: "runtime.mapiterinit",
296			rfi:  &ri.mapiterinit,
297			args: []types.Type{UnsafePointer, UnsafePointer},
298		},
299		{
300			name: "runtime.mapiternext",
301			rfi:  &ri.mapiternext,
302			args: []types.Type{UnsafePointer},
303		},
304		{
305			name: "__go_map_index",
306			rfi:  &ri.mapIndex,
307			args: []types.Type{UnsafePointer, UnsafePointer, Bool},
308			res:  []types.Type{UnsafePointer},
309		},
310		{
311			name: "__go_map_len",
312			rfi:  &ri.mapLen,
313			args: []types.Type{UnsafePointer},
314			res:  []types.Type{Int},
315		},
316		{
317			name:  "__go_new",
318			rfi:   &ri.New,
319			args:  []types.Type{UnsafePointer, Uintptr},
320			res:   []types.Type{UnsafePointer},
321			attrs: []llvm.Attribute{NoUnwindAttr},
322		},
323		{
324			name: "__go_new_channel",
325			rfi:  &ri.newChannel,
326			args: []types.Type{UnsafePointer, Uintptr},
327			res:  []types.Type{UnsafePointer},
328		},
329		{
330			name: "__go_new_map",
331			rfi:  &ri.newMap,
332			args: []types.Type{UnsafePointer, Uintptr},
333			res:  []types.Type{UnsafePointer},
334		},
335		{
336			name: "runtime.newselect",
337			rfi:  &ri.newSelect,
338			args: []types.Type{Int32},
339			res:  []types.Type{UnsafePointer},
340		},
341		{
342			name:  "__go_panic",
343			rfi:   &ri.panic,
344			args:  []types.Type{EmptyInterface},
345			attrs: []llvm.Attribute{NoReturnAttr},
346		},
347		{
348			name: "__go_print_bool",
349			rfi:  &ri.printBool,
350			args: []types.Type{Bool},
351		},
352		{
353			name: "__go_print_complex",
354			rfi:  &ri.printComplex,
355			args: []types.Type{Complex128},
356		},
357		{
358			name: "__go_print_double",
359			rfi:  &ri.printDouble,
360			args: []types.Type{Float64},
361		},
362		{
363			name: "__go_print_empty_interface",
364			rfi:  &ri.printEmptyInterface,
365			args: []types.Type{EmptyInterface},
366		},
367		{
368			name: "__go_print_interface",
369			rfi:  &ri.printInterface,
370			args: []types.Type{EmptyInterface},
371		},
372		{
373			name: "__go_print_int64",
374			rfi:  &ri.printInt64,
375			args: []types.Type{Int64},
376		},
377		{
378			name: "__go_print_nl",
379			rfi:  &ri.printNl,
380		},
381		{
382			name: "__go_print_pointer",
383			rfi:  &ri.printPointer,
384			args: []types.Type{UnsafePointer},
385		},
386		{
387			name: "__go_print_slice",
388			rfi:  &ri.printSlice,
389			args: []types.Type{IntSlice},
390		},
391		{
392			name: "__go_print_space",
393			rfi:  &ri.printSpace,
394		},
395		{
396			name: "__go_print_string",
397			rfi:  &ri.printString,
398			args: []types.Type{String},
399		},
400		{
401			name: "__go_print_uint64",
402			rfi:  &ri.printUint64,
403			args: []types.Type{Int64},
404		},
405		{
406			name: "__go_receive",
407			rfi:  &ri.receive,
408			args: []types.Type{UnsafePointer, UnsafePointer, UnsafePointer},
409		},
410		{
411			name: "__go_recover",
412			rfi:  &ri.recover,
413			res:  []types.Type{EmptyInterface},
414		},
415		{
416			name: "__go_register_gc_roots",
417			rfi:  &ri.registerGcRoots,
418			args: []types.Type{UnsafePointer},
419		},
420		{
421			name:  "__go_runtime_error",
422			rfi:   &ri.runtimeError,
423			args:  []types.Type{Int32},
424			attrs: []llvm.Attribute{NoReturnAttr},
425		},
426		{
427			name: "runtime.selectdefault",
428			rfi:  &ri.selectdefault,
429			args: []types.Type{UnsafePointer, Int32},
430		},
431		{
432			name: "runtime.selectgo",
433			rfi:  &ri.selectgo,
434			args: []types.Type{UnsafePointer},
435			res:  []types.Type{Int},
436		},
437		{
438			name: "runtime.selectrecv2",
439			rfi:  &ri.selectrecv2,
440			args: []types.Type{UnsafePointer, UnsafePointer, UnsafePointer, UnsafePointer, Int32},
441		},
442		{
443			name: "runtime.selectsend",
444			rfi:  &ri.selectsend,
445			args: []types.Type{UnsafePointer, UnsafePointer, UnsafePointer, Int32},
446		},
447		{
448			name: "__go_send_big",
449			rfi:  &ri.sendBig,
450			args: []types.Type{UnsafePointer, UnsafePointer, UnsafePointer},
451		},
452		{
453			name: "__go_set_defer_retaddr",
454			rfi:  &ri.setDeferRetaddr,
455			args: []types.Type{UnsafePointer},
456			res:  []types.Type{Bool},
457		},
458		{
459			name: "__go_strcmp",
460			rfi:  &ri.strcmp,
461			args: []types.Type{String, String},
462			res:  []types.Type{Int},
463		},
464		{
465			name: "__go_string_plus",
466			rfi:  &ri.stringPlus,
467			args: []types.Type{String, String},
468			res:  []types.Type{String},
469		},
470		{
471			name: "__go_string_slice",
472			rfi:  &ri.stringSlice,
473			args: []types.Type{String, Int, Int},
474			res:  []types.Type{String},
475		},
476		{
477			name:  "__go_string_to_byte_array",
478			rfi:   &ri.stringToByteArray,
479			args:  []types.Type{String},
480			res:   []types.Type{ByteSlice},
481			attrs: []llvm.Attribute{NoUnwindAttr},
482		},
483		{
484			name: "__go_string_to_int_array",
485			rfi:  &ri.stringToIntArray,
486			args: []types.Type{String},
487			res:  []types.Type{IntSlice},
488		},
489		{
490			name: "runtime.stringiter2",
491			rfi:  &ri.stringiter2,
492			args: []types.Type{String, Int},
493			res:  []types.Type{Int, Rune},
494		},
495		{
496			name: "__go_type_descriptors_equal",
497			rfi:  &ri.typeDescriptorsEqual,
498			args: []types.Type{UnsafePointer, UnsafePointer},
499			res:  []types.Type{Bool},
500		},
501		{
502			name: "__go_undefer",
503			rfi:  &ri.undefer,
504			args: []types.Type{UnsafePointer},
505		},
506	} {
507		rt.rfi.init(tm, module, rt.name, rt.args, rt.res)
508		for _, attr := range rt.attrs {
509			rt.rfi.fn.AddFunctionAttr(attr)
510		}
511	}
512
513	memsetName := "llvm.memset.p0i8.i" + strconv.Itoa(tm.target.IntPtrType().IntTypeWidth())
514	memsetType := llvm.FunctionType(
515		llvm.VoidType(),
516		[]llvm.Type{
517			llvm.PointerType(llvm.Int8Type(), 0),
518			llvm.Int8Type(),
519			tm.target.IntPtrType(),
520			llvm.Int1Type(),
521		},
522		false,
523	)
524	ri.memset = llvm.AddFunction(module, memsetName, memsetType)
525
526	memcpyName := "llvm.memcpy.p0i8.p0i8.i" + strconv.Itoa(tm.target.IntPtrType().IntTypeWidth())
527	memcpyType := llvm.FunctionType(
528		llvm.VoidType(),
529		[]llvm.Type{
530			llvm.PointerType(llvm.Int8Type(), 0),
531			llvm.PointerType(llvm.Int8Type(), 0),
532			llvm.Int64Type(),
533			llvm.Int1Type(),
534		},
535		false,
536	)
537	ri.memcpy = llvm.AddFunction(module, memcpyName, memcpyType)
538
539	returnaddressType := llvm.FunctionType(
540		llvm.PointerType(llvm.Int8Type(), 0),
541		[]llvm.Type{llvm.Int32Type()},
542		false,
543	)
544	ri.returnaddress = llvm.AddFunction(module, "llvm.returnaddress", returnaddressType)
545
546	gccgoPersonalityType := llvm.FunctionType(
547		llvm.Int32Type(),
548		[]llvm.Type{
549			llvm.Int32Type(),
550			llvm.Int64Type(),
551			llvm.PointerType(llvm.Int8Type(), 0),
552			llvm.PointerType(llvm.Int8Type(), 0),
553		},
554		false,
555	)
556	ri.gccgoPersonality = llvm.AddFunction(module, "__gccgo_personality_v0", gccgoPersonalityType)
557
558	ri.gccgoExceptionType = llvm.StructType(
559		[]llvm.Type{
560			llvm.PointerType(llvm.Int8Type(), 0),
561			llvm.Int32Type(),
562		},
563		false,
564	)
565
566	return &ri, nil
567}
568
569func (fr *frame) createZExtOrTrunc(v llvm.Value, t llvm.Type, name string) llvm.Value {
570	switch n := v.Type().IntTypeWidth() - t.IntTypeWidth(); {
571	case n < 0:
572		v = fr.builder.CreateZExt(v, fr.target.IntPtrType(), name)
573	case n > 0:
574		v = fr.builder.CreateTrunc(v, fr.target.IntPtrType(), name)
575	}
576	return v
577}
578
579func (fr *frame) createTypeMalloc(t types.Type) llvm.Value {
580	size := llvm.ConstInt(fr.target.IntPtrType(), uint64(fr.llvmtypes.Sizeof(t)), false)
581	malloc := fr.runtime.New.callOnly(fr, fr.types.ToRuntime(t), size)[0]
582	return fr.builder.CreateBitCast(malloc, llvm.PointerType(fr.types.ToLLVM(t), 0), "")
583}
584
585func (fr *frame) memsetZero(ptr llvm.Value, size llvm.Value) {
586	memset := fr.runtime.memset
587	ptr = fr.builder.CreateBitCast(ptr, llvm.PointerType(llvm.Int8Type(), 0), "")
588	fill := llvm.ConstNull(llvm.Int8Type())
589	size = fr.createZExtOrTrunc(size, fr.target.IntPtrType(), "")
590	isvolatile := llvm.ConstNull(llvm.Int1Type())
591	fr.builder.CreateCall(memset, []llvm.Value{ptr, fill, size, isvolatile}, "")
592}
593
594func (fr *frame) memcpy(dest llvm.Value, src llvm.Value, size llvm.Value) {
595	memcpy := fr.runtime.memcpy
596	dest = fr.builder.CreateBitCast(dest, llvm.PointerType(llvm.Int8Type(), 0), "")
597	src = fr.builder.CreateBitCast(src, llvm.PointerType(llvm.Int8Type(), 0), "")
598	size = fr.createZExtOrTrunc(size, fr.target.IntPtrType(), "")
599	isvolatile := llvm.ConstNull(llvm.Int1Type())
600	fr.builder.CreateCall(memcpy, []llvm.Value{dest, src, size, isvolatile}, "")
601}
602
603func (fr *frame) returnAddress(level uint64) llvm.Value {
604	returnaddress := fr.runtime.returnaddress
605	levelValue := llvm.ConstInt(llvm.Int32Type(), level, false)
606	return fr.builder.CreateCall(returnaddress, []llvm.Value{levelValue}, "")
607}
608