118 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			118 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			Go
		
	
	
	
//===- 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()
 | 
						|
	}
 | 
						|
}
 |