github.com/axw/llgo@v0.0.0-20160805011314-95b5fe4dca20/irgen/interfaces.go (about) 1 //===- interfaces.go - IR generation for interfaces -----------------------===// 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 dealing with interface values. 11 // 12 //===----------------------------------------------------------------------===// 13 14 package irgen 15 16 import ( 17 "llvm.org/llgo/third_party/gotools/go/types" 18 "llvm.org/llvm/bindings/go/llvm" 19 ) 20 21 // interfaceMethod returns a function and receiver pointer for the specified 22 // interface and method pair. 23 func (fr *frame) interfaceMethod(lliface llvm.Value, ifacety types.Type, method *types.Func) (fn, recv *govalue) { 24 llitab := fr.builder.CreateExtractValue(lliface, 0, "") 25 recv = newValue(fr.builder.CreateExtractValue(lliface, 1, ""), types.Typ[types.UnsafePointer]) 26 methodset := fr.types.MethodSet(ifacety) 27 // TODO(axw) cache ordered method index 28 index := -1 29 for i, m := range orderedMethodSet(methodset) { 30 if m.Obj() == method { 31 index = i 32 break 33 } 34 } 35 if index == -1 { 36 panic("could not find method index") 37 } 38 llitab = fr.builder.CreateBitCast(llitab, llvm.PointerType(llvm.PointerType(llvm.Int8Type(), 0), 0), "") 39 // Skip runtime type pointer. 40 llifnptr := fr.builder.CreateGEP(llitab, []llvm.Value{ 41 llvm.ConstInt(llvm.Int32Type(), uint64(index+1), false), 42 }, "") 43 44 llifn := fr.builder.CreateLoad(llifnptr, "") 45 // Replace receiver type with unsafe.Pointer. 46 recvparam := types.NewParam(0, nil, "", types.Typ[types.UnsafePointer]) 47 sig := method.Type().(*types.Signature) 48 sig = types.NewSignature(nil, recvparam, sig.Params(), sig.Results(), sig.Variadic()) 49 fn = newValue(llifn, sig) 50 return 51 } 52 53 // compareInterfaces emits code to compare two interfaces for 54 // equality. 55 func (fr *frame) compareInterfaces(a, b *govalue) *govalue { 56 aNull := a.value.IsNull() 57 bNull := b.value.IsNull() 58 if aNull && bNull { 59 return newValue(boolLLVMValue(true), types.Typ[types.Bool]) 60 } 61 62 compare := fr.runtime.emptyInterfaceCompare 63 aI := a.Type().Underlying().(*types.Interface).NumMethods() > 0 64 bI := b.Type().Underlying().(*types.Interface).NumMethods() > 0 65 switch { 66 case aI && bI: 67 compare = fr.runtime.interfaceCompare 68 case aI: 69 a = fr.convertI2E(a) 70 case bI: 71 b = fr.convertI2E(b) 72 } 73 74 result := compare.call(fr, a.value, b.value)[0] 75 result = fr.builder.CreateIsNull(result, "") 76 result = fr.builder.CreateZExt(result, llvm.Int8Type(), "") 77 return newValue(result, types.Typ[types.Bool]) 78 } 79 80 func (fr *frame) makeInterface(llv llvm.Value, vty types.Type, iface types.Type) *govalue { 81 if _, ok := vty.Underlying().(*types.Pointer); !ok { 82 ptr := fr.createTypeMalloc(vty) 83 fr.builder.CreateStore(llv, ptr) 84 llv = ptr 85 } 86 return fr.makeInterfaceFromPointer(llv, vty, iface) 87 } 88 89 func (fr *frame) makeInterfaceFromPointer(vptr llvm.Value, vty types.Type, iface types.Type) *govalue { 90 i8ptr := llvm.PointerType(llvm.Int8Type(), 0) 91 llv := fr.builder.CreateBitCast(vptr, i8ptr, "") 92 value := llvm.Undef(fr.types.ToLLVM(iface)) 93 itab := fr.types.getItabPointer(vty, iface.Underlying().(*types.Interface)) 94 value = fr.builder.CreateInsertValue(value, itab, 0, "") 95 value = fr.builder.CreateInsertValue(value, llv, 1, "") 96 return newValue(value, iface) 97 } 98 99 // Reads the type descriptor from the given interface type. 100 func (fr *frame) getInterfaceTypeDescriptor(v *govalue) llvm.Value { 101 isempty := v.Type().Underlying().(*types.Interface).NumMethods() == 0 102 itab := fr.builder.CreateExtractValue(v.value, 0, "") 103 if isempty { 104 return itab 105 } else { 106 itabnonnull := fr.builder.CreateIsNotNull(itab, "") 107 return fr.loadOrNull(itabnonnull, itab, types.Typ[types.UnsafePointer]).value 108 } 109 } 110 111 // Reads the value from the given interface type, assuming that the 112 // interface holds a value of the correct type. 113 func (fr *frame) getInterfaceValue(v *govalue, ty types.Type) *govalue { 114 val := fr.builder.CreateExtractValue(v.value, 1, "") 115 if _, ok := ty.Underlying().(*types.Pointer); !ok { 116 typedval := fr.builder.CreateBitCast(val, llvm.PointerType(fr.types.ToLLVM(ty), 0), "") 117 val = fr.builder.CreateLoad(typedval, "") 118 } 119 return newValue(val, ty) 120 } 121 122 // If cond is true, reads the value from the given interface type, otherwise 123 // returns a nil value. 124 func (fr *frame) getInterfaceValueOrNull(cond llvm.Value, v *govalue, ty types.Type) *govalue { 125 val := fr.builder.CreateExtractValue(v.value, 1, "") 126 if _, ok := ty.Underlying().(*types.Pointer); ok { 127 val = fr.builder.CreateSelect(cond, val, llvm.ConstNull(val.Type()), "") 128 } else { 129 val = fr.loadOrNull(cond, val, ty).value 130 } 131 return newValue(val, ty) 132 } 133 134 func (fr *frame) interfaceTypeCheck(val *govalue, ty types.Type) (v *govalue, okval *govalue) { 135 tytd := fr.types.ToRuntime(ty) 136 if _, ok := ty.Underlying().(*types.Interface); ok { 137 var result []llvm.Value 138 if val.Type().Underlying().(*types.Interface).NumMethods() > 0 { 139 result = fr.runtime.ifaceI2I2.call(fr, tytd, val.value) 140 } else { 141 result = fr.runtime.ifaceE2I2.call(fr, tytd, val.value) 142 } 143 v = newValue(result[0], ty) 144 okval = newValue(result[1], types.Typ[types.Bool]) 145 } else { 146 valtd := fr.getInterfaceTypeDescriptor(val) 147 tyequal := fr.runtime.typeDescriptorsEqual.call(fr, valtd, tytd)[0] 148 okval = newValue(tyequal, types.Typ[types.Bool]) 149 tyequal = fr.builder.CreateTrunc(tyequal, llvm.Int1Type(), "") 150 151 v = fr.getInterfaceValueOrNull(tyequal, val, ty) 152 } 153 return 154 } 155 156 func (fr *frame) interfaceTypeAssert(val *govalue, ty types.Type) *govalue { 157 if _, ok := ty.Underlying().(*types.Interface); ok { 158 return fr.changeInterface(val, ty, true) 159 } else { 160 valtytd := fr.types.ToRuntime(val.Type()) 161 valtd := fr.getInterfaceTypeDescriptor(val) 162 tytd := fr.types.ToRuntime(ty) 163 fr.runtime.checkInterfaceType.call(fr, valtd, tytd, valtytd) 164 165 return fr.getInterfaceValue(val, ty) 166 } 167 } 168 169 // convertI2E converts a non-empty interface value to an empty interface. 170 func (fr *frame) convertI2E(v *govalue) *govalue { 171 td := fr.getInterfaceTypeDescriptor(v) 172 val := fr.builder.CreateExtractValue(v.value, 1, "") 173 174 typ := types.NewInterface(nil, nil) 175 intf := llvm.Undef(fr.types.ToLLVM(typ)) 176 intf = fr.builder.CreateInsertValue(intf, td, 0, "") 177 intf = fr.builder.CreateInsertValue(intf, val, 1, "") 178 return newValue(intf, typ) 179 } 180 181 func (fr *frame) changeInterface(v *govalue, ty types.Type, assert bool) *govalue { 182 td := fr.getInterfaceTypeDescriptor(v) 183 tytd := fr.types.ToRuntime(ty) 184 var itab llvm.Value 185 if assert { 186 itab = fr.runtime.assertInterface.call(fr, tytd, td)[0] 187 } else { 188 itab = fr.runtime.convertInterface.call(fr, tytd, td)[0] 189 } 190 val := fr.builder.CreateExtractValue(v.value, 1, "") 191 192 intf := llvm.Undef(fr.types.ToLLVM(ty)) 193 intf = fr.builder.CreateInsertValue(intf, itab, 0, "") 194 intf = fr.builder.CreateInsertValue(intf, val, 1, "") 195 return newValue(intf, ty) 196 }