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