Skip to content

Commit

Permalink
Add enum for symbol memory access ordering semantics
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
Spencer-Comin committed Dec 11, 2024
1 parent 32ef86c commit 54a1183
Show file tree
Hide file tree
Showing 6 changed files with 184 additions and 27 deletions.
2 changes: 1 addition & 1 deletion compiler/aarch64/codegen/OMRTreeEvaluator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
71 changes: 58 additions & 13 deletions compiler/il/OMRSymbol.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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); }
Expand Down Expand Up @@ -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
//
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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
//
Expand Down
124 changes: 118 additions & 6 deletions compiler/il/OMRSymbol_inlines.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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()
{
Expand Down Expand Up @@ -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()
{
Expand Down Expand Up @@ -884,4 +994,6 @@ OMR::Symbol::getVariableSizeSymbol()
return self()->isVariableSizeSymbol() ? (TR::AutomaticSymbol *)this : 0;
}



#endif // OMR_SYMBOL_INLINES_INCL
4 changes: 2 additions & 2 deletions compiler/optimizer/OMRSimplifierHandlers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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))
{
Expand Down Expand Up @@ -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))
{
Expand Down
2 changes: 1 addition & 1 deletion compiler/p/codegen/OMRLoadStoreHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
8 changes: 4 additions & 4 deletions compiler/ras/Debug.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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()));
}
}
}
Expand Down

0 comments on commit 54a1183

Please sign in to comment.