From 05cdde162c2a983fa5cc504cbb6bf9dedfda81ab Mon Sep 17 00:00:00 2001 From: Phil Kedy Date: Thu, 28 Jul 2022 10:34:27 -0400 Subject: [PATCH] Set internal linkage and keeping default visibility for anonymous functions --- compiler/compiler.go | 11 +++- compiler/testdata/basic.ll | 2 +- compiler/testdata/defer-cortex-m-qemu.ll | 6 +-- .../testdata/goroutine-cortex-m-qemu-tasks.ll | 4 +- compiler/testdata/goroutine-wasm-asyncify.ll | 4 +- testdata/generics.go | 8 +++ testdata/generics.txt | 4 ++ testdata/generics/testa/testa.go | 20 +++++++ testdata/generics/testb/testb.go | 20 +++++++ testdata/generics/value/value.go | 53 +++++++++++++++++++ 10 files changed, 123 insertions(+), 9 deletions(-) create mode 100644 testdata/generics/testa/testa.go create mode 100644 testdata/generics/testb/testb.go create mode 100644 testdata/generics/value/value.go diff --git a/compiler/compiler.go b/compiler/compiler.go index 1b588d9c..f477baa3 100644 --- a/compiler/compiler.go +++ b/compiler/compiler.go @@ -1039,9 +1039,17 @@ func (b *builder) createFunctionStart() { b.addError(b.fn.Pos(), errValue) return } + b.addStandardDefinedAttributes(b.llvmFn) if !b.info.exported { - b.llvmFn.SetVisibility(llvm.HiddenVisibility) + // Do not set visibility for local linkage (internal or private). + // Otherwise a "local linkage requires default visibility" + // assertion error in llvm-project/llvm/include/llvm/IR/GlobalValue.h:236 + // is thrown. + if b.llvmFn.Linkage() != llvm.InternalLinkage && + b.llvmFn.Linkage() != llvm.PrivateLinkage { + b.llvmFn.SetVisibility(llvm.HiddenVisibility) + } b.llvmFn.SetUnnamedAddr(true) } if b.info.section != "" { @@ -1265,6 +1273,7 @@ func (b *builder) createFunction() { // Create anonymous functions (closures etc.). for _, sub := range b.fn.AnonFuncs { b := newBuilder(b.compilerContext, b.Builder, sub) + b.llvmFn.SetLinkage(llvm.InternalLinkage) b.createFunction() } } diff --git a/compiler/testdata/basic.ll b/compiler/testdata/basic.ll index 84a2bb91..4d88f66f 100644 --- a/compiler/testdata/basic.ll +++ b/compiler/testdata/basic.ll @@ -196,7 +196,7 @@ entry: } ; Function Attrs: nounwind -define hidden void @"main.foo$1"(%main.kv.0* dereferenceable_or_null(1) %b, i8* %context) unnamed_addr #1 { +define internal void @"main.foo$1"(%main.kv.0* dereferenceable_or_null(1) %b, i8* %context) unnamed_addr #1 { entry: ret void } diff --git a/compiler/testdata/defer-cortex-m-qemu.ll b/compiler/testdata/defer-cortex-m-qemu.ll index f604f377..693f1b07 100644 --- a/compiler/testdata/defer-cortex-m-qemu.ll +++ b/compiler/testdata/defer-cortex-m-qemu.ll @@ -115,7 +115,7 @@ declare i8* @llvm.stacksave() #2 declare void @runtime.setupDeferFrame(%runtime.deferFrame* dereferenceable_or_null(24), i8*, i8*) #0 ; Function Attrs: nounwind -define hidden void @"main.deferSimple$1"(i8* %context) unnamed_addr #1 { +define internal void @"main.deferSimple$1"(i8* %context) unnamed_addr #1 { entry: call void @runtime.printint32(i32 3, i8* undef) #3 ret void @@ -246,14 +246,14 @@ rundefers.end9: ; preds = %rundefers.loophead1 } ; Function Attrs: nounwind -define hidden void @"main.deferMultiple$1"(i8* %context) unnamed_addr #1 { +define internal void @"main.deferMultiple$1"(i8* %context) unnamed_addr #1 { entry: call void @runtime.printint32(i32 3, i8* undef) #3 ret void } ; Function Attrs: nounwind -define hidden void @"main.deferMultiple$2"(i8* %context) unnamed_addr #1 { +define internal void @"main.deferMultiple$2"(i8* %context) unnamed_addr #1 { entry: call void @runtime.printint32(i32 5, i8* undef) #3 ret void diff --git a/compiler/testdata/goroutine-cortex-m-qemu-tasks.ll b/compiler/testdata/goroutine-cortex-m-qemu-tasks.ll index 36b6d96d..edd4d666 100644 --- a/compiler/testdata/goroutine-cortex-m-qemu-tasks.ll +++ b/compiler/testdata/goroutine-cortex-m-qemu-tasks.ll @@ -51,7 +51,7 @@ entry: } ; Function Attrs: nounwind -define hidden void @"main.inlineFunctionGoroutine$1"(i32 %x, i8* %context) unnamed_addr #1 { +define internal void @"main.inlineFunctionGoroutine$1"(i32 %x, i8* %context) unnamed_addr #1 { entry: ret void } @@ -84,7 +84,7 @@ entry: } ; Function Attrs: nounwind -define hidden void @"main.closureFunctionGoroutine$1"(i32 %x, i8* %context) unnamed_addr #1 { +define internal void @"main.closureFunctionGoroutine$1"(i32 %x, i8* %context) unnamed_addr #1 { entry: %unpack.ptr = bitcast i8* %context to i32* store i32 7, i32* %unpack.ptr, align 4 diff --git a/compiler/testdata/goroutine-wasm-asyncify.ll b/compiler/testdata/goroutine-wasm-asyncify.ll index 4439c494..21da7477 100644 --- a/compiler/testdata/goroutine-wasm-asyncify.ll +++ b/compiler/testdata/goroutine-wasm-asyncify.ll @@ -53,7 +53,7 @@ entry: } ; Function Attrs: nounwind -define hidden void @"main.inlineFunctionGoroutine$1"(i32 %x, i8* %context) unnamed_addr #1 { +define internal void @"main.inlineFunctionGoroutine$1"(i32 %x, i8* %context) unnamed_addr #1 { entry: ret void } @@ -90,7 +90,7 @@ entry: } ; Function Attrs: nounwind -define hidden void @"main.closureFunctionGoroutine$1"(i32 %x, i8* %context) unnamed_addr #1 { +define internal void @"main.closureFunctionGoroutine$1"(i32 %x, i8* %context) unnamed_addr #1 { entry: %unpack.ptr = bitcast i8* %context to i32* store i32 7, i32* %unpack.ptr, align 4 diff --git a/testdata/generics.go b/testdata/generics.go index 2286bb0d..c2877dfd 100644 --- a/testdata/generics.go +++ b/testdata/generics.go @@ -1,11 +1,19 @@ package main +import ( + "github.com/tinygo-org/tinygo/testdata/generics/testa" + "github.com/tinygo-org/tinygo/testdata/generics/testb" +) + func main() { println("add:", Add(3, 5)) println("add:", Add(int8(3), 5)) var c C[int] c.F() // issue 2951 + + testa.Test() + testb.Test() } type Integer interface { diff --git a/testdata/generics.txt b/testdata/generics.txt index 073514b9..0fbe45fd 100644 --- a/testdata/generics.txt +++ b/testdata/generics.txt @@ -1,2 +1,6 @@ add: 8 add: 8 +value: 101 +value: 101 +value: 501 +value: 501 diff --git a/testdata/generics/testa/testa.go b/testdata/generics/testa/testa.go new file mode 100644 index 00000000..87cca737 --- /dev/null +++ b/testdata/generics/testa/testa.go @@ -0,0 +1,20 @@ +package testa + +import ( + "github.com/tinygo-org/tinygo/testdata/generics/value" +) + +func Test() { + v := value.New(1) + vm := value.Map(v, Plus100) + vm.Get(callback, callback) +} + +func callback(v int) { + println("value:", v) +} + +// Plus100 is a `Transform` that adds 100 to `value`. +func Plus100(value int) int { + return value + 100 +} diff --git a/testdata/generics/testb/testb.go b/testdata/generics/testb/testb.go new file mode 100644 index 00000000..263c7ce3 --- /dev/null +++ b/testdata/generics/testb/testb.go @@ -0,0 +1,20 @@ +package testb + +import ( + "github.com/tinygo-org/tinygo/testdata/generics/value" +) + +func Test() { + v := value.New(1) + vm := value.Map(v, Plus500) + vm.Get(callback, callback) +} + +func callback(v int) { + println("value:", v) +} + +// Plus500 is a `Transform` that adds 500 to `value`. +func Plus500(value int) int { + return value + 500 +} diff --git a/testdata/generics/value/value.go b/testdata/generics/value/value.go new file mode 100644 index 00000000..5348f184 --- /dev/null +++ b/testdata/generics/value/value.go @@ -0,0 +1,53 @@ +package value + +type ( + Value[T any] interface { + Get(Callback[T], Callback[T]) + } + + Callback[T any] func(T) + + Transform[S any, D any] func(S) D +) + +func New[T any](v T) Value[T] { + return &value[T]{ + v: v, + } +} + +type value[T any] struct { + v T +} + +func (v *value[T]) Get(fn1, fn2 Callback[T]) { + // For example purposes. + // Normally would be asynchronous callback. + fn1(v.v) + fn2(v.v) +} + +func Map[S, D any](v Value[S], tx Transform[S, D]) Value[D] { + return &mapper[S, D]{ + v: v, + tx: tx, + } +} + +type mapper[S, D any] struct { + v Value[S] + tx Transform[S, D] +} + +func (m *mapper[S, D]) Get(fn1, fn2 Callback[D]) { + // two callbacks are passed to generate more than + // one anonymous function symbol name. + m.v.Get(func(v S) { + // anonymous function inside of anonymous function. + func() { + fn1(m.tx(v)) + }() + }, func(v S) { + fn2(m.tx(v)) + }) +}