Skip to content

Commit c88b377

Browse files
Convert Volatile to JIT intrinsics (#88073)
1 parent eccca2f commit c88b377

File tree

10 files changed

+63
-244
lines changed

10 files changed

+63
-244
lines changed

src/coreclr/jit/importercalls.cpp

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2589,6 +2589,9 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis,
25892589
case NI_System_Threading_Interlocked_MemoryBarrier:
25902590
case NI_System_Threading_Interlocked_ReadMemoryBarrier:
25912591

2592+
case NI_System_Threading_Volatile_Read:
2593+
case NI_System_Threading_Volatile_Write:
2594+
25922595
betterToExpand = true;
25932596
break;
25942597

@@ -3842,6 +3845,51 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis,
38423845
break;
38433846
}
38443847

3848+
case NI_System_Threading_Volatile_Read:
3849+
{
3850+
assert((sig->sigInst.methInstCount == 0) || (sig->sigInst.methInstCount == 1));
3851+
var_types retType = sig->sigInst.methInstCount == 0 ? JITtype2varType(sig->retType) : TYP_REF;
3852+
#ifndef TARGET_64BIT
3853+
if ((retType == TYP_LONG) || (retType == TYP_DOUBLE))
3854+
{
3855+
break;
3856+
}
3857+
#endif // !TARGET_64BIT
3858+
assert(retType == TYP_REF || impIsPrimitive(sig->retType));
3859+
retNode = gtNewIndir(retType, impPopStack().val, GTF_IND_VOLATILE);
3860+
break;
3861+
}
3862+
3863+
case NI_System_Threading_Volatile_Write:
3864+
{
3865+
var_types type = TYP_REF;
3866+
if (sig->sigInst.methInstCount == 0)
3867+
{
3868+
CORINFO_CLASS_HANDLE typeHnd = nullptr;
3869+
CorInfoType jitType =
3870+
strip(info.compCompHnd->getArgType(sig, info.compCompHnd->getArgNext(sig->args), &typeHnd));
3871+
assert(impIsPrimitive(jitType));
3872+
type = JITtype2varType(jitType);
3873+
#ifndef TARGET_64BIT
3874+
if ((type == TYP_LONG) || (type == TYP_DOUBLE))
3875+
{
3876+
break;
3877+
}
3878+
#endif // !TARGET_64BIT
3879+
}
3880+
else
3881+
{
3882+
assert(sig->sigInst.methInstCount == 1);
3883+
assert(!eeIsValueClass(sig->sigInst.methInst[0]));
3884+
}
3885+
3886+
GenTree* value = impPopStack().val;
3887+
GenTree* addr = impPopStack().val;
3888+
3889+
retNode = gtNewStoreIndNode(type, addr, value, GTF_IND_VOLATILE);
3890+
break;
3891+
}
3892+
38453893
default:
38463894
break;
38473895
}
@@ -9158,6 +9206,17 @@ NamedIntrinsic Compiler::lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method)
91589206
result = NI_System_Threading_Thread_get_ManagedThreadId;
91599207
}
91609208
}
9209+
else if (strcmp(className, "Volatile") == 0)
9210+
{
9211+
if (strcmp(methodName, "Read") == 0)
9212+
{
9213+
result = NI_System_Threading_Volatile_Read;
9214+
}
9215+
else if (strcmp(methodName, "Write") == 0)
9216+
{
9217+
result = NI_System_Threading_Volatile_Write;
9218+
}
9219+
}
91619220
}
91629221
}
91639222
}

src/coreclr/jit/namedintrinsiclist.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ enum NamedIntrinsic : unsigned short
6868
NI_System_GC_KeepAlive,
6969
NI_System_Threading_Thread_get_CurrentThread,
7070
NI_System_Threading_Thread_get_ManagedThreadId,
71+
NI_System_Threading_Volatile_Read,
72+
NI_System_Threading_Volatile_Write,
7173
NI_System_Type_get_IsEnum,
7274
NI_System_Type_GetEnumUnderlyingType,
7375
NI_System_Type_get_IsValueType,

