Skip to content

Commit

Permalink
Fix incorrect r2r codegen for hardware instrinsics (dotnet#33090)
Browse files Browse the repository at this point in the history
* Address incorrect generation of insertps and dpps instructions in crossgen images
* Implement matching intrinsics processing for crossgen2
Fixes dotnet#32175
  • Loading branch information
davidwrighton authored Mar 4, 2020
1 parent 423d70a commit e66e9fa
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ public static bool IsHardwareIntrinsic(MethodDesc method)
return false;
}

#if !READYTORUN
public static bool IsIsSupportedMethod(MethodDesc method)
{
return method.Name == "get_IsSupported";
Expand Down Expand Up @@ -188,5 +189,6 @@ private static class XArchIntrinsicConstants
public const int Popcnt = 0x0040;
public const int Lzcnt = 0x0080;
}
#endif // !READYTORUN
}
}
11 changes: 11 additions & 0 deletions src/coreclr/src/tools/Common/JitInterface/CorInfoImpl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2826,13 +2826,24 @@ private uint getJitFlags(ref CORJIT_FLAGS flags, uint sizeInBytes)
#endif
)
{
#if !READYTORUN
// This list needs to match the list of intrinsics we can generate detection code for
// in HardwareIntrinsicHelpers.EmitIsSupportedIL.
#else
// For ReadyToRun, this list needs to match up with the behavior of FilterNamedIntrinsicMethodAttribs
// In particular, that this list of supported hardware will not generate non-SSE2 safe instruction
// sequences when paired with the behavior in FilterNamedIntrinsicMethodAttribs
#endif
flags.Set(CorJitFlag.CORJIT_FLAG_USE_AES);
flags.Set(CorJitFlag.CORJIT_FLAG_USE_PCLMULQDQ);
flags.Set(CorJitFlag.CORJIT_FLAG_USE_SSE3);
flags.Set(CorJitFlag.CORJIT_FLAG_USE_SSSE3);
flags.Set(CorJitFlag.CORJIT_FLAG_USE_LZCNT);
#if READYTORUN
flags.Set(CorJitFlag.CORJIT_FLAG_USE_SSE41);
flags.Set(CorJitFlag.CORJIT_FLAG_USE_SSE42);
flags.Set(CorJitFlag.CORJIT_FLAG_USE_POPCNT);
#endif
}

if (this.MethodBeingCompiled.IsNativeCallable)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1554,6 +1554,37 @@ private uint FilterNamedIntrinsicMethodAttribs(uint attribs, MethodDesc method)
fTreatAsRegularMethodCall = (methodName == "Round");
}
}
else if (namespaceName == "System.Numerics")
{
if ((className == "Vector3") || (className == "Vector4"))
{
if (methodName == ".ctor")
{
// Vector3 and Vector4 have constructors which take a smaller Vector and create bolt on
// a larger vector. This uses insertps instruction when compiled with SSE4.1 instruction support
// which must not be generated inline in R2R images that actually support an SSE2 only mode.
if ((method.Signature.Length > 1) && (method.Signature[0].IsValueType && !method.Signature[0].IsPrimitive))
{
fTreatAsRegularMethodCall = true;
}
}
else if (methodName == "Dot")
{
// The dot product operations uses the dpps instruction when compiled with SSE4.1 instruction
// support. This must not be generated inline in R2R images that actually support an SSE2 only mode.
fTreatAsRegularMethodCall = true;
}
}
else if ((className == "Vector2") || (className == "Vector") || (className == "Vector`1"))
{
if (methodName == "Dot")
{
// The dot product operations uses the dpps instruction when compiled with SSE4.1 instruction
// support. This must not be generated inline in R2R images that actually support an SSE2 only mode.
fTreatAsRegularMethodCall = true;
}
}
}
}

