llgo/ssa: vkFuncDecl/vkFuncPtr/vkClosure

This commit is contained in:
xushiwei
2024-05-03 15:40:24 +08:00
parent 85da86a4f1
commit afd3d40348
5 changed files with 95 additions and 24 deletions

View File

@@ -63,6 +63,9 @@ func Malloc(size uintptr) Pointer
//go:linkname Memcpy C.memcpy //go:linkname Memcpy C.memcpy
func Memcpy(dst, src Pointer, n uintptr) Pointer 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 //go:linkname Printf C.printf
func Printf(format *Char, __llgo_va_list ...any) Int func Printf(format *Char, __llgo_va_list ...any) Int

View File

@@ -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}
}

View File

@@ -979,7 +979,7 @@ func (b Builder) BuiltinCall(fn string, args ...Expr) (ret Expr) {
case *types.Slice: case *types.Slice:
return b.InlineCall(b.fn.pkg.rtFunc("SliceLen"), arg) return b.InlineCall(b.fn.pkg.rtFunc("SliceLen"), arg)
case *types.Basic: case *types.Basic:
if t.Info()&types.IsString != 0 { if t.Kind() == types.String {
return b.InlineCall(b.fn.pkg.rtFunc("StringLen"), arg) return b.InlineCall(b.fn.pkg.rtFunc("StringLen"), arg)
} }
} }

View File

