From afd3d4034870d9e1314588b6aac34b11b85d91c9 Mon Sep 17 00:00:00 2001 From: xushiwei Date: Fri, 3 May 2024 15:40:24 +0800 Subject: [PATCH] llgo/ssa: vkFuncDecl/vkFuncPtr/vkClosure --- internal/runtime/c/c.go | 3 ++ internal/runtime/z_closure.go | 32 ++++++++++++++++++ ssa/expr.go | 2 +- ssa/package.go | 21 ++++++++---- ssa/type.go | 61 +++++++++++++++++++++++++---------- 5 files changed, 95 insertions(+), 24 deletions(-) create mode 100644 internal/runtime/z_closure.go diff --git a/internal/runtime/c/c.go b/internal/runtime/c/c.go index ca111468..ac88b11a 100644 --- a/internal/runtime/c/c.go +++ b/internal/runtime/c/c.go @@ -63,6 +63,9 @@ func Malloc(size uintptr) Pointer //go:linkname Memcpy C.memcpy func Memcpy(dst, src Pointer, n uintptr) Pointer +//go:linkname Memset C.memset +func Memset(s Pointer, c Int, n uintptr) Pointer + //go:linkname Printf C.printf func Printf(format *Char, __llgo_va_list ...any) Int diff --git a/internal/runtime/z_closure.go b/internal/runtime/z_closure.go new file mode 100644 index 00000000..41899815 --- /dev/null +++ b/internal/runtime/z_closure.go @@ -0,0 +1,32 @@ +/* + * 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" +) + +// Closure represents a closure. +type Closure struct { + f unsafe.Pointer + data unsafe.Pointer // means no context if data is nil +} + +// NewClosure creates a closure. +func NewClosure(f, data unsafe.Pointer) Closure { + return Closure{f, data} +} diff --git a/ssa/expr.go b/ssa/expr.go index 5200bff4..3cadd364 100644 --- a/ssa/expr.go +++ b/ssa/expr.go @@ -979,7 +979,7 @@ func (b Builder) BuiltinCall(fn string, args ...Expr) (ret Expr) { case *types.Slice: return b.InlineCall(b.fn.pkg.rtFunc("SliceLen"), arg) case *types.Basic: - if t.Info()&types.IsString != 0 { + if t.Kind() == types.String { return b.InlineCall(b.fn.pkg.rtFunc("StringLen"), arg) } } diff --git a/ssa/package.go b/ssa/package.go index 900c7da9..985a155b 100644 --- a/ssa/package.go +++ b/ssa/package.go @@ -17,7 +17,6 @@ package ssa import ( - "go/constant" "go/types" "runtime" @@ -116,10 +115,11 @@ type aProgram struct { voidType llvm.Type voidPtrTy llvm.Type - rtStringTy llvm.Type - rtIfaceTy llvm.Type - rtSliceTy llvm.Type - rtMapTy llvm.Type + rtClosureTy llvm.Type + rtStringTy llvm.Type + rtIfaceTy llvm.Type + rtSliceTy llvm.Type + rtMapTy llvm.Type anyTy Type voidTy Type @@ -185,6 +185,13 @@ func (p Program) rtType(name string) Type { return p.Type(p.rtNamed(name)) } +func (p Program) rtClosure() llvm.Type { + if p.rtClosureTy.IsNil() { + p.rtClosureTy = p.rtType("Closure").ll + } + return p.rtClosureTy +} + func (p Program) rtIface() llvm.Type { if p.rtIfaceTy.IsNil() { p.rtIfaceTy = p.rtType("Interface").ll @@ -305,10 +312,12 @@ type aPackage struct { type Package = *aPackage +/* // NewConst creates a new named constant. func (p Package) NewConst(name string, val constant.Value) NamedConst { return &aNamedConst{} } +*/ // NewVar creates a new global variable. func (p Package) NewVar(name string, typ types.Type) Global { @@ -329,7 +338,7 @@ func (p Package) NewFunc(name string, sig *types.Signature) Function { if v, ok := p.fns[name]; ok { return v } - t := p.prog.llvmSignature(sig, false) + t := p.prog.llvmFuncDecl(sig) fn := llvm.AddFunction(p.mod, name, t.ll) ret := newFunction(fn, t, p, p.prog) p.fns[name] = ret diff --git a/ssa/type.go b/ssa/type.go index c33b1e5d..d2e764e2 100644 --- a/ssa/type.go +++ b/ssa/type.go @@ -40,12 +40,17 @@ const ( vkString vkBool vkPtr - vkFunc + vkFuncDecl // func decl + vkFuncPtr // func ptr in C + vkClosure // func ptr in Go vkTuple vkDelayExpr = -1 vkPhisExpr = -2 ) +// CFuncPtr represents a C function pointer. +type CFuncPtr types.Signature + // ----------------------------------------------------------------------------- const ( @@ -97,10 +102,17 @@ func methodToFunc(sig *types.Signature) *types.Signature { // ----------------------------------------------------------------------------- +// CType convert a cdecl type into Go type. +func CType(typ types.Type) types.Type { + panic("todo") +} + +// ----------------------------------------------------------------------------- + type aType struct { ll llvm.Type t types.Type - kind valueKind + kind valueKind // value kind of llvm.Type } type Type = *aType @@ -128,9 +140,11 @@ func (p Program) Field(typ Type, i int) Type { } func (p Program) Type(typ types.Type) Type { + /* TODO(xsw): no need? if sig, ok := typ.(*types.Signature); ok { // should methodToFunc return p.llvmSignature(sig, true) } + */ if v := p.typs.At(typ); v != nil { return v.(Type) } @@ -139,14 +153,9 @@ func (p Program) Type(typ types.Type) Type { return ret } -func (p Program) llvmSignature(sig *types.Signature, isPtr bool) Type { +func (p Program) llvmFuncDecl(sig *types.Signature) Type { sig = methodToFunc(sig) - if v := p.typs.At(sig); v != nil { - return v.(Type) - } - ret := p.toLLVMFunc(sig, isPtr) - p.typs.Set(sig, ret) - return ret + return p.toLLVMFunc(sig, false, true) // don't save func decl to cache } func (p Program) tyVoidPtr() llvm.Type { @@ -262,6 +271,8 @@ func (p Program) toLLVMType(typ types.Type) Type { return p.toLLVMStruct(t) case *types.Named: return p.toLLVMNamed(t) + case *types.Signature: + return p.toLLVMFunc(t, false, false) case *types.Array: elem := p.Type(t.Elem()) return &aType{llvm.ArrayType(elem.ll, int(t.Len())), typ, vkInvalid} @@ -307,12 +318,17 @@ func (p Program) toLLVMTypes(t *types.Tuple, n int) (ret []llvm.Type) { return } -func (p Program) toLLVMFunc(sig *types.Signature, isPtr bool) Type { +func (p Program) toLLVMFunc(sig *types.Signature, inC, isDecl bool) Type { + var hasVArg bool + var kind valueKind + var ft llvm.Type tParams := sig.Params() n := tParams.Len() - hasVArg := HasVArg(tParams, n) - if hasVArg { - n-- + if inC { + hasVArg = HasVArg(tParams, n) + if hasVArg { + n-- + } } params := p.toLLVMTypes(tParams, n) out := sig.Results() @@ -325,11 +341,19 @@ func (p Program) toLLVMFunc(sig *types.Signature, isPtr bool) Type { default: ret = p.toLLVMTuple(out) } - ft := llvm.FunctionType(ret, params, hasVArg) - if isPtr { - ft = llvm.PointerType(ft, 0) + if inC || isDecl { + ft = llvm.FunctionType(ret, params, hasVArg) + if isDecl { + kind = vkFuncDecl + } else { + ft = llvm.PointerType(ft, 0) + kind = vkFuncPtr + } + } else { + ft = p.rtClosure() + kind = vkClosure } - return &aType{ft, sig, vkFunc} + return &aType{ft, sig, kind} } func (p Program) retType(sig *types.Signature) Type { @@ -349,6 +373,9 @@ func (p Program) toLLVMNamed(typ *types.Named) Type { case *types.Struct: name := NameOf(typ) return &aType{p.toLLVMNamedStruct(name, t), typ, vkInvalid} + case *types.Signature: + inC := true // TODO(xsw): how to check in C + return p.toLLVMFunc(t, inC, false) default: return p.Type(t) }