blob: 404962fd85b1a2dfcb4b18246cd7eda482629a46 [file] [log] [blame]
Peter Collingbournead9841e2014-11-27 00:06:42 +00001//===- 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
14package irgen
15
16import (
17 "llvm.org/llgo/third_party/go.tools/go/types"
18 "llvm.org/llvm/bindings/go/llvm"
19)
20
21func (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
37func (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.
61func (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)".
72func (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
86func (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
113func (fr *frame) callPanic(arg *govalue) {
114 fr.runtime.panic.call(fr, arg.value)
115 fr.builder.CreateUnreachable()
116}