if (fTreatAsRegularMethodCall)
Expand Down
40 changes: 37 additions & 3 deletions src/coreclr/src/zap/zapinfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2102,7 +2102,7 @@ void ZapInfo::GetProfilingHandle(BOOL *pbHookFunction,
//
// This strips the CORINFO_FLG_JIT_INTRINSIC flag from some of the named intrinsic methods.
//
DWORD FilterNamedIntrinsicMethodAttribs(DWORD attribs, CORINFO_METHOD_HANDLE ftn, ICorDynamicInfo* pJitInfo)
DWORD FilterNamedIntrinsicMethodAttribs(ZapInfo* pZapInfo, DWORD attribs, CORINFO_METHOD_HANDLE ftn, ICorDynamicInfo* pJitInfo)
{
if (attribs & CORINFO_FLG_JIT_INTRINSIC)
{
Expand Down Expand Up @@ -2179,6 +2179,40 @@ DWORD FilterNamedIntrinsicMethodAttribs(DWORD attribs, CORINFO_METHOD_HANDLE ftn
fTreatAsRegularMethodCall = strcmp(methodName, "Round") == 0;
}
}
else if (strcmp(namespaceName, "System.Numerics") == 0)
{
if ((strcmp(className, "Vector3") == 0) || (strcmp(className, "Vector4") == 0))
{
// Vector3 and Vector4 have constructors which take a smaller Vector and create bolt on
// a larger vector. This uses insertps instruction when compiled with SSE4.1 instruction support
// which must not be generated inline in R2R images that actually support an SSE2 only mode.
if (strcmp(methodName, ".ctor") == 0)
{
CORINFO_SIG_INFO sig;
pZapInfo->getMethodSig(ftn, &sig, NULL);
CORINFO_CLASS_HANDLE argClass;
if ((CorInfoType)pZapInfo->getArgType(&sig, sig.args, &argClass) == CORINFO_TYPE_VALUECLASS)
{
fTreatAsRegularMethodCall = TRUE;
}
}
else if (strcmp(methodName, "Dot") == 0)
{
// The dot product operations uses the dpps instruction when compiled with SSE4.1 instruction
// support. This must not be generated inline in R2R images that actually support an SSE2 only mode.
fTreatAsRegularMethodCall = TRUE;
}
}
else if ((strcmp(className, "Vector2") == 0) || (strcmp(className, "Vector") == 0) || (strcmp(className, "Vector`1") == 0))
{
if (strcmp(methodName, "Dot") == 0)
{
// The dot product operations uses the dpps instruction when compiled with SSE4.1 instruction
// support. This must not be generated inline in R2R images that actually support an SSE2 only mode.
fTreatAsRegularMethodCall = TRUE;
}
}
}
#endif // defined(TARGET_X86) || defined(TARGET_AMD64)

if (fTreatAsRegularMethodCall)
Expand Down Expand Up @@ -2216,7 +2250,7 @@ void ZapInfo::getCallInfo(CORINFO_RESOLVED_TOKEN * pResolvedToken,
(CORINFO_CALLINFO_FLAGS)(flags | CORINFO_CALLINFO_KINDONLY),
pResult);

pResult->methodFlags = FilterNamedIntrinsicMethodAttribs(pResult->methodFlags, pResult->hMethod, m_pEEJitInfo);
pResult->methodFlags = FilterNamedIntrinsicMethodAttribs(this, pResult->methodFlags, pResult->hMethod, m_pEEJitInfo);

#ifdef FEATURE_READYTORUN_COMPILER
if (IsReadyToRunCompilation())
Expand Down Expand Up @@ -3766,7 +3800,7 @@ unsigned ZapInfo::getMethodHash(CORINFO_METHOD_HANDLE ftn)
DWORD ZapInfo::getMethodAttribs(CORINFO_METHOD_HANDLE ftn)
{
DWORD result = m_pEEJitInfo->getMethodAttribs(ftn);
return FilterNamedIntrinsicMethodAttribs(result, ftn, m_pEEJitInfo);
return FilterNamedIntrinsicMethodAttribs(this, result, ftn, m_pEEJitInfo);
}

void ZapInfo::setMethodAttribs(CORINFO_METHOD_HANDLE ftn, CorInfoMethodRuntimeFlags attribs)
Expand Down

0 comments on commit e66e9fa

Please sign in to comment.