@@ -1,20 +1,24 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/goplus/llgo/c/sync"
|
||||
"github.com/goplus/llgo/c/sync/atomic"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var v int64 = 100
|
||||
ret := sync.FetchAndAdd(&v, 1)
|
||||
var v int64
|
||||
|
||||
atomic.Store(&v, 100)
|
||||
println("store:", atomic.Load(&v))
|
||||
|
||||
ret := atomic.Add(&v, 1)
|
||||
println("ret:", ret, "v:", v)
|
||||
|
||||
ret = sync.CompareAndXchg(&v, 100, 102)
|
||||
ret = atomic.CompareAndExchange(&v, 100, 102)
|
||||
println("ret:", ret, "vs 100, v:", v)
|
||||
|
||||
ret = sync.CompareAndXchg(&v, 101, 102)
|
||||
ret = atomic.CompareAndExchange(&v, 101, 102)
|
||||
println("ret:", ret, "vs 101, v:", v)
|
||||
|
||||
ret = sync.FetchAndSub(&v, 1)
|
||||
ret = atomic.Sub(&v, 1)
|
||||
println("ret:", ret, "v:", v)
|
||||
}
|
||||
|
||||
71
c/sync/atomic/atomic.go
Normal file
71
c/sync/atomic/atomic.go
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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 atomic
|
||||
|
||||
import (
|
||||
_ "unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
LLGoPackage = "decl"
|
||||
)
|
||||
|
||||
type integer interface {
|
||||
~int | ~uint | ~uintptr | ~int32 | ~uint32 | ~int64 | ~uint64
|
||||
}
|
||||
|
||||
// llgo:link Add llgo.atomicAdd
|
||||
func Add[T integer](ptr *T, v T) T { return v }
|
||||
|
||||
// llgo:link Sub llgo.atomicSub
|
||||
func Sub[T integer](ptr *T, v T) T { return v }
|
||||
|
||||
// llgo:link And llgo.atomicAnd
|
||||
func And[T integer](ptr *T, v T) T { return v }
|
||||
|
||||
// llgo:link NotAnd llgo.atomicNand
|
||||
func NotAnd[T integer](ptr *T, v T) T { return v }
|
||||
|
||||
// llgo:link Or llgo.atomicOr
|
||||
func Or[T integer](ptr *T, v T) T { return v }
|
||||
|
||||
// llgo:link Xor llgo.atomicXor
|
||||
func Xor[T integer](ptr *T, v T) T { return v }
|
||||
|
||||
// llgo:link Max llgo.atomicMax
|
||||
func Max[T integer](ptr *T, v T) T { return v }
|
||||
|
||||
// llgo:link Min llgo.atomicMin
|
||||
func Min[T integer](ptr *T, v T) T { return v }
|
||||
|
||||
// llgo:link UMax llgo.atomicUMax
|
||||
func UMax[T integer](ptr *T, v T) T { return v }
|
||||
|
||||
// llgo:link UMin llgo.atomicUMin
|
||||
func UMin[T integer](ptr *T, v T) T { return v }
|
||||
|
||||
// llgo:link Load llgo.atomicLoad
|
||||
func Load[T integer](ptr *T) T { return *ptr }
|
||||
|
||||
// llgo:link Store llgo.atomicStore
|
||||
func Store[T integer](ptr *T, v T) {}
|
||||
|
||||
// llgo:link Exchange llgo.atomicXchg
|
||||
func Exchange[T integer](ptr *T, v T) T { return v }
|
||||
|
||||
// llgo:link CompareAndExchange llgo.atomicCmpXchg
|
||||
func CompareAndExchange[T integer](ptr *T, old, new T) T { return old }
|
||||
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
* 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 sync
|
||||
|
||||
import (
|
||||
_ "unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
LLGoPackage = "decl"
|
||||
)
|
||||
|
||||
type integer interface {
|
||||
~int | ~uint | ~uintptr | ~int32 | ~uint32 | ~int64 | ~uint64
|
||||
}
|
||||
|
||||
// llgo:link FetchAndXchg llgo.atomicXchg
|
||||
func FetchAndXchg[T integer](ptr *T, v T) T { return v }
|
||||
|
||||
// llgo:link FetchAndAdd llgo.atomicAdd
|
||||
func FetchAndAdd[T integer](ptr *T, v T) T { return v }
|
||||
|
||||
// llgo:link FetchAndSub llgo.atomicSub
|
||||
func FetchAndSub[T integer](ptr *T, v T) T { return v }
|
||||
|
||||
// llgo:link FetchAndAnd llgo.atomicAnd
|
||||
func FetchAndAnd[T integer](ptr *T, v T) T { return v }
|
||||
|
||||
// llgo:link FetchAndNand llgo.atomicNand
|
||||
func FetchAndNand[T integer](ptr *T, v T) T { return v }
|
||||
|
||||
// llgo:link FetchAndOr llgo.atomicOr
|
||||
func FetchAndOr[T integer](ptr *T, v T) T { return v }
|
||||
|
||||
// llgo:link FetchAndXor llgo.atomicXor
|
||||
func FetchAndXor[T integer](ptr *T, v T) T { return v }
|
||||
|
||||
// llgo:link FetchAndMax llgo.atomicMax
|
||||
func FetchAndMax[T integer](ptr *T, v T) T { return v }
|
||||
|
||||
// llgo:link FetchAndMin llgo.atomicMin
|
||||
func FetchAndMin[T integer](ptr *T, v T) T { return v }
|
||||
|
||||
// llgo:link FetchAndUMax llgo.atomicUMax
|
||||
func FetchAndUMax[T integer](ptr *T, v T) T { return v }
|
||||
|
||||
// llgo:link FetchAndUMin llgo.atomicUMin
|
||||
func FetchAndUMin[T integer](ptr *T, v T) T { return v }
|
||||
|
||||
// llgo:link CompareAndXchg llgo.atomicCmpXchg
|
||||
func CompareAndXchg[T integer](ptr *T, old, new T) T { return old }
|
||||
@@ -2,20 +2,24 @@ package main
|
||||
|
||||
import (
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/sync"
|
||||
"github.com/goplus/llgo/c/sync/atomic"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var v int64 = 100
|
||||
sync.FetchAndAdd(&v, 1)
|
||||
c.Printf(c.Str("%ld\n"), v)
|
||||
var v int64
|
||||
|
||||
sync.CompareAndXchg(&v, 100, 102)
|
||||
c.Printf(c.Str("%ld\n"), v)
|
||||
atomic.Store(&v, 100)
|
||||
c.Printf(c.Str("store: %ld\n"), atomic.Load(&v))
|
||||
|
||||
sync.CompareAndXchg(&v, 101, 102)
|
||||
c.Printf(c.Str("%ld\n"), v)
|
||||
atomic.Add(&v, 1)
|
||||
c.Printf(c.Str("v: %ld\n"), v)
|
||||
|
||||
sync.FetchAndSub(&v, 1)
|
||||
c.Printf(c.Str("%ld\n"), v)
|
||||
atomic.CompareAndExchange(&v, 100, 102)
|
||||
c.Printf(c.Str("v: %ld\n"), v)
|
||||
|
||||
atomic.CompareAndExchange(&v, 101, 102)
|
||||
c.Printf(c.Str("v: %ld\n"), v)
|
||||
|
||||
atomic.Sub(&v, 1)
|
||||
c.Printf(c.Str("v: %ld\n"), v)
|
||||
}
|
||||
|
||||
@@ -4,10 +4,11 @@ source_filename = "main"
|
||||
@"main.init$guard" = global i1 false, align 1
|
||||
@__llgo_argc = global i32 0, align 4
|
||||
@__llgo_argv = global ptr null, align 8
|
||||
@0 = private unnamed_addr constant [5 x i8] c"%ld\0A\00", align 1
|
||||
@1 = private unnamed_addr constant [5 x i8] c"%ld\0A\00", align 1
|
||||
@2 = private unnamed_addr constant [5 x i8] c"%ld\0A\00", align 1
|
||||
@3 = private unnamed_addr constant [5 x i8] c"%ld\0A\00", align 1
|
||||
@0 = private unnamed_addr constant [12 x i8] c"store: %ld\0A\00", align 1
|
||||
@1 = private unnamed_addr constant [8 x i8] c"v: %ld\0A\00", align 1
|
||||
@2 = private unnamed_addr constant [8 x i8] c"v: %ld\0A\00", align 1
|
||||
@3 = private unnamed_addr constant [8 x i8] c"v: %ld\0A\00", align 1
|
||||
@4 = private unnamed_addr constant [8 x i8] c"v: %ld\0A\00", align 1
|
||||
|
||||
define void @main.init() {
|
||||
_llgo_0:
|
||||
@@ -29,19 +30,21 @@ _llgo_0:
|
||||
call void @"github.com/goplus/llgo/internal/runtime.init"()
|
||||
call void @main.init()
|
||||
%2 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64 8)
|
||||
store i64 100, ptr %2, align 4
|
||||
%3 = atomicrmw add ptr %2, i64 1 seq_cst, align 8
|
||||
%4 = load i64, ptr %2, align 4
|
||||
%5 = call i32 (ptr, ...) @printf(ptr @0, i64 %4)
|
||||
%6 = cmpxchg ptr %2, i64 100, i64 102 seq_cst seq_cst, align 8
|
||||
%7 = load i64, ptr %2, align 4
|
||||
%8 = call i32 (ptr, ...) @printf(ptr @1, i64 %7)
|
||||
%9 = cmpxchg ptr %2, i64 101, i64 102 seq_cst seq_cst, align 8
|
||||
%10 = load i64, ptr %2, align 4
|
||||
%11 = call i32 (ptr, ...) @printf(ptr @2, i64 %10)
|
||||
%12 = atomicrmw sub ptr %2, i64 1 seq_cst, align 8
|
||||
%13 = load i64, ptr %2, align 4
|
||||
%14 = call i32 (ptr, ...) @printf(ptr @3, i64 %13)
|
||||
store atomic i64 100, ptr %2 seq_cst, align 4
|
||||
%3 = load atomic i64, ptr %2 seq_cst, align 4
|
||||
%4 = call i32 (ptr, ...) @printf(ptr @0, i64 %3)
|
||||
%5 = atomicrmw add ptr %2, i64 1 seq_cst, align 8
|
||||
%6 = load i64, ptr %2, align 4
|
||||
%7 = call i32 (ptr, ...) @printf(ptr @1, i64 %6)
|
||||
%8 = cmpxchg ptr %2, i64 100, i64 102 seq_cst seq_cst, align 8
|
||||
%9 = load i64, ptr %2, align 4
|
||||
%10 = call i32 (ptr, ...) @printf(ptr @2, i64 %9)
|
||||
%11 = cmpxchg ptr %2, i64 101, i64 102 seq_cst seq_cst, align 8
|
||||
%12 = load i64, ptr %2, align 4
|
||||
%13 = call i32 (ptr, ...) @printf(ptr @3, i64 %12)
|
||||
%14 = atomicrmw sub ptr %2, i64 1 seq_cst, align 8
|
||||
%15 = load i64, ptr %2, align 4
|
||||
%16 = call i32 (ptr, ...) @printf(ptr @4, i64 %15)
|
||||
ret i32 0
|
||||
}
|
||||
|
||||
|
||||
@@ -140,6 +140,10 @@ func TestErrBuiltin(t *testing.T) {
|
||||
test("siglongjmp", func(ctx *context) { ctx.siglongjmp(nil, nil) })
|
||||
test("cstr(NoArgs)", func(ctx *context) { cstr(nil, nil) })
|
||||
test("cstr(Nonconst)", func(ctx *context) { cstr(nil, []ssa.Value{&ssa.Parameter{}}) })
|
||||
test("atomic", func(ctx *context) { ctx.atomic(nil, 0, nil) })
|
||||
test("atomicLoad", func(ctx *context) { ctx.atomicLoad(nil, nil) })
|
||||
test("atomicStore", func(ctx *context) { ctx.atomicStore(nil, nil) })
|
||||
test("atomicCmpXchg", func(ctx *context) { ctx.atomicCmpXchg(nil, nil) })
|
||||
}
|
||||
|
||||
func TestPkgNoInit(t *testing.T) {
|
||||
|
||||
@@ -318,7 +318,10 @@ var llgoInstrs = map[string]int{
|
||||
"deferData": llgoDeferData,
|
||||
"unreachable": llgoUnreachable,
|
||||
|
||||
"atomicLoad": llgoAtomicLoad,
|
||||
"atomicStore": llgoAtomicStore,
|
||||
"atomicCmpXchg": llgoAtomicCmpXchg,
|
||||
|
||||
"atomicXchg": int(llgoAtomicXchg),
|
||||
"atomicAdd": int(llgoAtomicAdd),
|
||||
"atomicSub": int(llgoAtomicSub),
|
||||
@@ -564,6 +567,24 @@ func (p *context) atomic(b llssa.Builder, op llssa.AtomicOp, args []ssa.Value) (
|
||||
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])
|
||||
@@ -677,6 +698,10 @@ func (p *context) call(b llssa.Builder, act llssa.DoAction, call *ssa.CallCommon
|
||||
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:
|
||||
|
||||
12
cl/import.go
12
cl/import.go
@@ -343,14 +343,18 @@ const (
|
||||
llgoAdvance = llgoInstrBase + 4
|
||||
llgoIndex = llgoInstrBase + 5
|
||||
llgoStringData = llgoInstrBase + 6
|
||||
llgoPyList = llgoInstrBase + 7
|
||||
llgoDeferData = llgoInstrBase + 7
|
||||
|
||||
llgoSigjmpbuf = llgoInstrBase + 0xa
|
||||
llgoSigsetjmp = llgoInstrBase + 0xb
|
||||
llgoSiglongjmp = llgoInstrBase + 0xc
|
||||
llgoDeferData = llgoInstrBase + 0xd
|
||||
|
||||
llgoAtomicCmpXchg = llgoInstrBase + 0xf
|
||||
llgoAtomicOpBase = llgoInstrBase + 0x10
|
||||
llgoPyList = llgoInstrBase + 0x10
|
||||
|
||||
llgoAtomicLoad = llgoInstrBase + 0x1d
|
||||
llgoAtomicStore = llgoInstrBase + 0x1e
|
||||
llgoAtomicCmpXchg = llgoInstrBase + 0x1f
|
||||
llgoAtomicOpBase = llgoInstrBase + 0x20
|
||||
|
||||
llgoAtomicXchg = llgoAtomicOpBase + llssa.OpXchg
|
||||
llgoAtomicAdd = llgoAtomicOpBase + llssa.OpAdd
|
||||
|
||||
18
ssa/expr.go
18
ssa/expr.go
@@ -27,6 +27,18 @@ import (
|
||||
"github.com/goplus/llvm"
|
||||
)
|
||||
|
||||
type AtomicOrdering = llvm.AtomicOrdering
|
||||
|
||||
const (
|
||||
OrderingNotAtomic = llvm.AtomicOrderingNotAtomic
|
||||
OrderingUnordered = llvm.AtomicOrderingUnordered
|
||||
OrderingMonotonic = llvm.AtomicOrderingMonotonic
|
||||
OrderingAcquire = llvm.AtomicOrderingAcquire
|
||||
OrderingRelease = llvm.AtomicOrderingRelease
|
||||
OrderingAcquireRelease = llvm.AtomicOrderingAcquireRelease
|
||||
OrderingSeqConsistent = llvm.AtomicOrderingSequentiallyConsistent
|
||||
)
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
type Expr struct {
|
||||
@@ -41,6 +53,12 @@ func (v Expr) IsNil() bool {
|
||||
return v.Type == nil
|
||||
}
|
||||
|
||||
// SetOrdering sets the ordering of the atomic operation.
|
||||
func (v Expr) SetOrdering(ordering AtomicOrdering) Expr {
|
||||
v.impl.SetOrdering(ordering)
|
||||
return v
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
type builtinTy struct {
|
||||
|
||||
@@ -26,46 +26,6 @@ import (
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Advance returns the pointer ptr advanced by offset.
|
||||
func (b Builder) Advance(ptr Expr, offset Expr) Expr {
|
||||
if debugInstr {
|
||||
log.Printf("Advance %v, %v\n", ptr.impl, offset.impl)
|
||||
}
|
||||
var elem llvm.Type
|
||||
var prog = b.Prog
|
||||
switch t := ptr.raw.Type.(type) {
|
||||
case *types.Basic: // void
|
||||
elem = prog.tyInt8()
|
||||
default:
|
||||
elem = prog.rawType(t.(*types.Pointer).Elem()).ll
|
||||
}
|
||||
ret := llvm.CreateGEP(b.impl, elem, ptr.impl, []llvm.Value{offset.impl})
|
||||
return Expr{ret, ptr.Type}
|
||||
}
|
||||
|
||||
// Load returns the value at the pointer ptr.
|
||||
func (b Builder) Load(ptr Expr) Expr {
|
||||
if debugInstr {
|
||||
log.Printf("Load %v\n", ptr.impl)
|
||||
}
|
||||
if ptr.kind == vkPyVarRef {
|
||||
return b.pyLoad(ptr)
|
||||
}
|
||||
telem := b.Prog.Elem(ptr.Type)
|
||||
return Expr{llvm.CreateLoad(b.impl, telem.ll, ptr.impl), telem}
|
||||
}
|
||||
|
||||
// Store stores val at the pointer ptr.
|
||||
func (b Builder) Store(ptr, val Expr) Builder {
|
||||
raw := ptr.raw.Type
|
||||
if debugInstr {
|
||||
log.Printf("Store %v, %v, %v\n", raw, ptr.impl, val.impl)
|
||||
}
|
||||
val = checkExpr(val, raw.(*types.Pointer).Elem(), b)
|
||||
b.impl.CreateStore(val.impl, ptr.impl)
|
||||
return b
|
||||
}
|
||||
|
||||
func (b Builder) aggregateAllocU(t Type, flds ...llvm.Value) llvm.Value {
|
||||
prog := b.Prog
|
||||
size := prog.SizeOf(t)
|
||||
@@ -295,4 +255,43 @@ func (b Builder) AtomicCmpXchg(ptr, old, new Expr) Expr {
|
||||
return Expr{ret, t}
|
||||
}
|
||||
|
||||
// Load returns the value at the pointer ptr.
|
||||
func (b Builder) Load(ptr Expr) Expr {
|
||||
if debugInstr {
|
||||
log.Printf("Load %v\n", ptr.impl)
|
||||
}
|
||||
if ptr.kind == vkPyVarRef {
|
||||
return b.pyLoad(ptr)
|
||||
}
|
||||
telem := b.Prog.Elem(ptr.Type)
|
||||
return Expr{llvm.CreateLoad(b.impl, telem.ll, ptr.impl), telem}
|
||||
}
|
||||
|
||||
// Store stores val at the pointer ptr.
|
||||
func (b Builder) Store(ptr, val Expr) Expr {
|
||||
raw := ptr.raw.Type
|
||||
if debugInstr {
|
||||
log.Printf("Store %v, %v, %v\n", raw, ptr.impl, val.impl)
|
||||
}
|
||||
val = checkExpr(val, raw.(*types.Pointer).Elem(), b)
|
||||
return Expr{b.impl.CreateStore(val.impl, ptr.impl), b.Prog.Void()}
|
||||
}
|
||||
|
||||
// Advance returns the pointer ptr advanced by offset.
|
||||
func (b Builder) Advance(ptr Expr, offset Expr) Expr {
|
||||
if debugInstr {
|
||||
log.Printf("Advance %v, %v\n", ptr.impl, offset.impl)
|
||||
}
|
||||
var elem llvm.Type
|
||||
var prog = b.Prog
|
||||
switch t := ptr.raw.Type.(type) {
|
||||
case *types.Basic: // void
|
||||
elem = prog.tyInt8()
|
||||
default:
|
||||
elem = prog.rawType(t.(*types.Pointer).Elem()).ll
|
||||
}
|
||||
ret := llvm.CreateGEP(b.impl, elem, ptr.impl, []llvm.Value{offset.impl})
|
||||
return Expr{ret, ptr.Type}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user