Merge pull request #348 from xushiwei/q
c/pthread/sync.Mutex; sync.Mutex/Once; globalType: support typepatch
This commit is contained in:
@@ -208,6 +208,7 @@ Here are the Go packages that can be imported correctly:
|
|||||||
* [unicode/utf16](https://pkg.go.dev/unicode/utf16)
|
* [unicode/utf16](https://pkg.go.dev/unicode/utf16)
|
||||||
* [math/bits](https://pkg.go.dev/math/bits)
|
* [math/bits](https://pkg.go.dev/math/bits)
|
||||||
* [math](https://pkg.go.dev/math)
|
* [math](https://pkg.go.dev/math)
|
||||||
|
* [sync](https://pkg.go.dev/sync) (partially)
|
||||||
* [sync/atomic](https://pkg.go.dev/sync/atomic) (partially)
|
* [sync/atomic](https://pkg.go.dev/sync/atomic) (partially)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -42,3 +42,46 @@ var OnceInit Once
|
|||||||
func (o *Once) Do(f func()) c.Int { return 0 }
|
func (o *Once) Do(f func()) c.Int { return 0 }
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
type MutexType c.Int
|
||||||
|
|
||||||
|
const (
|
||||||
|
MutexNormal MutexType = C.PTHREAD_MUTEX_NORMAL
|
||||||
|
MutexErrorCheck MutexType = C.PTHREAD_MUTEX_ERRORCHECK
|
||||||
|
MutexRecursive MutexType = C.PTHREAD_MUTEX_RECURSIVE
|
||||||
|
MutexDefault MutexType = C.PTHREAD_MUTEX_DEFAULT
|
||||||
|
)
|
||||||
|
|
||||||
|
// MutexAttr is a mutex attribute object.
|
||||||
|
type MutexAttr C.pthread_mutexattr_t
|
||||||
|
|
||||||
|
// llgo:link (*MutexAttr).Init C.pthread_mutexattr_init
|
||||||
|
func (a *MutexAttr) Init(attr *MutexAttr) c.Int { return 0 }
|
||||||
|
|
||||||
|
// llgo:link (*MutexAttr).Destroy C.pthread_mutexattr_destroy
|
||||||
|
func (a *MutexAttr) Destroy() {}
|
||||||
|
|
||||||
|
// llgo:link (*MutexAttr).SetType C.pthread_mutexattr_settype
|
||||||
|
func (a *MutexAttr) SetType(typ MutexType) c.Int { return 0 }
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Mutex is a mutual exclusion lock.
|
||||||
|
type Mutex C.pthread_mutex_t
|
||||||
|
|
||||||
|
// llgo:link (*Mutex).Init C.pthread_mutex_init
|
||||||
|
func (m *Mutex) Init(attr *MutexAttr) c.Int { return 0 }
|
||||||
|
|
||||||
|
// llgo:link (*Mutex).Destroy C.pthread_mutex_destroy
|
||||||
|
func (m *Mutex) Destroy() {}
|
||||||
|
|
||||||
|
// llgo:link (*Mutex).Lock C.pthread_mutex_lock
|
||||||
|
func (m *Mutex) Lock() {}
|
||||||
|
|
||||||
|
// llgo:link (*Mutex).TryLock C.pthread_mutex_trylock
|
||||||
|
func (m *Mutex) TryLock() c.Int { return 0 }
|
||||||
|
|
||||||
|
// llgo:link (*Mutex).Unlock C.pthread_mutex_unlock
|
||||||
|
func (m *Mutex) Unlock() {}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|||||||
314
cl/compile.go
314
cl/compile.go
@@ -28,8 +28,9 @@ import (
|
|||||||
|
|
||||||
"github.com/goplus/llgo/cl/blocks"
|
"github.com/goplus/llgo/cl/blocks"
|
||||||
"github.com/goplus/llgo/internal/typepatch"
|
"github.com/goplus/llgo/internal/typepatch"
|
||||||
llssa "github.com/goplus/llgo/ssa"
|
|
||||||
"golang.org/x/tools/go/ssa"
|
"golang.org/x/tools/go/ssa"
|
||||||
|
|
||||||
|
llssa "github.com/goplus/llgo/ssa"
|
||||||
)
|
)
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
@@ -56,42 +57,6 @@ func SetDebug(dbgFlags dbgFlags) {
|
|||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
const (
|
|
||||||
fnNormal = iota
|
|
||||||
fnHasVArg
|
|
||||||
fnIgnore
|
|
||||||
)
|
|
||||||
|
|
||||||
func (p *context) funcKind(vfn ssa.Value) int {
|
|
||||||
if fn, ok := vfn.(*ssa.Function); ok {
|
|
||||||
params := fn.Signature.Params()
|
|
||||||
n := params.Len()
|
|
||||||
if n == 0 {
|
|
||||||
if fn.Signature.Recv() == nil {
|
|
||||||
if fn.Name() == "init" && p.pkgNoInit(fn.Pkg.Pkg) {
|
|
||||||
return fnIgnore
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
last := params.At(n - 1)
|
|
||||||
if last.Name() == llssa.NameValist {
|
|
||||||
return fnHasVArg
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return fnNormal
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *context) pkgNoInit(pkg *types.Package) bool {
|
|
||||||
p.ensureLoaded(pkg)
|
|
||||||
if i, ok := p.loaded[pkg]; ok {
|
|
||||||
return i.kind >= PkgNoInit
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
type instrOrValue interface {
|
type instrOrValue interface {
|
||||||
ssa.Instruction
|
ssa.Instruction
|
||||||
ssa.Value
|
ssa.Value
|
||||||
@@ -174,7 +139,7 @@ func (p *context) compileMethods(pkg llssa.Package, typ types.Type) {
|
|||||||
|
|
||||||
// Global variable.
|
// Global variable.
|
||||||
func (p *context) compileGlobal(pkg llssa.Package, gbl *ssa.Global) {
|
func (p *context) compileGlobal(pkg llssa.Package, gbl *ssa.Global) {
|
||||||
typ := gbl.Type()
|
typ := globalType(gbl)
|
||||||
name, vtype, define := p.varName(gbl.Pkg.Pkg, gbl)
|
name, vtype, define := p.varName(gbl.Pkg.Pkg, gbl)
|
||||||
if vtype == pyVar || ignoreName(name) || checkCgo(gbl.Name()) {
|
if vtype == pyVar || ignoreName(name) || checkCgo(gbl.Name()) {
|
||||||
return
|
return
|
||||||
@@ -287,69 +252,6 @@ func (p *context) compileFuncDecl(pkg llssa.Package, f *ssa.Function) (llssa.Fun
|
|||||||
return fn, nil, goFunc
|
return fn, nil, goFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
var llgoInstrs = map[string]int{
|
|
||||||
"cstr": llgoCstr,
|
|
||||||
"advance": llgoAdvance,
|
|
||||||
"index": llgoIndex,
|
|
||||||
"alloca": llgoAlloca,
|
|
||||||
"allocaCStr": llgoAllocaCStr,
|
|
||||||
"stringData": llgoStringData,
|
|
||||||
"pyList": llgoPyList,
|
|
||||||
"sigjmpbuf": llgoSigjmpbuf,
|
|
||||||
"sigsetjmp": llgoSigsetjmp,
|
|
||||||
"siglongjmp": llgoSiglongjmp,
|
|
||||||
"deferData": llgoDeferData,
|
|
||||||
"unreachable": llgoUnreachable,
|
|
||||||
|
|
||||||
"atomicLoad": llgoAtomicLoad,
|
|
||||||
"atomicStore": llgoAtomicStore,
|
|
||||||
"atomicCmpXchg": llgoAtomicCmpXchg,
|
|
||||||
|
|
||||||
"atomicXchg": int(llgoAtomicXchg),
|
|
||||||
"atomicAdd": int(llgoAtomicAdd),
|
|
||||||
"atomicSub": int(llgoAtomicSub),
|
|
||||||
"atomicAnd": int(llgoAtomicAnd),
|
|
||||||
"atomicNand": int(llgoAtomicNand),
|
|
||||||
"atomicOr": int(llgoAtomicOr),
|
|
||||||
"atomicXor": int(llgoAtomicXor),
|
|
||||||
"atomicMax": int(llgoAtomicMax),
|
|
||||||
"atomicMin": int(llgoAtomicMin),
|
|
||||||
"atomicUMax": int(llgoAtomicUMax),
|
|
||||||
"atomicUMin": int(llgoAtomicUMin),
|
|
||||||
}
|
|
||||||
|
|
||||||
// funcOf returns a function by name and set ftype = goFunc, cFunc, etc.
|
|
||||||
// or returns nil and set ftype = llgoCstr, llgoAlloca, llgoUnreachable, etc.
|
|
||||||
func (p *context) funcOf(fn *ssa.Function) (aFn llssa.Function, pyFn llssa.PyObjRef, ftype int) {
|
|
||||||
pkgTypes, name, ftype := p.funcName(fn, false)
|
|
||||||
switch ftype {
|
|
||||||
case pyFunc:
|
|
||||||
if kind, mod := pkgKindByScope(pkgTypes.Scope()); kind == PkgPyModule {
|
|
||||||
pkg := p.pkg
|
|
||||||
fnName := pysymPrefix + mod + "." + name
|
|
||||||
if pyFn = pkg.PyObjOf(fnName); pyFn == nil {
|
|
||||||
pyFn = pkg.PyNewFunc(fnName, fn.Signature, true)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ftype = ignoredFunc
|
|
||||||
case llgoInstr:
|
|
||||||
if ftype = llgoInstrs[name]; ftype == 0 {
|
|
||||||
panic("unknown llgo instruction: " + name)
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
pkg := p.pkg
|
|
||||||
if aFn = pkg.FuncOf(name); aFn == nil {
|
|
||||||
if len(fn.FreeVars) > 0 {
|
|
||||||
return nil, nil, ignoredFunc
|
|
||||||
}
|
|
||||||
sig := fn.Signature
|
|
||||||
aFn = pkg.NewFuncEx(name, sig, llssa.Background(ftype), false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *context) compileBlock(b llssa.Builder, block *ssa.BasicBlock, n int, doMainInit, doModInit bool) llssa.BasicBlock {
|
func (p *context) compileBlock(b llssa.Builder, block *ssa.BasicBlock, n int, doMainInit, doModInit bool) llssa.BasicBlock {
|
||||||
var last int
|
var last int
|
||||||
var pyModInit bool
|
var pyModInit bool
|
||||||
@@ -467,117 +369,6 @@ func isAllocVargs(ctx *context, v *ssa.Alloc) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// func cstr(string) *int8
|
|
||||||
func cstr(b llssa.Builder, args []ssa.Value) (ret llssa.Expr) {
|
|
||||||
if len(args) == 1 {
|
|
||||||
if c, ok := args[0].(*ssa.Const); ok {
|
|
||||||
if v := c.Value; v.Kind() == constant.String {
|
|
||||||
sv := constant.StringVal(v)
|
|
||||||
return b.CStr(sv)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
panic("cstr(<string-literal>): invalid arguments")
|
|
||||||
}
|
|
||||||
|
|
||||||
// func index(arr *T, idx int) T
|
|
||||||
func (p *context) index(b llssa.Builder, args []ssa.Value) (ret llssa.Expr) {
|
|
||||||
return b.Load(p.advance(b, args))
|
|
||||||
}
|
|
||||||
|
|
||||||
// func advance(ptr *T, offset int) *T
|
|
||||||
func (p *context) advance(b llssa.Builder, args []ssa.Value) (ret llssa.Expr) {
|
|
||||||
if len(args) == 2 {
|
|
||||||
ptr := p.compileValue(b, args[0])
|
|
||||||
offset := p.compileValue(b, args[1])
|
|
||||||
return b.Advance(ptr, offset)
|
|
||||||
}
|
|
||||||
panic("advance(p ptr, offset int): invalid arguments")
|
|
||||||
}
|
|
||||||
|
|
||||||
// func alloca(size uintptr) unsafe.Pointer
|
|
||||||
func (p *context) alloca(b llssa.Builder, args []ssa.Value) (ret llssa.Expr) {
|
|
||||||
if len(args) == 1 {
|
|
||||||
n := p.compileValue(b, args[0])
|
|
||||||
return b.Alloca(n)
|
|
||||||
}
|
|
||||||
panic("alloca(size uintptr): invalid arguments")
|
|
||||||
}
|
|
||||||
|
|
||||||
// func allocaCStr(s string) *int8
|
|
||||||
func (p *context) allocaCStr(b llssa.Builder, args []ssa.Value) (ret llssa.Expr) {
|
|
||||||
if len(args) == 1 {
|
|
||||||
s := p.compileValue(b, args[0])
|
|
||||||
return b.AllocaCStr(s)
|
|
||||||
}
|
|
||||||
panic("allocaCStr(s string): invalid arguments")
|
|
||||||
}
|
|
||||||
|
|
||||||
// func stringData(s string) *int8
|
|
||||||
func (p *context) stringData(b llssa.Builder, args []ssa.Value) (ret llssa.Expr) {
|
|
||||||
if len(args) == 1 {
|
|
||||||
s := p.compileValue(b, args[0])
|
|
||||||
return b.StringData(s)
|
|
||||||
}
|
|
||||||
panic("stringData(s string): invalid arguments")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *context) sigsetjmp(b llssa.Builder, args []ssa.Value) (ret llssa.Expr) {
|
|
||||||
if len(args) == 2 {
|
|
||||||
jb := p.compileValue(b, args[0])
|
|
||||||
savemask := p.compileValue(b, args[1])
|
|
||||||
return b.Sigsetjmp(jb, savemask)
|
|
||||||
}
|
|
||||||
panic("sigsetjmp(jb c.SigjmpBuf, savemask c.Int): invalid arguments")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *context) siglongjmp(b llssa.Builder, args []ssa.Value) {
|
|
||||||
if len(args) == 2 {
|
|
||||||
jb := p.compileValue(b, args[0])
|
|
||||||
retval := p.compileValue(b, args[1])
|
|
||||||
b.Siglongjmp(jb, retval)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
panic("siglongjmp(jb c.SigjmpBuf, retval c.Int): invalid arguments")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *context) atomic(b llssa.Builder, op llssa.AtomicOp, args []ssa.Value) (ret llssa.Expr) {
|
|
||||||
if len(args) == 2 {
|
|
||||||
addr := p.compileValue(b, args[0])
|
|
||||||
val := p.compileValue(b, args[1])
|
|
||||||
return b.Atomic(op, addr, val)
|
|
||||||
}
|
|
||||||
panic("atomicOp(addr *T, val T) T: invalid arguments")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *context) atomicLoad(b llssa.Builder, args []ssa.Value) llssa.Expr {
|
|
||||||
if len(args) == 1 {
|
|
||||||
addr := p.compileValue(b, args[0])
|
|
||||||
return b.Load(addr).SetOrdering(llssa.OrderingSeqConsistent)
|
|
||||||
}
|
|
||||||
panic("atomicLoad(addr *T) T: invalid arguments")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *context) atomicStore(b llssa.Builder, args []ssa.Value) {
|
|
||||||
if len(args) == 2 {
|
|
||||||
addr := p.compileValue(b, args[0])
|
|
||||||
val := p.compileValue(b, args[1])
|
|
||||||
b.Store(addr, val).SetOrdering(llssa.OrderingSeqConsistent)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
panic("atomicStore(addr *T, val T) T: invalid arguments")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *context) atomicCmpXchg(b llssa.Builder, args []ssa.Value) llssa.Expr {
|
|
||||||
if len(args) == 3 {
|
|
||||||
addr := p.compileValue(b, args[0])
|
|
||||||
old := p.compileValue(b, args[1])
|
|
||||||
new := p.compileValue(b, args[2])
|
|
||||||
return b.AtomicCmpXchg(addr, old, new)
|
|
||||||
}
|
|
||||||
panic("atomicCmpXchg(addr *T, old, new T) T: invalid arguments")
|
|
||||||
}
|
|
||||||
|
|
||||||
func isPhi(i ssa.Instruction) bool {
|
func isPhi(i ssa.Instruction) bool {
|
||||||
_, ok := i.(*ssa.Phi)
|
_, ok := i.(*ssa.Phi)
|
||||||
return ok
|
return ok
|
||||||
@@ -629,94 +420,6 @@ func (p *context) compilePhi(b llssa.Builder, v *ssa.Phi) (ret llssa.Expr) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *context) call(b llssa.Builder, act llssa.DoAction, call *ssa.CallCommon) (ret llssa.Expr) {
|
|
||||||
cv := call.Value
|
|
||||||
if mthd := call.Method; mthd != nil {
|
|
||||||
o := p.compileValue(b, cv)
|
|
||||||
fn := b.Imethod(o, mthd)
|
|
||||||
args := p.compileValues(b, call.Args, fnNormal)
|
|
||||||
ret = b.Do(act, fn, args...)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
kind := p.funcKind(cv)
|
|
||||||
if kind == fnIgnore {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
args := call.Args
|
|
||||||
if debugGoSSA {
|
|
||||||
log.Println(">>> Do", act, cv, args)
|
|
||||||
}
|
|
||||||
switch cv := cv.(type) {
|
|
||||||
case *ssa.Builtin:
|
|
||||||
fn := cv.Name()
|
|
||||||
if fn == "ssa:wrapnilchk" { // TODO(xsw): check nil ptr
|
|
||||||
arg := args[0]
|
|
||||||
ret = p.compileValue(b, arg)
|
|
||||||
} else {
|
|
||||||
args := p.compileValues(b, args, kind)
|
|
||||||
ret = b.Do(act, llssa.Builtin(fn), args...)
|
|
||||||
}
|
|
||||||
case *ssa.Function:
|
|
||||||
aFn, pyFn, ftype := p.compileFunction(cv)
|
|
||||||
// TODO(xsw): check ca != llssa.Call
|
|
||||||
switch ftype {
|
|
||||||
case cFunc:
|
|
||||||
p.inCFunc = true
|
|
||||||
args := p.compileValues(b, args, kind)
|
|
||||||
p.inCFunc = false
|
|
||||||
ret = b.Do(act, aFn.Expr, args...)
|
|
||||||
case goFunc:
|
|
||||||
args := p.compileValues(b, args, kind)
|
|
||||||
ret = b.Do(act, aFn.Expr, args...)
|
|
||||||
case pyFunc:
|
|
||||||
args := p.compileValues(b, args, kind)
|
|
||||||
ret = b.Do(act, pyFn.Expr, args...)
|
|
||||||
case llgoPyList:
|
|
||||||
args := p.compileValues(b, args, fnHasVArg)
|
|
||||||
ret = b.PyList(args...)
|
|
||||||
case llgoCstr:
|
|
||||||
ret = cstr(b, args)
|
|
||||||
case llgoAdvance:
|
|
||||||
ret = p.advance(b, args)
|
|
||||||
case llgoIndex:
|
|
||||||
ret = p.index(b, args)
|
|
||||||
case llgoAlloca:
|
|
||||||
ret = p.alloca(b, args)
|
|
||||||
case llgoAllocaCStr:
|
|
||||||
ret = p.allocaCStr(b, args)
|
|
||||||
case llgoStringData:
|
|
||||||
ret = p.stringData(b, args)
|
|
||||||
case llgoAtomicLoad:
|
|
||||||
ret = p.atomicLoad(b, args)
|
|
||||||
case llgoAtomicStore:
|
|
||||||
p.atomicStore(b, args)
|
|
||||||
case llgoAtomicCmpXchg:
|
|
||||||
ret = p.atomicCmpXchg(b, args)
|
|
||||||
case llgoSigsetjmp:
|
|
||||||
ret = p.sigsetjmp(b, args)
|
|
||||||
case llgoSiglongjmp:
|
|
||||||
p.siglongjmp(b, args)
|
|
||||||
case llgoSigjmpbuf: // func sigjmpbuf()
|
|
||||||
ret = b.AllocaSigjmpBuf()
|
|
||||||
case llgoDeferData: // func deferData() *Defer
|
|
||||||
ret = b.DeferData()
|
|
||||||
case llgoUnreachable: // func unreachable()
|
|
||||||
b.Unreachable()
|
|
||||||
default:
|
|
||||||
if ftype >= llgoAtomicOpBase && ftype <= llgoAtomicOpLast {
|
|
||||||
ret = p.atomic(b, llssa.AtomicOp(ftype-llgoAtomicOpBase), args)
|
|
||||||
} else {
|
|
||||||
log.Panicln("unknown ftype:", ftype)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
fn := p.compileValue(b, cv)
|
|
||||||
args := p.compileValues(b, args, kind)
|
|
||||||
ret = b.Do(act, fn, args...)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *context) compileInstrOrValue(b llssa.Builder, iv instrOrValue, asValue bool) (ret llssa.Expr) {
|
func (p *context) compileInstrOrValue(b llssa.Builder, iv instrOrValue, asValue bool) (ret llssa.Expr) {
|
||||||
if asValue {
|
if asValue {
|
||||||
if v, ok := p.bvals[iv]; ok {
|
if v, ok := p.bvals[iv]; ok {
|
||||||
@@ -1100,4 +803,15 @@ func processPkg(ctx *context, ret llssa.Package, pkg *ssa.Package) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func globalType(gbl *ssa.Global) types.Type {
|
||||||
|
t := gbl.Type()
|
||||||
|
if t, ok := t.(*types.Named); ok {
|
||||||
|
o := t.Obj()
|
||||||
|
if pkg := o.Pkg(); typepatch.IsPatched(pkg) {
|
||||||
|
return gbl.Pkg.Pkg.Scope().Lookup(o.Name()).Type()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -26,8 +26,9 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
llssa "github.com/goplus/llgo/ssa"
|
|
||||||
"golang.org/x/tools/go/ssa"
|
"golang.org/x/tools/go/ssa"
|
||||||
|
|
||||||
|
llssa "github.com/goplus/llgo/ssa"
|
||||||
)
|
)
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
@@ -462,7 +463,7 @@ func (p *context) varOf(b llssa.Builder, v *ssa.Global) llssa.Expr {
|
|||||||
}
|
}
|
||||||
ret := pkg.VarOf(name)
|
ret := pkg.VarOf(name)
|
||||||
if ret == nil {
|
if ret == nil {
|
||||||
ret = pkg.NewVar(name, v.Type(), llssa.Background(vtype))
|
ret = pkg.NewVar(name, globalType(v), llssa.Background(vtype))
|
||||||
}
|
}
|
||||||
return ret.Expr
|
return ret.Expr
|
||||||
}
|
}
|
||||||
|
|||||||
333
cl/instr.go
Normal file
333
cl/instr.go
Normal file
@@ -0,0 +1,333 @@
|
|||||||
|
/*
|
||||||
|
* 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 cl
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go/constant"
|
||||||
|
"go/types"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"golang.org/x/tools/go/ssa"
|
||||||
|
|
||||||
|
llssa "github.com/goplus/llgo/ssa"
|
||||||
|
)
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// func cstr(string) *int8
|
||||||
|
func cstr(b llssa.Builder, args []ssa.Value) (ret llssa.Expr) {
|
||||||
|
if len(args) == 1 {
|
||||||
|
if c, ok := args[0].(*ssa.Const); ok {
|
||||||
|
if v := c.Value; v.Kind() == constant.String {
|
||||||
|
sv := constant.StringVal(v)
|
||||||
|
return b.CStr(sv)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
panic("cstr(<string-literal>): invalid arguments")
|
||||||
|
}
|
||||||
|
|
||||||
|
// func index(arr *T, idx int) T
|
||||||
|
func (p *context) index(b llssa.Builder, args []ssa.Value) (ret llssa.Expr) {
|
||||||
|
return b.Load(p.advance(b, args))
|
||||||
|
}
|
||||||
|
|
||||||
|
// func advance(ptr *T, offset int) *T
|
||||||
|
func (p *context) advance(b llssa.Builder, args []ssa.Value) (ret llssa.Expr) {
|
||||||
|
if len(args) == 2 {
|
||||||
|
ptr := p.compileValue(b, args[0])
|
||||||
|
offset := p.compileValue(b, args[1])
|
||||||
|
return b.Advance(ptr, offset)
|
||||||
|
}
|
||||||
|
panic("advance(p ptr, offset int): invalid arguments")
|
||||||
|
}
|
||||||
|
|
||||||
|
// func alloca(size uintptr) unsafe.Pointer
|
||||||
|
func (p *context) alloca(b llssa.Builder, args []ssa.Value) (ret llssa.Expr) {
|
||||||
|
if len(args) == 1 {
|
||||||
|
n := p.compileValue(b, args[0])
|
||||||
|
return b.Alloca(n)
|
||||||
|
}
|
||||||
|
panic("alloca(size uintptr): invalid arguments")
|
||||||
|
}
|
||||||
|
|
||||||
|
// func allocaCStr(s string) *int8
|
||||||
|
func (p *context) allocaCStr(b llssa.Builder, args []ssa.Value) (ret llssa.Expr) {
|
||||||
|
if len(args) == 1 {
|
||||||
|
s := p.compileValue(b, args[0])
|
||||||
|
return b.AllocaCStr(s)
|
||||||
|
}
|
||||||
|
panic("allocaCStr(s string): invalid arguments")
|
||||||
|
}
|
||||||
|
|
||||||
|
// func stringData(s string) *int8
|
||||||
|
func (p *context) stringData(b llssa.Builder, args []ssa.Value) (ret llssa.Expr) {
|
||||||
|
if len(args) == 1 {
|
||||||
|
s := p.compileValue(b, args[0])
|
||||||
|
return b.StringData(s)
|
||||||
|
}
|
||||||
|
panic("stringData(s string): invalid arguments")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *context) sigsetjmp(b llssa.Builder, args []ssa.Value) (ret llssa.Expr) {
|
||||||
|
if len(args) == 2 {
|
||||||
|
jb := p.compileValue(b, args[0])
|
||||||
|
savemask := p.compileValue(b, args[1])
|
||||||
|
return b.Sigsetjmp(jb, savemask)
|
||||||
|
}
|
||||||
|
panic("sigsetjmp(jb c.SigjmpBuf, savemask c.Int): invalid arguments")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *context) siglongjmp(b llssa.Builder, args []ssa.Value) {
|
||||||
|
if len(args) == 2 {
|
||||||
|
jb := p.compileValue(b, args[0])
|
||||||
|
retval := p.compileValue(b, args[1])
|
||||||
|
b.Siglongjmp(jb, retval)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
panic("siglongjmp(jb c.SigjmpBuf, retval c.Int): invalid arguments")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *context) atomic(b llssa.Builder, op llssa.AtomicOp, args []ssa.Value) (ret llssa.Expr) {
|
||||||
|
if len(args) == 2 {
|
||||||
|
addr := p.compileValue(b, args[0])
|
||||||
|
val := p.compileValue(b, args[1])
|
||||||
|
return b.Atomic(op, addr, val)
|
||||||
|
}
|
||||||
|
panic("atomicOp(addr *T, val T) T: invalid arguments")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *context) atomicLoad(b llssa.Builder, args []ssa.Value) llssa.Expr {
|
||||||
|
if len(args) == 1 {
|
||||||
|
addr := p.compileValue(b, args[0])
|
||||||
|
return b.Load(addr).SetOrdering(llssa.OrderingSeqConsistent)
|
||||||
|
}
|
||||||
|
panic("atomicLoad(addr *T) T: invalid arguments")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *context) atomicStore(b llssa.Builder, args []ssa.Value) {
|
||||||
|
if len(args) == 2 {
|
||||||
|
addr := p.compileValue(b, args[0])
|
||||||
|
val := p.compileValue(b, args[1])
|
||||||
|
b.Store(addr, val).SetOrdering(llssa.OrderingSeqConsistent)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
panic("atomicStore(addr *T, val T) T: invalid arguments")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *context) atomicCmpXchg(b llssa.Builder, args []ssa.Value) llssa.Expr {
|
||||||
|
if len(args) == 3 {
|
||||||
|
addr := p.compileValue(b, args[0])
|
||||||
|
old := p.compileValue(b, args[1])
|
||||||
|
new := p.compileValue(b, args[2])
|
||||||
|
return b.AtomicCmpXchg(addr, old, new)
|
||||||
|
}
|
||||||
|
panic("atomicCmpXchg(addr *T, old, new T) T: invalid arguments")
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
var llgoInstrs = map[string]int{
|
||||||
|
"cstr": llgoCstr,
|
||||||
|
"advance": llgoAdvance,
|
||||||
|
"index": llgoIndex,
|
||||||
|
"alloca": llgoAlloca,
|
||||||
|
"allocaCStr": llgoAllocaCStr,
|
||||||
|
"stringData": llgoStringData,
|
||||||
|
"pyList": llgoPyList,
|
||||||
|
"sigjmpbuf": llgoSigjmpbuf,
|
||||||
|
"sigsetjmp": llgoSigsetjmp,
|
||||||
|
"siglongjmp": llgoSiglongjmp,
|
||||||
|
"deferData": llgoDeferData,
|
||||||
|
"unreachable": llgoUnreachable,
|
||||||
|
|
||||||
|
"atomicLoad": llgoAtomicLoad,
|
||||||
|
"atomicStore": llgoAtomicStore,
|
||||||
|
"atomicCmpXchg": llgoAtomicCmpXchg,
|
||||||
|
|
||||||
|
"atomicXchg": int(llgoAtomicXchg),
|
||||||
|
"atomicAdd": int(llgoAtomicAdd),
|
||||||
|
"atomicSub": int(llgoAtomicSub),
|
||||||
|
"atomicAnd": int(llgoAtomicAnd),
|
||||||
|
"atomicNand": int(llgoAtomicNand),
|
||||||
|
"atomicOr": int(llgoAtomicOr),
|
||||||
|
"atomicXor": int(llgoAtomicXor),
|
||||||
|
"atomicMax": int(llgoAtomicMax),
|
||||||
|
"atomicMin": int(llgoAtomicMin),
|
||||||
|
"atomicUMax": int(llgoAtomicUMax),
|
||||||
|
"atomicUMin": int(llgoAtomicUMin),
|
||||||
|
}
|
||||||
|
|
||||||
|
// funcOf returns a function by name and set ftype = goFunc, cFunc, etc.
|
||||||
|
// or returns nil and set ftype = llgoCstr, llgoAlloca, llgoUnreachable, etc.
|
||||||
|
func (p *context) funcOf(fn *ssa.Function) (aFn llssa.Function, pyFn llssa.PyObjRef, ftype int) {
|
||||||
|
pkgTypes, name, ftype := p.funcName(fn, false)
|
||||||
|
switch ftype {
|
||||||
|
case pyFunc:
|
||||||
|
if kind, mod := pkgKindByScope(pkgTypes.Scope()); kind == PkgPyModule {
|
||||||
|
pkg := p.pkg
|
||||||
|
fnName := pysymPrefix + mod + "." + name
|
||||||
|
if pyFn = pkg.PyObjOf(fnName); pyFn == nil {
|
||||||
|
pyFn = pkg.PyNewFunc(fnName, fn.Signature, true)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ftype = ignoredFunc
|
||||||
|
case llgoInstr:
|
||||||
|
if ftype = llgoInstrs[name]; ftype == 0 {
|
||||||
|
panic("unknown llgo instruction: " + name)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
pkg := p.pkg
|
||||||
|
if aFn = pkg.FuncOf(name); aFn == nil {
|
||||||
|
if len(fn.FreeVars) > 0 {
|
||||||
|
return nil, nil, ignoredFunc
|
||||||
|
}
|
||||||
|
sig := fn.Signature
|
||||||
|
aFn = pkg.NewFuncEx(name, sig, llssa.Background(ftype), false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
const (
|
||||||
|
fnNormal = iota
|
||||||
|
fnHasVArg
|
||||||
|
fnIgnore
|
||||||
|
)
|
||||||
|
|
||||||
|
func (p *context) funcKind(vfn ssa.Value) int {
|
||||||
|
if fn, ok := vfn.(*ssa.Function); ok {
|
||||||
|
params := fn.Signature.Params()
|
||||||
|
n := params.Len()
|
||||||
|
if n == 0 {
|
||||||
|
if fn.Signature.Recv() == nil {
|
||||||
|
if fn.Name() == "init" && p.pkgNoInit(fn.Pkg.Pkg) {
|
||||||
|
return fnIgnore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
last := params.At(n - 1)
|
||||||
|
if last.Name() == llssa.NameValist {
|
||||||
|
return fnHasVArg
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fnNormal
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *context) pkgNoInit(pkg *types.Package) bool {
|
||||||
|
p.ensureLoaded(pkg)
|
||||||
|
if i, ok := p.loaded[pkg]; ok {
|
||||||
|
return i.kind >= PkgNoInit
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
func (p *context) call(b llssa.Builder, act llssa.DoAction, call *ssa.CallCommon) (ret llssa.Expr) {
|
||||||
|
cv := call.Value
|
||||||
|
if mthd := call.Method; mthd != nil {
|
||||||
|
o := p.compileValue(b, cv)
|
||||||
|
fn := b.Imethod(o, mthd)
|
||||||
|
args := p.compileValues(b, call.Args, fnNormal)
|
||||||
|
ret = b.Do(act, fn, args...)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
kind := p.funcKind(cv)
|
||||||
|
if kind == fnIgnore {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
args := call.Args
|
||||||
|
if debugGoSSA {
|
||||||
|
log.Println(">>> Do", act, cv, args)
|
||||||
|
}
|
||||||
|
switch cv := cv.(type) {
|
||||||
|
case *ssa.Builtin:
|
||||||
|
fn := cv.Name()
|
||||||
|
if fn == "ssa:wrapnilchk" { // TODO(xsw): check nil ptr
|
||||||
|
arg := args[0]
|
||||||
|
ret = p.compileValue(b, arg)
|
||||||
|
} else {
|
||||||
|
args := p.compileValues(b, args, kind)
|
||||||
|
ret = b.Do(act, llssa.Builtin(fn), args...)
|
||||||
|
}
|
||||||
|
case *ssa.Function:
|
||||||
|
aFn, pyFn, ftype := p.compileFunction(cv)
|
||||||
|
// TODO(xsw): check ca != llssa.Call
|
||||||
|
switch ftype {
|
||||||
|
case cFunc:
|
||||||
|
p.inCFunc = true
|
||||||
|
args := p.compileValues(b, args, kind)
|
||||||
|
p.inCFunc = false
|
||||||
|
ret = b.Do(act, aFn.Expr, args...)
|
||||||
|
case goFunc:
|
||||||
|
args := p.compileValues(b, args, kind)
|
||||||
|
ret = b.Do(act, aFn.Expr, args...)
|
||||||
|
case pyFunc:
|
||||||
|
args := p.compileValues(b, args, kind)
|
||||||
|
ret = b.Do(act, pyFn.Expr, args...)
|
||||||
|
case llgoPyList:
|
||||||
|
args := p.compileValues(b, args, fnHasVArg)
|
||||||
|
ret = b.PyList(args...)
|
||||||
|
case llgoCstr:
|
||||||
|
ret = cstr(b, args)
|
||||||
|
case llgoAdvance:
|
||||||
|
ret = p.advance(b, args)
|
||||||
|
case llgoIndex:
|
||||||
|
ret = p.index(b, args)
|
||||||
|
case llgoAlloca:
|
||||||
|
ret = p.alloca(b, args)
|
||||||
|
case llgoAllocaCStr:
|
||||||
|
ret = p.allocaCStr(b, args)
|
||||||
|
case llgoStringData:
|
||||||
|
ret = p.stringData(b, args)
|
||||||
|
case llgoAtomicLoad:
|
||||||
|
ret = p.atomicLoad(b, args)
|
||||||
|
case llgoAtomicStore:
|
||||||
|
p.atomicStore(b, args)
|
||||||
|
case llgoAtomicCmpXchg:
|
||||||
|
ret = p.atomicCmpXchg(b, args)
|
||||||
|
case llgoSigsetjmp:
|
||||||
|
ret = p.sigsetjmp(b, args)
|
||||||
|
case llgoSiglongjmp:
|
||||||
|
p.siglongjmp(b, args)
|
||||||
|
case llgoSigjmpbuf: // func sigjmpbuf()
|
||||||
|
ret = b.AllocaSigjmpBuf()
|
||||||
|
case llgoDeferData: // func deferData() *Defer
|
||||||
|
ret = b.DeferData()
|
||||||
|
case llgoUnreachable: // func unreachable()
|
||||||
|
b.Unreachable()
|
||||||
|
default:
|
||||||
|
if ftype >= llgoAtomicOpBase && ftype <= llgoAtomicOpLast {
|
||||||
|
ret = p.atomic(b, llssa.AtomicOp(ftype-llgoAtomicOpBase), args)
|
||||||
|
} else {
|
||||||
|
log.Panicln("unknown ftype:", ftype)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
fn := p.compileValue(b, cv)
|
||||||
|
args := p.compileValues(b, args, kind)
|
||||||
|
ret = b.Do(act, fn, args...)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
@@ -21,7 +21,6 @@ import (
|
|||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/goplus/llgo/c"
|
"github.com/goplus/llgo/c"
|
||||||
"github.com/goplus/llgo/c/pthread"
|
|
||||||
"github.com/goplus/llgo/c/pthread/sync"
|
"github.com/goplus/llgo/c/pthread/sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -31,29 +30,42 @@ const (
|
|||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
var onceParam pthread.Key
|
type Mutex sync.Mutex
|
||||||
|
|
||||||
func init() {
|
func (m *Mutex) Lock() {
|
||||||
onceParam.Create(nil)
|
if *(*c.Long)(unsafe.Pointer(m)) == 0 {
|
||||||
}
|
(*sync.Mutex)(m).Init(nil)
|
||||||
|
|
||||||
type Once sync.Once
|
|
||||||
|
|
||||||
func (o *Once) Do(f func()) {
|
|
||||||
ptr := c.Malloc(unsafe.Sizeof(f))
|
|
||||||
*(*func())(ptr) = f
|
|
||||||
onceParam.Set(ptr)
|
|
||||||
if *(*c.Long)(unsafe.Pointer(o)) == 0 { // try init
|
|
||||||
*(*sync.Once)(o) = sync.OnceInit
|
|
||||||
}
|
}
|
||||||
onceDo(o, func() {
|
(*sync.Mutex)(m).Lock()
|
||||||
ptr := onceParam.Get()
|
|
||||||
(*(*func())(ptr))()
|
|
||||||
c.Free(ptr)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//go:linkname onceDo C.pthread_once
|
func (m *Mutex) TryLock() bool {
|
||||||
func onceDo(o *Once, f func()) c.Int
|
if *(*c.Long)(unsafe.Pointer(m)) == 0 {
|
||||||
|
(*sync.Mutex)(m).Init(nil)
|
||||||
|
}
|
||||||
|
return (*sync.Mutex)(m).TryLock() == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Mutex) Unlock() {
|
||||||
|
(*sync.Mutex)(m).Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
type Once struct {
|
||||||
|
m Mutex
|
||||||
|
done bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Once) Do(f func()) {
|
||||||
|
if !o.done {
|
||||||
|
o.m.Lock()
|
||||||
|
defer o.m.Unlock()
|
||||||
|
if !o.done {
|
||||||
|
o.done = true
|
||||||
|
f()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -55,14 +55,32 @@ type iface struct {
|
|||||||
data unsafe.Pointer
|
data unsafe.Pointer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
tagPatched = 0x17
|
||||||
|
)
|
||||||
|
|
||||||
|
func IsPatched(pkg *types.Package) bool {
|
||||||
|
if pkg == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
p := (*typesPackage)(unsafe.Pointer(pkg))
|
||||||
|
return *(*uint8)(unsafe.Pointer(&p.complete)) == tagPatched
|
||||||
|
}
|
||||||
|
|
||||||
|
func setPatched(pkg *types.Package) {
|
||||||
|
p := (*typesPackage)(unsafe.Pointer(pkg))
|
||||||
|
*(*uint8)(unsafe.Pointer(&p.complete)) = tagPatched
|
||||||
|
}
|
||||||
|
|
||||||
func setScope(pkg *types.Package, scope *types.Scope) {
|
func setScope(pkg *types.Package, scope *types.Scope) {
|
||||||
p := (*typesPackage)(unsafe.Pointer(pkg))
|
p := (*typesPackage)(unsafe.Pointer(pkg))
|
||||||
p.scope = scope
|
p.scope = scope
|
||||||
}
|
}
|
||||||
|
|
||||||
func setPkg(o types.Object, pkg *types.Package) {
|
func setPkgAndParent(o types.Object, pkg *types.Package, parent *types.Scope) {
|
||||||
data := (*iface)(unsafe.Pointer(&o)).data
|
data := (*iface)(unsafe.Pointer(&o)).data
|
||||||
(*object)(data).pkg = pkg
|
(*object)(data).pkg = pkg
|
||||||
|
(*object)(data).parent = parent
|
||||||
}
|
}
|
||||||
|
|
||||||
func getElems(scope *types.Scope) map[string]types.Object {
|
func getElems(scope *types.Scope) map[string]types.Object {
|
||||||
@@ -87,10 +105,11 @@ func Pkg(pkg, alt *types.Package) *types.Package {
|
|||||||
|
|
||||||
altScope := alt.Scope()
|
altScope := alt.Scope()
|
||||||
for name, o := range getElems(altScope) {
|
for name, o := range getElems(altScope) {
|
||||||
setPkg(o, pkg)
|
setPkgAndParent(o, &ret, &scope)
|
||||||
elems[name] = o
|
elems[name] = o
|
||||||
}
|
}
|
||||||
setElems(&scope, elems)
|
setElems(&scope, elems)
|
||||||
setScope(&ret, &scope)
|
setScope(&ret, &scope)
|
||||||
|
setPatched(pkg)
|
||||||
return &ret
|
return &ret
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user