1 /*
   2  * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *
  23  */
  24 
  25 #ifndef OS_CPU_LINUX_SPARC_VM_ATOMIC_LINUX_SPARC_INLINE_HPP
  26 #define OS_CPU_LINUX_SPARC_VM_ATOMIC_LINUX_SPARC_INLINE_HPP
  27 
  28 // Implementation of class atomic
  29 
  30 template<size_t byte_size>
  31 struct Atomic::PlatformAdd
  32   : Atomic::AddAndFetch<Atomic::PlatformAdd<byte_size> >
  33 {
  34   template<typename I, typename D>
  35   D add_and_fetch(I add_value, D volatile* dest) const;
  36 };
  37 
  38 template<>
  39 template<typename I, typename D>
  40 inline D Atomic::PlatformAdd<4>::add_and_fetch(I add_value, D volatile* dest) const {
  41   STATIC_ASSERT(4 == sizeof(I));
  42   STATIC_ASSERT(4 == sizeof(D));
  43 
  44   D rv;
  45   __asm__ volatile(
  46     "1: \n\t"
  47     " ld     [%2], %%o2\n\t"
  48     " add    %1, %%o2, %%o3\n\t"
  49     " cas    [%2], %%o2, %%o3\n\t"
  50     " cmp    %%o2, %%o3\n\t"
  51     " bne    1b\n\t"
  52     "  nop\n\t"
  53     " add    %1, %%o2, %0\n\t"
  54     : "=r" (rv)
  55     : "r" (add_value), "r" (dest)
  56     : "memory", "o2", "o3");
  57   return rv;
  58 }
  59 
  60 template<>
  61 template<typename I, typename D>
  62 inline D Atomic::PlatformAdd<8>::add_and_fetch(I add_value, D volatile* dest) const {
  63   STATIC_ASSERT(8 == sizeof(I));
  64   STATIC_ASSERT(8 == sizeof(D));
  65 
  66   D rv;
  67   __asm__ volatile(
  68     "1: \n\t"
  69     " ldx    [%2], %%o2\n\t"
  70     " add    %1, %%o2, %%o3\n\t"
  71     " casx   [%2], %%o2, %%o3\n\t"
  72     " cmp    %%o2, %%o3\n\t"
  73     " bne    %%xcc, 1b\n\t"
  74     "  nop\n\t"
  75     " add    %1, %%o2, %0\n\t"
  76     : "=r" (rv)
  77     : "r" (add_value), "r" (dest)
  78     : "memory", "o2", "o3");
  79   return rv;
  80 }
  81 
  82 template<>
  83 template<typename T>
  84 inline T Atomic::PlatformXchg<4>::operator()(T exchange_value,
  85                                              T volatile* dest) const {
  86   STATIC_ASSERT(4 == sizeof(T));
  87   T rv = exchange_value;
  88   __asm__ volatile(
  89     " swap   [%2],%1\n\t"
  90     : "=r" (rv)
  91     : "0" (exchange_value) /* we use same register as for return value */, "r" (dest)
  92     : "memory");
  93   return rv;
  94 }
  95 
  96 template<>
  97 template<typename T>
  98 inline T Atomic::PlatformXchg<8>::operator()(T exchange_value,
  99                                              T volatile* dest) const {
 100   STATIC_ASSERT(8 == sizeof(T));
 101   T rv = exchange_value;
 102   __asm__ volatile(
 103     "1:\n\t"
 104     " mov    %1, %%o3\n\t"
 105     " ldx    [%2], %%o2\n\t"
 106     " casx   [%2], %%o2, %%o3\n\t"
 107     " cmp    %%o2, %%o3\n\t"
 108     " bne    %%xcc, 1b\n\t"
 109     "  nop\n\t"
 110     " mov    %%o2, %0\n\t"
 111     : "=r" (rv)
 112     : "r" (exchange_value), "r" (dest)
 113     : "memory", "o2", "o3");
 114   return rv;
 115 }
 116 
 117 // No direct support for cmpxchg of bytes; emulate using int.
 118 template<>
 119 struct Atomic::PlatformCmpxchg<1> : Atomic::CmpxchgByteUsingInt {};
 120 
 121 template<>
 122 template<typename T>
 123 inline T Atomic::PlatformCmpxchg<4>::operator()(T exchange_value,
 124                                                 T volatile* dest,
 125                                                 T compare_value,
 126                                                 cmpxchg_memory_order order) const {
 127   STATIC_ASSERT(4 == sizeof(T));
 128   T rv;
 129   __asm__ volatile(
 130     " cas    [%2], %3, %0"
 131     : "=r" (rv)
 132     : "0" (exchange_value), "r" (dest), "r" (compare_value)
 133     : "memory");
 134   return rv;
 135 }
 136 
 137 template<>
 138 template<typename T>
 139 inline T Atomic::PlatformCmpxchg<8>::operator()(T exchange_value,
 140                                                 T volatile* dest,
 141                                                 T compare_value,
 142                                                 cmpxchg_memory_order order) const {
 143   STATIC_ASSERT(8 == sizeof(T));
 144   T rv;
 145   __asm__ volatile(
 146     " casx   [%2], %3, %0"
 147     : "=r" (rv)
 148     : "0" (exchange_value), "r" (dest), "r" (compare_value)
 149     : "memory");
 150   return rv;
 151 }
 152 
 153 #endif // OS_CPU_LINUX_SPARC_VM_ATOMIC_LINUX_SPARC_INLINE_HPP