nsprpub/pr/src/md/unix/os_SunOS_ultrasparc.s

changeset 0
6474c204b198
     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 +!

mercurial