github.com/aykevl/tinygo@v0.5.0/compiler/interface.go (about) 1 package compiler 2 3 // This file transforms interface-related instructions (*ssa.MakeInterface, 4 // *ssa.TypeAssert, calls on interface types) to an intermediate IR form, to be 5 // lowered to the final form by the interface lowering pass. See 6 // interface-lowering.go for more details. 7 8 import ( 9 "go/token" 10 "go/types" 11 "strconv" 12 "strings" 13 14 "github.com/tinygo-org/tinygo/ir" 15 "golang.org/x/tools/go/ssa" 16 "tinygo.org/x/go-llvm" 17 ) 18 19 // parseMakeInterface emits the LLVM IR for the *ssa.MakeInterface instruction. 20 // It tries to put the type in the interface value, but if that's not possible, 21 // it will do an allocation of the right size and put that in the interface 22 // value field. 23 // 24 // An interface value is a {typecode, value} tuple, or {i16, i8*} to be exact. 25 func (c *Compiler) parseMakeInterface(val llvm.Value, typ types.Type, pos token.Pos) (llvm.Value, error) { 26 var itfValue llvm.Value 27 size := c.targetData.TypeAllocSize(val.Type()) 28 if size > c.targetData.TypeAllocSize(c.i8ptrType) { 29 // Allocate on the heap and put a pointer in the interface. 30 // TODO: escape analysis. 31 sizeValue := llvm.ConstInt(c.uintptrType, size, false) 32 alloc := c.createRuntimeCall("alloc", []llvm.Value{sizeValue}, "makeinterface.alloc") 33 itfValueCast := c.builder.CreateBitCast(alloc, llvm.PointerType(val.Type(), 0), "makeinterface.cast.value") 34 c.builder.CreateStore(val, itfValueCast) 35 itfValue = c.builder.CreateBitCast(itfValueCast, c.i8ptrType, "makeinterface.cast.i8ptr") 36 } else if size == 0 { 37 itfValue = llvm.ConstPointerNull(c.i8ptrType) 38 } else { 39 // Directly place the value in the interface. 40 switch val.Type().TypeKind() { 41 case llvm.IntegerTypeKind: 42 itfValue = c.builder.CreateIntToPtr(val, c.i8ptrType, "makeinterface.cast.int") 43 case llvm.PointerTypeKind: 44 itfValue = c.builder.CreateBitCast(val, c.i8ptrType, "makeinterface.cast.ptr") 45 case llvm.StructTypeKind, llvm.FloatTypeKind, llvm.DoubleTypeKind: 46 // A bitcast would be useful here, but bitcast doesn't allow 47 // aggregate types. So we'll bitcast it using an alloca. 48 // Hopefully this will get optimized away. 49 mem := c.builder.CreateAlloca(c.i8ptrType, "makeinterface.cast.struct") 50 memStructPtr := c.builder.CreateBitCast(mem, llvm.PointerType(val.Type(), 0), "makeinterface.cast.struct.cast") 51 c.builder.CreateStore(val, memStructPtr) 52 itfValue = c.builder.CreateLoad(mem, "makeinterface.cast.load") 53 default: 54 return llvm.Value{}, c.makeError(pos, "todo: makeinterface: cast small type to i8*") 55 } 56 } 57 itfTypeCodeGlobal := c.getTypeCode(typ) 58 itfMethodSetGlobal, err := c.getTypeMethodSet(typ) 59 if err != nil { 60 return llvm.Value{}, nil 61 } 62 itfConcreteTypeGlobal := c.mod.NamedGlobal("typeInInterface:" + itfTypeCodeGlobal.Name()) 63 if itfConcreteTypeGlobal.IsNil() { 64 typeInInterface := c.mod.GetTypeByName("runtime.typeInInterface") 65 itfConcreteTypeGlobal = llvm.AddGlobal(c.mod, typeInInterface, "typeInInterface:"+itfTypeCodeGlobal.Name()) 66 itfConcreteTypeGlobal.SetInitializer(llvm.ConstNamedStruct(typeInInterface, []llvm.Value{itfTypeCodeGlobal, itfMethodSetGlobal})) 67 itfConcreteTypeGlobal.SetGlobalConstant(true) 68 itfConcreteTypeGlobal.SetLinkage(llvm.PrivateLinkage) 69 } 70 itfTypeCode := c.builder.CreatePtrToInt(itfConcreteTypeGlobal, c.uintptrType, "") 71 itf := llvm.Undef(c.mod.GetTypeByName("runtime._interface")) 72 itf = c.builder.CreateInsertValue(itf, itfTypeCode, 0, "") 73 itf = c.builder.CreateInsertValue(itf, itfValue, 1, "") 74 return itf, nil 75 } 76 77 // getTypeCode returns a reference to a type code. 78 // It returns a pointer to an external global which should be replaced with the 79 // real type in the interface lowering pass. 80 func (c *Compiler) getTypeCode(typ types.Type) llvm.Value { 81 globalName := "type:" + getTypeCodeName(typ) 82 global := c.mod.NamedGlobal(globalName) 83 if global.IsNil() { 84 global = llvm.AddGlobal(c.mod, c.mod.GetTypeByName("runtime.typecodeID"), globalName) 85 global.SetGlobalConstant(true) 86 } 87 return global 88 } 89 90 // getTypeCodeName returns a name for this type that can be used in the 91 // interface lowering pass to assign type codes as expected by the reflect 92 // package. See getTypeCodeNum. 93 func getTypeCodeName(t types.Type) string { 94 name := "" 95 if named, ok := t.(*types.Named); ok { 96 name = "~" + named.String() + ":" 97 t = t.Underlying() 98 } 99 switch t := t.(type) { 100 case *types.Array: 101 return "array:" + name + strconv.FormatInt(t.Len(), 10) + ":" + getTypeCodeName(t.Elem()) 102 case *types.Basic: 103 var kind string 104 switch t.Kind() { 105 case types.Bool: 106 kind = "bool" 107 case types.Int: 108 kind = "int" 109 case types.Int8: 110 kind = "int8" 111 case types.Int16: 112 kind = "int16" 113 case types.Int32: 114 kind = "int32" 115 case types.Int64: 116 kind = "int64" 117 case types.Uint: 118 kind = "uint" 119 case types.Uint8: 120 kind = "uint8" 121 case types.Uint16: 122 kind = "uint16" 123 case types.Uint32: 124 kind = "uint32" 125 case types.Uint64: 126 kind = "uint64" 127 case types.Uintptr: 128 kind = "uintptr" 129 case types.Float32: 130 kind = "float32" 131 case types.Float64: 132 kind = "float64" 133 case types.Complex64: 134 kind = "complex64" 135 case types.Complex128: 136 kind = "complex128" 137 case types.String: 138 kind = "string" 139 case types.UnsafePointer: 140 kind = "unsafeptr" 141 default: 142 panic("unknown basic type: " + t.Name()) 143 } 144 return "basic:" + name + kind 145 case *types.Chan: 146 return "chan:" + name + getTypeCodeName(t.Elem()) 147 case *types.Interface: 148 methods := make([]string, t.NumMethods()) 149 for i := 0; i < t.NumMethods(); i++ { 150 methods[i] = getTypeCodeName(t.Method(i).Type()) 151 } 152 return "interface:" + name + "{" + strings.Join(methods, ",") + "}" 153 case *types.Map: 154 keyType := getTypeCodeName(t.Key()) 155 elemType := getTypeCodeName(t.Elem()) 156 return "map:" + name + "{" + keyType + "," + elemType + "}" 157 case *types.Pointer: 158 return "pointer:" + name + getTypeCodeName(t.Elem()) 159 case *types.Signature: 160 params := make([]string, t.Params().Len()) 161 for i := 0; i < t.Params().Len(); i++ { 162 params[i] = getTypeCodeName(t.Params().At(i).Type()) 163 } 164 results := make([]string, t.Results().Len()) 165 for i := 0; i < t.Results().Len(); i++ { 166 results[i] = getTypeCodeName(t.Results().At(i).Type()) 167 } 168 return "func:" + name + "{" + strings.Join(params, ",") + "}{" + strings.Join(results, ",") + "}" 169 case *types.Slice: 170 return "slice:" + name + getTypeCodeName(t.Elem()) 171 case *types.Struct: 172 elems := make([]string, t.NumFields()) 173 if t.NumFields() > 2 && t.Field(0).Name() == "C union" { 174 // TODO: report this as a normal error instead of panicking. 175 panic("cgo unions are not allowed in interfaces") 176 } 177 for i := 0; i < t.NumFields(); i++ { 178 elems[i] = getTypeCodeName(t.Field(i).Type()) 179 } 180 return "struct:" + name + "{" + strings.Join(elems, ",") + "}" 181 default: 182 panic("unknown type: " + t.String()) 183 } 184 } 185 186 // getTypeMethodSet returns a reference (GEP) to a global method set. This 187 // method set should be unreferenced after the interface lowering pass. 188 func (c *Compiler) getTypeMethodSet(typ types.Type) (llvm.Value, error) { 189 global := c.mod.NamedGlobal(typ.String() + "$methodset") 190 zero := llvm.ConstInt(c.ctx.Int32Type(), 0, false) 191 if !global.IsNil() { 192 // the method set already exists 193 return llvm.ConstGEP(global, []llvm.Value{zero, zero}), nil 194 } 195 196 ms := c.ir.Program.MethodSets.MethodSet(typ) 197 if ms.Len() == 0 { 198 // no methods, so can leave that one out 199 return llvm.ConstPointerNull(llvm.PointerType(c.mod.GetTypeByName("runtime.interfaceMethodInfo"), 0)), nil 200 } 201 202 methods := make([]llvm.Value, ms.Len()) 203 interfaceMethodInfoType := c.mod.GetTypeByName("runtime.interfaceMethodInfo") 204 for i := 0; i < ms.Len(); i++ { 205 method := ms.At(i) 206 signatureGlobal := c.getMethodSignature(method.Obj().(*types.Func)) 207 f := c.ir.GetFunction(c.ir.Program.MethodValue(method)) 208 if f.LLVMFn.IsNil() { 209 // compiler error, so panic 210 panic("cannot find function: " + f.LinkName()) 211 } 212 fn, err := c.getInterfaceInvokeWrapper(f) 213 if err != nil { 214 return llvm.Value{}, err 215 } 216 methodInfo := llvm.ConstNamedStruct(interfaceMethodInfoType, []llvm.Value{ 217 signatureGlobal, 218 llvm.ConstPtrToInt(fn, c.uintptrType), 219 }) 220 methods[i] = methodInfo 221 } 222 arrayType := llvm.ArrayType(interfaceMethodInfoType, len(methods)) 223 value := llvm.ConstArray(interfaceMethodInfoType, methods) 224 global = llvm.AddGlobal(c.mod, arrayType, typ.String()+"$methodset") 225 global.SetInitializer(value) 226 global.SetGlobalConstant(true) 227 global.SetLinkage(llvm.PrivateLinkage) 228 return llvm.ConstGEP(global, []llvm.Value{zero, zero}), nil 229 } 230 231 // getInterfaceMethodSet returns a global variable with the method set of the 232 // given named interface type. This method set is used by the interface lowering 233 // pass. 234 func (c *Compiler) getInterfaceMethodSet(typ *types.Named) llvm.Value { 235 global := c.mod.NamedGlobal(typ.String() + "$interface") 236 zero := llvm.ConstInt(c.ctx.Int32Type(), 0, false) 237 if !global.IsNil() { 238 // method set already exist, return it 239 return llvm.ConstGEP(global, []llvm.Value{zero, zero}) 240 } 241 242 // Every method is a *i16 reference indicating the signature of this method. 243 methods := make([]llvm.Value, typ.Underlying().(*types.Interface).NumMethods()) 244 for i := range methods { 245 method := typ.Underlying().(*types.Interface).Method(i) 246 methods[i] = c.getMethodSignature(method) 247 } 248 249 value := llvm.ConstArray(methods[0].Type(), methods) 250 global = llvm.AddGlobal(c.mod, value.Type(), typ.String()+"$interface") 251 global.SetInitializer(value) 252 global.SetGlobalConstant(true) 253 global.SetLinkage(llvm.PrivateLinkage) 254 return llvm.ConstGEP(global, []llvm.Value{zero, zero}) 255 } 256 257 // getMethodSignature returns a global variable which is a reference to an 258 // external *i16 indicating the indicating the signature of this method. It is 259 // used during the interface lowering pass. 260 func (c *Compiler) getMethodSignature(method *types.Func) llvm.Value { 261 signature := ir.MethodSignature(method) 262 signatureGlobal := c.mod.NamedGlobal("func " + signature) 263 if signatureGlobal.IsNil() { 264 signatureGlobal = llvm.AddGlobal(c.mod, c.ctx.Int8Type(), "func "+signature) 265 signatureGlobal.SetGlobalConstant(true) 266 } 267 return signatureGlobal 268 } 269 270 // parseTypeAssert will emit the code for a typeassert, used in if statements 271 // and in type switches (Go SSA does not have type switches, only if/else 272 // chains). Note that even though the Go SSA does not contain type switches, 273 // LLVM will recognize the pattern and make it a real switch in many cases. 274 // 275 // Type asserts on concrete types are trivial: just compare type numbers. Type 276 // asserts on interfaces are more difficult, see the comments in the function. 277 func (c *Compiler) parseTypeAssert(frame *Frame, expr *ssa.TypeAssert) (llvm.Value, error) { 278 itf, err := c.parseExpr(frame, expr.X) 279 if err != nil { 280 return llvm.Value{}, err 281 } 282 assertedType, err := c.getLLVMType(expr.AssertedType) 283 if err != nil { 284 return llvm.Value{}, err 285 } 286 valueNil, err := c.getZeroValue(assertedType) 287 if err != nil { 288 return llvm.Value{}, err 289 } 290 291 actualTypeNum := c.builder.CreateExtractValue(itf, 0, "interface.type") 292 commaOk := llvm.Value{} 293 if _, ok := expr.AssertedType.Underlying().(*types.Interface); ok { 294 // Type assert on interface type. 295 // This pseudo call will be lowered in the interface lowering pass to a 296 // real call which checks whether the provided typecode is any of the 297 // concrete types that implements this interface. 298 // This is very different from how interface asserts are implemented in 299 // the main Go compiler, where the runtime checks whether the type 300 // implements each method of the interface. See: 301 // https://research.swtch.com/interfaces 302 methodSet := c.getInterfaceMethodSet(expr.AssertedType.(*types.Named)) 303 commaOk = c.createRuntimeCall("interfaceImplements", []llvm.Value{actualTypeNum, methodSet}, "") 304 305 } else { 306 // Type assert on concrete type. 307 // Call runtime.typeAssert, which will be lowered to a simple icmp or 308 // const false in the interface lowering pass. 309 assertedTypeCodeGlobal := c.getTypeCode(expr.AssertedType) 310 commaOk = c.createRuntimeCall("typeAssert", []llvm.Value{actualTypeNum, assertedTypeCodeGlobal}, "typecode") 311 } 312 313 // Add 2 new basic blocks (that should get optimized away): one for the 314 // 'ok' case and one for all instructions following this type assert. 315 // This is necessary because we need to insert the casted value or the 316 // nil value based on whether the assert was successful. Casting before 317 // this check tells LLVM that it can use this value and may 318 // speculatively dereference pointers before the check. This can lead to 319 // a miscompilation resulting in a segfault at runtime. 320 // Additionally, this is even required by the Go spec: a failed 321 // typeassert should return a zero value, not an incorrectly casted 322 // value. 323 324 prevBlock := c.builder.GetInsertBlock() 325 okBlock := c.ctx.AddBasicBlock(frame.fn.LLVMFn, "typeassert.ok") 326 nextBlock := c.ctx.AddBasicBlock(frame.fn.LLVMFn, "typeassert.next") 327 frame.blockExits[frame.currentBlock] = nextBlock // adjust outgoing block for phi nodes 328 c.builder.CreateCondBr(commaOk, okBlock, nextBlock) 329 330 // Retrieve the value from the interface if the type assert was 331 // successful. 332 c.builder.SetInsertPointAtEnd(okBlock) 333 var valueOk llvm.Value 334 if _, ok := expr.AssertedType.Underlying().(*types.Interface); ok { 335 // Type assert on interface type. Easy: just return the same 336 // interface value. 337 valueOk = itf 338 } else { 339 // Type assert on concrete type. Extract the underlying type from 340 // the interface (but only after checking it matches). 341 valuePtr := c.builder.CreateExtractValue(itf, 1, "typeassert.value.ptr") 342 size := c.targetData.TypeAllocSize(assertedType) 343 if size > c.targetData.TypeAllocSize(c.i8ptrType) { 344 // Value was stored in an allocated buffer, load it from there. 345 valuePtrCast := c.builder.CreateBitCast(valuePtr, llvm.PointerType(assertedType, 0), "") 346 valueOk = c.builder.CreateLoad(valuePtrCast, "typeassert.value.ok") 347 } else if size == 0 { 348 valueOk, err = c.getZeroValue(assertedType) 349 if err != nil { 350 return llvm.Value{}, err 351 } 352 } else { 353 // Value was stored directly in the interface. 354 switch assertedType.TypeKind() { 355 case llvm.IntegerTypeKind: 356 valueOk = c.builder.CreatePtrToInt(valuePtr, assertedType, "typeassert.value.ok") 357 case llvm.PointerTypeKind: 358 valueOk = c.builder.CreateBitCast(valuePtr, assertedType, "typeassert.value.ok") 359 default: // struct, float, etc. 360 // A bitcast would be useful here, but bitcast doesn't allow 361 // aggregate types. So we'll bitcast it using an alloca. 362 // Hopefully this will get optimized away. 363 mem := c.builder.CreateAlloca(c.i8ptrType, "") 364 c.builder.CreateStore(valuePtr, mem) 365 memCast := c.builder.CreateBitCast(mem, llvm.PointerType(assertedType, 0), "") 366 valueOk = c.builder.CreateLoad(memCast, "typeassert.value.ok") 367 } 368 } 369 } 370 c.builder.CreateBr(nextBlock) 371 372 // Continue after the if statement. 373 c.builder.SetInsertPointAtEnd(nextBlock) 374 phi := c.builder.CreatePHI(assertedType, "typeassert.value") 375 phi.AddIncoming([]llvm.Value{valueNil, valueOk}, []llvm.BasicBlock{prevBlock, okBlock}) 376 377 if expr.CommaOk { 378 tuple := c.ctx.ConstStruct([]llvm.Value{llvm.Undef(assertedType), llvm.Undef(c.ctx.Int1Type())}, false) // create empty tuple 379 tuple = c.builder.CreateInsertValue(tuple, phi, 0, "") // insert value 380 tuple = c.builder.CreateInsertValue(tuple, commaOk, 1, "") // insert 'comma ok' boolean 381 return tuple, nil 382 } else { 383 // This is kind of dirty as the branch above becomes mostly useless, 384 // but hopefully this gets optimized away. 385 c.createRuntimeCall("interfaceTypeAssert", []llvm.Value{commaOk}, "") 386 return phi, nil 387 } 388 } 389 390 // getInvokeCall creates and returns the function pointer and parameters of an 391 // interface call. It can be used in a call or defer instruction. 392 func (c *Compiler) getInvokeCall(frame *Frame, instr *ssa.CallCommon) (llvm.Value, []llvm.Value, error) { 393 // Call an interface method with dynamic dispatch. 394 itf, err := c.parseExpr(frame, instr.Value) // interface 395 if err != nil { 396 return llvm.Value{}, nil, err 397 } 398 399 llvmFnType, err := c.getRawFuncType(instr.Method.Type().(*types.Signature)) 400 if err != nil { 401 return llvm.Value{}, nil, err 402 } 403 404 typecode := c.builder.CreateExtractValue(itf, 0, "invoke.typecode") 405 values := []llvm.Value{ 406 typecode, 407 c.getInterfaceMethodSet(instr.Value.Type().(*types.Named)), 408 c.getMethodSignature(instr.Method), 409 } 410 fn := c.createRuntimeCall("interfaceMethod", values, "invoke.func") 411 fnCast := c.builder.CreateIntToPtr(fn, llvmFnType, "invoke.func.cast") 412 receiverValue := c.builder.CreateExtractValue(itf, 1, "invoke.func.receiver") 413 414 args := []llvm.Value{receiverValue} 415 for _, arg := range instr.Args { 416 val, err := c.parseExpr(frame, arg) 417 if err != nil { 418 return llvm.Value{}, nil, err 419 } 420 args = append(args, val) 421 } 422 // Add the context parameter. An interface call never takes a context but we 423 // have to supply the parameter anyway. 424 args = append(args, llvm.Undef(c.i8ptrType)) 425 // Add the parent goroutine handle. 426 args = append(args, llvm.Undef(c.i8ptrType)) 427 428 return fnCast, args, nil 429 } 430 431 // interfaceInvokeWrapper keeps some state between getInterfaceInvokeWrapper and 432 // createInterfaceInvokeWrapper. The former is called during IR construction 433 // itself and the latter is called when finishing up the IR. 434 type interfaceInvokeWrapper struct { 435 fn *ir.Function 436 wrapper llvm.Value 437 receiverType llvm.Type 438 } 439 440 // Wrap an interface method function pointer. The wrapper takes in a pointer to 441 // the underlying value, dereferences it, and calls the real method. This 442 // wrapper is only needed when the interface value actually doesn't fit in a 443 // pointer and a pointer to the value must be created. 444 func (c *Compiler) getInterfaceInvokeWrapper(f *ir.Function) (llvm.Value, error) { 445 wrapperName := f.LinkName() + "$invoke" 446 wrapper := c.mod.NamedFunction(wrapperName) 447 if !wrapper.IsNil() { 448 // Wrapper already created. Return it directly. 449 return wrapper, nil 450 } 451 452 // Get the expanded receiver type. 453 receiverType, err := c.getLLVMType(f.Params[0].Type()) 454 if err != nil { 455 return llvm.Value{}, err 456 } 457 expandedReceiverType := c.expandFormalParamType(receiverType) 458 459 // Does this method even need any wrapping? 460 if len(expandedReceiverType) == 1 && receiverType.TypeKind() == llvm.PointerTypeKind { 461 // Nothing to wrap. 462 // Casting a function signature to a different signature and calling it 463 // with a receiver pointer bitcasted to *i8 (as done in calls on an 464 // interface) is hopefully a safe (defined) operation. 465 return f.LLVMFn, nil 466 } 467 468 // create wrapper function 469 fnType := f.LLVMFn.Type().ElementType() 470 paramTypes := append([]llvm.Type{c.i8ptrType}, fnType.ParamTypes()[len(expandedReceiverType):]...) 471 wrapFnType := llvm.FunctionType(fnType.ReturnType(), paramTypes, false) 472 wrapper = llvm.AddFunction(c.mod, wrapperName, wrapFnType) 473 c.interfaceInvokeWrappers = append(c.interfaceInvokeWrappers, interfaceInvokeWrapper{ 474 fn: f, 475 wrapper: wrapper, 476 receiverType: receiverType, 477 }) 478 return wrapper, nil 479 } 480 481 // createInterfaceInvokeWrapper finishes the work of getInterfaceInvokeWrapper, 482 // see that function for details. 483 func (c *Compiler) createInterfaceInvokeWrapper(state interfaceInvokeWrapper) error { 484 wrapper := state.wrapper 485 fn := state.fn 486 receiverType := state.receiverType 487 wrapper.SetLinkage(llvm.InternalLinkage) 488 wrapper.SetUnnamedAddr(true) 489 490 // add debug info if needed 491 if c.Debug { 492 pos := c.ir.Program.Fset.Position(fn.Pos()) 493 difunc, err := c.attachDebugInfoRaw(fn, wrapper, "$invoke", pos.Filename, pos.Line) 494 if err != nil { 495 return err 496 } 497 c.builder.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), difunc, llvm.Metadata{}) 498 } 499 500 // set up IR builder 501 block := c.ctx.AddBasicBlock(wrapper, "entry") 502 c.builder.SetInsertPointAtEnd(block) 503 504 var receiverPtr llvm.Value 505 if c.targetData.TypeAllocSize(receiverType) > c.targetData.TypeAllocSize(c.i8ptrType) { 506 // The receiver is passed in using a pointer. We have to load it here 507 // and pass it by value to the real function. 508 509 // Load the underlying value. 510 receiverPtrType := llvm.PointerType(receiverType, 0) 511 receiverPtr = c.builder.CreateBitCast(wrapper.Param(0), receiverPtrType, "receiver.ptr") 512 } else { 513 // The value is stored in the interface, but it is of type struct which 514 // is expanded to multiple parameters (e.g. {i8, i8}). So we have to 515 // receive the struct as parameter, expand it, and pass it on to the 516 // real function. 517 518 // Cast the passed-in i8* to the struct value (using an alloca) and 519 // extract its values. 520 alloca := c.builder.CreateAlloca(c.i8ptrType, "receiver.alloca") 521 c.builder.CreateStore(wrapper.Param(0), alloca) 522 receiverPtr = c.builder.CreateBitCast(alloca, llvm.PointerType(receiverType, 0), "receiver.ptr") 523 } 524 525 receiverValue := c.builder.CreateLoad(receiverPtr, "receiver") 526 params := append(c.expandFormalParam(receiverValue), wrapper.Params()[1:]...) 527 if fn.LLVMFn.Type().ElementType().ReturnType().TypeKind() == llvm.VoidTypeKind { 528 c.builder.CreateCall(fn.LLVMFn, params, "") 529 c.builder.CreateRetVoid() 530 } else { 531 ret := c.builder.CreateCall(fn.LLVMFn, params, "ret") 532 c.builder.CreateRet(ret) 533 } 534 535 return nil 536 }