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