github.com/axw/llgo@v0.0.0-20160805011314-95b5fe4dca20/irgen/runtime.go (about) 1 //===- 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 14 package irgen 15 16 import ( 17 "strconv" 18 19 "llvm.org/llgo/third_party/gotools/go/types" 20 21 "llvm.org/llvm/bindings/go/llvm" 22 ) 23 24 type runtimeFnInfo struct { 25 fi *functionTypeInfo 26 fn llvm.Value 27 } 28 29 func (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 35 func (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 43 func (rfi *runtimeFnInfo) callOnly(f *frame, args ...llvm.Value) []llvm.Value { 44 return rfi.fi.call(f.llvmtypes.ctx, f.allocaBuilder, f.builder, rfi.fn, llvm.Value{nil}, args) 45 } 46 47 func (rfi *runtimeFnInfo) invoke(f *frame, lpad llvm.BasicBlock, args ...llvm.Value) []llvm.Value { 48 contbb := llvm.AddBasicBlock(f.function, "") 49 return rfi.fi.invoke(f.llvmtypes.ctx, f.allocaBuilder, f.builder, rfi.fn, llvm.Value{nil}, args, contbb, lpad) 50 } 51 52 // runtimeInterface is a struct containing references to 53 // runtime types and intrinsic function declarations. 54 type 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, 67 byteArrayToString, 68 canRecover, 69 chanCap, 70 chanLen, 71 chanrecv2, 72 checkDefer, 73 checkInterfaceType, 74 builtinClose, 75 convertInterface, 76 copy, 77 Defer, 78 deferredRecover, 79 emptyInterfaceCompare, 80 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, 96 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, 119 setDeferRetaddr, 120 strcmp, 121 stringiter2, 122 stringPlus, 123 stringSlice, 124 stringToByteArray, 125 stringToIntArray, 126 typeDescriptorsEqual, 127 undefer runtimeFnInfo 128 } 129 130 func 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) 145 ByteSlice := types.NewSlice(types.Typ[types.Byte]) 146 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 { 167 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 { 174 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 { 240 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 { 313 name: "__go_new", 314 rfi: &ri.New, 315 args: []types.Type{UnsafePointer, Uintptr}, 316 res: []types.Type{UnsafePointer}, 317 attrs: []llvm.Attribute{llvm.NoUnwindAttribute}, 318 }, 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 { 332 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 { 449 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 { 473 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 { 480 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 567 func (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 577 func (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 583 func (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 593 func (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 603 func (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 }