@@ -17,7 +17,6 @@
package ssa package ssa
import ( import (
"go/constant"
"go/types" "go/types"
"runtime" "runtime"
@@ -116,6 +115,7 @@ type aProgram struct {
voidType llvm.Type voidType llvm.Type
voidPtrTy llvm.Type voidPtrTy llvm.Type
rtClosureTy llvm.Type
rtStringTy llvm.Type rtStringTy llvm.Type
rtIfaceTy llvm.Type rtIfaceTy llvm.Type
rtSliceTy llvm.Type rtSliceTy llvm.Type
@@ -185,6 +185,13 @@ func (p Program) rtType(name string) Type {
return p.Type(p.rtNamed(name)) 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 { func (p Program) rtIface() llvm.Type {
if p.rtIfaceTy.IsNil() { if p.rtIfaceTy.IsNil() {
p.rtIfaceTy = p.rtType("Interface").ll p.rtIfaceTy = p.rtType("Interface").ll
@@ -305,10 +312,12 @@ type aPackage struct {
type Package = *aPackage type Package = *aPackage
/*
// NewConst creates a new named constant. // NewConst creates a new named constant.
func (p Package) NewConst(name string, val constant.Value) NamedConst { func (p Package) NewConst(name string, val constant.Value) NamedConst {
return &aNamedConst{} return &aNamedConst{}
} }
*/
// NewVar creates a new global variable. // NewVar creates a new global variable.
func (p Package) NewVar(name string, typ types.Type) Global { 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 { if v, ok := p.fns[name]; ok {
return v return v
} }
t := p.prog.llvmSignature(sig, false) t := p.prog.llvmFuncDecl(sig)
fn := llvm.AddFunction(p.mod, name, t.ll) fn := llvm.AddFunction(p.mod, name, t.ll)
ret := newFunction(fn, t, p, p.prog) ret := newFunction(fn, t, p, p.prog)
p.fns[name] = ret p.fns[name] = ret

View File

@@ -40,12 +40,17 @@ const (
vkString vkString
vkBool vkBool
vkPtr vkPtr
vkFunc vkFuncDecl // func decl
vkFuncPtr // func ptr in C
vkClosure // func ptr in Go
vkTuple vkTuple
vkDelayExpr = -1 vkDelayExpr = -1
vkPhisExpr = -2 vkPhisExpr = -2
) )
// CFuncPtr represents a C function pointer.
type CFuncPtr types.Signature
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
const ( 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 { type aType struct {
ll llvm.Type ll llvm.Type
t types.Type t types.Type
kind valueKind kind valueKind // value kind of llvm.Type
} }
type Type = *aType type Type = *aType
@@ -128,9 +140,11 @@ func (p Program) Field(typ Type, i int) Type {
} }
func (p Program) Type(typ types.Type) Type { func (p Program) Type(typ types.Type) Type {
/* TODO(xsw): no need?
if sig, ok := typ.(*types.Signature); ok { // should methodToFunc if sig, ok := typ.(*types.Signature); ok { // should methodToFunc
return p.llvmSignature(sig, true) return p.llvmSignature(sig, true)
} }
*/
if v := p.typs.At(typ); v != nil { if v := p.typs.At(typ); v != nil {
return v.(Type) return v.(Type)
} }
@@ -139,14 +153,9 @@ func (p Program) Type(typ types.Type) Type {
return ret return ret
} }
func (p Program) llvmSignature(sig *types.Signature, isPtr bool) Type { func (p Program) llvmFuncDecl(sig *types.Signature) Type {
sig = methodToFunc(sig) sig = methodToFunc(sig)
if v := p.typs.At(sig); v != nil { return p.toLLVMFunc(sig, false, true) // don't save func decl to cache
return v.(Type)
}
ret := p.toLLVMFunc(sig, isPtr)
p.typs.Set(sig, ret)
return ret
} }
func (p Program) tyVoidPtr() llvm.Type { func (p Program) tyVoidPtr() llvm.Type {
@@ -262,6 +271,8 @@ func (p Program) toLLVMType(typ types.Type) Type {
return p.toLLVMStruct(t) return p.toLLVMStruct(t)
case *types.Named: case *types.Named:
return p.toLLVMNamed(t) return p.toLLVMNamed(t)
case *types.Signature:
return p.toLLVMFunc(t, false, false)
case *types.Array: case *types.Array:
elem := p.Type(t.Elem()) elem := p.Type(t.Elem())
return &aType{llvm.ArrayType(elem.ll, int(t.Len())), typ, vkInvalid} return &aType{llvm.ArrayType(elem.ll, int(t.Len())), typ, vkInvalid}
@@ -307,13 +318,18 @@ func (p Program) toLLVMTypes(t *types.Tuple, n int) (ret []llvm.Type) {
return 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() tParams := sig.Params()
n := tParams.Len() n := tParams.Len()
hasVArg := HasVArg(tParams, n) if inC {
hasVArg = HasVArg(tParams, n)
if hasVArg { if hasVArg {
n-- n--
} }
}
params := p.toLLVMTypes(tParams, n) params := p.toLLVMTypes(tParams, n)
out := sig.Results() out := sig.Results()
var ret llvm.Type var ret llvm.Type
@@ -325,11 +341,19 @@ func (p Program) toLLVMFunc(sig *types.Signature, isPtr bool) Type {
default: default:
ret = p.toLLVMTuple(out) ret = p.toLLVMTuple(out)
} }
ft := llvm.FunctionType(ret, params, hasVArg) if inC || isDecl {
if isPtr { ft = llvm.FunctionType(ret, params, hasVArg)
if isDecl {
kind = vkFuncDecl
} else {
ft = llvm.PointerType(ft, 0) ft = llvm.PointerType(ft, 0)
kind = vkFuncPtr
} }
return &aType{ft, sig, vkFunc} } else {
ft = p.rtClosure()
kind = vkClosure
}
return &aType{ft, sig, kind}
} }
func (p Program) retType(sig *types.Signature) Type { func (p Program) retType(sig *types.Signature) Type {
@@ -349,6 +373,9 @@ func (p Program) toLLVMNamed(typ *types.Named) Type {
case *types.Struct: case *types.Struct:
name := NameOf(typ) name := NameOf(typ)
return &aType{p.toLLVMNamedStruct(name, t), typ, vkInvalid} 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: default:
return p.Type(t) return p.Type(t)
} }