From e61ebb4eb9926e3230782585f6b440abcfb031b4 Mon Sep 17 00:00:00 2001 From: xushiwei Date: Mon, 20 May 2024 08:46:39 +0800 Subject: [PATCH] abi.Name; runtime: MakeAnyInt => MakeAnyIntptr; llgo/ssa: AllocU; builtin unsafe.String; MakeInterface; prog.PointerSize --- README.md | 2 +- go.mod | 2 +- internal/abi/llgo_autogen.lla | Bin 1680 -> 4424 bytes internal/abi/type.go | 195 +++++++++++++++++++++++++----- internal/runtime/llgo_autogen.lla | Bin 6918 -> 6919 bytes internal/runtime/z_iface.go | 2 +- internal/runtime/z_string.go | 1 + ssa/_abi/abi.go | 73 +++++++++++ ssa/cl_test.go | 3 + ssa/expr.go | 23 +++- ssa/interface.go | 91 ++++++++++---- ssa/package.go | 9 +- ssa/type.go | 4 + 13 files changed, 342 insertions(+), 63 deletions(-) create mode 100644 ssa/_abi/abi.go diff --git a/README.md b/README.md index cdb38794..97e95bb9 100644 --- a/README.md +++ b/README.md @@ -152,7 +152,7 @@ See [github.com/goplus/llgo/py](https://pkg.go.dev/github.com/goplus/llgo/py) fo LLGo can easily import any libraries from the C ecosystem. Currently, this import process is still manual, but in the future, it will be automated similar to Python library imports. -The currently imported libraries include: +The currently supported libraries include: * [llama2.c](https://pkg.go.dev/github.com/goplus/llgo/c/llama2) * [cjson](https://pkg.go.dev/github.com/goplus/llgo/c/cjson) diff --git a/go.mod b/go.mod index d1455dbd..5e702b52 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/goplus/llgo -go 1.18 +go 1.20 require ( github.com/aykevl/go-wasm v0.0.1 diff --git a/internal/abi/llgo_autogen.lla b/internal/abi/llgo_autogen.lla index cccf2f81e2804574b2566ee466b99e79cfe3bc60..4f8bcd999012ee293df371a59bbd1d0db0936bcf 100644 GIT binary patch delta 4401 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 I1^@s60Q=ts00000 diff --git a/internal/abi/type.go b/internal/abi/type.go index 549a135a..17b61967 100644 --- a/internal/abi/type.go +++ b/internal/abi/type.go @@ -213,36 +213,6 @@ type StructType struct { Fields []StructField } -// Name is an encoded type Name with optional extra data. -// -// The first byte is a bit field containing: -// -// 1<<0 the name is exported -// 1<<1 tag data follows the name -// 1<<2 pkgPath nameOff follows the name and tag -// 1<<3 the name is of an embedded (a.k.a. anonymous) field -// -// Following that, there is a varint-encoded length of the name, -// followed by the name itself. -// -// If tag data is present, it also has a varint-encoded length -// followed by the tag itself. -// -// If the import path follows, then 4 bytes at the end of -// the data form a nameOff. The import path is only set for concrete -// methods that are defined in a different package than their type. -// -// If a name starts with "*", then the exported bit represents -// whether the pointed to type is exported. -// -// Note: this encoding must match here and in: -// cmd/compile/internal/reflectdata/reflect.go -// cmd/link/internal/ld/decodesym.go - -type Name struct { - Bytes *byte -} - type InterfaceType struct { Type PkgPath Name // import path @@ -330,3 +300,168 @@ func (t *Type) InterfaceType() *InterfaceType { } // ----------------------------------------------------------------------------- + +// addChecked returns p+x. +// +// The whySafe string is ignored, so that the function still inlines +// as efficiently as p+x, but all call sites should use the string to +// record why the addition is safe, which is to say why the addition +// does not cause x to advance to the very end of p's allocation +// and therefore point incorrectly at the next block in memory. +func addChecked(p unsafe.Pointer, x uintptr, whySafe string) unsafe.Pointer { + _ = whySafe + return unsafe.Pointer(uintptr(p) + x) +} + +// Name is an encoded type Name with optional extra data. +// +// The first byte is a bit field containing: +// +// 1<<0 the name is exported +// 1<<1 tag data follows the name +// 1<<2 pkgPath nameOff follows the name and tag +// 1<<3 the name is of an embedded (a.k.a. anonymous) field +// +// Following that, there is a varint-encoded length of the name, +// followed by the name itself. +// +// If tag data is present, it also has a varint-encoded length +// followed by the tag itself. +// +// If the import path follows, then 4 bytes at the end of +// the data form a nameOff. The import path is only set for concrete +// methods that are defined in a different package than their type. +// +// If a name starts with "*", then the exported bit represents +// whether the pointed to type is exported. +// +// Note: this encoding must match here and in: +// cmd/compile/internal/reflectdata/reflect.go +// cmd/link/internal/ld/decodesym.go + +type Name struct { + Bytes *byte +} + +// DataChecked does pointer arithmetic on n's Bytes, and that arithmetic is asserted to +// be safe for the reason in whySafe (which can appear in a backtrace, etc.) +func (n Name) DataChecked(off int, whySafe string) *byte { + return (*byte)(addChecked(unsafe.Pointer(n.Bytes), uintptr(off), whySafe)) +} + +// Data does pointer arithmetic on n's Bytes, and that arithmetic is asserted to +// be safe because the runtime made the call (other packages use DataChecked) +func (n Name) Data(off int) *byte { + return (*byte)(addChecked(unsafe.Pointer(n.Bytes), uintptr(off), "the runtime doesn't need to give you a reason")) +} + +// IsExported returns "is n exported?" +func (n Name) IsExported() bool { + return (*n.Bytes)&(1<<0) != 0 +} + +// HasTag returns true iff there is tag data following this name +func (n Name) HasTag() bool { + return (*n.Bytes)&(1<<1) != 0 +} + +// IsEmbedded returns true iff n is embedded (an anonymous field). +func (n Name) IsEmbedded() bool { + return (*n.Bytes)&(1<<3) != 0 +} + +// ReadVarint parses a varint as encoded by encoding/binary. +// It returns the number of encoded bytes and the encoded value. +func (n Name) ReadVarint(off int) (int, int) { + v := 0 + for i := 0; ; i++ { + x := *n.DataChecked(off+i, "read varint") + v += int(x&0x7f) << (7 * i) + if x&0x80 == 0 { + return i + 1, v + } + } +} + +// IsBlank indicates whether n is "_". +func (n Name) IsBlank() bool { + if n.Bytes == nil { + return false + } + _, l := n.ReadVarint(1) + return l == 1 && *n.Data(2) == '_' +} + +// writeVarint writes n to buf in varint form. Returns the +// number of bytes written. n must be nonnegative. +// Writes at most 10 bytes. +func writeVarint(buf []byte, n int) int { + for i := 0; ; i++ { + b := byte(n & 0x7f) + n >>= 7 + if n == 0 { + buf[i] = b + return i + 1 + } + buf[i] = b | 0x80 + } +} + +// Name returns the tag string for n, or empty if there is none. +func (n Name) Name() string { + if n.Bytes == nil { + return "" + } + i, l := n.ReadVarint(1) + return unsafe.String(n.DataChecked(1+i, "non-empty string"), l) +} + +// Tag returns the tag string for n, or empty if there is none. +func (n Name) Tag() string { + if !n.HasTag() { + return "" + } + i, l := n.ReadVarint(1) + i2, l2 := n.ReadVarint(1 + i + l) + return unsafe.String(n.DataChecked(1+i+l+i2, "non-empty string"), l2) +} + +func NewName(n, tag string, exported, embedded bool) Name { + if len(n) >= 1<<29 { + panic("abi.NewName: name too long: " + n[:1024] + "...") + } + if len(tag) >= 1<<29 { + panic("abi.NewName: tag too long: " + tag[:1024] + "...") + } + var nameLen [10]byte + var tagLen [10]byte + nameLenLen := writeVarint(nameLen[:], len(n)) + tagLenLen := writeVarint(tagLen[:], len(tag)) + + var bits byte + l := 1 + nameLenLen + len(n) + if exported { + bits |= 1 << 0 + } + if len(tag) > 0 { + l += tagLenLen + len(tag) + bits |= 1 << 1 + } + if embedded { + bits |= 1 << 3 + } + + b := make([]byte, l) + b[0] = bits + copy(b[1:], nameLen[:nameLenLen]) + copy(b[1+nameLenLen:], n) + if len(tag) > 0 { + tb := b[1+nameLenLen+len(n):] + copy(tb, tagLen[:tagLenLen]) + copy(tb[tagLenLen:], tag) + } + + return Name{Bytes: &b[0]} +} + +// ----------------------------------------------------------------------------- diff --git a/internal/runtime/llgo_autogen.lla b/internal/runtime/llgo_autogen.lla index 6257d02dcf6df798f320d4ec2621762c94edb2e5..94569d3013459d3fc524e9367f2ac91e08697462 100644 GIT binary patch delta 1099 zcmV-R1ho5xHitGjP)h>@6aWAK2mo$Hv{*wA1#MFr002l10RRsG8~|)=XK!C&b#!lM zWo|BPY*kbV00Xd`N@lX0O0hZc27l()_(D{#-Gx10*z<)wU)Xa<_Dq;-JFMB@6)>AY z?ydH>q1-#^VBZd&_3-RFos@lh7$PSM9-WwcpsYyc<}JD69oYK9f!`bX=`g(s;cK#p zzA#Q9iU0QU33-XW;9|+*FbOV}5>xaY5lbP~;IibT=qs(FFSEJtEG#iUE`R!p?6S*dna;J`@{{v1d;6ieik#$MDXzSFTVOPcYzxwh2id?wMea1xYYyQGb;Fl=7dFTO<8o z@)&tW&nml7Rf><=H8np|h&&#nV?)B#uKnST)7dNurzR=fsp!y>c-@+&1*KdI;^1W* zyf7^Qy1|1QcwCE9TL9ozgck5}PWn$QJ2F#fA2pX%h+Y4^WLKQ{TrmN%FrYz@LJ69p zZ?047#fmUACR;?%q%jgSrx;_xpvnC6gUoISj0PAq^Apgd44T{r8f>%T7L2RIl1mGm zk2ZrA(@5{107>_gRS7j9TCb)a9FO>atbK0A?@SZUMR%(IO+R0iV(ny#Y|MR=ld1_E z0tE4s$O$eEG(sxP7^y)Zv$>?U>iv@h3MejQg6zo&Y#qpr)i9;ljy<>Z$a&nr+2ybaQ<|43@ECzJ`Fh5qk z+?fN(XdwGK+A{ZU>_4<5*L=0vEWI8>NIvn$5NH-s>S~bTQ}n4Wy|FkKVHm@V8w}^H zZ4&N59>TowZ-0{=3nv0vvy(;(DFFzRa0^op>CJZwbO>))gGKg*2)%og(hG$F-;-Dj zjsazp=M1s|#gm#1cns`LstCorJteXs^%avI4jBPglQ<4g0i?5u4ov|8SCiKdAp*Wz zlll+pAVWMh4JJezHpkxQdJ&FK8K?f(klMm5d<)B7J=L`*kCOxuK@B$AZKJA6XspWl z>7EvoQV}o#5tD-vUIIR5lj9Mv0UMK)5+MN*v$hiP2MumTv{*wA1#MFr002mnv>GV` Ru$)Sh;2IzXoEiWC0064O?nnRt delta 1098 zcmV-Q1hxBzHikAiP)h>@6aWAK2ms)lvsec4&M;CM002b}0RRsG8~|)=XK!C&b#!lM zWo|BPY*kbV00Z;lNoMroNwGQb27hMk%#mGo7v6l~%@^K$;msj=GvTc5ux5i-z-$Kj zw%Xr@vhJjVcRRS%!}IQRQr_)hg`B8%bYk*>QX-X`wx{2)Ebhk9eTwH)6`C zF1|iJMm;uX9hrNNV^ml;tA|k$pWv(vn=VGhr)X5z_-dEc0IiJoBXsx-yKKZNe?px} zzN@zOlrRSjTD6m|s_ol7nt!;R^{S&JY;f(_F%B ziD0~*!OGZ~PH|ysB)b<0r>h@X1on6NP;5BHo;l4ciZK=^Lu0QR$j*^hLIz5i*aSqB zbWsugm!j(|<>jjyb>)Gms|Z3}xk6n$yMR~OCM0vXXLdmrB)gzRQGfbV%7033jogFD z1LPS!tL#QqDL!h~)cj2G@pz1O4GCAf_J=!8XR{=nnxt^2qC-pKMQfTClyWVIgO_pe z!qoqFg9kP6xE80@|KmP{7VvUT`cEu1GE-EU7-Pbq$^4Up%vK1D1{gH+6VRj#n%oB(Y_sD2i>t$uOADNg zHiH(^NN=71N$ZnV2{j;2ucjUxkNAJAO>V|-OB2pTcdGeKKVOw%?PQ8<%zZPHs|g$e z?C_Jx2`&zFK`PA{sX-vKxumx0&65QRC@x`w?8ymi9mtK3D4Y%~jdZtEz!Z>l& zYLwg(0ver&g=wkxkt~&SgqHSrlUoWnf49L1{V8E)qB&36lQ2ya+-MfQaVJ$jSV3xxsGlUWRo z0a=si46*^alba2A4CYR%2*tcTC9)y)36mcV838AgISx<(p|gq(O#uNXlh_X-0zO)k z`w!|MD?Bz0CPW)H$KL095spt8r~cBA+QKY+3(H 0 { b.InlineCall(b.Pkg.rtFunc("PrintString"), b.Str(" ")) + // TODO(visualfc): maybe use PrintCStr is more efficient } var fn string - var typ Type + var typ Type // TODO(visualfc): typ uninitialized in some cases switch arg.kind { case vkBool: fn = "PrintBool" @@ -1002,6 +1014,8 @@ func (b Builder) BuiltinCall(fn string, args ...Expr) (ret Expr) { case vkSlice: fn = "PrintSlice" case vkPtr, vkFuncPtr, vkFuncDecl, vkClosure, vkPyVarRef, vkPyFuncRef: + // TODO(visualfc): vkClosure is not a pointer + // TODO(visualfc): vkPyVarRef, vkPyFuncRef is pointer of pointer fn = "PrintPointer" typ = b.Prog.VoidPtr() case vkString: @@ -1037,8 +1051,11 @@ func (b Builder) BuiltinCall(fn string, args ...Expr) (ret Expr) { } } } + case "String": // unsafe.String + // TODO(xsw): make this a builtin + return b.InlineCall(b.Pkg.rtFunc("NewString"), args[0], args[1]) } - panic("todo") + panic("todo: " + fn) } // ----------------------------------------------------------------------------- diff --git a/ssa/interface.go b/ssa/interface.go index ee9a451e..16004054 100644 --- a/ssa/interface.go +++ b/ssa/interface.go @@ -27,19 +27,29 @@ import ( // ----------------------------------------------------------------------------- -// AbiBasic returns the abi type of the specified basic kind. -func (b Builder) AbiBasic(kind types.BasicKind) Expr { +// abiBasic returns the abi type of the specified basic kind. +func (b Builder) abiBasic(kind types.BasicKind) Expr { return b.InlineCall(b.Pkg.rtFunc("Basic"), b.Prog.Val(int(kind))) } /* -// AbiStruct returns the abi type of the specified struct type. -func (b Builder) AbiStruct(t *types.Struct) Expr { - panic("todo") - // return b.InlineCall(b.Pkg.rtFunc("Struct"), b.Prog.Val(t.NumFields())) +// abiStruct returns the abi type of the specified struct type. +func (b Builder) abiStruct(t *types.Struct) Expr { + // name := "__llgo_" + b.Prog.abi.StructName(t) } */ +// AbiType returns the abi type of the specified type. +func (b Builder) AbiType(t Type) Expr { + switch tx := t.raw.Type.(type) { + case *types.Basic: + return b.abiBasic(tx.Kind()) + //case *types.Struct: + // return b.abiStruct(tx) + } + panic("todo") +} + // ----------------------------------------------------------------------------- // MakeInterface constructs an instance of an interface type from a @@ -57,37 +67,66 @@ func (b Builder) AbiStruct(t *types.Struct) Expr { // t1 = make interface{} <- int (42:int) // t2 = make Stringer <- t0 func (b Builder) MakeInterface(tinter Type, x Expr) (ret Expr) { - raw := tinter.raw.Type + rawIntf := tinter.raw.Type.Underlying().(*types.Interface) if debugInstr { - log.Printf("MakeInterface %v, %v\n", raw, x.impl) + log.Printf("MakeInterface %v, %v\n", rawIntf, x.impl) } prog := b.Prog - pkg := b.Pkg - switch tx := x.raw.Type.Underlying().(type) { + typ := x.Type + switch tx := typ.raw.Type.Underlying().(type) { case *types.Basic: kind := tx.Kind() switch { case kind >= types.Bool && kind <= types.Uintptr: - t := b.AbiBasic(kind) - tptr := prog.Uintptr() - vptr := Expr{llvm.CreateIntCast(b.impl, x.impl, tptr.ll), tptr} - return Expr{b.InlineCall(pkg.rtFunc("MakeAnyInt"), t, vptr).impl, tinter} + if prog.is32Bits && (kind == types.Int64 || kind == types.Uint64) { + return b.makeIntfAlloc(tinter, rawIntf, typ, x) + } + return b.makeIntfByIntptr(tinter, rawIntf, typ, x.impl) case kind == types.Float32: - t := b.AbiBasic(kind) - tptr := prog.Uintptr() - i32 := llvm.CreateBitCast(b.impl, x.impl, prog.tyInt32()) // TODO(xsw): more effective - vptr := Expr{llvm.CreateIntCast(b.impl, i32, tptr.ll), tptr} - return Expr{b.InlineCall(pkg.rtFunc("MakeAnyInt"), t, vptr).impl, tinter} + i32 := llvm.CreateBitCast(b.impl, x.impl, prog.tyInt32()) + return b.makeIntfByIntptr(tinter, rawIntf, typ, i32) case kind == types.Float64: - t := b.AbiBasic(kind) - tptr := prog.Uintptr() - vptr := Expr{llvm.CreateBitCast(b.impl, x.impl, tptr.ll), tptr} - return Expr{b.InlineCall(pkg.rtFunc("MakeAnyInt"), t, vptr).impl, tinter} + if prog.is32Bits { + return b.makeIntfAlloc(tinter, rawIntf, typ, x) + } + i64 := llvm.CreateBitCast(b.impl, x.impl, prog.tyInt64()) + return b.makeIntfByIntptr(tinter, rawIntf, typ, i64) case kind == types.String: - return Expr{b.InlineCall(pkg.rtFunc("MakeAnyString"), x).impl, tinter} + return Expr{b.InlineCall(b.Pkg.rtFunc("MakeAnyString"), x).impl, tinter} } - // case *types.Struct: - // t := b.AbiStruct(tx) + /* case *types.Struct: + size := int(prog.SizeOf(typ)) + if size > prog.PointerSize() { + return b.makeIntfAlloc(tinter, rawIntf, typ, x) + } + tv := prog.ctx.IntType(size * 8) + iv := llvm.CreateBitCast(b.impl, x.impl, tv) + return b.makeIntfByIntptr(tinter, rawIntf, typ, iv) */ + } + panic("todo") +} + +func (b Builder) makeIntfAlloc(tinter Type, rawIntf *types.Interface, typ Type, x Expr) (ret Expr) { + vptr := b.AllocU(typ) + b.Store(vptr, x) + return b.makeIntfByPtr(tinter, rawIntf, typ, vptr) +} + +func (b Builder) makeIntfByPtr(tinter Type, rawIntf *types.Interface, typ Type, vptr Expr) (ret Expr) { + if rawIntf.Empty() { + ret = b.InlineCall(b.Pkg.rtFunc("MakeAny"), b.AbiType(typ), vptr) + ret.Type = tinter + return + } + panic("todo") +} + +func (b Builder) makeIntfByIntptr(tinter Type, rawIntf *types.Interface, typ Type, x llvm.Value) (ret Expr) { + if rawIntf.Empty() { + tptr := b.Prog.Uintptr() + x = llvm.CreateIntCast(b.impl, x, tptr.ll) + impl := b.InlineCall(b.Pkg.rtFunc("MakeAnyIntptr"), b.AbiType(typ), Expr{x, tptr}).impl + return Expr{impl, tinter} } panic("todo") } diff --git a/ssa/package.go b/ssa/package.go index bc9cb7cc..ca8ec18c 100644 --- a/ssa/package.go +++ b/ssa/package.go @@ -99,6 +99,7 @@ type aProgram struct { ctx llvm.Context typs typeutil.Map // rawType -> Type gocvt goTypes + //abi *abi.Builder rt *types.Package rtget func() *types.Package @@ -158,6 +159,7 @@ type aProgram struct { NeedRuntime bool NeedPyInit bool + is32Bits bool } // A Program presents a program. @@ -180,7 +182,12 @@ func NewProgram(target *Target) Program { // TODO(xsw): Finalize may cause panic, so comment it. ctx.Finalize() */ - return &aProgram{ctx: ctx, gocvt: newGoTypes(), target: target, td: td, named: make(map[string]llvm.Type)} + is32Bits := (td.PointerSize() == 4) + return &aProgram{ + ctx: ctx, gocvt: newGoTypes(), // abi: abi.New(), + target: target, td: td, is32Bits: is32Bits, + named: make(map[string]llvm.Type), + } } // SetPython sets the Python package. diff --git a/ssa/type.go b/ssa/type.go index 17f5bd07..b7307c39 100644 --- a/ssa/type.go +++ b/ssa/type.go @@ -99,6 +99,10 @@ func (p Program) SizeOf(typ Type, n ...int64) uint64 { return size } +func (p Program) PointerSize() int { + return p.td.PointerSize() +} + func (p Program) Slice(typ Type) Type { return p.rawType(types.NewSlice(typ.raw.Type)) }