github.com/axw/llgo@v0.0.0-20160805011314-95b5fe4dca20/irgen/builtins.go (about)

     1  //===- builtins.go - IR generation for builtins ---------------------------===//
     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 the built-in functions.
    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  func (fr *frame) callCap(arg *govalue) *govalue {
    22  	var v llvm.Value
    23  	switch typ := arg.Type().Underlying().(type) {
    24  	case *types.Array:
    25  		v = llvm.ConstInt(fr.llvmtypes.inttype, uint64(typ.Len()), false)
    26  	case *types.Pointer:
    27  		atyp := typ.Elem().Underlying().(*types.Array)
    28  		v = llvm.ConstInt(fr.llvmtypes.inttype, uint64(atyp.Len()), false)
    29  	case *types.Slice:
    30  		v = fr.builder.CreateExtractValue(arg.value, 2, "")
    31  	case *types.Chan:
    32  		v = fr.runtime.chanCap.call(fr, arg.value)[0]
    33  	}
    34  	return newValue(v, types.Typ[types.Int])
    35  }
    36  
    37  func (fr *frame) callLen(arg *govalue) *govalue {
    38  	var lenvalue llvm.Value
    39  	switch typ := arg.Type().Underlying().(type) {
    40  	case *types.Array:
    41  		lenvalue = llvm.ConstInt(fr.llvmtypes.inttype, uint64(typ.Len()), false)
    42  	case *types.Pointer:
    43  		atyp := typ.Elem().Underlying().(*types.Array)
    44  		lenvalue = llvm.ConstInt(fr.llvmtypes.inttype, uint64(atyp.Len()), false)
    45  	case *types.Slice:
    46  		lenvalue = fr.builder.CreateExtractValue(arg.value, 1, "")
    47  	case *types.Map:
    48  		lenvalue = fr.runtime.mapLen.call(fr, arg.value)[0]
    49  	case *types.Basic:
    50  		if isString(typ) {
    51  			lenvalue = fr.builder.CreateExtractValue(arg.value, 1, "")
    52  		}
    53  	case *types.Chan:
    54  		lenvalue = fr.runtime.chanLen.call(fr, arg.value)[0]
    55  	}
    56  	return newValue(lenvalue, types.Typ[types.Int])
    57  }
    58  
    59  // callAppend takes two slices of the same type, and yields
    60  // the result of appending the second to the first.
    61  func (fr *frame) callAppend(a, b *govalue) *govalue {
    62  	bptr := fr.builder.CreateExtractValue(b.value, 0, "")
    63  	blen := fr.builder.CreateExtractValue(b.value, 1, "")
    64  	elemsizeInt64 := fr.types.Sizeof(a.Type().Underlying().(*types.Slice).Elem())
    65  	elemsize := llvm.ConstInt(fr.target.IntPtrType(), uint64(elemsizeInt64), false)
    66  	result := fr.runtime.append.call(fr, a.value, bptr, blen, elemsize)[0]
    67  	return newValue(result, a.Type())
    68  }
    69  
    70  // callCopy takes two slices a and b of the same type, and
    71  // yields the result of calling "copy(a, b)".
    72  func (fr *frame) callCopy(dest, source *govalue) *govalue {
    73  	aptr := fr.builder.CreateExtractValue(dest.value, 0, "")
    74  	alen := fr.builder.CreateExtractValue(dest.value, 1, "")
    75  	bptr := fr.builder.CreateExtractValue(source.value, 0, "")
    76  	blen := fr.builder.CreateExtractValue(source.value, 1, "")
    77  	aless := fr.builder.CreateICmp(llvm.IntULT, alen, blen, "")
    78  	minlen := fr.builder.CreateSelect(aless, alen, blen, "")
    79  	elemsizeInt64 := fr.types.Sizeof(dest.Type().Underlying().(*types.Slice).Elem())
    80  	elemsize := llvm.ConstInt(fr.types.inttype, uint64(elemsizeInt64), false)
    81  	bytes := fr.builder.CreateMul(minlen, elemsize, "")
    82  	fr.runtime.copy.call(fr, aptr, bptr, bytes)
    83  	return newValue(minlen, types.Typ[types.Int])
    84  }
    85  
    86  func (fr *frame) callRecover(isDeferredRecover bool) *govalue {
    87  	startbb := fr.builder.GetInsertBlock()
    88  	recoverbb := llvm.AddBasicBlock(fr.function, "")
    89  	contbb := llvm.AddBasicBlock(fr.function, "")
    90  	canRecover := fr.builder.CreateTrunc(fr.canRecover, llvm.Int1Type(), "")
    91  	fr.builder.CreateCondBr(canRecover, recoverbb, contbb)
    92  
    93  	fr.builder.SetInsertPointAtEnd(recoverbb)
    94  	var recovered llvm.Value
    95  	if isDeferredRecover {
    96  		recovered = fr.runtime.deferredRecover.call(fr)[0]
    97  	} else {
    98  		recovered = fr.runtime.recover.call(fr)[0]
    99  	}
   100  	recoverbb = fr.builder.GetInsertBlock()
   101  	fr.builder.CreateBr(contbb)
   102  
   103  	fr.builder.SetInsertPointAtEnd(contbb)
   104  	eface := types.NewInterface(nil, nil)
   105  	llv := fr.builder.CreatePHI(fr.types.ToLLVM(eface), "")
   106  	llv.AddIncoming(
   107  		[]llvm.Value{llvm.ConstNull(llv.Type()), recovered},
   108  		[]llvm.BasicBlock{startbb, recoverbb},
   109  	)
   110  	return newValue(llv, eface)
   111  }
   112  
   113  func (fr *frame) callPanic(arg *govalue, term bool) {
   114  	fr.runtime.panic.call(fr, arg.value)
   115  	if term {
   116  		fr.builder.CreateUnreachable()
   117  	}
   118  }