var all []*sys.Arch
var p4 []*sys.Arch
var p8 []*sys.Arch
+ var lwatomics []*sys.Arch
for _, a := range sys.Archs {
all = append(all, a)
if a.PtrSize == 4 {
} else {
p8 = append(p8, a)
}
+ if a.Family != sys.PPC64 {
+ lwatomics = append(lwatomics, a)
+ }
}
// add adds the intrinsic b for pkg.fn for the given list of architectures.
return s.newValue1(ssa.OpSelect0, types.Types[TUINT64], v)
},
sys.AMD64, sys.ARM64, sys.S390X, sys.MIPS64, sys.PPC64)
+ addF("runtime/internal/atomic", "LoadAcq",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ v := s.newValue2(ssa.OpAtomicLoadAcq32, types.NewTuple(types.Types[TUINT32], types.TypeMem), args[0], s.mem())
+ s.vars[&memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
+ return s.newValue1(ssa.OpSelect0, types.Types[TUINT32], v)
+ },
+ sys.PPC64)
addF("runtime/internal/atomic", "Loadp",
func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
v := s.newValue2(ssa.OpAtomicLoadPtr, types.NewTuple(s.f.Config.Types.BytePtr, types.TypeMem), args[0], s.mem())
return nil
},
sys.AMD64, sys.ARM64, sys.S390X, sys.MIPS, sys.MIPS64)
+ addF("runtime/internal/atomic", "StoreRel",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ s.vars[&memVar] = s.newValue3(ssa.OpAtomicStoreRel32, types.TypeMem, args[0], args[1], s.mem())
+ return nil
+ },
+ sys.PPC64)
addF("runtime/internal/atomic", "Xchg",
func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
return s.newValue1(ssa.OpSelect0, types.Types[TBOOL], v)
},
sys.AMD64, sys.ARM64, sys.S390X, sys.MIPS64, sys.PPC64)
+ addF("runtime/internal/atomic", "CasRel",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ v := s.newValue4(ssa.OpAtomicCompareAndSwap32, types.NewTuple(types.Types[TBOOL], types.TypeMem), args[0], args[1], args[2], s.mem())
+ s.vars[&memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
+ return s.newValue1(ssa.OpSelect0, types.Types[TBOOL], v)
+ },
+ sys.PPC64)
addF("runtime/internal/atomic", "And8",
func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
alias("runtime/internal/atomic", "Loaduint", "runtime/internal/atomic", "Load64", p8...)
alias("runtime/internal/atomic", "Loaduintptr", "runtime/internal/atomic", "Load", p4...)
alias("runtime/internal/atomic", "Loaduintptr", "runtime/internal/atomic", "Load64", p8...)
+ alias("runtime/internal/atomic", "LoadAcq", "runtime/internal/atomic", "Load", lwatomics...)
alias("runtime/internal/atomic", "Storeuintptr", "runtime/internal/atomic", "Store", p4...)
alias("runtime/internal/atomic", "Storeuintptr", "runtime/internal/atomic", "Store64", p8...)
+ alias("runtime/internal/atomic", "StoreRel", "runtime/internal/atomic", "Store", lwatomics...)
alias("runtime/internal/atomic", "Xchguintptr", "runtime/internal/atomic", "Xchg", p4...)
alias("runtime/internal/atomic", "Xchguintptr", "runtime/internal/atomic", "Xchg64", p8...)
alias("runtime/internal/atomic", "Xadduintptr", "runtime/internal/atomic", "Xadd", p4...)
alias("runtime/internal/atomic", "Casuintptr", "runtime/internal/atomic", "Cas64", p8...)
alias("runtime/internal/atomic", "Casp1", "runtime/internal/atomic", "Cas", p4...)
alias("runtime/internal/atomic", "Casp1", "runtime/internal/atomic", "Cas64", p8...)
+ alias("runtime/internal/atomic", "CasRel", "runtime/internal/atomic", "Cas", lwatomics...)
alias("runtime/internal/sys", "Ctz8", "math/bits", "TrailingZeros8", all...)
}
arg0 := v.Args[0].Reg()
out := v.Reg0()
- // SYNC
- psync := s.Prog(ppc64.ASYNC)
- psync.To.Type = obj.TYPE_NONE
+ // SYNC when AuxInt == 1; otherwise, load-acquire
+ if v.AuxInt == 1 {
+ psync := s.Prog(ppc64.ASYNC)
+ psync.To.Type = obj.TYPE_NONE
+ }
// Load
p := s.Prog(ld)
p.From.Type = obj.TYPE_MEM
case ssa.OpPPC64LoweredAtomicStore32,
ssa.OpPPC64LoweredAtomicStore64:
- // SYNC
+ // SYNC or LWSYNC
// MOVD/MOVW arg1,(arg0)
st := ppc64.AMOVD
if v.Op == ssa.OpPPC64LoweredAtomicStore32 {
}
arg0 := v.Args[0].Reg()
arg1 := v.Args[1].Reg()
+ // If AuxInt == 0, LWSYNC (Store-Release), else SYNC
// SYNC
- psync := s.Prog(ppc64.ASYNC)
+ syncOp := ppc64.ASYNC
+ if v.AuxInt == 0 {
+ syncOp = ppc64.ALWSYNC
+ }
+ psync := s.Prog(syncOp)
psync.To.Type = obj.TYPE_NONE
// Store
p := s.Prog(st)
ssa.OpPPC64LoweredAtomicCas32:
// LWSYNC
// loop:
- // LDAR (Rarg0), Rtmp
+ // LDAR (Rarg0), MutexHint, Rtmp
// CMP Rarg1, Rtmp
// BNE fail
// STDCCC Rarg2, (Rarg0)
// BNE loop
- // LWSYNC
+ // LWSYNC // Only for sequential consistency; not required in CasRel.
// MOVD $1, Rout
// BR end
// fail:
p.From.Reg = r0
p.To.Type = obj.TYPE_REG
p.To.Reg = ppc64.REGTMP
+ // If it is a Compare-and-Swap-Release operation, set the EH field with
+ // the release hint.
+ if v.AuxInt == 0 {
+ p.SetFrom3(obj.Addr{Type: obj.TYPE_CONST, Offset: 0})
+ }
// CMP reg1,reg2
p1 := s.Prog(cmp)
p1.From.Type = obj.TYPE_REG
gc.Patch(p4, p)
// LWSYNC - Assuming shared data not write-through-required nor
// caching-inhibited. See Appendix B.2.1.1 in the ISA 2.07b.
- plwsync2 := s.Prog(ppc64.ALWSYNC)
- plwsync2.To.Type = obj.TYPE_NONE
+ // If the operation is a CAS-Release, then synchronization is not necessary.
+ if v.AuxInt != 0 {
+ plwsync2 := s.Prog(ppc64.ALWSYNC)
+ plwsync2.To.Type = obj.TYPE_NONE
+ }
// return true
p5 := s.Prog(ppc64.AMOVD)
p5.From.Type = obj.TYPE_CONST
(MOVBstorezero [off1+off2] {mergeSym(sym1,sym2)} x mem)
// atomic intrinsics
-(AtomicLoad(32|64|Ptr) ptr mem) -> (LoweredAtomicLoad(32|64|Ptr) ptr mem)
+(AtomicLoad(32|64|Ptr) ptr mem) -> (LoweredAtomicLoad(32|64|Ptr) [1] ptr mem)
+(AtomicLoadAcq32 ptr mem) -> (LoweredAtomicLoad32 [0] ptr mem)
-(AtomicStore(32|64) ptr val mem) -> (LoweredAtomicStore(32|64) ptr val mem)
+(AtomicStore(32|64) ptr val mem) -> (LoweredAtomicStore(32|64) [1] ptr val mem)
+(AtomicStoreRel32 ptr val mem) -> (LoweredAtomicStore32 [0] ptr val mem)
//(AtomicStorePtrNoWB ptr val mem) -> (STLR ptr val mem)
(AtomicExchange(32|64) ptr val mem) -> (LoweredAtomicExchange(32|64) ptr val mem)
(AtomicAdd(32|64) ptr val mem) -> (LoweredAtomicAdd(32|64) ptr val mem)
-(AtomicCompareAndSwap(32|64) ptr old new_ mem) -> (LoweredAtomicCas(32|64) ptr old new_ mem)
+(AtomicCompareAndSwap(32|64) ptr old new_ mem) -> (LoweredAtomicCas(32|64) [1] ptr old new_ mem)
+(AtomicCompareAndSwapRel32 ptr old new_ mem) -> (LoweredAtomicCas32 [0] ptr old new_ mem)
(AtomicAnd8 ptr val mem) -> (LoweredAtomicAnd8 ptr val mem)
(AtomicOr8 ptr val mem) -> (LoweredAtomicOr8 ptr val mem)
faultOnNilArg1: true,
},
- {name: "LoweredAtomicStore32", argLength: 3, reg: gpstore, typ: "Mem", faultOnNilArg0: true, hasSideEffects: true},
- {name: "LoweredAtomicStore64", argLength: 3, reg: gpstore, typ: "Mem", faultOnNilArg0: true, hasSideEffects: true},
+ {name: "LoweredAtomicStore32", argLength: 3, reg: gpstore, typ: "Mem", aux: "Int64", faultOnNilArg0: true, hasSideEffects: true},
+ {name: "LoweredAtomicStore64", argLength: 3, reg: gpstore, typ: "Mem", aux: "Int64", faultOnNilArg0: true, hasSideEffects: true},
- {name: "LoweredAtomicLoad32", argLength: 2, reg: gpload, typ: "UInt32", clobberFlags: true, faultOnNilArg0: true},
- {name: "LoweredAtomicLoad64", argLength: 2, reg: gpload, typ: "Int64", clobberFlags: true, faultOnNilArg0: true},
- {name: "LoweredAtomicLoadPtr", argLength: 2, reg: gpload, typ: "Int64", clobberFlags: true, faultOnNilArg0: true},
+ {name: "LoweredAtomicLoad32", argLength: 2, reg: gpload, typ: "UInt32", aux: "Int64", clobberFlags: true, faultOnNilArg0: true},
+ {name: "LoweredAtomicLoad64", argLength: 2, reg: gpload, typ: "Int64", aux: "Int64", clobberFlags: true, faultOnNilArg0: true},
+ {name: "LoweredAtomicLoadPtr", argLength: 2, reg: gpload, typ: "Int64", aux: "Int64", clobberFlags: true, faultOnNilArg0: true},
// atomic add32, 64
// SYNC
// BNE -4(PC)
// CBNZ Rtmp, -4(PC)
// CSET EQ, Rout
- {name: "LoweredAtomicCas64", argLength: 4, reg: gpcas, resultNotInArgs: true, clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true},
- {name: "LoweredAtomicCas32", argLength: 4, reg: gpcas, resultNotInArgs: true, clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true},
+ {name: "LoweredAtomicCas64", argLength: 4, reg: gpcas, resultNotInArgs: true, aux: "Int64", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true},
+ {name: "LoweredAtomicCas32", argLength: 4, reg: gpcas, resultNotInArgs: true, aux: "Int64", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true},
// atomic 8 and/or.
// *arg0 &= (|=) arg1. arg2=mem. returns memory. auxint must be zero.
// Atomic loads return a new memory so that the loads are properly ordered
// with respect to other loads and stores.
// TODO: use for sync/atomic at some point.
- {name: "AtomicLoad32", argLength: 2, typ: "(UInt32,Mem)"}, // Load from arg0. arg1=memory. Returns loaded value and new memory.
- {name: "AtomicLoad64", argLength: 2, typ: "(UInt64,Mem)"}, // Load from arg0. arg1=memory. Returns loaded value and new memory.
- {name: "AtomicLoadPtr", argLength: 2, typ: "(BytePtr,Mem)"}, // Load from arg0. arg1=memory. Returns loaded value and new memory.
- {name: "AtomicStore32", argLength: 3, typ: "Mem", hasSideEffects: true}, // Store arg1 to *arg0. arg2=memory. Returns memory.
- {name: "AtomicStore64", argLength: 3, typ: "Mem", hasSideEffects: true}, // Store arg1 to *arg0. arg2=memory. Returns memory.
- {name: "AtomicStorePtrNoWB", argLength: 3, typ: "Mem", hasSideEffects: true}, // Store arg1 to *arg0. arg2=memory. Returns memory.
- {name: "AtomicExchange32", argLength: 3, typ: "(UInt32,Mem)", hasSideEffects: true}, // Store arg1 to *arg0. arg2=memory. Returns old contents of *arg0 and new memory.
- {name: "AtomicExchange64", argLength: 3, typ: "(UInt64,Mem)", hasSideEffects: true}, // Store arg1 to *arg0. arg2=memory. Returns old contents of *arg0 and new memory.
- {name: "AtomicAdd32", argLength: 3, typ: "(UInt32,Mem)", hasSideEffects: true}, // Do *arg0 += arg1. arg2=memory. Returns sum and new memory.
- {name: "AtomicAdd64", argLength: 3, typ: "(UInt64,Mem)", hasSideEffects: true}, // Do *arg0 += arg1. arg2=memory. Returns sum and new memory.
- {name: "AtomicCompareAndSwap32", argLength: 4, typ: "(Bool,Mem)", hasSideEffects: true}, // if *arg0==arg1, then set *arg0=arg2. Returns true iff store happens and new memory.
- {name: "AtomicCompareAndSwap64", argLength: 4, typ: "(Bool,Mem)", hasSideEffects: true}, // if *arg0==arg1, then set *arg0=arg2. Returns true iff store happens and new memory.
- {name: "AtomicAnd8", argLength: 3, typ: "Mem", hasSideEffects: true}, // *arg0 &= arg1. arg2=memory. Returns memory.
- {name: "AtomicOr8", argLength: 3, typ: "Mem", hasSideEffects: true}, // *arg0 |= arg1. arg2=memory. Returns memory.
+ {name: "AtomicLoad32", argLength: 2, typ: "(UInt32,Mem)"}, // Load from arg0. arg1=memory. Returns loaded value and new memory.
+ {name: "AtomicLoad64", argLength: 2, typ: "(UInt64,Mem)"}, // Load from arg0. arg1=memory. Returns loaded value and new memory.
+ {name: "AtomicLoadPtr", argLength: 2, typ: "(BytePtr,Mem)"}, // Load from arg0. arg1=memory. Returns loaded value and new memory.
+ {name: "AtomicLoadAcq32", argLength: 2, typ: "(UInt32,Mem)"}, // Load from arg0. arg1=memory. Lock acquisition, returns loaded value and new memory.
+ {name: "AtomicStore32", argLength: 3, typ: "Mem", hasSideEffects: true}, // Store arg1 to *arg0. arg2=memory. Returns memory.
+ {name: "AtomicStore64", argLength: 3, typ: "Mem", hasSideEffects: true}, // Store arg1 to *arg0. arg2=memory. Returns memory.
+ {name: "AtomicStorePtrNoWB", argLength: 3, typ: "Mem", hasSideEffects: true}, // Store arg1 to *arg0. arg2=memory. Returns memory.
+ {name: "AtomicStoreRel32", argLength: 3, typ: "Mem", hasSideEffects: true}, // Store arg1 to *arg0. arg2=memory. Lock release, returns memory.
+ {name: "AtomicExchange32", argLength: 3, typ: "(UInt32,Mem)", hasSideEffects: true}, // Store arg1 to *arg0. arg2=memory. Returns old contents of *arg0 and new memory.
+ {name: "AtomicExchange64", argLength: 3, typ: "(UInt64,Mem)", hasSideEffects: true}, // Store arg1 to *arg0. arg2=memory. Returns old contents of *arg0 and new memory.
+ {name: "AtomicAdd32", argLength: 3, typ: "(UInt32,Mem)", hasSideEffects: true}, // Do *arg0 += arg1. arg2=memory. Returns sum and new memory.
+ {name: "AtomicAdd64", argLength: 3, typ: "(UInt64,Mem)", hasSideEffects: true}, // Do *arg0 += arg1. arg2=memory. Returns sum and new memory.
+ {name: "AtomicCompareAndSwap32", argLength: 4, typ: "(Bool,Mem)", hasSideEffects: true}, // if *arg0==arg1, then set *arg0=arg2. Returns true if store happens and new memory.
+ {name: "AtomicCompareAndSwap64", argLength: 4, typ: "(Bool,Mem)", hasSideEffects: true}, // if *arg0==arg1, then set *arg0=arg2. Returns true if store happens and new memory.
+ {name: "AtomicCompareAndSwapRel32", argLength: 4, typ: "(Bool,Mem)", hasSideEffects: true}, // if *arg0==arg1, then set *arg0=arg2. Lock release, returns true if store happens and new memory.
+ {name: "AtomicAnd8", argLength: 3, typ: "Mem", hasSideEffects: true}, // *arg0 &= arg1. arg2=memory. Returns memory.
+ {name: "AtomicOr8", argLength: 3, typ: "Mem", hasSideEffects: true}, // *arg0 |= arg1. arg2=memory. Returns memory.
// Atomic operation variants
// These variants have the same semantics as above atomic operations.
OpAtomicLoad32
OpAtomicLoad64
OpAtomicLoadPtr
+ OpAtomicLoadAcq32
OpAtomicStore32
OpAtomicStore64
OpAtomicStorePtrNoWB
+ OpAtomicStoreRel32
OpAtomicExchange32
OpAtomicExchange64
OpAtomicAdd32
OpAtomicAdd64
OpAtomicCompareAndSwap32
OpAtomicCompareAndSwap64
+ OpAtomicCompareAndSwapRel32
OpAtomicAnd8
OpAtomicOr8
OpAtomicAdd32Variant
},
{
name: "LoweredAtomicStore32",
+ auxType: auxInt64,
argLen: 3,
faultOnNilArg0: true,
hasSideEffects: true,
},
{
name: "LoweredAtomicStore64",
+ auxType: auxInt64,
argLen: 3,
faultOnNilArg0: true,
hasSideEffects: true,
},
{
name: "LoweredAtomicLoad32",
+ auxType: auxInt64,
argLen: 2,
clobberFlags: true,
faultOnNilArg0: true,
},
{
name: "LoweredAtomicLoad64",
+ auxType: auxInt64,
argLen: 2,
clobberFlags: true,
faultOnNilArg0: true,
},
{
name: "LoweredAtomicLoadPtr",
+ auxType: auxInt64,
argLen: 2,
clobberFlags: true,
faultOnNilArg0: true,
},
{
name: "LoweredAtomicCas64",
+ auxType: auxInt64,
argLen: 4,
resultNotInArgs: true,
clobberFlags: true,
},
{
name: "LoweredAtomicCas32",
+ auxType: auxInt64,
argLen: 4,
resultNotInArgs: true,
clobberFlags: true,
argLen: 2,
generic: true,
},
+ {
+ name: "AtomicLoadAcq32",
+ argLen: 2,
+ generic: true,
+ },
{
name: "AtomicStore32",
argLen: 3,
hasSideEffects: true,
generic: true,
},
+ {
+ name: "AtomicStoreRel32",
+ argLen: 3,
+ hasSideEffects: true,
+ generic: true,
+ },
{
name: "AtomicExchange32",
argLen: 3,
hasSideEffects: true,
generic: true,
},
+ {
+ name: "AtomicCompareAndSwapRel32",
+ argLen: 4,
+ hasSideEffects: true,
+ generic: true,
+ },
{
name: "AtomicAnd8",
argLen: 3,
return rewriteValuePPC64_OpAtomicCompareAndSwap32_0(v)
case OpAtomicCompareAndSwap64:
return rewriteValuePPC64_OpAtomicCompareAndSwap64_0(v)
+ case OpAtomicCompareAndSwapRel32:
+ return rewriteValuePPC64_OpAtomicCompareAndSwapRel32_0(v)
case OpAtomicExchange32:
return rewriteValuePPC64_OpAtomicExchange32_0(v)
case OpAtomicExchange64:
return rewriteValuePPC64_OpAtomicLoad32_0(v)
case OpAtomicLoad64:
return rewriteValuePPC64_OpAtomicLoad64_0(v)
+ case OpAtomicLoadAcq32:
+ return rewriteValuePPC64_OpAtomicLoadAcq32_0(v)
case OpAtomicLoadPtr:
return rewriteValuePPC64_OpAtomicLoadPtr_0(v)
case OpAtomicOr8:
return rewriteValuePPC64_OpAtomicStore32_0(v)
case OpAtomicStore64:
return rewriteValuePPC64_OpAtomicStore64_0(v)
+ case OpAtomicStoreRel32:
+ return rewriteValuePPC64_OpAtomicStoreRel32_0(v)
case OpAvg64u:
return rewriteValuePPC64_OpAvg64u_0(v)
case OpBitLen32:
func rewriteValuePPC64_OpAtomicCompareAndSwap32_0(v *Value) bool {
// match: (AtomicCompareAndSwap32 ptr old new_ mem)
// cond:
- // result: (LoweredAtomicCas32 ptr old new_ mem)
+ // result: (LoweredAtomicCas32 [1] ptr old new_ mem)
for {
_ = v.Args[3]
ptr := v.Args[0]
new_ := v.Args[2]
mem := v.Args[3]
v.reset(OpPPC64LoweredAtomicCas32)
+ v.AuxInt = 1
v.AddArg(ptr)
v.AddArg(old)
v.AddArg(new_)
func rewriteValuePPC64_OpAtomicCompareAndSwap64_0(v *Value) bool {
// match: (AtomicCompareAndSwap64 ptr old new_ mem)
// cond:
- // result: (LoweredAtomicCas64 ptr old new_ mem)
+ // result: (LoweredAtomicCas64 [1] ptr old new_ mem)
for {
_ = v.Args[3]
ptr := v.Args[0]
new_ := v.Args[2]
mem := v.Args[3]
v.reset(OpPPC64LoweredAtomicCas64)
+ v.AuxInt = 1
+ v.AddArg(ptr)
+ v.AddArg(old)
+ v.AddArg(new_)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValuePPC64_OpAtomicCompareAndSwapRel32_0(v *Value) bool {
+ // match: (AtomicCompareAndSwapRel32 ptr old new_ mem)
+ // cond:
+ // result: (LoweredAtomicCas32 [0] ptr old new_ mem)
+ for {
+ _ = v.Args[3]
+ ptr := v.Args[0]
+ old := v.Args[1]
+ new_ := v.Args[2]
+ mem := v.Args[3]
+ v.reset(OpPPC64LoweredAtomicCas32)
+ v.AuxInt = 0
v.AddArg(ptr)
v.AddArg(old)
v.AddArg(new_)
func rewriteValuePPC64_OpAtomicLoad32_0(v *Value) bool {
// match: (AtomicLoad32 ptr mem)
// cond:
- // result: (LoweredAtomicLoad32 ptr mem)
+ // result: (LoweredAtomicLoad32 [1] ptr mem)
for {
_ = v.Args[1]
ptr := v.Args[0]
mem := v.Args[1]
v.reset(OpPPC64LoweredAtomicLoad32)
+ v.AuxInt = 1
v.AddArg(ptr)
v.AddArg(mem)
return true
func rewriteValuePPC64_OpAtomicLoad64_0(v *Value) bool {
// match: (AtomicLoad64 ptr mem)
// cond:
- // result: (LoweredAtomicLoad64 ptr mem)
+ // result: (LoweredAtomicLoad64 [1] ptr mem)
for {
_ = v.Args[1]
ptr := v.Args[0]
mem := v.Args[1]
v.reset(OpPPC64LoweredAtomicLoad64)
+ v.AuxInt = 1
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValuePPC64_OpAtomicLoadAcq32_0(v *Value) bool {
+ // match: (AtomicLoadAcq32 ptr mem)
+ // cond:
+ // result: (LoweredAtomicLoad32 [0] ptr mem)
+ for {
+ _ = v.Args[1]
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ v.reset(OpPPC64LoweredAtomicLoad32)
+ v.AuxInt = 0
v.AddArg(ptr)
v.AddArg(mem)
return true
func rewriteValuePPC64_OpAtomicLoadPtr_0(v *Value) bool {
// match: (AtomicLoadPtr ptr mem)
// cond:
- // result: (LoweredAtomicLoadPtr ptr mem)
+ // result: (LoweredAtomicLoadPtr [1] ptr mem)
for {
_ = v.Args[1]
ptr := v.Args[0]
mem := v.Args[1]
v.reset(OpPPC64LoweredAtomicLoadPtr)
+ v.AuxInt = 1
v.AddArg(ptr)
v.AddArg(mem)
return true
func rewriteValuePPC64_OpAtomicStore32_0(v *Value) bool {
// match: (AtomicStore32 ptr val mem)
// cond:
- // result: (LoweredAtomicStore32 ptr val mem)
+ // result: (LoweredAtomicStore32 [1] ptr val mem)
for {
_ = v.Args[2]
ptr := v.Args[0]
val := v.Args[1]
mem := v.Args[2]
v.reset(OpPPC64LoweredAtomicStore32)
+ v.AuxInt = 1
v.AddArg(ptr)
v.AddArg(val)
v.AddArg(mem)
func rewriteValuePPC64_OpAtomicStore64_0(v *Value) bool {
// match: (AtomicStore64 ptr val mem)
// cond:
- // result: (LoweredAtomicStore64 ptr val mem)
+ // result: (LoweredAtomicStore64 [1] ptr val mem)
for {
_ = v.Args[2]
ptr := v.Args[0]
val := v.Args[1]
mem := v.Args[2]
v.reset(OpPPC64LoweredAtomicStore64)
+ v.AuxInt = 1
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValuePPC64_OpAtomicStoreRel32_0(v *Value) bool {
+ // match: (AtomicStoreRel32 ptr val mem)
+ // cond:
+ // result: (LoweredAtomicStore32 [0] ptr val mem)
+ for {
+ _ = v.Args[2]
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ v.reset(OpPPC64LoweredAtomicStore32)
+ v.AuxInt = 0
v.AddArg(ptr)
v.AddArg(val)
v.AddArg(mem)
TEXT runtime∕internal∕atomic·Casuintptr(SB), NOSPLIT, $0-13
JMP runtime∕internal∕atomic·Cas(SB)
+TEXT runtime∕internal∕atomic·CasRel(SB), NOSPLIT, $0-13
+ JMP runtime∕internal∕atomic·Cas(SB)
+
TEXT runtime∕internal∕atomic·Loaduintptr(SB), NOSPLIT, $0-8
JMP runtime∕internal∕atomic·Load(SB)
XCHGL AX, 0(BX)
RET
+TEXT runtime∕internal∕atomic·StoreRel(SB), NOSPLIT, $0-8
+ JMP runtime∕internal∕atomic·Store(SB)
+
// uint64 atomicload64(uint64 volatile* addr);
TEXT runtime∕internal∕atomic·Load64(SB), NOSPLIT, $0-12
MOVL ptr+0(FP), AX
TEXT runtime∕internal∕atomic·Casuintptr(SB), NOSPLIT, $0-25
JMP runtime∕internal∕atomic·Cas64(SB)
+TEXT runtime∕internal∕atomic·CasRel(SB), NOSPLIT, $0-17
+ JMP runtime∕internal∕atomic·Cas(SB)
+
TEXT runtime∕internal∕atomic·Loaduintptr(SB), NOSPLIT, $0-16
JMP runtime∕internal∕atomic·Load64(SB)
XCHGL AX, 0(BX)
RET
+TEXT runtime∕internal∕atomic·StoreRel(SB), NOSPLIT, $0-12
+ JMP runtime∕internal∕atomic·Store(SB)
+
TEXT runtime∕internal∕atomic·Store64(SB), NOSPLIT, $0-16
MOVQ ptr+0(FP), BX
MOVQ val+8(FP), AX
TEXT runtime∕internal∕atomic·Casuintptr(SB), NOSPLIT, $0-17
JMP runtime∕internal∕atomic·Cas(SB)
+TEXT runtime∕internal∕atomic·CasRel(SB), NOSPLIT, $0-17
+ JMP runtime∕internal∕atomic·Cas(SB)
+
TEXT runtime∕internal∕atomic·Loaduintptr(SB), NOSPLIT, $0-12
JMP runtime∕internal∕atomic·Load(SB)
XCHGL AX, 0(BX)
RET
+TEXT runtime∕internal∕atomic·StoreRel(SB), NOSPLIT, $0-8
+ JMP runtime∕internal∕atomic·Store(SB)
+
TEXT runtime∕internal∕atomic·Store64(SB), NOSPLIT, $0-16
MOVL ptr+0(FP), BX
MOVQ val+8(FP), AX
TEXT runtime∕internal∕atomic·Loadp(SB),NOSPLIT|NOFRAME,$0-8
B runtime∕internal∕atomic·Load(SB)
+TEXT runtime∕internal∕atomic·LoadAcq(SB),NOSPLIT|NOFRAME,$0-8
+ B runtime∕internal∕atomic·Load(SB)
+
TEXT runtime∕internal∕atomic·Casuintptr(SB),NOSPLIT,$0-13
B runtime∕internal∕atomic·Cas(SB)
TEXT runtime∕internal∕atomic·Casp1(SB),NOSPLIT,$0-13
B runtime∕internal∕atomic·Cas(SB)
+TEXT runtime∕internal∕atomic·CasRel(SB),NOSPLIT,$0-13
+ B runtime∕internal∕atomic·Cas(SB)
+
TEXT runtime∕internal∕atomic·Loaduintptr(SB),NOSPLIT,$0-8
B runtime∕internal∕atomic·Load(SB)
TEXT runtime∕internal∕atomic·StorepNoWB(SB),NOSPLIT,$0-8
B runtime∕internal∕atomic·Store(SB)
+TEXT runtime∕internal∕atomic·StoreRel(SB),NOSPLIT,$0-8
+ B runtime∕internal∕atomic·Store(SB)
+
TEXT runtime∕internal∕atomic·Xadduintptr(SB),NOSPLIT,$0-12
B runtime∕internal∕atomic·Xadd(SB)
TEXT runtime∕internal∕atomic·Casuintptr(SB), NOSPLIT, $0-25
B runtime∕internal∕atomic·Cas64(SB)
+TEXT runtime∕internal∕atomic·CasRel(SB), NOSPLIT, $0-17
+ B runtime∕internal∕atomic·Cas(SB)
+
TEXT runtime∕internal∕atomic·Loaduintptr(SB), NOSPLIT, $0-16
B runtime∕internal∕atomic·Load64(SB)
TEXT ·Casuintptr(SB), NOSPLIT, $0-25
JMP ·Cas64(SB)
+TEXT ·CasRel(SB), NOSPLIT, $0-17
+ JMP ·Cas(SB)
+
TEXT ·Loaduintptr(SB), NOSPLIT|NOFRAME, $0-16
JMP ·Load64(SB)
TEXT ·StorepNoWB(SB), NOSPLIT, $0-16
JMP ·Store64(SB)
+TEXT ·StoreRel(SB), NOSPLIT, $0-12
+ JMP ·Store(SB)
+
TEXT ·Store(SB), NOSPLIT, $0-12
MOVV ptr+0(FP), R1
MOVW val+8(FP), R2
TEXT ·Casuintptr(SB),NOSPLIT,$0-13
JMP ·Cas(SB)
+TEXT ·CasRel(SB),NOSPLIT,$0-13
+ JMP ·Cas(SB)
+
TEXT ·Loaduintptr(SB),NOSPLIT,$0-8
JMP ·Load(SB)
TEXT ·StorepNoWB(SB),NOSPLIT,$0-8
JMP ·Store(SB)
+TEXT ·StoreRel(SB),NOSPLIT,$0-8
+ JMP ·Store(SB)
+
// void Or8(byte volatile*, byte);
TEXT ·Or8(SB),NOSPLIT,$0-5
MOVW ptr+0(FP), R1
MOVB R0, ret+24(FP)
RET
+TEXT runtime∕internal∕atomic·CasRel(SB), NOSPLIT, $0-17
+ MOVD ptr+0(FP), R3
+ MOVWZ old+8(FP), R4
+ MOVWZ new+12(FP), R5
+ LWSYNC
+cas_again:
+ LWAR (R3), $0, R6 // 0 = Mutex release hint
+ CMPW R6, R4
+ BNE cas_fail
+ STWCCC R5, (R3)
+ BNE cas_again
+ MOVD $1, R3
+ MOVB R3, ret+16(FP)
+ RET
+cas_fail:
+ MOVB R0, ret+16(FP)
+ RET
+
TEXT runtime∕internal∕atomic·Casuintptr(SB), NOSPLIT, $0-25
BR runtime∕internal∕atomic·Cas64(SB)
MOVD R4, 0(R3)
RET
+TEXT runtime∕internal∕atomic·StoreRel(SB), NOSPLIT, $0-12
+ MOVD ptr+0(FP), R3
+ MOVW val+8(FP), R4
+ LWSYNC
+ MOVW R4, 0(R3)
+ RET
+
// void runtime∕internal∕atomic·Or8(byte volatile*, byte);
TEXT runtime∕internal∕atomic·Or8(SB), NOSPLIT, $0-9
MOVD ptr+0(FP), R3
TEXT ·Casuintptr(SB), NOSPLIT, $0-25
BR ·Cas64(SB)
+// func CasRel(ptr *uint32, old, new uint32) bool
+TEXT ·CasRel(SB), NOSPLIT, $0-17
+ BR ·Cas(SB)
+
// func Loaduintptr(ptr *uintptr) uintptr
TEXT ·Loaduintptr(SB), NOSPLIT, $0-16
BR ·Load64(SB)
return *(*unsafe.Pointer)(ptr)
}
+//go:nosplit
+//go:noinline
+func LoadAcq(ptr *uint32) uint32 {
+ return *ptr
+}
+
//go:noescape
func Xadd64(ptr *uint64, delta int64) uint64
//go:noescape
func Cas64(ptr *uint64, old, new uint64) bool
+//go:noescape
+func CasRel(ptr *uint32, old, new uint32) bool
+
//go:noescape
func Store(ptr *uint32, val uint32)
//go:noescape
func Store64(ptr *uint64, val uint64)
+//go:noescape
+func StoreRel(ptr *uint32, val uint32)
+
// NO go:noescape annotation; see atomic_pointer.go.
func StorepNoWB(ptr unsafe.Pointer, val unsafe.Pointer)
return *ptr
}
+//go:nosplit
+//go:noinline
+func LoadAcq(ptr *uint32) uint32 {
+ return *ptr
+}
+
//go:noescape
func Xadd(ptr *uint32, delta int32) uint32
//go:noescape
func Cas64(ptr *uint64, old, new uint64) bool
+//go:noescape
+func CasRel(ptr *uint32, old, new uint32) bool
+
//go:noescape
func Store(ptr *uint32, val uint32)
//go:noescape
func Store64(ptr *uint64, val uint64)
+//go:noescape
+func StoreRel(ptr *uint32, val uint32)
+
// StorepNoWB performs *ptr = val atomically and without a write
// barrier.
//
//go:noescape
func Store(addr *uint32, v uint32)
+//go:noescape
+func StoreRel(addr *uint32, v uint32)
+
//go:nosplit
func goCas64(addr *uint64, old, new uint64) bool {
if uintptr(unsafe.Pointer(addr))&7 != 0 {
//go:noescape
func Loadp(addr unsafe.Pointer) unsafe.Pointer
+//go:noescape
+func LoadAcq(addr *uint32) uint32
+
//go:noescape
func Cas64(addr *uint64, old, new uint64) bool
+//go:noescape
+func CasRel(addr *uint32, old, new uint32) bool
+
//go:noescape
func Xadd64(addr *uint64, delta int64) uint64
//go:noescape
func Loadp(ptr unsafe.Pointer) unsafe.Pointer
+//go:noescape
+func LoadAcq(addr *uint32) uint32
+
//go:noescape
func Or8(ptr *uint8, val uint8)
//go:noescape
func Cas64(ptr *uint64, old, new uint64) bool
+//go:noescape
+func CasRel(ptr *uint32, old, new uint32) bool
+
//go:noescape
func Store(ptr *uint32, val uint32)
// NO go:noescape annotation; see atomic_pointer.go.
func StorepNoWB(ptr unsafe.Pointer, val unsafe.Pointer)
+
+//go:noescape
+func StoreRel(ptr *uint32, val uint32)
MOVD R0, ret+8(FP)
RET
+// uint32 runtime∕internal∕atomic·LoadAcq(uint32 volatile* addr)
+TEXT ·LoadAcq(SB),NOSPLIT,$0-12
+ B ·Load(SB)
+
TEXT runtime∕internal∕atomic·StorepNoWB(SB), NOSPLIT, $0-16
B runtime∕internal∕atomic·Store64(SB)
+TEXT runtime∕internal∕atomic·StoreRel(SB), NOSPLIT, $0-12
+ B runtime∕internal∕atomic·Store(SB)
+
TEXT runtime∕internal∕atomic·Store(SB), NOSPLIT, $0-12
MOVD ptr+0(FP), R0
MOVW val+8(FP), R1
//go:noescape
func Loadp(ptr unsafe.Pointer) unsafe.Pointer
+//go:noescape
+func LoadAcq(ptr *uint32) uint32
+
//go:noescape
func And8(ptr *uint8, val uint8)
//go:noescape
func Cas64(ptr *uint64, old, new uint64) bool
+//go:noescape
+func CasRel(ptr *uint32, old, new uint32) bool
+
//go:noescape
func Store(ptr *uint32, val uint32)
// NO go:noescape annotation; see atomic_pointer.go.
func StorepNoWB(ptr unsafe.Pointer, val unsafe.Pointer)
+
+//go:noescape
+func StoreRel(ptr *uint32, val uint32)
SYNC
MOVV R1, ret+8(FP)
RET
+
+// uint32 runtime∕internal∕atomic·LoadAcq(uint32 volatile* ptr)
+TEXT ·LoadAcq(SB),NOSPLIT|NOFRAME,$0-12
+ JMP atomic·Load(SB)
//go:noescape
func Loadp(ptr unsafe.Pointer) unsafe.Pointer
+//go:noescape
+func LoadAcq(ptr *uint32) uint32
+
//go:noescape
func And8(ptr *uint8, val uint8)
// NO go:noescape annotation; see atomic_pointer.go.
func StorepNoWB(ptr unsafe.Pointer, val unsafe.Pointer)
+
+//go:noescape
+func StoreRel(ptr *uint32, val uint32)
+
+//go:noescape
+func CasRel(addr *uint32, old, new uint32) bool
//go:noescape
func Loadp(ptr unsafe.Pointer) unsafe.Pointer
+//go:noescape
+func LoadAcq(ptr *uint32) uint32
+
//go:noescape
func And8(ptr *uint8, val uint8)
//go:noescape
func Cas64(ptr *uint64, old, new uint64) bool
+//go:noescape
+func CasRel(ptr *uint32, old, new uint32) bool
+
//go:noescape
func Store(ptr *uint32, val uint32)
//go:noescape
func Store64(ptr *uint64, val uint64)
+//go:noescape
+func StoreRel(ptr *uint32, val uint32)
+
// NO go:noescape annotation; see atomic_pointer.go.
func StorepNoWB(ptr unsafe.Pointer, val unsafe.Pointer)
ISYNC
MOVD R3, ret+8(FP)
RET
+
+// uint32 runtime∕internal∕atomic·LoadAcq(uint32 volatile* ptr)
+TEXT ·LoadAcq(SB),NOSPLIT|NOFRAME,$-8-12
+ MOVD ptr+0(FP), R3
+ MOVWZ 0(R3), R3
+ CMPW R3, R3, CR7
+ BC 4, 30, 1(PC) // bne- cr7, 0x4
+ MOVW R3, ret+8(FP)
+ RET
return *ptr
}
+//go:nosplit
+//go:noinline
+func LoadAcq(ptr *uint32) uint32 {
+ return *ptr
+}
+
//go:noinline
//go:nosplit
func Store(ptr *uint32, val uint32) {
*(*uintptr)(ptr) = uintptr(val)
}
+//go:noinline
+//go:nosplit
+func StoreRel(ptr *uint32, val uint32) {
+ *ptr = val
+}
+
//go:noescape
func And8(ptr *uint8, val uint8)
//go:noescape
func Cas64(ptr *uint64, old, new uint64) bool
+
+//go:noescape
+func CasRel(ptr *uint32, old, new uint32) bool
return *(*unsafe.Pointer)(ptr)
}
+//go:nosplit
+//go:noinline
+func LoadAcq(ptr *uint32) uint32 {
+ return *ptr
+}
+
//go:nosplit
//go:noinline
func Load64(ptr *uint64) uint64 {
*ptr = val
}
+//go:nosplit
+//go:noinline
+func StoreRel(ptr *uint32, val uint32) {
+ *ptr = val
+}
+
//go:nosplit
//go:noinline
func Store64(ptr *uint64, val uint64) {
return false
}
+//go:nosplit
+//go:noinline
+func CasRel(ptr *uint32, old, new uint32) bool {
+ if *ptr == old {
+ *ptr = new
+ return true
+ }
+ return false
+}
+
//go:nosplit
//go:noinline
func Storeuintptr(ptr *uintptr, new uintptr) {
}
retry:
- h := atomic.Load(&_p_.runqhead) // load-acquire, synchronize with consumers
+ h := atomic.LoadAcq(&_p_.runqhead) // load-acquire, synchronize with consumers
t := _p_.runqtail
if t-h < uint32(len(_p_.runq)) {
_p_.runq[t%uint32(len(_p_.runq))].set(gp)
- atomic.Store(&_p_.runqtail, t+1) // store-release, makes the item available for consumption
+ atomic.StoreRel(&_p_.runqtail, t+1) // store-release, makes the item available for consumption
return
}
if runqputslow(_p_, gp, h, t) {
for i := uint32(0); i < n; i++ {
batch[i] = _p_.runq[(h+i)%uint32(len(_p_.runq))].ptr()
}
- if !atomic.Cas(&_p_.runqhead, h, h+n) { // cas-release, commits consume
+ if !atomic.CasRel(&_p_.runqhead, h, h+n) { // cas-release, commits consume
return false
}
batch[n] = gp
}
for {
- h := atomic.Load(&_p_.runqhead) // load-acquire, synchronize with other consumers
+ h := atomic.LoadAcq(&_p_.runqhead) // load-acquire, synchronize with other consumers
t := _p_.runqtail
if t == h {
return nil, false
}
gp := _p_.runq[h%uint32(len(_p_.runq))].ptr()
- if atomic.Cas(&_p_.runqhead, h, h+1) { // cas-release, commits consume
+ if atomic.CasRel(&_p_.runqhead, h, h+1) { // cas-release, commits consume
return gp, false
}
}
// Can be executed by any P.
func runqgrab(_p_ *p, batch *[256]guintptr, batchHead uint32, stealRunNextG bool) uint32 {
for {
- h := atomic.Load(&_p_.runqhead) // load-acquire, synchronize with other consumers
- t := atomic.Load(&_p_.runqtail) // load-acquire, synchronize with the producer
+ h := atomic.LoadAcq(&_p_.runqhead) // load-acquire, synchronize with other consumers
+ t := atomic.LoadAcq(&_p_.runqtail) // load-acquire, synchronize with the producer
n := t - h
n = n - n/2
if n == 0 {
g := _p_.runq[(h+i)%uint32(len(_p_.runq))]
batch[(batchHead+i)%uint32(len(batch))] = g
}
- if atomic.Cas(&_p_.runqhead, h, h+n) { // cas-release, commits consume
+ if atomic.CasRel(&_p_.runqhead, h, h+n) { // cas-release, commits consume
return n
}
}
if n == 0 {
return gp
}
- h := atomic.Load(&_p_.runqhead) // load-acquire, synchronize with consumers
+ h := atomic.LoadAcq(&_p_.runqhead) // load-acquire, synchronize with consumers
if t-h+n >= uint32(len(_p_.runq)) {
throw("runqsteal: runq overflow")
}
- atomic.Store(&_p_.runqtail, t+n) // store-release, makes the item available for consumption
+ atomic.StoreRel(&_p_.runqtail, t+n) // store-release, makes the item available for consumption
return gp
}