From 54a1183724dd12d67fd021bc625e219a66e96bb4 Mon Sep 17 00:00:00 2001 From: Spencer Comin Date: Fri, 22 Nov 2024 11:28:04 -0500 Subject: [PATCH] Add enum for symbol memory access ordering semantics This change expands the possible memory ordering semantics for a symbol from volatile and non-volatile to volatile, acquire/release, optimization opaque, and transparent. An enum and helper methods are added to facilitate working with memory ordering semantics. Signed-off-by: Spencer Comin --- compiler/aarch64/codegen/OMRTreeEvaluator.cpp | 2 +- compiler/il/OMRSymbol.hpp | 71 ++++++++-- compiler/il/OMRSymbol_inlines.hpp | 124 +++++++++++++++++- compiler/optimizer/OMRSimplifierHandlers.cpp | 4 +- compiler/p/codegen/OMRLoadStoreHandler.cpp | 2 +- compiler/ras/Debug.cpp | 8 +- 6 files changed, 184 insertions(+), 27 deletions(-) diff --git a/compiler/aarch64/codegen/OMRTreeEvaluator.cpp b/compiler/aarch64/codegen/OMRTreeEvaluator.cpp index 7332730c994..5cf1389af70 100644 --- a/compiler/aarch64/codegen/OMRTreeEvaluator.cpp +++ b/compiler/aarch64/codegen/OMRTreeEvaluator.cpp @@ -6196,7 +6196,7 @@ TR::Register *commonStoreEvaluator(TR::Node *node, TR::InstOpCode::Mnemonic op, bool needSync = (node->getSymbolReference()->getSymbol()->isSyncVolatile() && cg->comp()->target().isSMP()); bool lazyVolatile = false; if (node->getSymbolReference()->getSymbol()->isShadow() && - node->getSymbolReference()->getSymbol()->isOrdered() && cg->comp()->target().isSMP()) + node->getSymbolReference()->getSymbol()->isAcquireRelease() && cg->comp()->target().isSMP()) { needSync = true; lazyVolatile = true; diff --git a/compiler/il/OMRSymbol.hpp b/compiler/il/OMRSymbol.hpp index 1733e0dcd11..23cf8de9b0e 100644 --- a/compiler/il/OMRSymbol.hpp +++ b/compiler/il/OMRSymbol.hpp @@ -246,11 +246,6 @@ class OMR_EXTENSIBLE Symbol void setConst() { _flags.set(Const); } bool isConst() { return _flags.testAny(Const); } - void setVolatile() { _flags.set(Volatile); } - void resetVolatile() { _flags.reset(Volatile); } - bool isVolatile() { return _flags.testAny(Volatile); } - inline bool isSyncVolatile(); - void setInitializedReference() { _flags.set(InitializedReference); } void setUninitializedReference() { _flags.reset(InitializedReference); } bool isInitializedReference() { return _flags.testAny(InitializedReference); } @@ -398,8 +393,48 @@ class OMR_EXTENSIBLE Symbol inline void setMemoryTypeShadowSymbol(); inline bool isMemoryTypeShadowSymbol(); - void setOrdered() { _flags.set(Ordered); } - bool isOrdered() { return _flags.testAny(Ordered); } + enum MemoryOrdering + { + TransparentSemantics, ///< Access to transparent symbols is unsynchronized, and only guaranteed to be bitwise + ///< atomic for symbols that are addresses or have data types 32 bits or smaller. + OpaqueSemantics, ///< Access to opaque symbols are bitwise atomic. The execution order of all opaque + ///< accesses to any given address in a single thread is the same as the program order of + ///< accesses to that address, with no guarantees for memory ordering effects on other threads. + AcquireReleaseSemantics, ///< Loads of acquire/release symbols are acquire loads; i.e., memory accesses that are after + ///< a given acquire load in program order will not be reordered to before that acquire load in + ///< execution order. This matches the semantics of C's memory_order_acquire. + ///< Stores to acquire/release symbols are release stores; i.e., memory accesses that are before + ///< a given release store in program order will not be reordered to after that release store in + ///< execution order. This matches the semantics of C's memory_order_release. + ///< Acquire/release symbols also have all the same guarantees that opaque symbols have. + VolatileSemantics, ///< All memory accesses that are before an access to a given volatile symbol in program order + ///< will not be reordered to after that volatile access in execution order, and all memory + ///< accesses that are after that volatile access in program order will not be reordered to + ///< before that volatile access in execution order. + ///< This matches the semantics of C's memory_order_seq_cst. + ///< Volatile symbols also have all the same guarantees that acquire/release symbols have. + + LastMemoryOrdering = VolatileSemantics + }; + + static inline const char *getMemoryOrderingName(MemoryOrdering ordering); + + inline void setMemoryOrdering(MemoryOrdering ordering); + inline MemoryOrdering getMemoryOrdering(); + + inline void setTransparent(); + inline bool isTransparent(); + + inline void setOpaque(); + inline bool isOpaque(); + inline bool isAtLeastOrStrongerThanOpaque(); + + inline void setAcquireRelease(); + inline bool isAcquireRelease(); + inline bool isAtLeastOrStrongerThanAcquireRelease(); + + inline void setVolatile(); + inline bool isVolatile(); // flag methods specific to labels // @@ -494,17 +529,30 @@ class OMR_EXTENSIBLE Symbol */ KindMask = 0x00000700, - IsInGlobalRegister = 0x00000800, Const = 0x00001000, - Volatile = 0x00002000, - InitializedReference = 0x00004000, + + /** + * Memory access ordering semantics flags + * These flags line up with the MemoryOrdering enum + */ + Transparent = 0x00000000, + Opaque = 0x00002000, + AcquireRelease = 0x00004000, + Volatile = 0x00006000, + + /** + * Mask used to access memory ordering semantics + */ + MemoryOrderingMask = 0x00006000, + ClassObject = 0x00008000, ///< class object pointer NotCollected = 0x00010000, Final = 0x00020000, InternalPointer = 0x00040000, Private = 0x00080000, AddressOfClassObject = 0x00100000, ///< address of a class object pointer + InitializedReference = 0x00200000, SlotSharedByRefAndNonRef = 0x00400000, ///< used in fsd to indicate that an reference symbol shares a slot with a nonreference symbol HoldsMonitoredObject = 0x08000000, @@ -555,9 +603,6 @@ class OMR_EXTENSIBLE Symbol RecognizedKnownObjectShadow = 0x10000000, GlobalFragmentShadow = 0x08000000, MemoryTypeShadow = 0x04000000, - Ordered = 0x02000000, - // Available = 0x01000000, - // Available = 0x00800000, // only use by Symbols for which isLabel is true // diff --git a/compiler/il/OMRSymbol_inlines.hpp b/compiler/il/OMRSymbol_inlines.hpp index 5ff98c60517..b43ab9690db 100644 --- a/compiler/il/OMRSymbol_inlines.hpp +++ b/compiler/il/OMRSymbol_inlines.hpp @@ -491,6 +491,122 @@ OMR::Symbol::isMemoryTypeShadowSymbol() return self()->isShadow() && _flags.testAny(MemoryTypeShadow); } +const char * +OMR::Symbol::getMemoryOrderingName(OMR::Symbol::MemoryOrdering ordering) + { + switch (ordering) + { + case TransparentSemantics: return "transparent"; + case OpaqueSemantics: return "opaque"; + case AcquireReleaseSemantics: return "acquire/release"; + case VolatileSemantics: return "volatile"; + + default: + TR_ASSERT_FATAL(false, "Unrecognized memory ordering type"); + return NULL; + } + } + +void +OMR::Symbol::setMemoryOrdering(OMR::Symbol::MemoryOrdering ordering) + { + switch (ordering) + { + case TransparentSemantics: + setTransparent(); + break; + case OpaqueSemantics: + setOpaque(); + break; + case AcquireReleaseSemantics: + setAcquireRelease(); + break; + case VolatileSemantics: + setVolatile(); + break; + + default: + TR_ASSERT_FATAL(false, "Unrecognized memory access ordering type"); + break; + } + } + +OMR::Symbol::MemoryOrdering +OMR::Symbol::getMemoryOrdering() + { + switch (_flags.getValue(MemoryOrderingMask)) + { + case Transparent: return TransparentSemantics; + case Opaque: return OpaqueSemantics; + case AcquireRelease: return AcquireReleaseSemantics; + case Volatile: return VolatileSemantics; + + default: + TR_ASSERT_FATAL(false, "This should be unreachable"); + return 0; + } + } + +void +OMR::Symbol::setTransparent() + { + _flags.setValue(MemoryOrderingMask, Transparent); + } + +bool +OMR::Symbol::isTransparent() + { + return _flags.testValue(MemoryOrderingMask, Transparent); + } + +void +OMR::Symbol::setOpaque() + { + _flags.setValue(MemoryOrderingMask, Opaque); + } + +bool +OMR::Symbol::isOpaque() + { + return _flags.testValue(MemoryOrderingMask, Opaque); + } + +bool +OMR::Symbol::isAtLeastOrStrongerThanOpaque() + { + return _flags.getValue(MemoryOrderingMask) >= Opaque; + } + +void +OMR::Symbol::setAcquireRelease() + { + _flags.setValue(MemoryOrderingMask, AcquireRelease); + } + +bool +OMR::Symbol::isAcquireRelease() + { + return _flags.testValue(MemoryOrderingMask, AcquireRelease); + } + +bool +OMR::Symbol::isAtLeastOrStrongerThanAcquireRelease() + { + return _flags.getValue(MemoryOrderingMask) >= AcquireRelease; + } + +void +OMR::Symbol::setVolatile() + { + _flags.setValue(MemoryOrderingMask, Volatile); + } + +bool +OMR::Symbol::isVolatile() + { + return _flags.testValue(MemoryOrderingMask, Volatile); + } + void OMR::Symbol::setStartOfColdInstructionStream() { @@ -751,12 +867,6 @@ OMR::Symbol::isRegularShadow() return self()->isShadow() && !self()->isAutoField() && !self()->isParmField(); } -bool -OMR::Symbol::isSyncVolatile() - { - return self()->isVolatile(); - } - void OMR::Symbol::setDummyResolvedMethod() { @@ -884,4 +994,6 @@ OMR::Symbol::getVariableSizeSymbol() return self()->isVariableSizeSymbol() ? (TR::AutomaticSymbol *)this : 0; } + + #endif // OMR_SYMBOL_INLINES_INCL diff --git a/compiler/optimizer/OMRSimplifierHandlers.cpp b/compiler/optimizer/OMRSimplifierHandlers.cpp index fa1988ecf4b..f8a3aee8b78 100644 --- a/compiler/optimizer/OMRSimplifierHandlers.cpp +++ b/compiler/optimizer/OMRSimplifierHandlers.cpp @@ -5553,7 +5553,7 @@ TR::Node *indirectLoadSimplifier(TR::Node * node, TR::Block * block, TR::Simplif (node->getSymbol()->getSize() == firstChild->getSymbol()->getSize()) && (firstChild->getSymbolReference()->getSymbol()->isAutoOrParm() || localStatic) && node->getSymbolReference()->getOffset() == 0 && - (node->getSymbol()->isVolatile() == firstChild->getSymbol()->isVolatile()) && + (node->getSymbol()->getMemoryOrdering() == firstChild->getSymbol()->getMemoryOrdering()) && performTransformation(s->comp(), "%sReplace indirect load %s [" POINTER_PRINTF_FORMAT "] with ", s->optDetailString(), node->getOpCode().getName(),node)) { @@ -5677,7 +5677,7 @@ TR::Node *indirectStoreSimplifier(TR::Node * node, TR::Block * block, TR::Simpli if ((storeDataType == addrDataType && isSameType) && (firstChild->getSymbolReference()->getSymbol()->isAutoOrParm() || localStatic) && node->getSymbolReference()->getOffset() == 0 && - (node->getSymbol()->isVolatile() == firstChild->getSymbol()->isVolatile()) && + (node->getSymbol()->getMemoryOrdering() == firstChild->getSymbol()->getMemoryOrdering()) && performTransformation(s->comp(), "%sReplace indirect store %s [" POINTER_PRINTF_FORMAT "] with ", s->optDetailString(), node->getOpCode().getName(),node)) { diff --git a/compiler/p/codegen/OMRLoadStoreHandler.cpp b/compiler/p/codegen/OMRLoadStoreHandler.cpp index 88aac1f249f..b4e7d4e78ac 100644 --- a/compiler/p/codegen/OMRLoadStoreHandler.cpp +++ b/compiler/p/codegen/OMRLoadStoreHandler.cpp @@ -282,7 +282,7 @@ StoreSyncRequirements getStoreSyncRequirements(TR::CodeGenerator *cg, TR::Node * return StoreSyncRequirements::Full; } - else if (node->getSymbol()->isShadow() && node->getSymbol()->isOrdered() && cg->comp()->target().isSMP()) + else if (node->getSymbol()->isShadow() && node->getSymbol()->isAcquireRelease() && cg->comp()->target().isSMP()) { return StoreSyncRequirements::LazySet; } diff --git a/compiler/ras/Debug.cpp b/compiler/ras/Debug.cpp index 1bda7e7070c..ba5ffb7ee5c 100644 --- a/compiler/ras/Debug.cpp +++ b/compiler/ras/Debug.cpp @@ -1070,8 +1070,8 @@ TR_Debug::print(TR::SymbolReference * symRef, TR_PrettyPrinterString& output, bo } if (symRef->getSymbol()->isFinal()) symRefKind.appends(" final"); - if (symRef->getSymbol()->isVolatile()) - symRefKind.appends(" volatile"); + if (!symRef->getSymbol()->isTransparent()) + symRefKind.appendf(" %s", TR::Symbol::getMemoryOrderingName(symRef->getSymbol()->getMemoryOrdering())); switch (sym->getKind()) { case TR::Symbol::IsAutomatic: @@ -1208,9 +1208,9 @@ TR_Debug::print(TR::SymbolReference * symRef, TR_PrettyPrinterString& output, bo output.appendf(")"); - if (sym->isVolatile()) + if (!sym->isTransparent()) { - output.appends(" [volatile]"); + output.appendf(" [%s]", TR::Symbol::getMemoryOrderingName(sym->getMemoryOrdering())); } } }