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,10 +115,11 @@ type aProgram struct {
voidType llvm.Type voidType llvm.Type
voidPtrTy llvm.Type voidPtrTy llvm.Type
rtStringTy llvm.Type rtClosureTy llvm.Type
rtIfaceTy llvm.Type rtStringTy llvm.Type
rtSliceTy llvm.Type rtIfaceTy llvm.Type
rtMapTy llvm.Type rtSliceTy llvm.Type
rtMapTy llvm.Type
anyTy Type anyTy Type
voidTy Type voidTy 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,12 +318,17 @@ 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 {
if hasVArg { hasVArg = HasVArg(tParams, n)
n-- if hasVArg {
n--
}
} }
params := p.toLLVMTypes(tParams, n) params := p.toLLVMTypes(tParams, n)
out := sig.Results() out := sig.Results()
@@ -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)
ft = llvm.PointerType(ft, 0) 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 { 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)
} }