mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-07-26 06:38:42 +00:00
compiler: implement internal/abi.Escape
This commit is contained in:
committed by
Ron Evans
parent
5c46efb4d1
commit
34efc3a381
@@ -121,6 +121,29 @@ func (b *builder) createKeepAliveImpl() {
|
||||
b.CreateRetVoid()
|
||||
}
|
||||
|
||||
// createAbiEscapeImpl implements the generic internal/abi.Escape function. It
|
||||
// currently only supports pointer types.
|
||||
func (b *builder) createAbiEscapeImpl() {
|
||||
b.createFunctionStart(true)
|
||||
|
||||
// The first parameter is assumed to be a pointer. This is checked at the
|
||||
// call site of createAbiEscapeImpl.
|
||||
pointerValue := b.getValue(b.fn.Params[0], getPos(b.fn))
|
||||
|
||||
// Create an equivalent of the following C code, which is basically just a
|
||||
// nop but ensures the pointerValue is kept alive:
|
||||
//
|
||||
// __asm__ __volatile__("" : : "r"(pointerValue))
|
||||
//
|
||||
// It should be portable to basically everything as the "r" register type
|
||||
// exists basically everywhere.
|
||||
asmType := llvm.FunctionType(b.dataPtrType, []llvm.Type{b.dataPtrType}, false)
|
||||
asmFn := llvm.InlineAsm(asmType, "", "=r,0", true, false, 0, false)
|
||||
result := b.createCall(asmType, asmFn, []llvm.Value{pointerValue}, "")
|
||||
|
||||
b.CreateRet(result)
|
||||
}
|
||||
|
||||
var mathToLLVMMapping = map[string]string{
|
||||
"math.Ceil": "llvm.ceil.f64",
|
||||
"math.Exp": "llvm.exp.f64",
|
||||
|
||||
@@ -253,6 +253,23 @@ func (c *compilerContext) maybeCreateSyntheticFunction(fn *ssa.Function, llvmFn
|
||||
// The exception is the package initializer, which does appear in the
|
||||
// *ssa.Package members and so shouldn't be created here.
|
||||
if fn.Synthetic != "" && fn.Synthetic != "package initializer" && fn.Synthetic != "generic function" && fn.Synthetic != "range-over-func yield" {
|
||||
if origin := fn.Origin(); origin != nil && origin.RelString(nil) == "internal/abi.Escape" {
|
||||
// This is a special implementation or internal/abi.Escape, which
|
||||
// can only really be implemented in the compiler.
|
||||
// For simplicity we'll only implement pointer parameters for now.
|
||||
if _, ok := fn.Params[0].Type().Underlying().(*types.Pointer); ok {
|
||||
irbuilder := c.ctx.NewBuilder()
|
||||
defer irbuilder.Dispose()
|
||||
b := newBuilder(c, irbuilder, fn)
|
||||
b.createAbiEscapeImpl()
|
||||
llvmFn.SetLinkage(llvm.LinkOnceODRLinkage)
|
||||
llvmFn.SetUnnamedAddr(true)
|
||||
}
|
||||
// If the parameter is not of a pointer type, it will be left
|
||||
// unimplemented. This will result in a linker error if the function
|
||||
// is really called, making it clear it needs to be implemented.
|
||||
return
|
||||
}
|
||||
if len(fn.Blocks) == 0 {
|
||||
c.addError(fn.Pos(), "missing function body")
|
||||
return
|
||||
|
||||
@@ -8,3 +8,10 @@ import "unsafe"
|
||||
func NoEscape(p unsafe.Pointer) unsafe.Pointer {
|
||||
return p
|
||||
}
|
||||
|
||||
func Escape[T any](x T) T {
|
||||
// This function is either implemented in the compiler, or left undefined
|
||||
// for some variation of T. The body of this function should not be compiled
|
||||
// as-is.
|
||||
panic("internal/abi.Escape: unreachable (implemented in the compiler)")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user