1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/nsprpub/pr/src/md/unix/os_SunOS_ultrasparc.s Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,173 @@ 1.4 +! -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- 1.5 +! 1.6 +! This Source Code Form is subject to the terms of the Mozilla Public 1.7 +! License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 +! file, You can obtain one at http://mozilla.org/MPL/2.0/. 1.9 + 1.10 +! 1.11 +! atomic increment, decrement and swap routines for V8+ sparc (ultrasparc) 1.12 +! using CAS (compare-and-swap) atomic instructions 1.13 +! 1.14 +! this MUST be compiled with an ultrasparc-aware assembler 1.15 +! 1.16 +! standard asm linkage macros; this module must be compiled 1.17 +! with the -P option (use C preprocessor) 1.18 + 1.19 +#include <sys/asm_linkage.h> 1.20 + 1.21 +! ====================================================================== 1.22 +! 1.23 +! Perform the sequence a = a + 1 atomically with respect to other 1.24 +! fetch-and-adds to location a in a wait-free fashion. 1.25 +! 1.26 +! usage : val = PR_AtomicIncrement(address) 1.27 +! return: current value (you'd think this would be old val) 1.28 +! 1.29 +! ----------------------- 1.30 +! Note on REGISTER USAGE: 1.31 +! as this is a LEAF procedure, a new stack frame is not created; 1.32 +! we use the caller's stack frame so what would normally be %i (input) 1.33 +! registers are actually %o (output registers). Also, we must not 1.34 +! overwrite the contents of %l (local) registers as they are not 1.35 +! assumed to be volatile during calls. 1.36 +! 1.37 +! So, the registers used are: 1.38 +! %o0 [input] - the address of the value to increment 1.39 +! %o1 [local] - work register 1.40 +! %o2 [local] - work register 1.41 +! %o3 [local] - work register 1.42 +! ----------------------- 1.43 + 1.44 + ENTRY(PR_AtomicIncrement) ! standard assembler/ELF prologue 1.45 + 1.46 +retryAI: 1.47 + ld [%o0], %o2 ! set o2 to the current value 1.48 + add %o2, 0x1, %o3 ! calc the new value 1.49 + mov %o3, %o1 ! save the return value 1.50 + cas [%o0], %o2, %o3 ! atomically set if o0 hasn't changed 1.51 + cmp %o2, %o3 ! see if we set the value 1.52 + bne retryAI ! if not, try again 1.53 + nop ! empty out the branch pipeline 1.54 + retl ! return back to the caller 1.55 + mov %o1, %o0 ! set the return code to the new value 1.56 + 1.57 + SET_SIZE(PR_AtomicIncrement) ! standard assembler/ELF epilogue 1.58 + 1.59 +! 1.60 +! end 1.61 +! 1.62 +! ====================================================================== 1.63 +! 1.64 + 1.65 +! ====================================================================== 1.66 +! 1.67 +! Perform the sequence a = a - 1 atomically with respect to other 1.68 +! fetch-and-decs to location a in a wait-free fashion. 1.69 +! 1.70 +! usage : val = PR_AtomicDecrement(address) 1.71 +! return: current value (you'd think this would be old val) 1.72 +! 1.73 +! ----------------------- 1.74 +! Note on REGISTER USAGE: 1.75 +! as this is a LEAF procedure, a new stack frame is not created; 1.76 +! we use the caller's stack frame so what would normally be %i (input) 1.77 +! registers are actually %o (output registers). Also, we must not 1.78 +! overwrite the contents of %l (local) registers as they are not 1.79 +! assumed to be volatile during calls. 1.80 +! 1.81 +! So, the registers used are: 1.82 +! %o0 [input] - the address of the value to increment 1.83 +! %o1 [local] - work register 1.84 +! %o2 [local] - work register 1.85 +! %o3 [local] - work register 1.86 +! ----------------------- 1.87 + 1.88 + ENTRY(PR_AtomicDecrement) ! standard assembler/ELF prologue 1.89 + 1.90 +retryAD: 1.91 + ld [%o0], %o2 ! set o2 to the current value 1.92 + sub %o2, 0x1, %o3 ! calc the new value 1.93 + mov %o3, %o1 ! save the return value 1.94 + cas [%o0], %o2, %o3 ! atomically set if o0 hasn't changed 1.95 + cmp %o2, %o3 ! see if we set the value 1.96 + bne retryAD ! if not, try again 1.97 + nop ! empty out the branch pipeline 1.98 + retl ! return back to the caller 1.99 + mov %o1, %o0 ! set the return code to the new value 1.100 + 1.101 + SET_SIZE(PR_AtomicDecrement) ! standard assembler/ELF epilogue 1.102 + 1.103 +! 1.104 +! end 1.105 +! 1.106 +! ====================================================================== 1.107 +! 1.108 + 1.109 +! ====================================================================== 1.110 +! 1.111 +! Perform the sequence a = b atomically with respect to other 1.112 +! fetch-and-stores to location a in a wait-free fashion. 1.113 +! 1.114 +! usage : old_val = PR_AtomicSet(address, newval) 1.115 +! 1.116 +! ----------------------- 1.117 +! Note on REGISTER USAGE: 1.118 +! as this is a LEAF procedure, a new stack frame is not created; 1.119 +! we use the caller's stack frame so what would normally be %i (input) 1.120 +! registers are actually %o (output registers). Also, we must not 1.121 +! overwrite the contents of %l (local) registers as they are not 1.122 +! assumed to be volatile during calls. 1.123 +! 1.124 +! So, the registers used are: 1.125 +! %o0 [input] - the address of the value to increment 1.126 +! %o1 [input] - the new value to set for [%o0] 1.127 +! %o2 [local] - work register 1.128 +! %o3 [local] - work register 1.129 +! ----------------------- 1.130 + 1.131 + ENTRY(PR_AtomicSet) ! standard assembler/ELF prologue 1.132 + 1.133 +retryAS: 1.134 + ld [%o0], %o2 ! set o2 to the current value 1.135 + mov %o1, %o3 ! set up the new value 1.136 + cas [%o0], %o2, %o3 ! atomically set if o0 hasn't changed 1.137 + cmp %o2, %o3 ! see if we set the value 1.138 + bne retryAS ! if not, try again 1.139 + nop ! empty out the branch pipeline 1.140 + retl ! return back to the caller 1.141 + mov %o3, %o0 ! set the return code to the prev value 1.142 + 1.143 + SET_SIZE(PR_AtomicSet) ! standard assembler/ELF epilogue 1.144 + 1.145 +! 1.146 +! end 1.147 +! 1.148 +! ====================================================================== 1.149 +! 1.150 + 1.151 +! ====================================================================== 1.152 +! 1.153 +! Perform the sequence a = a + b atomically with respect to other 1.154 +! fetch-and-adds to location a in a wait-free fashion. 1.155 +! 1.156 +! usage : newval = PR_AtomicAdd(address, val) 1.157 +! return: the value after addition 1.158 +! 1.159 + ENTRY(PR_AtomicAdd) ! standard assembler/ELF prologue 1.160 + 1.161 +retryAA: 1.162 + ld [%o0], %o2 ! set o2 to the current value 1.163 + add %o2, %o1, %o3 ! calc the new value 1.164 + mov %o3, %o4 ! save the return value 1.165 + cas [%o0], %o2, %o3 ! atomically set if o0 hasn't changed 1.166 + cmp %o2, %o3 ! see if we set the value 1.167 + bne retryAA ! if not, try again 1.168 + nop ! empty out the branch pipeline 1.169 + retl ! return back to the caller 1.170 + mov %o4, %o0 ! set the return code to the new value 1.171 + 1.172 + SET_SIZE(PR_AtomicAdd) ! standard assembler/ELF epilogue 1.173 + 1.174 +! 1.175 +! end 1.176 +!