src/coreclr/tools/Common/TypeSystem/IL/NativeAotILProvider.cs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,6 @@ private static MethodIL TryGetIntrinsicMethodIL(MethodDesc method)
5858
return UnsafeIntrinsics.EmitIL(method);
5959
}
6060
break;
61-
case "Volatile":
62-
{
63-
if (owningType.Namespace == "System.Threading")
64-
return VolatileIntrinsics.EmitIL(method);
65-
}
66-
break;
6761
case "Debug":
6862
{
6963
if (owningType.Namespace == "System.Diagnostics" && method.Name == "DebugBreak")

src/coreclr/tools/Common/TypeSystem/IL/Stubs/VolatileIntrinsics.cs

Lines changed: 0 additions & 106 deletions
This file was deleted.

src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -665,9 +665,6 @@
665665
<Compile Include="..\..\Common\TypeSystem\IL\Stubs\UnsafeIntrinsics.cs">
666666
<Link>IL\Stubs\UnsafeIntrinsics.cs</Link>
667667
</Compile>
668-
<Compile Include="..\..\Common\TypeSystem\IL\Stubs\VolatileIntrinsics.cs">
669-
<Link>IL\Stubs\VolatileIntrinsics.cs</Link>
670-
</Compile>
671668
<Compile Include="..\..\Common\JitInterface\CorInfoInstructionSet.cs">
672669
<Link>JitInterface\CorInfoInstructionSet.cs</Link>
673670
</Compile>

src/coreclr/tools/aot/ILCompiler.ReadyToRun/IL/ReadyToRunILProvider.cs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -85,11 +85,6 @@ private MethodIL TryGetIntrinsicMethodIL(MethodDesc method)
8585
return UnsafeIntrinsics.EmitIL(method);
8686
}
8787

