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  }