Skip to content

Commit d0878d2

Browse files
committed
ssa: abi type support anonymouse struct methods
1 parent 92f7635 commit d0878d2

File tree

9 files changed

+293
-81
lines changed

9 files changed

+293
-81
lines changed

_demo/go/abimethod/main.go

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
package main
2+
3+
import (
4+
"bytes"
5+
"fmt"
6+
"sync/atomic"
7+
"unsafe"
8+
)
9+
10+
func main() {
11+
testGeneric()
12+
testNamed1()
13+
testNamed2()
14+
testNamed3()
15+
testAnonymous1()
16+
testAnonymous2()
17+
testAnonymous3()
18+
testAnonymous4()
19+
testAnonymous5()
20+
testAnonymous6()
21+
testAnonymous7()
22+
testAnonymous8()
23+
testAnonymousBuffer()
24+
}
25+
26+
func testNamed1() {
27+
var a I = &T{100}
28+
if a.Demo1() != 100 {
29+
panic("testNamed1 error")
30+
}
31+
}
32+
33+
func testNamed2() {
34+
var a I = T{100}
35+
if a.Demo1() != 100 {
36+
panic("testNamed2 error")
37+
}
38+
}
39+
40+
func testNamed3() {
41+
var a I2 = &T{100}
42+
if a.Demo2() != 100 {
43+
panic("testNamed4 error")
44+
}
45+
}
46+
47+
type Pointer[T any] struct {
48+
// Mention *T in a field to disallow conversion between Pointer types.
49+
// See go.dev/issue/56603 for more details.
50+
// Use *T, not T, to avoid spurious recursive type definition errors.
51+
_ [0]*T
52+
v unsafe.Pointer
53+
}
54+
55+
// Load atomically loads and returns the value stored in x.
56+
func (x *Pointer[T]) Load() *T { return (*T)(atomic.LoadPointer(&x.v)) }
57+
58+
// Store atomically stores val into x.
59+
func (x *Pointer[T]) Store(val *T) { atomic.StorePointer(&x.v, unsafe.Pointer(val)) }
60+
61+
type IP interface {
62+
Store(*any)
63+
Load() *any
64+
}
65+
66+
func testGeneric() {
67+
var p IP = &Pointer[any]{}
68+
p.Store(func() *any {
69+
var a any = 100
70+
return &a
71+
}())
72+
if (*p.Load()).(int) != 100 {
73+
panic("testGeneric error")
74+
}
75+
}
76+
77+
func testAnonymous1() {
78+
var s I = &struct {
79+
m int
80+
*T
81+
}{10, &T{100}}
82+
if s.Demo1() != 100 {
83+
panic("testAnonymous1 error")
84+
}
85+
}
86+
87+
func testAnonymous2() {
88+
var s I = struct {
89+
m int
90+
*T
91+
}{10, &T{100}}
92+
if s.Demo1() != 100 {
93+
panic("testAnonymous2 error")
94+
}
95+
}
96+
97+
func testAnonymous3() {
98+
var s I = struct {
99+
m int
100+
T
101+
}{10, T{100}}
102+
if s.Demo1() != 100 {
103+
panic("testAnonymous3 error")
104+
}
105+
}
106+
107+
func testAnonymous4() {
108+
var s I = &struct {
109+
m int
110+
T
111+
}{10, T{100}}
112+
if s.Demo1() != 100 {
113+
panic("testAnonymous4 error")
114+
}
115+
}
116+
117+
func testAnonymous5() {
118+
var s I2 = &struct {
119+
m int
120+
T
121+
}{10, T{100}}
122+
if s.Demo2() != 100 {
123+
panic("testAnonymous5 error")
124+
}
125+
}
126+
127+
func testAnonymous6() {
128+
var s I2 = struct {
129+
m int
130+
*T
131+
}{10, &T{100}}
132+
if s.Demo2() != 100 {
133+
panic("testAnonymous6 error")
134+
}
135+
}
136+
137+
func testAnonymous7() {
138+
var s interface {
139+
Demo1() int
140+
Demo2() int
141+
} = struct {
142+
m int
143+
*T
144+
}{10, &T{100}}
145+
if s.Demo1() != 100 {
146+
panic("testAnonymous7 error")
147+
}
148+
if s.Demo2() != 100 {
149+
panic("testAnonymous7 error")
150+
}
151+
}
152+
153+
func testAnonymous8() {
154+
var s interface {
155+
Demo1() int
156+
Demo2() int
157+
demo3() int
158+
} = struct {
159+
m int
160+
*T
161+
}{10, &T{100}}
162+
if s.Demo1() != 100 {
163+
panic("testAnonymous8 error")
164+
}
165+
if s.Demo2() != 100 {
166+
panic("testAnonymous8 error")
167+
}
168+
if s.demo3() != 100 {
169+
panic("testAnonymous8 error")
170+
}
171+
}
172+
173+
func testAnonymousBuffer() {
174+
var s fmt.Stringer = &struct {
175+
m int
176+
*bytes.Buffer
177+
}{10, bytes.NewBufferString("hello")}
178+
if s.String() != "hello" {
179+
panic("testAnonymousBuffer error")
180+
}
181+
}
182+
183+
type T struct {
184+
n int
185+
}
186+
187+
func (t T) Demo1() int {
188+
return t.n
189+
}
190+
191+
func (t *T) Demo2() int {
192+
return t.n
193+
}
194+
195+
func (t *T) demo3() int {
196+
return t.n
197+
}
198+
199+
type I interface {
200+
Demo1() int
201+
}
202+
203+
type I2 interface {
204+
Demo2() int
205+
}
Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,14 @@ func main() {
1313
})
1414
r := fn.Interface().(func(string, int) string)("abc", 2)
1515
if r != "abcabc" {
16-
panic("reflect.MakeFunc error")
16+
panic("reflect.FuncOf error")
1717
}
18+
_, ok := reflect.New(reflect.SliceOf(reflect.TypeOf(t{}))).Elem().Interface().([]t)
19+
if !ok {
20+
panic("reflect.SliceOf error")
21+
}
22+
}
23+
24+
type t struct {
25+
n int
1826
}

