Merge pull request #333 from xushiwei/q
patch sync/atomic; typepatch fix (don't change types)
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/atomic](https://pkg.go.dev/sync/atomic) (partially)
|
||||||
|
|
||||||
|
|
||||||
## How to install
|
## How to install
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
package atomic
|
package atomic
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"unsafe"
|
||||||
_ "unsafe"
|
_ "unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -24,48 +25,48 @@ const (
|
|||||||
LLGoPackage = "decl"
|
LLGoPackage = "decl"
|
||||||
)
|
)
|
||||||
|
|
||||||
type integer interface {
|
type valtype interface {
|
||||||
~int | ~uint | ~uintptr | ~int32 | ~uint32 | ~int64 | ~uint64
|
~int | ~uint | ~uintptr | ~int32 | ~uint32 | ~int64 | ~uint64 | ~unsafe.Pointer
|
||||||
}
|
}
|
||||||
|
|
||||||
// llgo:link Add llgo.atomicAdd
|
// llgo:link Add llgo.atomicAdd
|
||||||
func Add[T integer](ptr *T, v T) T { return v }
|
func Add[T valtype](ptr *T, v T) T { return v }
|
||||||
|
|
||||||
// llgo:link Sub llgo.atomicSub
|
// llgo:link Sub llgo.atomicSub
|
||||||
func Sub[T integer](ptr *T, v T) T { return v }
|
func Sub[T valtype](ptr *T, v T) T { return v }
|
||||||
|
|
||||||
// llgo:link And llgo.atomicAnd
|
// llgo:link And llgo.atomicAnd
|
||||||
func And[T integer](ptr *T, v T) T { return v }
|
func And[T valtype](ptr *T, v T) T { return v }
|
||||||
|
|
||||||
// llgo:link NotAnd llgo.atomicNand
|
// llgo:link NotAnd llgo.atomicNand
|
||||||
func NotAnd[T integer](ptr *T, v T) T { return v }
|
func NotAnd[T valtype](ptr *T, v T) T { return v }
|
||||||
|
|
||||||
// llgo:link Or llgo.atomicOr
|
// llgo:link Or llgo.atomicOr
|
||||||
func Or[T integer](ptr *T, v T) T { return v }
|
func Or[T valtype](ptr *T, v T) T { return v }
|
||||||
|
|
||||||
// llgo:link Xor llgo.atomicXor
|
// llgo:link Xor llgo.atomicXor
|
||||||
func Xor[T integer](ptr *T, v T) T { return v }
|
func Xor[T valtype](ptr *T, v T) T { return v }
|
||||||
|
|
||||||
// llgo:link Max llgo.atomicMax
|
// llgo:link Max llgo.atomicMax
|
||||||
func Max[T integer](ptr *T, v T) T { return v }
|
func Max[T valtype](ptr *T, v T) T { return v }
|
||||||
|
|
||||||
// llgo:link Min llgo.atomicMin
|
// llgo:link Min llgo.atomicMin
|
||||||
func Min[T integer](ptr *T, v T) T { return v }
|
func Min[T valtype](ptr *T, v T) T { return v }
|
||||||
|
|
||||||
// llgo:link UMax llgo.atomicUMax
|
// llgo:link UMax llgo.atomicUMax
|
||||||
func UMax[T integer](ptr *T, v T) T { return v }
|
func UMax[T valtype](ptr *T, v T) T { return v }
|
||||||
|
|
||||||
// llgo:link UMin llgo.atomicUMin
|
// llgo:link UMin llgo.atomicUMin
|
||||||
func UMin[T integer](ptr *T, v T) T { return v }
|
func UMin[T valtype](ptr *T, v T) T { return v }
|
||||||
|
|
||||||
// llgo:link Load llgo.atomicLoad
|
// llgo:link Load llgo.atomicLoad
|
||||||
func Load[T integer](ptr *T) T { return *ptr }
|
func Load[T valtype](ptr *T) T { return *ptr }
|
||||||
|
|
||||||
// llgo:link Store llgo.atomicStore
|
// llgo:link Store llgo.atomicStore
|
||||||
func Store[T integer](ptr *T, v T) {}
|
func Store[T valtype](ptr *T, v T) {}
|
||||||
|
|
||||||
// llgo:link Exchange llgo.atomicXchg
|
// llgo:link Exchange llgo.atomicXchg
|
||||||
func Exchange[T integer](ptr *T, v T) T { return v }
|
func Exchange[T valtype](ptr *T, v T) T { return v }
|
||||||
|
|
||||||
// llgo:link CompareAndExchange llgo.atomicCmpXchg
|
// llgo:link CompareAndExchange llgo.atomicCmpXchg
|
||||||
func CompareAndExchange[T integer](ptr *T, old, new T) (T, bool) { return old, false }
|
func CompareAndExchange[T valtype](ptr *T, old, new T) (T, bool) { return old, false }
|
||||||
|
|||||||
@@ -5,6 +5,20 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
var v int64 = 100
|
var v int64
|
||||||
println(atomic.AddInt64(&v, 1))
|
|
||||||
|
atomic.StoreInt64(&v, 100)
|
||||||
|
println("store:", atomic.LoadInt64(&v))
|
||||||
|
|
||||||
|
ret := atomic.AddInt64(&v, 1)
|
||||||
|
println("ret:", ret, "v:", v)
|
||||||
|
|
||||||
|
swp := atomic.CompareAndSwapInt64(&v, 100, 102)
|
||||||
|
println("swp:", swp, "v:", v)
|
||||||
|
|
||||||
|
swp = atomic.CompareAndSwapInt64(&v, 101, 102)
|
||||||
|
println("swp:", swp, "v:", v)
|
||||||
|
|
||||||
|
ret = atomic.AddInt64(&v, -1)
|
||||||
|
println("ret:", ret, "v:", v)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,15 @@
|
|||||||
; ModuleID = 'main'
|
; ModuleID = 'main'
|
||||||
source_filename = "main"
|
source_filename = "main"
|
||||||
|
|
||||||
|
%"github.com/goplus/llgo/internal/runtime.String" = type { ptr, i64 }
|
||||||
|
|
||||||
@"main.init$guard" = global i1 false, align 1
|
@"main.init$guard" = global i1 false, align 1
|
||||||
@__llgo_argc = global i32 0, align 4
|
@__llgo_argc = global i32 0, align 4
|
||||||
@__llgo_argv = global ptr null, align 8
|
@__llgo_argv = global ptr null, align 8
|
||||||
|
@0 = private unnamed_addr constant [6 x i8] c"store:", align 1
|
||||||
|
@1 = private unnamed_addr constant [4 x i8] c"ret:", align 1
|
||||||
|
@2 = private unnamed_addr constant [2 x i8] c"v:", align 1
|
||||||
|
@3 = private unnamed_addr constant [4 x i8] c"swp:", align 1
|
||||||
|
|
||||||
define void @main.init() {
|
define void @main.init() {
|
||||||
_llgo_0:
|
_llgo_0:
|
||||||
@@ -26,10 +32,106 @@ _llgo_0:
|
|||||||
call void @"github.com/goplus/llgo/internal/runtime.init"()
|
call void @"github.com/goplus/llgo/internal/runtime.init"()
|
||||||
call void @main.init()
|
call void @main.init()
|
||||||
%2 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64 8)
|
%2 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64 8)
|
||||||
store i64 100, ptr %2, align 4
|
call void @"sync/atomic.StoreInt64"(ptr %2, i64 100)
|
||||||
%3 = call i64 @"sync/atomic.AddInt64"(ptr %2, i64 1)
|
%3 = call i64 @"sync/atomic.LoadInt64"(ptr %2)
|
||||||
|
%4 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
|
||||||
|
%5 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %4, i32 0, i32 0
|
||||||
|
store ptr @0, ptr %5, align 8
|
||||||
|
%6 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %4, i32 0, i32 1
|
||||||
|
store i64 6, ptr %6, align 4
|
||||||
|
%7 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %4, align 8
|
||||||
|
call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %7)
|
||||||
|
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 32)
|
||||||
call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 %3)
|
call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 %3)
|
||||||
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10)
|
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10)
|
||||||
|
%8 = call i64 @"sync/atomic.AddInt64"(ptr %2, i64 1)
|
||||||
|
%9 = load i64, ptr %2, align 4
|
||||||
|
%10 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
|
||||||
|
%11 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %10, i32 0, i32 0
|
||||||
|
store ptr @1, ptr %11, align 8
|
||||||
|
%12 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %10, i32 0, i32 1
|
||||||
|
store i64 4, ptr %12, align 4
|
||||||
|
%13 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %10, align 8
|
||||||
|
%14 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
|
||||||
|
%15 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %14, i32 0, i32 0
|
||||||
|
store ptr @2, ptr %15, align 8
|
||||||
|
%16 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %14, i32 0, i32 1
|
||||||
|
store i64 2, ptr %16, align 4
|
||||||
|
%17 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %14, align 8
|
||||||
|
call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %13)
|
||||||
|
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 32)
|
||||||
|
call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 %8)
|
||||||
|
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 32)
|
||||||
|
call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %17)
|
||||||
|
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 32)
|
||||||
|
call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 %9)
|
||||||
|
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10)
|
||||||
|
%18 = call i1 @"sync/atomic.CompareAndSwapInt64"(ptr %2, i64 100, i64 102)
|
||||||
|
%19 = load i64, ptr %2, align 4
|
||||||
|
%20 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
|
||||||
|
%21 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %20, i32 0, i32 0
|
||||||
|
store ptr @3, ptr %21, align 8
|
||||||
|
%22 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %20, i32 0, i32 1
|
||||||
|
store i64 4, ptr %22, align 4
|
||||||
|
%23 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %20, align 8
|
||||||
|
%24 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
|
||||||
|
%25 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %24, i32 0, i32 0
|
||||||
|
store ptr @2, ptr %25, align 8
|
||||||
|
%26 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %24, i32 0, i32 1
|
||||||
|
store i64 2, ptr %26, align 4
|
||||||
|
%27 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %24, align 8
|
||||||
|
call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %23)
|
||||||
|
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 32)
|
||||||
|
call void @"github.com/goplus/llgo/internal/runtime.PrintBool"(i1 %18)
|
||||||
|
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 32)
|
||||||
|
call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %27)
|
||||||
|
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 32)
|
||||||
|
call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 %19)
|
||||||
|
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10)
|
||||||
|
%28 = call i1 @"sync/atomic.CompareAndSwapInt64"(ptr %2, i64 101, i64 102)
|
||||||
|
%29 = load i64, ptr %2, align 4
|
||||||
|
%30 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
|
||||||
|
%31 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %30, i32 0, i32 0
|
||||||
|
store ptr @3, ptr %31, align 8
|
||||||
|
%32 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %30, i32 0, i32 1
|
||||||
|
store i64 4, ptr %32, align 4
|
||||||
|
%33 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %30, align 8
|
||||||
|
%34 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
|
||||||
|
%35 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %34, i32 0, i32 0
|
||||||
|
store ptr @2, ptr %35, align 8
|
||||||
|
%36 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %34, i32 0, i32 1
|
||||||
|
store i64 2, ptr %36, align 4
|
||||||
|
%37 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %34, align 8
|
||||||
|
call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %33)
|
||||||
|
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 32)
|
||||||
|
call void @"github.com/goplus/llgo/internal/runtime.PrintBool"(i1 %28)
|
||||||
|
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 32)
|
||||||
|
call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %37)
|
||||||
|
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 32)
|
||||||
|
call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 %29)
|
||||||
|
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10)
|
||||||
|
%38 = call i64 @"sync/atomic.AddInt64"(ptr %2, i64 -1)
|
||||||
|
%39 = load i64, ptr %2, align 4
|
||||||
|
%40 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
|
||||||
|
%41 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %40, i32 0, i32 0
|
||||||
|
store ptr @1, ptr %41, align 8
|
||||||
|
%42 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %40, i32 0, i32 1
|
||||||
|
store i64 4, ptr %42, align 4
|
||||||
|
%43 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %40, align 8
|
||||||
|
%44 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
|
||||||
|
%45 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %44, i32 0, i32 0
|
||||||
|
store ptr @2, ptr %45, align 8
|
||||||
|
%46 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %44, i32 0, i32 1
|
||||||
|
store i64 2, ptr %46, align 4
|
||||||
|
%47 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %44, align 8
|
||||||
|
call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %43)
|
||||||
|
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 32)
|
||||||
|
call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 %38)
|
||||||
|
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 32)
|
||||||
|
call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %47)
|
||||||
|
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 32)
|
||||||
|
call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 %39)
|
||||||
|
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10)
|
||||||
ret i32 0
|
ret i32 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,8 +141,18 @@ declare void @"github.com/goplus/llgo/internal/runtime.init"()
|
|||||||
|
|
||||||
declare ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64)
|
declare ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64)
|
||||||
|
|
||||||
declare i64 @"sync/atomic.AddInt64"(ptr, i64)
|
declare void @"sync/atomic.StoreInt64"(ptr, i64)
|
||||||
|
|
||||||
|
declare i64 @"sync/atomic.LoadInt64"(ptr)
|
||||||
|
|
||||||
|
declare void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String")
|
||||||
|
|
||||||
|
declare void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8)
|
||||||
|
|
||||||
declare void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64)
|
declare void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64)
|
||||||
|
|
||||||
declare void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8)
|
declare i64 @"sync/atomic.AddInt64"(ptr, i64)
|
||||||
|
|
||||||
|
declare i1 @"sync/atomic.CompareAndSwapInt64"(ptr, i64, i64)
|
||||||
|
|
||||||
|
declare void @"github.com/goplus/llgo/internal/runtime.PrintBool"(i1)
|
||||||
|
|||||||
@@ -29,6 +29,8 @@ import (
|
|||||||
|
|
||||||
func TestCollectSkipNames(t *testing.T) {
|
func TestCollectSkipNames(t *testing.T) {
|
||||||
ctx := &context{skips: make(map[string]none)}
|
ctx := &context{skips: make(map[string]none)}
|
||||||
|
ctx.collectSkipNames("//llgo:skipall")
|
||||||
|
ctx.collectSkipNames("//llgo:skip")
|
||||||
ctx.collectSkipNames("//llgo:skip abs")
|
ctx.collectSkipNames("//llgo:skip abs")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,6 +220,13 @@ func TestErrImport(t *testing.T) {
|
|||||||
var ctx context
|
var ctx context
|
||||||
pkg := types.NewPackage("foo", "foo")
|
pkg := types.NewPackage("foo", "foo")
|
||||||
ctx.importPkg(pkg, nil)
|
ctx.importPkg(pkg, nil)
|
||||||
|
|
||||||
|
alt := types.NewPackage("bar", "bar")
|
||||||
|
alt.Scope().Insert(
|
||||||
|
types.NewConst(0, alt, "LLGoPackage", types.Typ[types.String], constant.MakeString("noinit")),
|
||||||
|
)
|
||||||
|
ctx.patches = Patches{"foo": &ssa.Package{Pkg: alt}}
|
||||||
|
ctx.importPkg(pkg, &pkgInfo{})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestErrInitLinkname(t *testing.T) {
|
func TestErrInitLinkname(t *testing.T) {
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/goplus/llgo/cl/blocks"
|
"github.com/goplus/llgo/cl/blocks"
|
||||||
|
"github.com/goplus/llgo/internal/typepatch"
|
||||||
llssa "github.com/goplus/llgo/ssa"
|
llssa "github.com/goplus/llgo/ssa"
|
||||||
"golang.org/x/tools/go/ssa"
|
"golang.org/x/tools/go/ssa"
|
||||||
)
|
)
|
||||||
@@ -143,6 +144,7 @@ type context struct {
|
|||||||
bvals map[ssa.Value]llssa.Expr // block values
|
bvals map[ssa.Value]llssa.Expr // block values
|
||||||
vargs map[*ssa.Alloc][]llssa.Expr // varargs
|
vargs map[*ssa.Alloc][]llssa.Expr // varargs
|
||||||
|
|
||||||
|
patches Patches
|
||||||
blkInfos []blocks.Info
|
blkInfos []blocks.Info
|
||||||
|
|
||||||
inits []func()
|
inits []func()
|
||||||
@@ -1000,33 +1002,41 @@ func (p *context) compileValues(b llssa.Builder, vals []ssa.Value, hasVArg int)
|
|||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Patches is patches of some packages.
|
||||||
|
type Patches = map[string]*ssa.Package
|
||||||
|
|
||||||
// NewPackage compiles a Go package to LLVM IR package.
|
// NewPackage compiles a Go package to LLVM IR package.
|
||||||
func NewPackage(prog llssa.Program, pkg *ssa.Package, files []*ast.File) (ret llssa.Package, err error) {
|
func NewPackage(prog llssa.Program, pkg *ssa.Package, files []*ast.File) (ret llssa.Package, err error) {
|
||||||
return NewPackageEx(prog, pkg, nil, files)
|
return NewPackageEx(prog, nil, pkg, files)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPackageEx compiles a Go package (pkg) to LLVM IR package.
|
// NewPackageEx compiles a Go package to LLVM IR package.
|
||||||
// The Go package may have an alternative package (alt).
|
func NewPackageEx(prog llssa.Program, patches Patches, pkg *ssa.Package, files []*ast.File) (ret llssa.Package, err error) {
|
||||||
// The pkg and alt have the same (Pkg *types.Package).
|
|
||||||
func NewPackageEx(prog llssa.Program, pkg, alt *ssa.Package, files []*ast.File) (ret llssa.Package, err error) {
|
|
||||||
pkgProg := pkg.Prog
|
pkgProg := pkg.Prog
|
||||||
pkgTypes := pkg.Pkg
|
pkgTypes := pkg.Pkg
|
||||||
pkgName, pkgPath := pkgTypes.Name(), llssa.PathOf(pkgTypes)
|
pkgName, pkgPath := pkgTypes.Name(), llssa.PathOf(pkgTypes)
|
||||||
|
alt, hasPatch := patches[pkgPath]
|
||||||
|
if hasPatch {
|
||||||
|
pkgTypes = typepatch.Pkg(pkgTypes, alt.Pkg)
|
||||||
|
pkg.Pkg = pkgTypes
|
||||||
|
alt.Pkg = pkgTypes
|
||||||
|
}
|
||||||
if pkgPath == llssa.PkgRuntime {
|
if pkgPath == llssa.PkgRuntime {
|
||||||
prog.SetRuntime(pkgTypes)
|
prog.SetRuntime(pkgTypes)
|
||||||
}
|
}
|
||||||
ret = prog.NewPackage(pkgName, pkgPath)
|
ret = prog.NewPackage(pkgName, pkgPath)
|
||||||
|
|
||||||
ctx := &context{
|
ctx := &context{
|
||||||
prog: prog,
|
prog: prog,
|
||||||
pkg: ret,
|
pkg: ret,
|
||||||
fset: pkgProg.Fset,
|
fset: pkgProg.Fset,
|
||||||
goProg: pkgProg,
|
goProg: pkgProg,
|
||||||
goTyps: pkgTypes,
|
goTyps: pkgTypes,
|
||||||
goPkg: pkg,
|
goPkg: pkg,
|
||||||
link: make(map[string]string),
|
patches: patches,
|
||||||
skips: make(map[string]none),
|
link: make(map[string]string),
|
||||||
vargs: make(map[*ssa.Alloc][]llssa.Expr),
|
skips: make(map[string]none),
|
||||||
|
vargs: make(map[*ssa.Alloc][]llssa.Expr),
|
||||||
loaded: map[*types.Package]*pkgInfo{
|
loaded: map[*types.Package]*pkgInfo{
|
||||||
types.Unsafe: {kind: PkgDeclOnly}, // TODO(xsw): PkgNoInit or PkgDeclOnly?
|
types.Unsafe: {kind: PkgDeclOnly}, // TODO(xsw): PkgNoInit or PkgDeclOnly?
|
||||||
},
|
},
|
||||||
@@ -1034,7 +1044,7 @@ func NewPackageEx(prog llssa.Program, pkg, alt *ssa.Package, files []*ast.File)
|
|||||||
ctx.initPyModule()
|
ctx.initPyModule()
|
||||||
ctx.initFiles(pkgPath, files)
|
ctx.initFiles(pkgPath, files)
|
||||||
|
|
||||||
if alt != nil {
|
if hasPatch {
|
||||||
skips := ctx.skips
|
skips := ctx.skips
|
||||||
ctx.skips = nil
|
ctx.skips = nil
|
||||||
processPkg(ctx, ret, alt)
|
processPkg(ctx, ret, alt)
|
||||||
|
|||||||
10
cl/import.go
10
cl/import.go
@@ -127,14 +127,22 @@ func pkgKindByScope(scope *types.Scope) (int, string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *context) importPkg(pkg *types.Package, i *pkgInfo) {
|
func (p *context) importPkg(pkg *types.Package, i *pkgInfo) {
|
||||||
|
pkgPath := llssa.PathOf(pkg)
|
||||||
scope := pkg.Scope()
|
scope := pkg.Scope()
|
||||||
kind, _ := pkgKindByScope(scope)
|
kind, _ := pkgKindByScope(scope)
|
||||||
if kind == PkgNormal {
|
if kind == PkgNormal {
|
||||||
|
if alt, ok := p.patches[pkgPath]; ok {
|
||||||
|
pkg = alt.Pkg
|
||||||
|
scope = pkg.Scope()
|
||||||
|
if kind, _ = pkgKindByScope(scope); kind != PkgNormal {
|
||||||
|
goto start
|
||||||
|
}
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
start:
|
||||||
i.kind = kind
|
i.kind = kind
|
||||||
fset := p.fset
|
fset := p.fset
|
||||||
pkgPath := llssa.PathOf(pkg)
|
|
||||||
names := scope.Names()
|
names := scope.Names()
|
||||||
syms := newPkgSymInfo()
|
syms := newPkgSymInfo()
|
||||||
for _, name := range names {
|
for _, name := range names {
|
||||||
|
|||||||
@@ -34,7 +34,6 @@ import (
|
|||||||
|
|
||||||
"github.com/goplus/llgo/cl"
|
"github.com/goplus/llgo/cl"
|
||||||
"github.com/goplus/llgo/internal/packages"
|
"github.com/goplus/llgo/internal/packages"
|
||||||
"github.com/goplus/llgo/internal/typepatch"
|
|
||||||
"github.com/goplus/llgo/xtool/clang"
|
"github.com/goplus/llgo/xtool/clang"
|
||||||
"github.com/goplus/llgo/xtool/env"
|
"github.com/goplus/llgo/xtool/env"
|
||||||
|
|
||||||
@@ -50,6 +49,10 @@ const (
|
|||||||
ModeRun
|
ModeRun
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
debugBuild = packages.DebugPackagesLoad
|
||||||
|
)
|
||||||
|
|
||||||
func needLLFile(mode Mode) bool {
|
func needLLFile(mode Mode) bool {
|
||||||
return mode != ModeBuild
|
return mode != ModeBuild
|
||||||
}
|
}
|
||||||
@@ -129,35 +132,25 @@ func Do(args []string, conf *Config) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
altPkgPaths := altPkgs(initial, llssa.PkgRuntime)
|
||||||
|
altPkgs, err := packages.LoadEx(dedup, sizes, cfg, altPkgPaths...)
|
||||||
|
check(err)
|
||||||
|
|
||||||
var needRt bool
|
var needRt bool
|
||||||
var rt []*packages.Package
|
|
||||||
load := func() []*packages.Package {
|
|
||||||
if rt == nil {
|
|
||||||
var err error
|
|
||||||
rt, err = packages.LoadEx(dedup, sizes, cfg, llssa.PkgRuntime, llssa.PkgPython)
|
|
||||||
check(err)
|
|
||||||
}
|
|
||||||
return rt
|
|
||||||
}
|
|
||||||
prog.SetRuntime(func() *types.Package {
|
prog.SetRuntime(func() *types.Package {
|
||||||
needRt = true
|
needRt = true
|
||||||
rt := load()
|
return altPkgs[0].Types
|
||||||
return rt[0].Types
|
|
||||||
})
|
})
|
||||||
prog.SetPython(func() *types.Package {
|
prog.SetPython(func() *types.Package {
|
||||||
rt := load()
|
return dedup.Check(llssa.PkgPython).Types
|
||||||
return rt[1].Types
|
|
||||||
})
|
})
|
||||||
|
|
||||||
imp := func(pkgPath string) *packages.Package {
|
|
||||||
if ret, e := packages.LoadEx(dedup, sizes, cfg, pkgPath); e == nil {
|
|
||||||
return ret[0]
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
progSSA := ssa.NewProgram(initial[0].Fset, ssaBuildMode)
|
progSSA := ssa.NewProgram(initial[0].Fset, ssaBuildMode)
|
||||||
pkgs := buildAllPkgs(prog, progSSA, imp, initial, nil, mode, verbose)
|
patches := make(cl.Patches, len(altPkgPaths))
|
||||||
|
altSSAPkgs(progSSA, patches, altPkgs[1:])
|
||||||
|
|
||||||
|
ctx := &context{progSSA, prog, dedup, patches, make(map[string]none), mode, verbose}
|
||||||
|
pkgs := buildAllPkgs(ctx, initial)
|
||||||
|
|
||||||
var runtimeFiles []string
|
var runtimeFiles []string
|
||||||
if needRt {
|
if needRt {
|
||||||
@@ -165,11 +158,7 @@ func Do(args []string, conf *Config) {
|
|||||||
llssa.SetDebug(0)
|
llssa.SetDebug(0)
|
||||||
cl.SetDebug(0)
|
cl.SetDebug(0)
|
||||||
|
|
||||||
skip := make(map[string]bool)
|
dpkg := buildAllPkgs(ctx, altPkgs[:1])
|
||||||
for _, v := range pkgs {
|
|
||||||
skip[v.PkgPath] = true
|
|
||||||
}
|
|
||||||
dpkg := buildAllPkgs(prog, progSSA, imp, rt[:1], skip, mode, verbose)
|
|
||||||
for _, pkg := range dpkg {
|
for _, pkg := range dpkg {
|
||||||
if !strings.HasSuffix(pkg.ExportFile, ".ll") {
|
if !strings.HasSuffix(pkg.ExportFile, ".ll") {
|
||||||
continue
|
continue
|
||||||
@@ -212,21 +201,33 @@ const (
|
|||||||
ssaBuildMode = ssa.SanityCheckFunctions
|
ssaBuildMode = ssa.SanityCheckFunctions
|
||||||
)
|
)
|
||||||
|
|
||||||
func buildAllPkgs(prog llssa.Program, progSSA *ssa.Program, imp importer, initial []*packages.Package, skip map[string]bool, mode Mode, verbose bool) (pkgs []*aPackage) {
|
type context struct {
|
||||||
// Create SSA-form program representation.
|
progSSA *ssa.Program
|
||||||
pkgs, errPkgs := allPkgs(progSSA, imp, initial, verbose)
|
prog llssa.Program
|
||||||
|
dedup packages.Deduper
|
||||||
|
patches cl.Patches
|
||||||
|
built map[string]none
|
||||||
|
mode Mode
|
||||||
|
verbose bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildAllPkgs(ctx *context, initial []*packages.Package) (pkgs []*aPackage) {
|
||||||
|
prog := ctx.prog
|
||||||
|
pkgs, errPkgs := allPkgs(ctx, initial)
|
||||||
for _, errPkg := range errPkgs {
|
for _, errPkg := range errPkgs {
|
||||||
for _, err := range errPkg.Errors {
|
for _, err := range errPkg.Errors {
|
||||||
fmt.Fprintln(os.Stderr, err)
|
fmt.Fprintln(os.Stderr, err)
|
||||||
}
|
}
|
||||||
fmt.Fprintln(os.Stderr, "cannot build SSA for package", errPkg)
|
fmt.Fprintln(os.Stderr, "cannot build SSA for package", errPkg)
|
||||||
}
|
}
|
||||||
|
built := ctx.built
|
||||||
for _, aPkg := range pkgs {
|
for _, aPkg := range pkgs {
|
||||||
pkg := aPkg.Package
|
pkg := aPkg.Package
|
||||||
if skip[pkg.PkgPath] {
|
if _, ok := built[pkg.PkgPath]; ok {
|
||||||
pkg.ExportFile = ""
|
pkg.ExportFile = ""
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
built[pkg.PkgPath] = none{}
|
||||||
switch kind, param := cl.PkgKindOf(pkg.Types); kind {
|
switch kind, param := cl.PkgKindOf(pkg.Types); kind {
|
||||||
case cl.PkgDeclOnly:
|
case cl.PkgDeclOnly:
|
||||||
// skip packages that only contain declarations
|
// skip packages that only contain declarations
|
||||||
@@ -277,7 +278,7 @@ func buildAllPkgs(prog llssa.Program, progSSA *ssa.Program, imp importer, initia
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
buildPkg(prog, aPkg, mode, verbose)
|
buildPkg(ctx, aPkg)
|
||||||
setNeedRuntimeOrPyInit(pkg, prog.NeedRuntime, prog.NeedPyInit)
|
setNeedRuntimeOrPyInit(pkg, prog.NeedRuntime, prog.NeedPyInit)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -375,27 +376,23 @@ func linkMainPkg(pkg *packages.Package, pkgs []*aPackage, runtimeFiles []string,
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildPkg(prog llssa.Program, aPkg *aPackage, mode Mode, verbose bool) {
|
func buildPkg(ctx *context, aPkg *aPackage) {
|
||||||
pkg := aPkg.Package
|
pkg := aPkg.Package
|
||||||
pkgPath := pkg.PkgPath
|
pkgPath := pkg.PkgPath
|
||||||
if verbose {
|
if debugBuild || ctx.verbose {
|
||||||
fmt.Fprintln(os.Stderr, pkgPath)
|
fmt.Fprintln(os.Stderr, pkgPath)
|
||||||
}
|
}
|
||||||
if canSkipToBuild(pkgPath) {
|
if canSkipToBuild(pkgPath) {
|
||||||
pkg.ExportFile = ""
|
pkg.ExportFile = ""
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
altSSA := aPkg.AltSSA
|
var syntax = pkg.Syntax
|
||||||
syntax := pkg.Syntax
|
|
||||||
if altPkg := aPkg.AltPkg; altPkg != nil {
|
if altPkg := aPkg.AltPkg; altPkg != nil {
|
||||||
syntax = append(syntax, altPkg.Syntax...)
|
syntax = append(syntax, altPkg.Syntax...)
|
||||||
if altSSA != nil {
|
|
||||||
altSSA.Pkg = typepatch.Pkg(pkg.Types, altPkg.Types)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ret, err := cl.NewPackageEx(prog, aPkg.SSA, altSSA, syntax)
|
ret, err := cl.NewPackageEx(ctx.prog, ctx.patches, aPkg.SSA, syntax)
|
||||||
check(err)
|
check(err)
|
||||||
if needLLFile(mode) {
|
if needLLFile(ctx.mode) {
|
||||||
pkg.ExportFile += ".ll"
|
pkg.ExportFile += ".ll"
|
||||||
os.WriteFile(pkg.ExportFile, []byte(ret.String()), 0644)
|
os.WriteFile(pkg.ExportFile, []byte(ret.String()), 0644)
|
||||||
}
|
}
|
||||||
@@ -404,7 +401,7 @@ func buildPkg(prog llssa.Program, aPkg *aPackage, mode Mode, verbose bool) {
|
|||||||
|
|
||||||
func canSkipToBuild(pkgPath string) bool {
|
func canSkipToBuild(pkgPath string) bool {
|
||||||
switch pkgPath {
|
switch pkgPath {
|
||||||
case "unsafe", "errors":
|
case "unsafe", "errors", "runtime", "sync": // TODO(xsw): remove it
|
||||||
return true
|
return true
|
||||||
default:
|
default:
|
||||||
return strings.HasPrefix(pkgPath, "internal/") ||
|
return strings.HasPrefix(pkgPath, "internal/") ||
|
||||||
@@ -412,14 +409,6 @@ func canSkipToBuild(pkgPath string) bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type aPackage struct {
|
|
||||||
*packages.Package
|
|
||||||
SSA *ssa.Package
|
|
||||||
AltPkg *packages.Package
|
|
||||||
AltSSA *ssa.Package
|
|
||||||
LPkg llssa.Package
|
|
||||||
}
|
|
||||||
|
|
||||||
type none struct{}
|
type none struct{}
|
||||||
|
|
||||||
var hasAltPkg = map[string]none{
|
var hasAltPkg = map[string]none{
|
||||||
@@ -429,26 +418,59 @@ var hasAltPkg = map[string]none{
|
|||||||
"runtime": {},
|
"runtime": {},
|
||||||
}
|
}
|
||||||
|
|
||||||
type importer = func(pkgPath string) *packages.Package
|
const (
|
||||||
|
altPkgPathPrefix = "github.com/goplus/llgo/internal/lib/"
|
||||||
|
)
|
||||||
|
|
||||||
func allPkgs(prog *ssa.Program, imp importer, initial []*packages.Package, verbose bool) (all []*aPackage, errs []*packages.Package) {
|
func altPkgs(initial []*packages.Package, alts ...string) []string {
|
||||||
packages.Visit(initial, nil, func(p *packages.Package) {
|
packages.Visit(initial, nil, func(p *packages.Package) {
|
||||||
if p.Types != nil && !p.IllTyped {
|
if p.Types != nil && !p.IllTyped {
|
||||||
var altPkg *packages.Package
|
if _, ok := hasAltPkg[p.PkgPath]; ok {
|
||||||
var altSSA *ssa.Package
|
alts = append(alts, altPkgPathPrefix+p.PkgPath)
|
||||||
var ssaPkg = createSSAPkg(prog, p)
|
}
|
||||||
if imp != nil {
|
}
|
||||||
if _, ok := hasAltPkg[p.PkgPath]; ok {
|
})
|
||||||
if verbose {
|
return alts
|
||||||
log.Println("==> Patching", p.PkgPath)
|
}
|
||||||
}
|
|
||||||
altPkgPath := "github.com/goplus/llgo/internal/lib/" + p.PkgPath
|
func altSSAPkgs(prog *ssa.Program, patches cl.Patches, alts []*packages.Package) {
|
||||||
if altPkg = imp(altPkgPath); altPkg != nil { // TODO(xsw): how to minimize import times
|
packages.Visit(alts, nil, func(p *packages.Package) {
|
||||||
altSSA = createAltSSAPkg(prog, altPkg)
|
if p.Types != nil && !p.IllTyped {
|
||||||
}
|
pkgSSA := prog.CreatePackage(p.Types, p.Syntax, p.TypesInfo, true)
|
||||||
|
if strings.HasPrefix(p.PkgPath, altPkgPathPrefix) {
|
||||||
|
path := p.PkgPath[len(altPkgPathPrefix):]
|
||||||
|
patches[path] = pkgSSA
|
||||||
|
if debugBuild {
|
||||||
|
log.Println("==> Patching", path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
all = append(all, &aPackage{p, ssaPkg, altPkg, altSSA, nil})
|
}
|
||||||
|
})
|
||||||
|
prog.Build()
|
||||||
|
}
|
||||||
|
|
||||||
|
type aPackage struct {
|
||||||
|
*packages.Package
|
||||||
|
SSA *ssa.Package
|
||||||
|
AltPkg *packages.Cached
|
||||||
|
LPkg llssa.Package
|
||||||
|
}
|
||||||
|
|
||||||
|
func allPkgs(ctx *context, initial []*packages.Package) (all []*aPackage, errs []*packages.Package) {
|
||||||
|
prog := ctx.progSSA
|
||||||
|
verbose := ctx.verbose
|
||||||
|
built := ctx.built
|
||||||
|
packages.Visit(initial, nil, func(p *packages.Package) {
|
||||||
|
if p.Types != nil && !p.IllTyped {
|
||||||
|
if _, ok := built[p.PkgPath]; ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var altPkg *packages.Cached
|
||||||
|
var ssaPkg = createSSAPkg(prog, p, verbose)
|
||||||
|
if _, ok := hasAltPkg[p.PkgPath]; ok {
|
||||||
|
altPkg = ctx.dedup.Check(altPkgPathPrefix + p.PkgPath)
|
||||||
|
}
|
||||||
|
all = append(all, &aPackage{p, ssaPkg, altPkg, nil})
|
||||||
} else {
|
} else {
|
||||||
errs = append(errs, p)
|
errs = append(errs, p)
|
||||||
}
|
}
|
||||||
@@ -456,22 +478,12 @@ func allPkgs(prog *ssa.Program, imp importer, initial []*packages.Package, verbo
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func createAltSSAPkg(prog *ssa.Program, alt *packages.Package) *ssa.Package {
|
func createSSAPkg(prog *ssa.Program, p *packages.Package, verbose bool) *ssa.Package {
|
||||||
altSSA := prog.ImportedPackage(alt.PkgPath)
|
|
||||||
if altSSA == nil {
|
|
||||||
packages.Visit([]*packages.Package{alt}, nil, func(p *packages.Package) {
|
|
||||||
if p.Types != nil && !p.IllTyped {
|
|
||||||
createSSAPkg(prog, p)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
altSSA = prog.ImportedPackage(alt.PkgPath)
|
|
||||||
}
|
|
||||||
return altSSA
|
|
||||||
}
|
|
||||||
|
|
||||||
func createSSAPkg(prog *ssa.Program, p *packages.Package) *ssa.Package {
|
|
||||||
pkgSSA := prog.ImportedPackage(p.PkgPath)
|
pkgSSA := prog.ImportedPackage(p.PkgPath)
|
||||||
if pkgSSA == nil {
|
if pkgSSA == nil {
|
||||||
|
if debugBuild || verbose {
|
||||||
|
log.Println("==> BuildSSA", p.PkgPath)
|
||||||
|
}
|
||||||
pkgSSA = prog.CreatePackage(p.Types, p.Syntax, p.TypesInfo, true)
|
pkgSSA = prog.CreatePackage(p.Types, p.Syntax, p.TypesInfo, true)
|
||||||
pkgSSA.Build() // TODO(xsw): build concurrently
|
pkgSSA.Build() // TODO(xsw): build concurrently
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,17 +16,125 @@
|
|||||||
|
|
||||||
package atomic
|
package atomic
|
||||||
|
|
||||||
|
// llgo:skipall
|
||||||
import (
|
import (
|
||||||
_ "unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
LLGoPackage = true
|
LLGoPackage = true
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:linkname cAddInt64 llgo.atomicAdd
|
type valtype interface {
|
||||||
func cAddInt64(addr *int64, delta int64) (old int64)
|
~int | ~uint | ~uintptr | ~int32 | ~uint32 | ~int64 | ~uint64 | ~unsafe.Pointer
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:linkname SwapInt32 llgo.atomicXchg
|
||||||
|
func SwapInt32(addr *int32, new int32) (old int32)
|
||||||
|
|
||||||
|
//go:linkname SwapInt64 llgo.atomicXchg
|
||||||
|
func SwapInt64(addr *int64, new int64) (old int64)
|
||||||
|
|
||||||
|
//go:linkname SwapUint32 llgo.atomicXchg
|
||||||
|
func SwapUint32(addr *uint32, new uint32) (old uint32)
|
||||||
|
|
||||||
|
//go:linkname SwapUint64 llgo.atomicXchg
|
||||||
|
func SwapUint64(addr *uint64, new uint64) (old uint64)
|
||||||
|
|
||||||
|
//go:linkname SwapUintptr llgo.atomicXchg
|
||||||
|
func SwapUintptr(addr *uintptr, new uintptr) (old uintptr)
|
||||||
|
|
||||||
|
//go:linkname SwapPointer llgo.atomicXchg
|
||||||
|
func SwapPointer(addr *unsafe.Pointer, new unsafe.Pointer) (old unsafe.Pointer)
|
||||||
|
|
||||||
|
// llgo:link atomicCmpXchg llgo.atomicCmpXchg
|
||||||
|
func atomicCmpXchg[T valtype](ptr *T, old, new T) (T, bool) { return old, false }
|
||||||
|
|
||||||
|
func CompareAndSwapInt32(addr *int32, old, new int32) (swapped bool) {
|
||||||
|
_, swapped = atomicCmpXchg(addr, old, new)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func CompareAndSwapInt64(addr *int64, old, new int64) (swapped bool) {
|
||||||
|
_, swapped = atomicCmpXchg(addr, old, new)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func CompareAndSwapUint32(addr *uint32, old, new uint32) (swapped bool) {
|
||||||
|
_, swapped = atomicCmpXchg(addr, old, new)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func CompareAndSwapUint64(addr *uint64, old, new uint64) (swapped bool) {
|
||||||
|
_, swapped = atomicCmpXchg(addr, old, new)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func CompareAndSwapUintptr(addr *uintptr, old, new uintptr) (swapped bool) {
|
||||||
|
_, swapped = atomicCmpXchg(addr, old, new)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func CompareAndSwapPointer(addr *unsafe.Pointer, old, new unsafe.Pointer) (swapped bool) {
|
||||||
|
_, swapped = atomicCmpXchg(addr, old, new)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// llgo:link atomicAdd llgo.atomicAdd
|
||||||
|
func atomicAdd[T valtype](ptr *T, v T) T { return v }
|
||||||
|
|
||||||
|
func AddInt32(addr *int32, delta int32) (new int32) {
|
||||||
|
return atomicAdd(addr, delta) + delta
|
||||||
|
}
|
||||||
|
|
||||||
|
func AddUint32(addr *uint32, delta uint32) (new uint32) {
|
||||||
|
return atomicAdd(addr, delta) + delta
|
||||||
|
}
|
||||||
|
|
||||||
func AddInt64(addr *int64, delta int64) (new int64) {
|
func AddInt64(addr *int64, delta int64) (new int64) {
|
||||||
return cAddInt64(addr, delta) + delta
|
return atomicAdd(addr, delta) + delta
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func AddUint64(addr *uint64, delta uint64) (new uint64) {
|
||||||
|
return atomicAdd(addr, delta) + delta
|
||||||
|
}
|
||||||
|
|
||||||
|
func AddUintptr(addr *uintptr, delta uintptr) (new uintptr) {
|
||||||
|
return atomicAdd(addr, delta) + delta
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:linkname LoadInt32 llgo.atomicLoad
|
||||||
|
func LoadInt32(addr *int32) (val int32)
|
||||||
|
|
||||||
|
//go:linkname LoadInt64 llgo.atomicLoad
|
||||||
|
func LoadInt64(addr *int64) (val int64)
|
||||||
|
|
||||||
|
//go:linkname LoadUint32 llgo.atomicLoad
|
||||||
|
func LoadUint32(addr *uint32) (val uint32)
|
||||||
|
|
||||||
|
//go:linkname LoadUint64 llgo.atomicLoad
|
||||||
|
func LoadUint64(addr *uint64) (val uint64)
|
||||||
|
|
||||||
|
//go:linkname LoadUintptr llgo.atomicLoad
|
||||||
|
func LoadUintptr(addr *uintptr) (val uintptr)
|
||||||
|
|
||||||
|
//go:linkname LoadPointer llgo.atomicLoad
|
||||||
|
func LoadPointer(addr *unsafe.Pointer) (val unsafe.Pointer)
|
||||||
|
|
||||||
|
//go:linkname StoreInt32 llgo.atomicStore
|
||||||
|
func StoreInt32(addr *int32, val int32)
|
||||||
|
|
||||||
|
//go:linkname StoreInt64 llgo.atomicStore
|
||||||
|
func StoreInt64(addr *int64, val int64)
|
||||||
|
|
||||||
|
//go:linkname StoreUint32 llgo.atomicStore
|
||||||
|
func StoreUint32(addr *uint32, val uint32)
|
||||||
|
|
||||||
|
//go:linkname StoreUint64 llgo.atomicStore
|
||||||
|
func StoreUint64(addr *uint64, val uint64)
|
||||||
|
|
||||||
|
//go:linkname StoreUintptr llgo.atomicStore
|
||||||
|
func StoreUintptr(addr *uintptr, val uintptr)
|
||||||
|
|
||||||
|
//go:linkname StorePointer llgo.atomicStore
|
||||||
|
func StorePointer(addr *unsafe.Pointer, val unsafe.Pointer)
|
||||||
|
|||||||
@@ -61,6 +61,10 @@ const (
|
|||||||
typecheckCgo = NeedModule - 1 // TODO(xsw): how to check
|
typecheckCgo = NeedModule - 1 // TODO(xsw): how to check
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
DebugPackagesLoad = false
|
||||||
|
)
|
||||||
|
|
||||||
// A Config specifies details about how packages should be loaded.
|
// A Config specifies details about how packages should be loaded.
|
||||||
// The zero value is a valid configuration.
|
// The zero value is a valid configuration.
|
||||||
// Calls to Load do not modify this struct.
|
// Calls to Load do not modify this struct.
|
||||||
@@ -99,7 +103,7 @@ type loader struct {
|
|||||||
requestedMode LoadMode
|
requestedMode LoadMode
|
||||||
}
|
}
|
||||||
|
|
||||||
type cachedPackage struct {
|
type Cached struct {
|
||||||
Types *types.Package
|
Types *types.Package
|
||||||
TypesInfo *types.Info
|
TypesInfo *types.Info
|
||||||
Syntax []*ast.File
|
Syntax []*ast.File
|
||||||
@@ -115,14 +119,20 @@ func NewDeduper() Deduper {
|
|||||||
return &aDeduper{}
|
return &aDeduper{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p Deduper) check(pkgPath string) *cachedPackage {
|
func (p Deduper) Check(pkgPath string) *Cached {
|
||||||
if v, ok := p.cache.Load(pkgPath); ok {
|
if v, ok := p.cache.Load(pkgPath); ok {
|
||||||
return v.(*cachedPackage)
|
if DebugPackagesLoad {
|
||||||
|
log.Println("==> dedup.check:", pkgPath)
|
||||||
|
}
|
||||||
|
return v.(*Cached)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p Deduper) set(pkgPath string, cp *cachedPackage) {
|
func (p Deduper) set(pkgPath string, cp *Cached) {
|
||||||
|
if DebugPackagesLoad {
|
||||||
|
log.Println("==> dedup.set:", pkgPath)
|
||||||
|
}
|
||||||
p.cache.Store(pkgPath, cp)
|
p.cache.Store(pkgPath, cp)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,7 +172,7 @@ func loadPackageEx(dedup Deduper, ld *loader, lpkg *loaderPackage) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if dedup != nil {
|
if dedup != nil {
|
||||||
if cp := dedup.check(lpkg.PkgPath); cp != nil {
|
if cp := dedup.Check(lpkg.PkgPath); cp != nil {
|
||||||
lpkg.Types = cp.Types
|
lpkg.Types = cp.Types
|
||||||
lpkg.Fset = ld.Fset
|
lpkg.Fset = ld.Fset
|
||||||
lpkg.TypesInfo = cp.TypesInfo
|
lpkg.TypesInfo = cp.TypesInfo
|
||||||
@@ -172,7 +182,7 @@ func loadPackageEx(dedup Deduper, ld *loader, lpkg *loaderPackage) {
|
|||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
if !lpkg.IllTyped && lpkg.needtypes && lpkg.needsrc {
|
if !lpkg.IllTyped && lpkg.needtypes && lpkg.needsrc {
|
||||||
dedup.set(lpkg.PkgPath, &cachedPackage{
|
dedup.set(lpkg.PkgPath, &Cached{
|
||||||
Types: lpkg.Types,
|
Types: lpkg.Types,
|
||||||
TypesInfo: lpkg.TypesInfo,
|
TypesInfo: lpkg.TypesInfo,
|
||||||
Syntax: lpkg.Syntax,
|
Syntax: lpkg.Syntax,
|
||||||
|
|||||||
@@ -22,6 +22,17 @@ import (
|
|||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type typesPackage struct {
|
||||||
|
path string
|
||||||
|
name string
|
||||||
|
scope *types.Scope
|
||||||
|
imports []*types.Package
|
||||||
|
complete bool
|
||||||
|
fake bool // scope lookup errors are silently dropped if package is fake (internal use only)
|
||||||
|
cgo bool // uses of this package will be rewritten into uses of declarations from _cgo_gotypes.go
|
||||||
|
goVersion string // minimum Go version required for package (by Config.GoVersion, typically from go.mod)
|
||||||
|
}
|
||||||
|
|
||||||
type typesScope struct {
|
type typesScope struct {
|
||||||
parent *types.Scope
|
parent *types.Scope
|
||||||
children []*types.Scope
|
children []*types.Scope
|
||||||
@@ -44,23 +55,42 @@ type iface struct {
|
|||||||
data unsafe.Pointer
|
data unsafe.Pointer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func setScope(pkg *types.Package, scope *types.Scope) {
|
||||||
|
p := (*typesPackage)(unsafe.Pointer(pkg))
|
||||||
|
p.scope = scope
|
||||||
|
}
|
||||||
|
|
||||||
func setPkg(o types.Object, pkg *types.Package) {
|
func setPkg(o types.Object, pkg *types.Package) {
|
||||||
data := (*iface)(unsafe.Pointer(&o)).data
|
data := (*iface)(unsafe.Pointer(&o)).data
|
||||||
(*object)(data).pkg = pkg
|
(*object)(data).pkg = pkg
|
||||||
}
|
}
|
||||||
|
|
||||||
func setObject(scope *types.Scope, name string, o types.Object) {
|
func getElems(scope *types.Scope) map[string]types.Object {
|
||||||
s := (*typesScope)(unsafe.Pointer(scope))
|
s := (*typesScope)(unsafe.Pointer(scope))
|
||||||
s.elems[name] = o
|
return s.elems
|
||||||
|
}
|
||||||
|
|
||||||
|
func setElems(scope *types.Scope, elems map[string]types.Object) {
|
||||||
|
s := (*typesScope)(unsafe.Pointer(scope))
|
||||||
|
s.elems = elems
|
||||||
}
|
}
|
||||||
|
|
||||||
func Pkg(pkg, alt *types.Package) *types.Package {
|
func Pkg(pkg, alt *types.Package) *types.Package {
|
||||||
scope := pkg.Scope()
|
ret := *pkg
|
||||||
altScope := alt.Scope()
|
scope := *pkg.Scope()
|
||||||
for _, name := range altScope.Names() {
|
|
||||||
o := altScope.Lookup(name)
|
old := getElems(&scope)
|
||||||
setPkg(o, pkg)
|
elems := make(map[string]types.Object, len(old))
|
||||||
setObject(scope, name, o)
|
for name, o := range old {
|
||||||
|
elems[name] = o
|
||||||
}
|
}
|
||||||
return pkg
|
|
||||||
|
altScope := alt.Scope()
|
||||||
|
for name, o := range getElems(altScope) {
|
||||||
|
setPkg(o, pkg)
|
||||||
|
elems[name] = o
|
||||||
|
}
|
||||||
|
setElems(&scope, elems)
|
||||||
|
setScope(&ret, &scope)
|
||||||
|
return &ret
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user