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