cl/_testgo/tpinst/out.ll

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -190,14 +190,6 @@ _llgo_0:
190190

191191
declare ptr @"github.com/goplus/llgo/runtime/internal/runtime.AllocZ"(i64)
192192

193-
declare i1 @"github.com/goplus/llgo/runtime/internal/runtime.memequalptr"(ptr, ptr)
194-
195-
define linkonce i1 @"__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr"(ptr %0, ptr %1, ptr %2) {
196-
_llgo_0:
197-
%3 = tail call i1 @"github.com/goplus/llgo/runtime/internal/runtime.memequalptr"(ptr %1, ptr %2)
198-
ret i1 %3
199-
}
200-
201193
define linkonce i64 @"github.com/goplus/llgo/cl/_testgo/tpinst.(*M[int]).Value"(ptr %0) {
202194
_llgo_0:
203195
%1 = getelementptr inbounds %"github.com/goplus/llgo/cl/_testgo/tpinst.M[int]", ptr %0, i32 0, i32 0
@@ -212,6 +204,14 @@ _llgo_0:
212204
ret i64 %2
213205
}
214206

207+
declare i1 @"github.com/goplus/llgo/runtime/internal/runtime.memequalptr"(ptr, ptr)
208+
209+
define linkonce i1 @"__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr"(ptr %0, ptr %1, ptr %2) {
210+
_llgo_0:
211+
%3 = tail call i1 @"github.com/goplus/llgo/runtime/internal/runtime.memequalptr"(ptr %1, ptr %2)
212+
ret i1 %3
213+
}
214+
215215
declare i1 @"github.com/goplus/llgo/runtime/internal/runtime.structequal"(ptr, ptr, ptr)
216216

217217
declare i1 @"github.com/goplus/llgo/runtime/internal/runtime.memequal64"(ptr, ptr)

cl/_testrt/tpabi/out.ll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,8 @@ _llgo_0:
148148
ret void
149149
}
150150

151+
declare i1 @"github.com/goplus/llgo/runtime/internal/runtime.structequal"(ptr, ptr, ptr)
152+
151153
define linkonce void @"github.com/goplus/llgo/cl/_testrt/tpabi.(*T[string,int]).Demo"(ptr %0) {
152154
_llgo_0:
153155
%1 = getelementptr inbounds %"github.com/goplus/llgo/cl/_testrt/tpabi.T[string,int]", ptr %0, i32 0, i32 0
@@ -168,8 +170,6 @@ _llgo_0:
168170
ret void
169171
}
170172

171-
declare i1 @"github.com/goplus/llgo/runtime/internal/runtime.structequal"(ptr, ptr, ptr)
172-
173173
declare i1 @"github.com/goplus/llgo/runtime/internal/runtime.memequalptr"(ptr, ptr)
174174

