diff --git a/internal/runtime/z_eface.go b/internal/runtime/z_eface.go new file mode 100644 index 00000000..7cd7ba48 --- /dev/null +++ b/internal/runtime/z_eface.go @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package runtime + +import ( + "unsafe" + + "github.com/goplus/llgo/internal/abi" + "github.com/goplus/llgo/internal/runtime/c" +) + +func InterfaceEqual(x, y any, xeface, yeface bool) bool { + return efaceEqual(unpackEface(x, xeface), unpackEface(y, yeface)) +} + +func unpackEface(i any, emtpy bool) eface { + if emtpy { + return *(*eface)(unsafe.Pointer(&i)) + } + e := (*iface)(unsafe.Pointer(&i)) + if e.tab == nil { + return eface{} + } + return eface{e.tab._type, e.data} +} + +func efaceEqual(v, u eface) bool { + if v.Kind() == abi.Interface { + v = v.Elem() + } + if u.Kind() == abi.Interface { + u = u.Elem() + } + if v._type == nil || u._type == nil { + return v._type == u._type + } + if v._type != u._type { + return false + } + if v._type.Kind_&abi.KindDirectIface != 0 { + return v.data == u.data + } + switch v.Kind() { + case abi.Bool, + abi.Int, abi.Int8, abi.Int16, abi.Int32, abi.Int64, + abi.Uint, abi.Uint8, abi.Uint16, abi.Uint32, abi.Uint64, abi.Uintptr, + abi.Float32, abi.Float64: + return *(*uintptr)(v.data) == *(*uintptr)(u.data) + case abi.Complex64, abi.Complex128: + panic("TODO complex") + case abi.String: + return *(*string)(v.data) == *(*string)(u.data) + case abi.Pointer, abi.UnsafePointer: + return v.data == u.data + case abi.Array: + n := v._type.Len() + tt := v._type.ArrayType() + index := func(data unsafe.Pointer, i int) eface { + offset := i * int(tt.Elem.Size_) + return eface{tt.Elem, c.Advance(data, offset)} + } + for i := 0; i < n; i++ { + if !efaceEqual(index(v.data, i), index(u.data, i)) { + return false + } + } + return true + case abi.Struct: + st := v._type.StructType() + field := func(data unsafe.Pointer, ft *abi.StructField) eface { + return eface{ft.Typ, c.Advance(data, int(ft.Offset))} + } + for _, ft := range st.Fields { + if !efaceEqual(field(v.data, &ft), field(u.data, &ft)) { + return false + } + } + return true + case abi.Func, abi.Map, abi.Slice: + break + } + panic("not comparable") +} + +func (v eface) Kind() abi.Kind { + if v._type == nil { + return abi.Invalid + } + return v._type.Kind() +} + +func (v eface) Elem() eface { + switch v.Kind() { + case abi.Interface: + var i any + tt := (*abi.InterfaceType)(unsafe.Pointer(v._type)) + if len(tt.Methods) == 0 { + i = *(*any)(v.data) + } else { + i = (any)(*(*interface { + M() + })(v.data)) + } + return *(*eface)(unsafe.Pointer(&i)) + case abi.Pointer: + ptr := v.data + if v._type.Kind_&abi.KindDirectIface != 0 { + ptr = *(*unsafe.Pointer)(ptr) + } + if ptr == nil { + return eface{} + } + return eface{v._type.Elem(), ptr} + } + panic("invalid eface elem") +} diff --git a/ssa/abi/abi.go b/ssa/abi/abi.go index 4289d6bd..4841b895 100644 --- a/ssa/abi/abi.go +++ b/ssa/abi/abi.go @@ -166,6 +166,9 @@ func (b *Builder) TypeName(t types.Type) (ret string, pub bool) { // PathOf returns the package path of the specified package. func PathOf(pkg *types.Package) string { + if pkg == nil { + return "" + } if pkg.Name() == "main" { return "main" } @@ -174,6 +177,9 @@ func PathOf(pkg *types.Package) string { // FullName returns the full name of a package member. func FullName(pkg *types.Package, name string) string { + if pkg == nil { + return name + } return PathOf(pkg) + "." + name } diff --git a/ssa/abitype.go b/ssa/abitype.go index e41fda58..83f5cfe5 100644 --- a/ssa/abitype.go +++ b/ssa/abitype.go @@ -118,14 +118,12 @@ func (b Builder) abiMethods(t *types.Named) (ret, pret int) { } // Method{name string, typ *FuncType, ifn, tfn abi.Text} -func (b Builder) abiMethodOf(m *types.Func /*, bg Background = InGo */) (mthd, ptrMthd Expr) { +func (b Builder) abiMethodOf(mPkg *types.Package, mName string, mSig *types.Signature /*, bg Background = InGo */) (mthd, ptrMthd Expr) { prog := b.Prog - mPkg, mName := m.Pkg(), m.Name() - mSig := m.Type().(*types.Signature) name := b.Str(mName).impl if !token.IsExported(mName) { - name = b.Str(abi.FullName(mPkg, m.Name())).impl + name = b.Str(abi.FullName(mPkg, mName)).impl } abiSigGo := types.NewSignatureType(nil, nil, nil, mSig.Params(), mSig.Results(), mSig.Variadic()) abiSig := prog.FuncDecl(abiSigGo, InGo).raw.Type @@ -217,8 +215,8 @@ func (b Builder) abiInitNamed(ret Expr, t *types.Named) func() Expr { var mthds []Expr var ptrMthds = make([]Expr, 0, n) for i := 0; i < n; i++ { - m := mset[i].Obj().(*types.Func) - mthd, ptrMthd := b.abiMethodOf(m) + sel := mset[i] + mthd, ptrMthd := b.abiMethodOf(sel.Obj().Pkg(), sel.Obj().Name(), sel.Type().(*types.Signature)) if !mthd.IsNil() { mthds = append(mthds, mthd) } diff --git a/ssa/expr.go b/ssa/expr.go index 960f1cde..f63d0da2 100644 --- a/ssa/expr.go +++ b/ssa/expr.go @@ -425,6 +425,16 @@ func (b Builder) BinOp(op token.Token, x, y Expr) Expr { ret.impl = llvm.CreateNot(b.impl, ret.impl) return ret } + case vkIface, vkEface: + prog := b.Prog + switch op { + case token.EQL: + return b.InlineCall(b.Pkg.rtFunc("InterfaceEqual"), x, y, prog.BoolVal(x.kind == vkEface), prog.BoolVal(y.kind == vkEface)) + case token.NEQ: + ret := b.InlineCall(b.Pkg.rtFunc("InterfaceEqual"), x, y, prog.BoolVal(x.kind == vkEface), prog.BoolVal(y.kind == vkEface)) + ret.impl = llvm.CreateNot(b.impl, ret.impl) + return ret + } } } panic("todo")