88-
if (mdType.Name == "Volatile" && mdType.Namespace == "System.Threading")
89-
{
90-
return VolatileIntrinsics.EmitIL(method);
91-
}
92-
9388
if (mdType.Name == "Interlocked" && mdType.Namespace == "System.Threading")
9489
{
9590
return InterlockedIntrinsics.EmitIL(_compilationModuleGroup, method);

src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@
4949
<Compile Include="..\..\Common\TypeSystem\IL\Stubs\InterlockedIntrinsics.cs" Link="IL\Stubs\InterlockedIntrinsics.cs" />
5050
<Compile Include="..\..\Common\TypeSystem\IL\Stubs\RuntimeHelpersIntrinsics.cs" Link="IL\Stubs\RuntimeHelpersIntrinsics.cs" />
5151
<Compile Include="..\..\Common\TypeSystem\IL\Stubs\UnsafeIntrinsics.cs" Link="IL\Stubs\UnsafeIntrinsics.cs" />
52-
<Compile Include="..\..\Common\TypeSystem\IL\Stubs\VolatileIntrinsics.cs" Link="IL\Stubs\VolatileIntrinsics.cs" />
5352
<Compile Include="..\..\Common\TypeSystem\IL\Stubs\PInvokeILCodeStreams.cs" Link="IL\Stubs\PInvokeILCodeStreams.cs" />
5453
<Compile Include="..\..\Common\TypeSystem\Interop\IL\Marshaller.cs" Link="Interop\IL\Marshaller.cs" />
5554
<Compile Include="..\..\Common\TypeSystem\Interop\IL\MarshallerKind.cs" Link="Interop\IL\MarshallerKind.cs" />

src/coreclr/vm/corelib.h

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -615,29 +615,6 @@ END_ILLINK_FEATURE_SWITCH()
615615
DEFINE_CLASS(MONITOR, Threading, Monitor)
616616
DEFINE_METHOD(MONITOR, ENTER, Enter, SM_Obj_RetVoid)
617617

618-
DEFINE_CLASS(VOLATILE, Threading, Volatile)
619-
620-
#define DEFINE_VOLATILE_METHODS(methodType, paramType) \
621-
DEFINE_METHOD(VOLATILE, READ_##paramType, Read, methodType##_Ref##paramType##_Ret##paramType) \
622-
DEFINE_METHOD(VOLATILE, WRITE_##paramType, Write, methodType##_Ref##paramType##_##paramType)
623-
624-
DEFINE_VOLATILE_METHODS(SM,Bool)
625-
DEFINE_VOLATILE_METHODS(SM,SByt)
626-
DEFINE_VOLATILE_METHODS(SM,Byte)
627-
DEFINE_VOLATILE_METHODS(SM,Shrt)
628-
DEFINE_VOLATILE_METHODS(SM,UShrt)
629-
DEFINE_VOLATILE_METHODS(SM,Int)
630-
DEFINE_VOLATILE_METHODS(SM,UInt)
631-
DEFINE_VOLATILE_METHODS(SM,Long)
632-
DEFINE_VOLATILE_METHODS(SM,ULong)
633-
DEFINE_VOLATILE_METHODS(SM,IntPtr)
634-
DEFINE_VOLATILE_METHODS(SM,UIntPtr)
635-
DEFINE_VOLATILE_METHODS(SM,Flt)
636-
DEFINE_VOLATILE_METHODS(SM,Dbl)
637-
DEFINE_VOLATILE_METHODS(GM,T)
638-
639-
#undef DEFINE_VOLATILE_METHODS
640-
641618
DEFINE_CLASS(PARAMETER, Reflection, ParameterInfo)
642619

643620
DEFINE_CLASS(PARAMETER_MODIFIER, Reflection, ParameterModifier)

src/coreclr/vm/jitinterface.cpp

Lines changed: 0 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -7104,100 +7104,6 @@ bool getILIntrinsicImplementationForUnsafe(MethodDesc * ftn,
71047104
return false;
71057105
}
71067106

7107-
bool getILIntrinsicImplementationForVolatile(MethodDesc * ftn,
7108-
CORINFO_METHOD_INFO * methInfo)
7109-
{
7110-
STANDARD_VM_CONTRACT;
7111-
7112-
//
7113-
// This replaces the implementations of Volatile.* in CoreLib with more efficient ones.
7114-
// We do this because we cannot otherwise express these in C#. What we *want* to do is
7115-
// to treat the byref args to these methods as "volatile." In pseudo-C#, this would look
7116-
// like:
7117-
//
7118-
// int Read(ref volatile int location)
7119-
// {
7120-
// return location;
7121-
// }
7122-
//
7123-
// However, C# does not yet provide a way to declare a byref as "volatile." So instead,
7124-
// we substitute raw IL bodies for these methods that use the correct volatile instructions.
7125-
//
7126-
7127-
_ASSERTE(CoreLibBinder::IsClass(ftn->GetMethodTable(), CLASS__VOLATILE));
7128-
7129-
const size_t VolatileMethodBodySize = 6;
7130-
7131-
struct VolatileMethodImpl
7132-
{
7133-
BinderMethodID methodId;
7134-
BYTE body[VolatileMethodBodySize];
7135-
};
7136-
7137-
#define VOLATILE_IMPL(type, loadinst, storeinst) \
7138-
{ \
7139-
METHOD__VOLATILE__READ_##type, \
7140-
{ \
7141-
CEE_LDARG_0, \
7142-
CEE_PREFIX1, (CEE_VOLATILE & 0xFF), \
7143-
loadinst, \
7144-
CEE_NOP, /*pad to VolatileMethodBodySize bytes*/ \
7145-
CEE_RET \
7146-
} \
7147-
}, \
7148-
{ \
7149-
METHOD__VOLATILE__WRITE_##type, \
7150-
{ \
7151-
CEE_LDARG_0, \
7152-
CEE_LDARG_1, \
7153-
CEE_PREFIX1, (CEE_VOLATILE & 0xFF), \
7154-
storeinst, \
7155-
CEE_RET \
7156-
} \
7157-
},
7158-
7159-
static const VolatileMethodImpl volatileImpls[] =
7160-
{
7161-
VOLATILE_IMPL(T, CEE_LDIND_REF, CEE_STIND_REF)
7162-
VOLATILE_IMPL(Bool, CEE_LDIND_I1, CEE_STIND_I1)
7163-
VOLATILE_IMPL(Int, CEE_LDIND_I4, CEE_STIND_I4)
7164-
VOLATILE_IMPL(IntPtr, CEE_LDIND_I, CEE_STIND_I)
7165-
VOLATILE_IMPL(UInt, CEE_LDIND_U4, CEE_STIND_I4)
7166-
VOLATILE_IMPL(UIntPtr, CEE_LDIND_I, CEE_STIND_I)
7167-
VOLATILE_IMPL(SByt, CEE_LDIND_I1, CEE_STIND_I1)
7168-
VOLATILE_IMPL(Byte, CEE_LDIND_U1, CEE_STIND_I1)
7169-
VOLATILE_IMPL(Shrt, CEE_LDIND_I2, CEE_STIND_I2)
7170-
VOLATILE_IMPL(UShrt, CEE_LDIND_U2, CEE_STIND_I2)
7171-
VOLATILE_IMPL(Flt, CEE_LDIND_R4, CEE_STIND_R4)
7172-
7173-
//
7174-
// Ordinary volatile loads and stores only guarantee atomicity for pointer-sized (or smaller) data.
7175-
// So, on 32-bit platforms we must use Interlocked operations instead for the 64-bit types.
7176-
// The implementation in CoreLib already does this, so we will only substitute a new
7177-
// IL body if we're running on a 64-bit platform.
7178-
//
7179-
IN_TARGET_64BIT(VOLATILE_IMPL(Long, CEE_LDIND_I8, CEE_STIND_I8))
7180-
IN_TARGET_64BIT(VOLATILE_IMPL(ULong, CEE_LDIND_I8, CEE_STIND_I8))
7181-
IN_TARGET_64BIT(VOLATILE_IMPL(Dbl, CEE_LDIND_R8, CEE_STIND_R8))
7182-
};
7183-
7184-
mdMethodDef md = ftn->GetMemberDef();
7185-
for (unsigned i = 0; i < ARRAY_SIZE(volatileImpls); i++)
7186-
{
7187-
if (md == CoreLibBinder::GetMethod(volatileImpls[i].methodId)->GetMemberDef())
7188-
{
7189-
methInfo->ILCode = const_cast<BYTE*>(volatileImpls[i].body);
7190-
methInfo->ILCodeSize = VolatileMethodBodySize;
7191-
methInfo->maxStack = 2;
7192-
methInfo->EHcount = 0;
7193-
methInfo->options = (CorInfoOptions)0;
7194-
return true;
7195-
}
7196-
}
7197-
7198-
return false;
7199-
}
7200-
72017107
bool getILIntrinsicImplementationForInterlocked(MethodDesc * ftn,
72027108
CORINFO_METHOD_INFO * methInfo)
72037109
{
@@ -7618,10 +7524,6 @@ static void getMethodInfoHelper(
76187524
{
76197525
fILIntrinsic = getILIntrinsicImplementationForInterlocked(ftn, methInfo);
76207526
}
7621-
else if (CoreLibBinder::IsClass(pMT, CLASS__VOLATILE))
7622-
{
7623-
fILIntrinsic = getILIntrinsicImplementationForVolatile(ftn, methInfo);
7624-
}
76257527
else if (CoreLibBinder::IsClass(pMT, CLASS__RUNTIME_HELPERS))
76267528
{
76277529
fILIntrinsic = getILIntrinsicImplementationForRuntimeHelpers(ftn, methInfo);

src/libraries/System.Private.CoreLib/src/System/Threading/Volatile.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ namespace System.Threading
1010
/// <summary>Methods for accessing memory with volatile semantics.</summary>
1111
public static unsafe class Volatile
1212
{
13-
// The VM may replace these implementations with more efficient ones in some cases.
14-
// In coreclr, for example, see getILIntrinsicImplementationForVolatile() in jitinterface.cpp.
13+
// The runtime may replace these implementations with more efficient ones in some cases.
14+
// In coreclr, for example, see importercalls.cpp.
1515

1616
#region Boolean
1717
private struct VolatileBoolean { public volatile bool Value; }

0 commit comments

Comments
 (0)