|
| 1 | +package compiler |
| 2 | + |
| 3 | +import ( |
| 4 | + "golang.org/x/tools/go/ssa" |
| 5 | + "tinygo.org/x/go-llvm" |
| 6 | +) |
| 7 | + |
| 8 | +// createAtomicOp lowers an atomic library call by lowering it as an LLVM atomic |
| 9 | +// operation. It returns the result of the operation and true if the call could |
| 10 | +// be lowered inline, and false otherwise. |
| 11 | +func (b *builder) createAtomicOp(call *ssa.CallCommon) (llvm.Value, bool) { |
| 12 | + name := call.Value.(*ssa.Function).Name() |
| 13 | + switch name { |
| 14 | + case "AddInt32", "AddInt64", "AddUint32", "AddUint64", "AddUintptr": |
| 15 | + ptr := b.getValue(call.Args[0]) |
| 16 | + val := b.getValue(call.Args[1]) |
| 17 | + oldVal := b.CreateAtomicRMW(llvm.AtomicRMWBinOpAdd, ptr, val, llvm.AtomicOrderingSequentiallyConsistent, true) |
| 18 | + // Return the new value, not the original value returned by atomicrmw. |
| 19 | + return b.CreateAdd(oldVal, val, ""), true |
| 20 | + case "SwapInt32", "SwapInt64", "SwapUint32", "SwapUint64", "SwapUintptr", "SwapPointer": |
| 21 | + ptr := b.getValue(call.Args[0]) |
| 22 | + val := b.getValue(call.Args[1]) |
| 23 | + isPointer := val.Type().TypeKind() == llvm.PointerTypeKind |
| 24 | + if isPointer { |
| 25 | + // atomicrmw only supports integers, so cast to an integer. |
| 26 | + val = b.CreatePtrToInt(val, b.uintptrType, "") |
| 27 | + ptr = b.CreateBitCast(ptr, llvm.PointerType(val.Type(), 0), "") |
| 28 | + } |
| 29 | + oldVal := b.CreateAtomicRMW(llvm.AtomicRMWBinOpXchg, ptr, val, llvm.AtomicOrderingSequentiallyConsistent, true) |
| 30 | + if isPointer { |
| 31 | + oldVal = b.CreateIntToPtr(oldVal, b.i8ptrType, "") |
| 32 | + } |
| 33 | + return oldVal, true |
| 34 | + case "CompareAndSwapInt32", "CompareAndSwapInt64", "CompareAndSwapUint32", "CompareAndSwapUint64", "CompareAndSwapUintptr", "CompareAndSwapPointer": |
| 35 | + ptr := b.getValue(call.Args[0]) |
| 36 | + old := b.getValue(call.Args[1]) |
| 37 | + newVal := b.getValue(call.Args[2]) |
| 38 | + tuple := b.CreateAtomicCmpXchg(ptr, old, newVal, llvm.AtomicOrderingSequentiallyConsistent, llvm.AtomicOrderingSequentiallyConsistent, true) |
| 39 | + swapped := b.CreateExtractValue(tuple, 1, "") |
| 40 | + return swapped, true |
| 41 | + case "LoadInt32", "LoadInt64", "LoadUint32", "LoadUint64", "LoadUintptr", "LoadPointer": |
| 42 | + ptr := b.getValue(call.Args[0]) |
| 43 | + val := b.CreateLoad(ptr, "") |
| 44 | + val.SetOrdering(llvm.AtomicOrderingSequentiallyConsistent) |
| 45 | + val.SetAlignment(b.targetData.PrefTypeAlignment(val.Type())) // required |
| 46 | + return val, true |
| 47 | + case "StoreInt32", "StoreInt64", "StoreUint32", "StoreUint64", "StoreUintptr", "StorePointer": |
| 48 | + ptr := b.getValue(call.Args[0]) |
| 49 | + val := b.getValue(call.Args[1]) |
| 50 | + store := b.CreateStore(val, ptr) |
| 51 | + store.SetOrdering(llvm.AtomicOrderingSequentiallyConsistent) |
| 52 | + store.SetAlignment(b.targetData.PrefTypeAlignment(val.Type())) // required |
| 53 | + return store, true |
| 54 | + default: |
| 55 | + return llvm.Value{}, false |
| 56 | + } |
| 57 | +} |
0 commit comments