blob: fba95ba5aa0f89b72d1409ce57685c9bcf6a3a09 [file] [log] [blame]
Peter Collingbournead9841e2014-11-27 00:06:42 +00001//===- 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
14package irgen
15
16import (
Peter Collingbourne56109b72015-01-13 20:45:08 +000017 "llvm.org/llgo/third_party/gotools/go/types"
Peter Collingbournead9841e2014-11-27 00:06:42 +000018 "llvm.org/llvm/bindings/go/llvm"
19)
20
21// interfaceMethod returns a function and receiver pointer for the specified
22// interface and method pair.
23func (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.
55func (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
80func (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
89func (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.
100func (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.
113func (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.
124func (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
134func (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
156func (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.
170func (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
181func (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}