175175
define linkonce i1 @"__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr"(ptr %0, ptr %1, ptr %2) {

cl/_testrt/tpmethod/out.ll

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -180,14 +180,6 @@ declare void @"github.com/goplus/llgo/runtime/internal/runtime.PrintByte"(i8)
180180

181181
declare ptr @"github.com/goplus/llgo/runtime/internal/runtime.AllocZ"(i64)
182182

183-
declare i1 @"github.com/goplus/llgo/runtime/internal/runtime.memequalptr"(ptr, ptr)
184-
185-
define linkonce i1 @"__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr"(ptr %0, ptr %1, ptr %2) {
186-
_llgo_0:
187-
%3 = tail call i1 @"github.com/goplus/llgo/runtime/internal/runtime.memequalptr"(ptr %1, ptr %2)
188-
ret i1 %3
189-
}
190-
191183
define linkonce void @"github.com/goplus/llgo/cl/_testrt/tpmethod.(*future[github.com/goplus/llgo/cl/_testrt/tpmethod.Tuple[error]]).Then"(ptr %0, { ptr, ptr } %1) {
192184
_llgo_0:
193185
%2 = getelementptr inbounds %"github.com/goplus/llgo/cl/_testrt/tpmethod.future[github.com/goplus/llgo/cl/_testrt/tpmethod.Tuple[error]]", ptr %0, i32 0, i32 0
@@ -198,15 +190,23 @@ _llgo_0:
198190
ret void
199191
}
200192

193+
declare i1 @"github.com/goplus/llgo/runtime/internal/runtime.memequalptr"(ptr, ptr)
194+
195+
define linkonce i1 @"__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.memequalptr"(ptr %0, ptr %1, ptr %2) {
196+
_llgo_0:
197+
%3 = tail call i1 @"github.com/goplus/llgo/runtime/internal/runtime.memequalptr"(ptr %1, ptr %2)
198+
ret i1 %3
199+
}
200+
201+
declare i1 @"github.com/goplus/llgo/runtime/internal/runtime.structequal"(ptr, ptr, ptr)
202+
201203
define linkonce %"github.com/goplus/llgo/runtime/internal/runtime.iface" @"github.com/goplus/llgo/cl/_testrt/tpmethod.(*Tuple[error]).Get"(ptr %0) {
202204
_llgo_0:
203205
%1 = load %"github.com/goplus/llgo/cl/_testrt/tpmethod.Tuple[error]", ptr %0, align 8
204206
%2 = call %"github.com/goplus/llgo/runtime/internal/runtime.iface" @"github.com/goplus/llgo/cl/_testrt/tpmethod.Tuple[error].Get"(%"github.com/goplus/llgo/cl/_testrt/tpmethod.Tuple[error]" %1)
205207
ret %"github.com/goplus/llgo/runtime/internal/runtime.iface" %2
206208
}
207209

208-
declare i1 @"github.com/goplus/llgo/runtime/internal/runtime.structequal"(ptr, ptr, ptr)
209-
210210
declare i1 @"github.com/goplus/llgo/runtime/internal/runtime.interequal"(ptr, ptr)
211211

212212
define linkonce i1 @"__llgo_stub.github.com/goplus/llgo/runtime/internal/runtime.interequal"(ptr %0, ptr %1, ptr %2) {

cl/compile.go

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -333,8 +333,6 @@ func (p *context) compileFuncDecl(pkg llssa.Package, f *ssa.Function) (llssa.Fun
333333
fn.Inline(llssa.NoInline)
334334
}
335335
}
336-
// set compiled to check generic function global instantiation
337-
pkg.Prog.SetFuncCompiled(name)
338336
isCgo := isCgoExternSymbol(f)
339337
if nblk := len(f.Blocks); nblk > 0 {
340338
p.cgoCalled = false
@@ -1139,7 +1137,7 @@ func NewPackageEx(prog llssa.Program, patches Patches, rewrites map[string]strin
11391137
ctx.initPyModule()
11401138
ctx.initFiles(pkgPath, files, pkgName == "C")
11411139
ctx.prog.SetPatch(ctx.patchType)
1142-
ctx.prog.SetCheckRuntimeNamed(ctx.checkRuntimeNamed)
1140+
ctx.prog.SetCompileMethods(ctx.checkCompileMethods)
11431141
ret.SetResolveLinkname(ctx.resolveLinkname)
11441142

11451143
if hasPatch {
@@ -1352,15 +1350,26 @@ func (p *context) resolveLinkname(name string) string {
13521350
return name
13531351
}
13541352

1355-
// checkRuntimeNamed compiles methods for generic type instantiations.
1356-
// Only types with type arguments (instantiated generics) need method compilation
1357-
// here, as non-generic types have their methods compiled elsewhere.
1358-
func (p *context) checkRuntimeNamed(pkg llssa.Package, typ *types.Named) {
1359-
if typ.TypeArgs() == nil {
1360-
return
1353+
// checkCompileMethods ensures that all methods attached to the given type
1354+
// (and to the types it refers to) are compiled and emitted into the
1355+
// current SSA package. Generic named types and struct types are the
1356+
// primary targets; pointer types are followed until a non-pointer is
1357+
// reached. non-generic named have their methods compiled elsewhere.
1358+
func (p *context) checkCompileMethods(pkg llssa.Package, typ types.Type) {
1359+
nt := typ
1360+
retry:
1361+
switch t := nt.(type) {
1362+
case *types.Named:
1363+
if t.TypeArgs() == nil {
1364+
return
1365+
}
1366+
p.compileMethods(pkg, typ)
1367+
case *types.Struct:
1368+
p.compileMethods(pkg, typ)
1369+
case *types.Pointer:
1370+
nt = t.Elem()
1371+
goto retry
13611372
}
1362-
p.compileMethods(pkg, typ)
1363-
p.compileMethods(pkg, types.NewPointer(typ))
13641373
}
13651374

13661375
// -----------------------------------------------------------------------------

0 commit comments

Comments
 (0)