| //===- 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() |
| } |
| } |