Path: blob/master/src/hotspot/os_cpu/aix_ppc/atomic_aix_ppc.hpp
40930 views
/*1* Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.2* Copyright (c) 2012, 2019 SAP SE. 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 it6* under the terms of the GNU General Public License version 2 only, as7* published by the Free Software Foundation.8*9* This code is distributed in the hope that it will be useful, but WITHOUT10* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or11* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License12* version 2 for more details (a copy is included in the LICENSE file that13* accompanied this code).14*15* You should have received a copy of the GNU General Public License version16* 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 USA20* or visit www.oracle.com if you need additional information or have any21* questions.22*23*/2425#ifndef OS_CPU_AIX_PPC_ATOMIC_AIX_PPC_HPP26#define OS_CPU_AIX_PPC_ATOMIC_AIX_PPC_HPP2728#ifndef PPC6429#error "Atomic currently only implemented for PPC64"30#endif3132#include "orderAccess_aix_ppc.hpp"33#include "utilities/debug.hpp"3435// Implementation of class atomic3637//38// machine barrier instructions:39//40// - sync two-way memory barrier, aka fence41// - lwsync orders Store|Store,42// Load|Store,43// Load|Load,44// but not Store|Load45// - eieio orders memory accesses for device memory (only)46// - isync invalidates speculatively executed instructions47// From the POWER ISA 2.06 documentation:48// "[...] an isync instruction prevents the execution of49// instructions following the isync until instructions50// preceding the isync have completed, [...]"51// From IBM's AIX assembler reference:52// "The isync [...] instructions causes the processor to53// refetch any instructions that might have been fetched54// prior to the isync instruction. The instruction isync55// causes the processor to wait for all previous instructions56// to complete. Then any instructions already fetched are57// discarded and instruction processing continues in the58// environment established by the previous instructions."59//60// semantic barrier instructions:61// (as defined in orderAccess.hpp)62//63// - release orders Store|Store, (maps to lwsync)64// Load|Store65// - acquire orders Load|Store, (maps to lwsync)66// Load|Load67// - fence orders Store|Store, (maps to sync)68// Load|Store,69// Load|Load,70// Store|Load71//7273inline void pre_membar(atomic_memory_order order) {74switch (order) {75case memory_order_relaxed:76case memory_order_acquire: break;77case memory_order_release:78case memory_order_acq_rel: __asm__ __volatile__ ("lwsync" : : : "memory"); break;79default /*conservative*/ : __asm__ __volatile__ ("sync" : : : "memory"); break;80}81}8283inline void post_membar(atomic_memory_order order) {84switch (order) {85case memory_order_relaxed:86case memory_order_release: break;87case memory_order_acquire:88case memory_order_acq_rel: __asm__ __volatile__ ("isync" : : : "memory"); break;89default /*conservative*/ : __asm__ __volatile__ ("sync" : : : "memory"); break;90}91}929394template<size_t byte_size>95struct Atomic::PlatformAdd {96template<typename D, typename I>97D add_and_fetch(D volatile* dest, I add_value, atomic_memory_order order) const;9899template<typename D, typename I>100D fetch_and_add(D volatile* dest, I add_value, atomic_memory_order order) const {101return add_and_fetch(dest, add_value, order) - add_value;102}103};104105template<>106template<typename D, typename I>107inline D Atomic::PlatformAdd<4>::add_and_fetch(D volatile* dest, I add_value,108atomic_memory_order order) const {109STATIC_ASSERT(4 == sizeof(I));110STATIC_ASSERT(4 == sizeof(D));111112D result;113114pre_membar(order);115116__asm__ __volatile__ (117"1: lwarx %0, 0, %2 \n"118" add %0, %0, %1 \n"119" stwcx. %0, 0, %2 \n"120" bne- 1b \n"121: /*%0*/"=&r" (result)122: /*%1*/"r" (add_value), /*%2*/"r" (dest)123: "cc", "memory" );124125post_membar(order);126127return result;128}129130131template<>132template<typename D, typename I>133inline D Atomic::PlatformAdd<8>::add_and_fetch(D volatile* dest, I add_value,134atomic_memory_order order) const {135STATIC_ASSERT(8 == sizeof(I));136STATIC_ASSERT(8 == sizeof(D));137138D result;139140pre_membar(order);141142__asm__ __volatile__ (143"1: ldarx %0, 0, %2 \n"144" add %0, %0, %1 \n"145" stdcx. %0, 0, %2 \n"146" bne- 1b \n"147: /*%0*/"=&r" (result)148: /*%1*/"r" (add_value), /*%2*/"r" (dest)149: "cc", "memory" );150151post_membar(order);152153return result;154}155156template<>157template<typename T>158inline T Atomic::PlatformXchg<4>::operator()(T volatile* dest,159T exchange_value,160atomic_memory_order order) const {161// Note that xchg doesn't necessarily do an acquire162// (see synchronizer.cpp).163164T old_value;165const uint64_t zero = 0;166167pre_membar(order);168169__asm__ __volatile__ (170/* atomic loop */171"1: \n"172" lwarx %[old_value], %[dest], %[zero] \n"173" stwcx. %[exchange_value], %[dest], %[zero] \n"174" bne- 1b \n"175/* exit */176"2: \n"177/* out */178: [old_value] "=&r" (old_value),179"=m" (*dest)180/* in */181: [dest] "b" (dest),182[zero] "r" (zero),183[exchange_value] "r" (exchange_value),184"m" (*dest)185/* clobber */186: "cc",187"memory"188);189190post_membar(order);191192return old_value;193}194195template<>196template<typename T>197inline T Atomic::PlatformXchg<8>::operator()(T volatile* dest,198T exchange_value,199atomic_memory_order order) const {200STATIC_ASSERT(8 == sizeof(T));201// Note that xchg doesn't necessarily do an acquire202// (see synchronizer.cpp).203204T old_value;205const uint64_t zero = 0;206207pre_membar(order);208209__asm__ __volatile__ (210/* atomic loop */211"1: \n"212" ldarx %[old_value], %[dest], %[zero] \n"213" stdcx. %[exchange_value], %[dest], %[zero] \n"214" bne- 1b \n"215/* exit */216"2: \n"217/* out */218: [old_value] "=&r" (old_value),219"=m" (*dest)220/* in */221: [dest] "b" (dest),222[zero] "r" (zero),223[exchange_value] "r" (exchange_value),224"m" (*dest)225/* clobber */226: "cc",227"memory"228);229230post_membar(order);231232return old_value;233}234235template<>236template<typename T>237inline T Atomic::PlatformCmpxchg<1>::operator()(T volatile* dest,238T compare_value,239T exchange_value,240atomic_memory_order order) const {241STATIC_ASSERT(1 == sizeof(T));242243// Note that cmpxchg guarantees a two-way memory barrier across244// the cmpxchg, so it's really a a 'fence_cmpxchg_fence' if not245// specified otherwise (see atomic.hpp).246247// Using 32 bit internally.248volatile int *dest_base = (volatile int*)((uintptr_t)dest & ~3);249250#ifdef VM_LITTLE_ENDIAN251const unsigned int shift_amount = ((uintptr_t)dest & 3) * 8;252#else253const unsigned int shift_amount = ((~(uintptr_t)dest) & 3) * 8;254#endif255const unsigned int masked_compare_val = ((unsigned int)(unsigned char)compare_value),256masked_exchange_val = ((unsigned int)(unsigned char)exchange_value),257xor_value = (masked_compare_val ^ masked_exchange_val) << shift_amount;258259unsigned int old_value, value32;260261pre_membar(order);262263__asm__ __volatile__ (264/* simple guard */265" lbz %[old_value], 0(%[dest]) \n"266" cmpw %[masked_compare_val], %[old_value] \n"267" bne- 2f \n"268/* atomic loop */269"1: \n"270" lwarx %[value32], 0, %[dest_base] \n"271/* extract byte and compare */272" srd %[old_value], %[value32], %[shift_amount] \n"273" clrldi %[old_value], %[old_value], 56 \n"274" cmpw %[masked_compare_val], %[old_value] \n"275" bne- 2f \n"276/* replace byte and try to store */277" xor %[value32], %[xor_value], %[value32] \n"278" stwcx. %[value32], 0, %[dest_base] \n"279" bne- 1b \n"280/* exit */281"2: \n"282/* out */283: [old_value] "=&r" (old_value),284[value32] "=&r" (value32),285"=m" (*dest),286"=m" (*dest_base)287/* in */288: [dest] "b" (dest),289[dest_base] "b" (dest_base),290[shift_amount] "r" (shift_amount),291[masked_compare_val] "r" (masked_compare_val),292[xor_value] "r" (xor_value),293"m" (*dest),294"m" (*dest_base)295/* clobber */296: "cc",297"memory"298);299300post_membar(order);301302return PrimitiveConversions::cast<T>((unsigned char)old_value);303}304305template<>306template<typename T>307inline T Atomic::PlatformCmpxchg<4>::operator()(T volatile* dest,308T compare_value,309T exchange_value,310atomic_memory_order order) const {311STATIC_ASSERT(4 == sizeof(T));312313// Note that cmpxchg guarantees a two-way memory barrier across314// the cmpxchg, so it's really a a 'fence_cmpxchg_fence' if not315// specified otherwise (see atomic.hpp).316317T old_value;318const uint64_t zero = 0;319320pre_membar(order);321322__asm__ __volatile__ (323/* simple guard */324" lwz %[old_value], 0(%[dest]) \n"325" cmpw %[compare_value], %[old_value] \n"326" bne- 2f \n"327/* atomic loop */328"1: \n"329" lwarx %[old_value], %[dest], %[zero] \n"330" cmpw %[compare_value], %[old_value] \n"331" bne- 2f \n"332" stwcx. %[exchange_value], %[dest], %[zero] \n"333" bne- 1b \n"334/* exit */335"2: \n"336/* out */337: [old_value] "=&r" (old_value),338"=m" (*dest)339/* in */340: [dest] "b" (dest),341[zero] "r" (zero),342[compare_value] "r" (compare_value),343[exchange_value] "r" (exchange_value),344"m" (*dest)345/* clobber */346: "cc",347"memory"348);349350post_membar(order);351352return old_value;353}354355template<>356template<typename T>357inline T Atomic::PlatformCmpxchg<8>::operator()(T volatile* dest,358T compare_value,359T exchange_value,360atomic_memory_order order) const {361STATIC_ASSERT(8 == sizeof(T));362363// Note that cmpxchg guarantees a two-way memory barrier across364// the cmpxchg, so it's really a a 'fence_cmpxchg_fence' if not365// specified otherwise (see atomic.hpp).366367T old_value;368const uint64_t zero = 0;369370pre_membar(order);371372__asm__ __volatile__ (373/* simple guard */374" ld %[old_value], 0(%[dest]) \n"375" cmpd %[compare_value], %[old_value] \n"376" bne- 2f \n"377/* atomic loop */378"1: \n"379" ldarx %[old_value], %[dest], %[zero] \n"380" cmpd %[compare_value], %[old_value] \n"381" bne- 2f \n"382" stdcx. %[exchange_value], %[dest], %[zero] \n"383" bne- 1b \n"384/* exit */385"2: \n"386/* out */387: [old_value] "=&r" (old_value),388"=m" (*dest)389/* in */390: [dest] "b" (dest),391[zero] "r" (zero),392[compare_value] "r" (compare_value),393[exchange_value] "r" (exchange_value),394"m" (*dest)395/* clobber */396: "cc",397"memory"398);399400post_membar(order);401402return old_value;403}404405template<size_t byte_size>406struct Atomic::PlatformOrderedLoad<byte_size, X_ACQUIRE> {407template <typename T>408T operator()(const volatile T* p) const {409T t = Atomic::load(p);410// Use twi-isync for load_acquire (faster than lwsync).411__asm__ __volatile__ ("twi 0,%0,0\n isync\n" : : "r" (t) : "memory");412return t;413}414};415416#endif // OS_CPU_AIX_PPC_ATOMIC_AIX_PPC_HPP417418419