github.com/axw/llgo@v0.0.0-20160805011314-95b5fe4dca20/irgen/indirect.go (about) 1 //===- indirect.go - IR generation for thunks -----------------------------===// 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 thunks required by the "defer" and 11 // "go" builtins. 12 // 13 //===----------------------------------------------------------------------===// 14 15 package irgen 16 17 import ( 18 "llvm.org/llgo/third_party/gotools/go/ssa" 19 "llvm.org/llgo/third_party/gotools/go/types" 20 "llvm.org/llvm/bindings/go/llvm" 21 ) 22 23 // createThunk creates a thunk from a 24 // given function and arguments, suitable for use with 25 // "defer" and "go". 26 func (fr *frame) createThunk(call ssa.CallInstruction) (thunk llvm.Value, arg llvm.Value) { 27 seenarg := make(map[ssa.Value]bool) 28 var args []ssa.Value 29 var argtypes []*types.Var 30 31 packArg := func(arg ssa.Value) { 32 switch arg.(type) { 33 case *ssa.Builtin, *ssa.Function, *ssa.Const, *ssa.Global: 34 // Do nothing: we can generate these in the thunk 35 default: 36 if !seenarg[arg] { 37 seenarg[arg] = true 38 args = append(args, arg) 39 field := types.NewField(0, nil, "_", arg.Type(), true) 40 argtypes = append(argtypes, field) 41 } 42 } 43 } 44 45 packArg(call.Common().Value) 46 for _, arg := range call.Common().Args { 47 packArg(arg) 48 } 49 50 var isRecoverCall bool 51 i8ptr := llvm.PointerType(llvm.Int8Type(), 0) 52 var structllptr llvm.Type 53 if len(args) == 0 { 54 if builtin, ok := call.Common().Value.(*ssa.Builtin); ok { 55 isRecoverCall = builtin.Name() == "recover" 56 } 57 if isRecoverCall { 58 // When creating a thunk for recover(), we must pass fr.canRecover. 59 arg = fr.builder.CreateZExt(fr.canRecover, fr.target.IntPtrType(), "") 60 arg = fr.builder.CreateIntToPtr(arg, i8ptr, "") 61 } else { 62 arg = llvm.ConstPointerNull(i8ptr) 63 } 64 } else { 65 structtype := types.NewStruct(argtypes, nil) 66 arg = fr.createTypeMalloc(structtype) 67 structllptr = arg.Type() 68 for i, ssaarg := range args { 69 argptr := fr.builder.CreateStructGEP(arg, i, "") 70 fr.builder.CreateStore(fr.llvmvalue(ssaarg), argptr) 71 } 72 arg = fr.builder.CreateBitCast(arg, i8ptr, "") 73 } 74 75 thunkfntype := llvm.FunctionType(llvm.VoidType(), []llvm.Type{i8ptr}, false) 76 thunkfn := llvm.AddFunction(fr.module.Module, "", thunkfntype) 77 thunkfn.SetLinkage(llvm.InternalLinkage) 78 fr.addCommonFunctionAttrs(thunkfn) 79 80 thunkfr := newFrame(fr.unit, thunkfn) 81 defer thunkfr.dispose() 82 83 prologuebb := llvm.AddBasicBlock(thunkfn, "prologue") 84 thunkfr.builder.SetInsertPointAtEnd(prologuebb) 85 86 if isRecoverCall { 87 thunkarg := thunkfn.Param(0) 88 thunkarg = thunkfr.builder.CreatePtrToInt(thunkarg, fr.target.IntPtrType(), "") 89 thunkfr.canRecover = thunkfr.builder.CreateTrunc(thunkarg, llvm.Int1Type(), "") 90 } else if len(args) > 0 { 91 thunkarg := thunkfn.Param(0) 92 thunkarg = thunkfr.builder.CreateBitCast(thunkarg, structllptr, "") 93 for i, ssaarg := range args { 94 thunkargptr := thunkfr.builder.CreateStructGEP(thunkarg, i, "") 95 thunkarg := thunkfr.builder.CreateLoad(thunkargptr, "") 96 thunkfr.env[ssaarg] = newValue(thunkarg, ssaarg.Type()) 97 } 98 } 99 100 _, isDefer := call.(*ssa.Defer) 101 102 entrybb := llvm.AddBasicBlock(thunkfn, "entry") 103 br := thunkfr.builder.CreateBr(entrybb) 104 thunkfr.allocaBuilder.SetInsertPointBefore(br) 105 106 thunkfr.builder.SetInsertPointAtEnd(entrybb) 107 var exitbb llvm.BasicBlock 108 if isDefer { 109 exitbb = llvm.AddBasicBlock(thunkfn, "exit") 110 thunkfr.runtime.setDeferRetaddr.call(thunkfr, llvm.BlockAddress(thunkfn, exitbb)) 111 } 112 if isDefer && isRecoverCall { 113 thunkfr.callRecover(true) 114 } else { 115 thunkfr.callInstruction(call) 116 } 117 if isDefer { 118 thunkfr.builder.CreateBr(exitbb) 119 thunkfr.builder.SetInsertPointAtEnd(exitbb) 120 } 121 thunkfr.builder.CreateRetVoid() 122 123 thunk = fr.builder.CreateBitCast(thunkfn, i8ptr, "") 124 return 125 }