atomic.go raw
1 package compiler
2
3 import (
4 "tinygo.org/x/go-llvm"
5 )
6
7 // createAtomicOp lowers a sync/atomic function by lowering it as an LLVM atomic
8 // operation. It returns the result of the operation, or a zero llvm.Value if
9 // the result is void.
10 func (b *builder) createAtomicOp(name string) llvm.Value {
11 switch name {
12 case "AddInt32", "AddInt64", "AddUint32", "AddUint64", "AddUintptr":
13 ptr := b.getValue(b.fn.Params[0], getPos(b.fn))
14 val := b.getValue(b.fn.Params[1], getPos(b.fn))
15 oldVal := b.CreateAtomicRMW(llvm.AtomicRMWBinOpAdd, ptr, val, llvm.AtomicOrderingSequentiallyConsistent, true)
16 // Return the new value, not the original value returned by atomicrmw.
17 return b.CreateAdd(oldVal, val, "")
18 case "AndInt32", "AndInt64", "AndUint32", "AndUint64", "AndUintptr":
19 ptr := b.getValue(b.fn.Params[0], getPos(b.fn))
20 val := b.getValue(b.fn.Params[1], getPos(b.fn))
21 oldVal := b.CreateAtomicRMW(llvm.AtomicRMWBinOpAnd, ptr, val, llvm.AtomicOrderingSequentiallyConsistent, true)
22 return oldVal
23 case "OrInt32", "OrInt64", "OrUint32", "OrUint64", "OrUintptr":
24 ptr := b.getValue(b.fn.Params[0], getPos(b.fn))
25 val := b.getValue(b.fn.Params[1], getPos(b.fn))
26 oldVal := b.CreateAtomicRMW(llvm.AtomicRMWBinOpOr, ptr, val, llvm.AtomicOrderingSequentiallyConsistent, true)
27 return oldVal
28 case "SwapInt32", "SwapInt64", "SwapUint32", "SwapUint64", "SwapUintptr", "SwapPointer":
29 ptr := b.getValue(b.fn.Params[0], getPos(b.fn))
30 val := b.getValue(b.fn.Params[1], getPos(b.fn))
31 oldVal := b.CreateAtomicRMW(llvm.AtomicRMWBinOpXchg, ptr, val, llvm.AtomicOrderingSequentiallyConsistent, true)
32 return oldVal
33 case "CompareAndSwapInt32", "CompareAndSwapInt64", "CompareAndSwapUint32", "CompareAndSwapUint64", "CompareAndSwapUintptr", "CompareAndSwapPointer":
34 ptr := b.getValue(b.fn.Params[0], getPos(b.fn))
35 old := b.getValue(b.fn.Params[1], getPos(b.fn))
36 newVal := b.getValue(b.fn.Params[2], getPos(b.fn))
37 tuple := b.CreateAtomicCmpXchg(ptr, old, newVal, llvm.AtomicOrderingSequentiallyConsistent, llvm.AtomicOrderingSequentiallyConsistent, true)
38 swapped := b.CreateExtractValue(tuple, 1, "")
39 return swapped
40 case "LoadInt32", "LoadInt64", "LoadUint32", "LoadUint64", "LoadUintptr", "LoadPointer":
41 ptr := b.getValue(b.fn.Params[0], getPos(b.fn))
42 val := b.CreateLoad(b.getLLVMType(b.fn.Signature.Results().At(0).Type()), ptr, "")
43 val.SetOrdering(llvm.AtomicOrderingSequentiallyConsistent)
44 val.SetAlignment(b.targetData.PrefTypeAlignment(val.Type())) // required
45 return val
46 case "StoreInt32", "StoreInt64", "StoreUint32", "StoreUint64", "StoreUintptr", "StorePointer":
47 ptr := b.getValue(b.fn.Params[0], getPos(b.fn))
48 val := b.getValue(b.fn.Params[1], getPos(b.fn))
49 store := b.CreateStore(val, ptr)
50 store.SetOrdering(llvm.AtomicOrderingSequentiallyConsistent)
51 store.SetAlignment(b.targetData.PrefTypeAlignment(val.Type())) // required
52 return llvm.Value{}
53 default:
54 b.addError(b.fn.Pos(), "unknown atomic operation: "+b.fn.Name())
55 return llvm.Value{}
56 }
57 }
58