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