@@ -4,19 +4,17 @@ import (
4
4
"fmt"
5
5
"strings"
6
6
7
- "golang.org/x/tools/go/ssa"
8
7
"tinygo.org/x/go-llvm"
9
8
)
10
9
11
- // createAtomicOp lowers an atomic library call by lowering it as an LLVM atomic
12
- // operation. It returns the result of the operation and true if the call could
13
- // be lowered inline, and false otherwise.
14
- func (b * builder ) createAtomicOp (call * ssa.CallCommon ) (llvm.Value , bool ) {
15
- name := call .Value .(* ssa.Function ).Name ()
10
+ // createAtomicOp lowers a sync/atomic function by lowering it as an LLVM atomic
11
+ // operation. It returns the result of the operation, or a zero llvm.Value if
12
+ // the result is void.
13
+ func (b * builder ) createAtomicOp (name string ) llvm.Value {
16
14
switch name {
17
15
case "AddInt32" , "AddInt64" , "AddUint32" , "AddUint64" , "AddUintptr" :
18
- ptr := b .getValue (call . Args [0 ])
19
- val := b .getValue (call . Args [1 ])
16
+ ptr := b .getValue (b . fn . Params [0 ])
17
+ val := b .getValue (b . fn . Params [1 ])
20
18
if strings .HasPrefix (b .Triple , "avr" ) {
21
19
// AtomicRMW does not work on AVR as intended:
22
20
// - There are some register allocation issues (fixed by https://reviews.llvm.org/D97127 which is not yet in a usable LLVM release)
@@ -29,41 +27,42 @@ func (b *builder) createAtomicOp(call *ssa.CallCommon) (llvm.Value, bool) {
29
27
}
30
28
oldVal := b .createCall (fn , []llvm.Value {ptr , val }, "" )
31
29
// Return the new value, not the original value returned.
32
- return b .CreateAdd (oldVal , val , "" ), true
30
+ return b .CreateAdd (oldVal , val , "" )
33
31
}
34
32
oldVal := b .CreateAtomicRMW (llvm .AtomicRMWBinOpAdd , ptr , val , llvm .AtomicOrderingSequentiallyConsistent , true )
35
33
// Return the new value, not the original value returned by atomicrmw.
36
- return b .CreateAdd (oldVal , val , "" ), true
34
+ return b .CreateAdd (oldVal , val , "" )
37
35
case "SwapInt32" , "SwapInt64" , "SwapUint32" , "SwapUint64" , "SwapUintptr" , "SwapPointer" :
38
- ptr := b .getValue (call . Args [0 ])
39
- val := b .getValue (call . Args [1 ])
36
+ ptr := b .getValue (b . fn . Params [0 ])
37
+ val := b .getValue (b . fn . Params [1 ])
40
38
isPointer := val .Type ().TypeKind () == llvm .PointerTypeKind
41
39
if isPointer {
42
40
// atomicrmw only supports integers, so cast to an integer.
41
+ // TODO: this is fixed in LLVM 15.
43
42
val = b .CreatePtrToInt (val , b .uintptrType , "" )
44
43
ptr = b .CreateBitCast (ptr , llvm .PointerType (val .Type (), 0 ), "" )
45
44
}
46
45
oldVal := b .CreateAtomicRMW (llvm .AtomicRMWBinOpXchg , ptr , val , llvm .AtomicOrderingSequentiallyConsistent , true )
47
46
if isPointer {
48
47
oldVal = b .CreateIntToPtr (oldVal , b .i8ptrType , "" )
49
48
}
50
- return oldVal , true
49
+ return oldVal
51
50
case "CompareAndSwapInt32" , "CompareAndSwapInt64" , "CompareAndSwapUint32" , "CompareAndSwapUint64" , "CompareAndSwapUintptr" , "CompareAndSwapPointer" :
52
- ptr := b .getValue (call . Args [0 ])
53
- old := b .getValue (call . Args [1 ])
54
- newVal := b .getValue (call . Args [2 ])
51
+ ptr := b .getValue (b . fn . Params [0 ])
52
+ old := b .getValue (b . fn . Params [1 ])
53
+ newVal := b .getValue (b . fn . Params [2 ])
55
54
tuple := b .CreateAtomicCmpXchg (ptr , old , newVal , llvm .AtomicOrderingSequentiallyConsistent , llvm .AtomicOrderingSequentiallyConsistent , true )
56
55
swapped := b .CreateExtractValue (tuple , 1 , "" )
57
- return swapped , true
56
+ return swapped
58
57
case "LoadInt32" , "LoadInt64" , "LoadUint32" , "LoadUint64" , "LoadUintptr" , "LoadPointer" :
59
- ptr := b .getValue (call . Args [0 ])
58
+ ptr := b .getValue (b . fn . Params [0 ])
60
59
val := b .CreateLoad (ptr , "" )
61
60
val .SetOrdering (llvm .AtomicOrderingSequentiallyConsistent )
62
61
val .SetAlignment (b .targetData .PrefTypeAlignment (val .Type ())) // required
63
- return val , true
62
+ return val
64
63
case "StoreInt32" , "StoreInt64" , "StoreUint32" , "StoreUint64" , "StoreUintptr" , "StorePointer" :
65
- ptr := b .getValue (call . Args [0 ])
66
- val := b .getValue (call . Args [1 ])
64
+ ptr := b .getValue (b . fn . Params [0 ])
65
+ val := b .getValue (b . fn . Params [1 ])
67
66
if strings .HasPrefix (b .Triple , "avr" ) {
68
67
// SelectionDAGBuilder is currently missing the "are unaligned atomics allowed" check for stores.
69
68
vType := val .Type ()
@@ -79,13 +78,15 @@ func (b *builder) createAtomicOp(call *ssa.CallCommon) (llvm.Value, bool) {
79
78
if fn .IsNil () {
80
79
fn = llvm .AddFunction (b .mod , name , llvm .FunctionType (vType , []llvm.Type {ptr .Type (), vType , b .uintptrType }, false ))
81
80
}
82
- return b .createCall (fn , []llvm.Value {ptr , val , llvm .ConstInt (b .uintptrType , 5 , false )}, "" ), true
81
+ b .createCall (fn , []llvm.Value {ptr , val , llvm .ConstInt (b .uintptrType , 5 , false )}, "" )
82
+ return llvm.Value {}
83
83
}
84
84
store := b .CreateStore (val , ptr )
85
85
store .SetOrdering (llvm .AtomicOrderingSequentiallyConsistent )
86
86
store .SetAlignment (b .targetData .PrefTypeAlignment (val .Type ())) // required
87
- return store , true
87
+ return llvm. Value {}
88
88
default :
89
- return llvm.Value {}, false
89
+ b .addError (b .fn .Pos (), "unknown atomic operation: " + b .fn .Name ())
90
+ return llvm.Value {}
90
91
}
91
92
}
0 commit comments