diff --git a/docs/area-owners.md b/docs/area-owners.md
index e1889072f9f736..7960fcaa9ef907 100644
--- a/docs/area-owners.md
+++ b/docs/area-owners.md
@@ -31,7 +31,7 @@ Note: Editing this file doesn't update the mapping used by `@dotnet-policy-servi
| area-Diagnostics-mono | @tommcdon | @tommcdon @mdh1418 @thaystg | |
| area-EnC-mono | @tommcdon | @mikelle-rogers @thaystg | Hot Reload on WebAssembly, Android, iOS, etc . @lambdageek to consult |
| area-ExceptionHandling-coreclr | @mangod9 | @janvorli | |
-| area-Extensions-Caching | @ericstj | @dotnet/area-extensions-caching | Consultants: @mgravell, @sebastienros |
+| area-Extensions-Caching | @jeffhandley | @dotnet/area-extensions-caching | Consultants: @mgravell, @sebastienros |
| area-Extensions-Configuration | @ericstj | @dotnet/area-extensions-configuration | Consultants: @eerhardt |
| area-Extensions-DependencyInjection | @ericstj | @dotnet/area-extensions-dependencyinjection | Consultants: @halter73, @benjaminpetit |
| area-Extensions-FileSystem | @jeffhandley | @dotnet/area-extensions-filesystem | |
@@ -128,15 +128,15 @@ Note: Editing this file doesn't update the mapping used by `@dotnet-policy-servi
| area-System.ServiceModel | @HongGit | @HongGit @mconnew | Repo: https://github.com/dotnet/WCF
Packages:
- System.ServiceModel.Primitives
- System.ServiceModel.Http
- System.ServiceModel.NetTcp
- System.ServiceModel.Duplex
- System.ServiceModel.Security
|
| area-System.ServiceModel.Syndication | @HongGit | @StephenMolloy @HongGit | |
| area-System.ServiceProcess | @ericstj | @dotnet/area-system-serviceprocess | |
-| area-System.Speech | @jeffhandley | @ericstj @jeffhandley | |
-| area-System.Text.Encoding | @jeffhandley | @dotnet/area-system-text-encoding | |
-| area-System.Text.Encodings.Web | @jeffhandley | @dotnet/area-system-text-encodings-web | |
+| area-System.Speech | @ericstj | @dotnet/area-system-speech | |
+| area-System.Text.Encoding | @ericstj | @dotnet/area-system-text-encoding | |
+| area-System.Text.Encodings.Web | @ericstj | @dotnet/area-system-text-encodings-web | |
| area-System.Text.Json | @jeffhandley | @dotnet/area-system-text-json | |
| area-System.Text.RegularExpressions | @ericstj | @dotnet/area-system-text-regularexpressions | Consultants: @stephentoub |
| area-System.Threading | @mangod9 | @kouvel | |
-| area-System.Threading.Channels | @ericstj | @dotnet/area-system-threading-channels | Consultants: @stephentoub |
+| area-System.Threading.Channels | @jeffhandley | @dotnet/area-system-threading-channels | Consultants: @stephentoub |
| area-System.Threading.RateLimiting | @rafikiassumani-msft | @BrennanConroy @halter73 | |
-| area-System.Threading.Tasks | @ericstj | @dotnet/area-system-threading-tasks | Consultants: @stephentoub |
+| area-System.Threading.Tasks | @jeffhandley | @dotnet/area-system-threading-tasks | Consultants: @stephentoub |
| area-System.Transactions | @sammonort | @roji | |
| area-System.Xml | @jeffhandley | @dotnet/area-system-xml | |
| area-TieredCompilation-coreclr | @mangod9 | @kouvel | |
diff --git a/eng/Subsets.props b/eng/Subsets.props
index 502fd50fbc25c5..4ff3be6bccf268 100644
--- a/eng/Subsets.props
+++ b/eng/Subsets.props
@@ -89,7 +89,7 @@
CoreCLR
- CoreCLR
+ CoreCLR
Mono
Mono
$(PrimaryRuntimeFlavor)
diff --git a/eng/testing/BrowserVersions.props b/eng/testing/BrowserVersions.props
index 561cdb08a28a20..674577d8559fc2 100644
--- a/eng/testing/BrowserVersions.props
+++ b/eng/testing/BrowserVersions.props
@@ -1,13 +1,13 @@
- 131.0.6778.85
- 1368529
- https://storage.googleapis.com/chromium-browser-snapshots/Linux_x64/1368532
- 13.1.201
- 131.0.6778.33
- 1368529
- https://storage.googleapis.com/chromium-browser-snapshots/Win_x64/1368547
- 13.1.201
+ 132.0.6834.83
+ 1381561
+ https://storage.googleapis.com/chromium-browser-snapshots/Linux_x64/1381561
+ 13.2.152
+ 132.0.6834.84
+ 1381561
+ https://storage.googleapis.com/chromium-browser-snapshots/Win_x64/1381570
+ 13.2.152
125.0.1
0.34.0
125.0.1
diff --git a/src/coreclr/jit/assertionprop.cpp b/src/coreclr/jit/assertionprop.cpp
index 288891b0daab44..12f0ed85e03c66 100644
--- a/src/coreclr/jit/assertionprop.cpp
+++ b/src/coreclr/jit/assertionprop.cpp
@@ -5258,30 +5258,6 @@ static GCInfo::WriteBarrierForm GetWriteBarrierForm(Compiler* comp, ValueNum vn)
return GetWriteBarrierForm(comp, funcApp.m_args[0]);
}
}
- if (funcApp.m_func == VNF_InitVal)
- {
- unsigned lclNum = vnStore->CoercedConstantValue(funcApp.m_args[0]);
- assert(lclNum != BAD_VAR_NUM);
- CORINFO_CLASS_HANDLE srcCls = NO_CLASS_HANDLE;
-
- if (comp->compMethodHasRetVal() && (lclNum == comp->info.compRetBuffArg))
- {
- // See if the address is in current method's return buffer
- // while the return type is a byref-like type.
- srcCls = comp->info.compMethodInfo->args.retTypeClass;
- }
- else if (lclNum == comp->info.compThisArg)
- {
- // Same for implicit "this" parameter
- assert(!comp->info.compIsStatic);
- srcCls = comp->info.compClassHnd;
- }
-
- if ((srcCls != NO_CLASS_HANDLE) && comp->eeIsByrefLike(srcCls))
- {
- return GCInfo::WriteBarrierForm::WBF_NoBarrier;
- }
- }
}
return GCInfo::WriteBarrierForm::WBF_BarrierUnknown;
}
diff --git a/src/coreclr/jit/codegen.h b/src/coreclr/jit/codegen.h
index e465cd68058ef4..79964ca1289842 100644
--- a/src/coreclr/jit/codegen.h
+++ b/src/coreclr/jit/codegen.h
@@ -650,6 +650,7 @@ class CodeGen final : public CodeGenInterface
#if defined(TARGET_AMD64)
void genAmd64EmitterUnitTestsSse2();
void genAmd64EmitterUnitTestsApx();
+ void genAmd64EmitterUnitTestsAvx10v2();
#endif
#endif // defined(DEBUG)
diff --git a/src/coreclr/jit/codegenarm64.cpp b/src/coreclr/jit/codegenarm64.cpp
index 50b947bc5bce14..9c215b0ec69918 100644
--- a/src/coreclr/jit/codegenarm64.cpp
+++ b/src/coreclr/jit/codegenarm64.cpp
@@ -2675,6 +2675,12 @@ void CodeGen::genCodeForBinary(GenTreeOp* tree)
break;
}
+ case GT_AND_NOT:
+ {
+ ins = INS_bics;
+ break;
+ }
+
default:
{
noway_assert(!"Unexpected BinaryOp with GTF_SET_FLAGS set");
diff --git a/src/coreclr/jit/codegencommon.cpp b/src/coreclr/jit/codegencommon.cpp
index dec27882bb2285..d535dfb1454570 100644
--- a/src/coreclr/jit/codegencommon.cpp
+++ b/src/coreclr/jit/codegencommon.cpp
@@ -1832,15 +1832,26 @@ void CodeGen::genGenerateMachineCode()
#if defined(TARGET_X86)
if (compiler->canUseEvexEncoding())
{
- if (compiler->compOpportunisticallyDependsOn(InstructionSet_AVX10v1))
+ if (compiler->compOpportunisticallyDependsOn(InstructionSet_AVX10v2))
+ {
+ if (compiler->compOpportunisticallyDependsOn(InstructionSet_AVX10v2_V512))
+ {
+ printf("X86 with AVX10.2/512");
+ }
+ else
+ {
+ printf("X86 with AVX10.2/256");
+ }
+ }
+ else if (compiler->compOpportunisticallyDependsOn(InstructionSet_AVX10v1))
{
if (compiler->compOpportunisticallyDependsOn(InstructionSet_AVX10v1_V512))
{
- printf("X86 with AVX10/512");
+ printf("X86 with AVX10.1/512");
}
else
{
- printf("X86 with AVX10/256");
+ printf("X86 with AVX10.1/256");
}
}
else
@@ -1860,15 +1871,26 @@ void CodeGen::genGenerateMachineCode()
#elif defined(TARGET_AMD64)
if (compiler->canUseEvexEncoding())
{
- if (compiler->compOpportunisticallyDependsOn(InstructionSet_AVX10v1))
+ if (compiler->compOpportunisticallyDependsOn(InstructionSet_AVX10v2))
+ {
+ if (compiler->compOpportunisticallyDependsOn(InstructionSet_AVX10v2_V512))
+ {
+ printf("X64 with AVX10.2/512");
+ }
+ else
+ {
+ printf("X64 with AVX10.2/256");
+ }
+ }
+ else if (compiler->compOpportunisticallyDependsOn(InstructionSet_AVX10v1))
{
if (compiler->compOpportunisticallyDependsOn(InstructionSet_AVX10v1_V512))
{
- printf("X64 with AVX10/512");
+ printf("X64 with AVX10.1/512");
}
else
{
- printf("X64 with AVX10/256");
+ printf("X64 with AVX10.1/256");
}
}
else
diff --git a/src/coreclr/jit/codegenlinear.cpp b/src/coreclr/jit/codegenlinear.cpp
index 53257afb010b74..945f468d86fa81 100644
--- a/src/coreclr/jit/codegenlinear.cpp
+++ b/src/coreclr/jit/codegenlinear.cpp
@@ -2712,6 +2712,10 @@ void CodeGen::genEmitterUnitTests()
{
genAmd64EmitterUnitTestsApx();
}
+ if (unitTestSectionAll || (strstr(unitTestSection, "avx10v2") != nullptr))
+ {
+ genAmd64EmitterUnitTestsAvx10v2();
+ }
#elif defined(TARGET_ARM64)
if (unitTestSectionAll || (strstr(unitTestSection, "general") != nullptr))
diff --git a/src/coreclr/jit/codegenxarch.cpp b/src/coreclr/jit/codegenxarch.cpp
index 750b2d9818ba73..4f9b2c4f0184b2 100644
--- a/src/coreclr/jit/codegenxarch.cpp
+++ b/src/coreclr/jit/codegenxarch.cpp
@@ -9239,6 +9239,159 @@ void CodeGen::genAmd64EmitterUnitTestsApx()
theEmitter->emitIns_S(INS_not, EA_2BYTE, 0, 0);
}
+void CodeGen::genAmd64EmitterUnitTestsAvx10v2()
+{
+ // All the Avx10.2 instructions are evex and evex only has one size.
+ // Also, there is no specialized handling for XMM0 vs XMM9 vs XMM16
+
+ emitter* theEmitter = GetEmitter();
+
+ genDefineTempLabel(genCreateTempLabel());
+
+ // This test suite needs AVX10.2 enabled.
+ if (!theEmitter->emitComp->compIsaSupportedDebugOnly(InstructionSet_AVX10v2))
+ {
+ return;
+ }
+
+ // packed conversion instructions
+ theEmitter->emitIns_R_R(INS_vcvttps2dqs, EA_16BYTE, REG_XMM0, REG_XMM1); // xmm
+ theEmitter->emitIns_R_R(INS_vcvttps2dqs, EA_16BYTE, REG_XMM9, REG_XMM10); // xmm
+ theEmitter->emitIns_R_R(INS_vcvttps2dqs, EA_16BYTE, REG_XMM15, REG_XMM16); // xmm
+ theEmitter->emitIns_R_R(INS_vcvttps2dqs, EA_32BYTE, REG_XMM0, REG_XMM1); // ymm
+ theEmitter->emitIns_R_R(INS_vcvttps2dqs, EA_64BYTE, REG_XMM0, REG_XMM1); // zmm
+
+ theEmitter->emitIns_R_R(INS_vcvttps2udqs, EA_16BYTE, REG_XMM0, REG_XMM1); // xmm
+ theEmitter->emitIns_R_R(INS_vcvttps2udqs, EA_16BYTE, REG_XMM9, REG_XMM10); // xmm
+ theEmitter->emitIns_R_R(INS_vcvttps2udqs, EA_16BYTE, REG_XMM15, REG_XMM16); // xmm
+ theEmitter->emitIns_R_R(INS_vcvttps2udqs, EA_32BYTE, REG_XMM0, REG_XMM1); // ymm
+ theEmitter->emitIns_R_R(INS_vcvttps2udqs, EA_64BYTE, REG_XMM0, REG_XMM1); // zmm
+
+ theEmitter->emitIns_R_R(INS_vcvttpd2qqs, EA_16BYTE, REG_XMM0, REG_XMM1); // xmm
+ theEmitter->emitIns_R_R(INS_vcvttpd2qqs, EA_16BYTE, REG_XMM9, REG_XMM10); // xmm
+ theEmitter->emitIns_R_R(INS_vcvttpd2qqs, EA_16BYTE, REG_XMM15, REG_XMM16); // xmm
+ theEmitter->emitIns_R_R(INS_vcvttpd2qqs, EA_32BYTE, REG_XMM0, REG_XMM1); // ymm
+ theEmitter->emitIns_R_R(INS_vcvttpd2qqs, EA_64BYTE, REG_XMM0, REG_XMM1); // zmm
+
+ theEmitter->emitIns_R_R(INS_vcvttpd2uqqs, EA_16BYTE, REG_XMM0, REG_XMM1); // xmm
+ theEmitter->emitIns_R_R(INS_vcvttpd2uqqs, EA_16BYTE, REG_XMM9, REG_XMM10); // xmm
+ theEmitter->emitIns_R_R(INS_vcvttpd2uqqs, EA_16BYTE, REG_XMM15, REG_XMM16); // xmm
+ theEmitter->emitIns_R_R(INS_vcvttpd2uqqs, EA_32BYTE, REG_XMM0, REG_XMM1); // ymm
+ theEmitter->emitIns_R_R(INS_vcvttpd2uqqs, EA_64BYTE, REG_XMM0, REG_XMM1); // zmm
+
+ // scalar conversion instructions
+ theEmitter->emitIns_R_R(INS_vcvttsd2sis32, EA_4BYTE, REG_EAX, REG_XMM0);
+ theEmitter->emitIns_R_R(INS_vcvttsd2sis64, EA_8BYTE, REG_RAX, REG_XMM0);
+ theEmitter->emitIns_R_R(INS_vcvttsd2usis32, EA_4BYTE, REG_EAX, REG_XMM0);
+ theEmitter->emitIns_R_R(INS_vcvttsd2usis64, EA_8BYTE, REG_RAX, REG_XMM0);
+ theEmitter->emitIns_R_R(INS_vcvttss2sis32, EA_4BYTE, REG_EAX, REG_XMM0);
+ theEmitter->emitIns_R_R(INS_vcvttss2sis64, EA_8BYTE, REG_RAX, REG_XMM0);
+ theEmitter->emitIns_R_R(INS_vcvttss2usis32, EA_4BYTE, REG_EAX, REG_XMM0);
+ theEmitter->emitIns_R_R(INS_vcvttss2usis64, EA_8BYTE, REG_RAX, REG_XMM0);
+
+ // minmax instruction
+ theEmitter->emitIns_R_R_R_I(INS_vminmaxss, EA_16BYTE, REG_XMM0, REG_XMM1, REG_XMM2, 0);
+ theEmitter->emitIns_R_R_R_I(INS_vminmaxss, EA_16BYTE, REG_XMM8, REG_XMM9, REG_XMM10, 0);
+ theEmitter->emitIns_R_R_R_I(INS_vminmaxss, EA_16BYTE, REG_XMM14, REG_XMM15, REG_XMM16, 0);
+
+ theEmitter->emitIns_R_R_R_I(INS_vminmaxsd, EA_16BYTE, REG_XMM0, REG_XMM1, REG_XMM2, 0);
+ theEmitter->emitIns_R_R_R_I(INS_vminmaxsd, EA_16BYTE, REG_XMM9, REG_XMM10, REG_XMM11, 0);
+ theEmitter->emitIns_R_R_R_I(INS_vminmaxsd, EA_16BYTE, REG_XMM16, REG_XMM17, REG_XMM18, 0);
+
+ theEmitter->emitIns_R_R_R_I(INS_vminmaxps, EA_32BYTE, REG_XMM0, REG_XMM1, REG_XMM2, 0);
+ theEmitter->emitIns_R_R_R_I(INS_vminmaxpd, EA_32BYTE, REG_XMM0, REG_XMM1, REG_XMM2, 0);
+ theEmitter->emitIns_R_R_R_I(INS_vminmaxps, EA_64BYTE, REG_XMM0, REG_XMM1, REG_XMM2, 0);
+ theEmitter->emitIns_R_R_R_I(INS_vminmaxpd, EA_64BYTE, REG_XMM0, REG_XMM1, REG_XMM2, 0);
+
+ // VCVT[,T]PS2I[,U]BS
+ theEmitter->emitIns_R_R(INS_vcvtps2ibs, EA_16BYTE, REG_XMM0, REG_XMM1);
+ theEmitter->emitIns_R_R(INS_vcvtps2ibs, EA_32BYTE, REG_XMM0, REG_XMM1);
+ theEmitter->emitIns_R_R(INS_vcvtps2ibs, EA_32BYTE, REG_XMM0, REG_XMM1, INS_OPTS_EVEX_er_ru);
+ theEmitter->emitIns_R_R(INS_vcvtps2ibs, EA_64BYTE, REG_XMM0, REG_XMM1);
+ theEmitter->emitIns_R_R(INS_vcvtps2ibs, EA_64BYTE, REG_XMM0, REG_XMM1, INS_OPTS_EVEX_er_ru);
+
+ theEmitter->emitIns_R_R(INS_vcvtps2iubs, EA_16BYTE, REG_XMM0, REG_XMM1);
+ theEmitter->emitIns_R_R(INS_vcvtps2iubs, EA_32BYTE, REG_XMM0, REG_XMM1);
+ theEmitter->emitIns_R_R(INS_vcvtps2iubs, EA_32BYTE, REG_XMM0, REG_XMM1, INS_OPTS_EVEX_er_rz);
+ theEmitter->emitIns_R_R(INS_vcvtps2iubs, EA_64BYTE, REG_XMM0, REG_XMM1);
+ theEmitter->emitIns_R_R(INS_vcvtps2iubs, EA_64BYTE, REG_XMM0, REG_XMM1, INS_OPTS_EVEX_er_rz);
+
+ theEmitter->emitIns_R_R(INS_vcvttps2ibs, EA_16BYTE, REG_XMM0, REG_XMM1);
+ theEmitter->emitIns_R_R(INS_vcvttps2ibs, EA_32BYTE, REG_XMM0, REG_XMM1);
+ theEmitter->emitIns_R_R(INS_vcvttps2ibs, EA_32BYTE, REG_XMM0, REG_XMM1, INS_OPTS_EVEX_eb_er_rd);
+ theEmitter->emitIns_R_R(INS_vcvttps2ibs, EA_64BYTE, REG_XMM0, REG_XMM1);
+
+ theEmitter->emitIns_R_R(INS_vcvttps2iubs, EA_16BYTE, REG_XMM0, REG_XMM1);
+ theEmitter->emitIns_R_R(INS_vcvttps2iubs, EA_32BYTE, REG_XMM0, REG_XMM1);
+ theEmitter->emitIns_R_R(INS_vcvttps2iubs, EA_32BYTE, REG_XMM0, REG_XMM1, INS_OPTS_EVEX_er_ru);
+ theEmitter->emitIns_R_R(INS_vcvttps2iubs, EA_64BYTE, REG_XMM0, REG_XMM1);
+
+ // VPDPW[SU,US,UU]D[,S]
+ theEmitter->emitIns_R_R_R(INS_vpdpwsud, EA_16BYTE, REG_XMM0, REG_XMM1, REG_XMM2);
+ theEmitter->emitIns_R_R_R(INS_vpdpwsud, EA_32BYTE, REG_XMM0, REG_XMM1, REG_XMM2);
+ theEmitter->emitIns_R_R_R(INS_vpdpwsud, EA_64BYTE, REG_XMM0, REG_XMM1, REG_XMM2);
+ theEmitter->emitIns_R_R_R(INS_vpdpwsuds, EA_16BYTE, REG_XMM0, REG_XMM1, REG_XMM2);
+ theEmitter->emitIns_R_R_R(INS_vpdpwsuds, EA_32BYTE, REG_XMM0, REG_XMM1, REG_XMM2);
+ theEmitter->emitIns_R_R_R(INS_vpdpwsuds, EA_64BYTE, REG_XMM0, REG_XMM1, REG_XMM2);
+
+ theEmitter->emitIns_R_R_R(INS_vpdpwusd, EA_16BYTE, REG_XMM0, REG_XMM1, REG_XMM2);
+ theEmitter->emitIns_R_R_R(INS_vpdpwusd, EA_32BYTE, REG_XMM0, REG_XMM1, REG_XMM2);
+ theEmitter->emitIns_R_R_R(INS_vpdpwusd, EA_64BYTE, REG_XMM0, REG_XMM1, REG_XMM2);
+ theEmitter->emitIns_R_R_R(INS_vpdpwusds, EA_16BYTE, REG_XMM0, REG_XMM1, REG_XMM2);
+ theEmitter->emitIns_R_R_R(INS_vpdpwusds, EA_32BYTE, REG_XMM0, REG_XMM1, REG_XMM2);
+ theEmitter->emitIns_R_R_R(INS_vpdpwusds, EA_64BYTE, REG_XMM0, REG_XMM1, REG_XMM2);
+
+ theEmitter->emitIns_R_R_R(INS_vpdpwuud, EA_16BYTE, REG_XMM0, REG_XMM1, REG_XMM2);
+ theEmitter->emitIns_R_R_R(INS_vpdpwuud, EA_32BYTE, REG_XMM0, REG_XMM1, REG_XMM2);
+ theEmitter->emitIns_R_R_R(INS_vpdpwuud, EA_64BYTE, REG_XMM0, REG_XMM1, REG_XMM2);
+ theEmitter->emitIns_R_R_R(INS_vpdpwuuds, EA_16BYTE, REG_XMM0, REG_XMM1, REG_XMM2);
+ theEmitter->emitIns_R_R_R(INS_vpdpwuuds, EA_32BYTE, REG_XMM0, REG_XMM1, REG_XMM2);
+ theEmitter->emitIns_R_R_R(INS_vpdpwuuds, EA_64BYTE, REG_XMM0, REG_XMM1, REG_XMM2);
+
+ // VPDPB[SU,UU,SS]D[,S]
+ theEmitter->emitIns_R_R_R(INS_vpdpbssd, EA_16BYTE, REG_XMM0, REG_XMM1, REG_XMM2);
+ theEmitter->emitIns_R_R_R(INS_vpdpbssd, EA_32BYTE, REG_XMM0, REG_XMM1, REG_XMM2);
+ theEmitter->emitIns_R_R_R(INS_vpdpbssd, EA_64BYTE, REG_XMM0, REG_XMM1, REG_XMM2);
+ theEmitter->emitIns_R_R_R(INS_vpdpbssds, EA_16BYTE, REG_XMM0, REG_XMM1, REG_XMM2);
+ theEmitter->emitIns_R_R_R(INS_vpdpbssds, EA_32BYTE, REG_XMM0, REG_XMM1, REG_XMM2);
+ theEmitter->emitIns_R_R_R(INS_vpdpbssds, EA_64BYTE, REG_XMM0, REG_XMM1, REG_XMM2);
+
+ theEmitter->emitIns_R_R_R(INS_vpdpbsud, EA_16BYTE, REG_XMM0, REG_XMM1, REG_XMM2);
+ theEmitter->emitIns_R_R_R(INS_vpdpbsud, EA_32BYTE, REG_XMM0, REG_XMM1, REG_XMM2);
+ theEmitter->emitIns_R_R_R(INS_vpdpbsud, EA_64BYTE, REG_XMM0, REG_XMM1, REG_XMM2);
+ theEmitter->emitIns_R_R_R(INS_vpdpbsuds, EA_16BYTE, REG_XMM0, REG_XMM1, REG_XMM2);
+ theEmitter->emitIns_R_R_R(INS_vpdpbsuds, EA_32BYTE, REG_XMM0, REG_XMM1, REG_XMM2);
+ theEmitter->emitIns_R_R_R(INS_vpdpbsuds, EA_64BYTE, REG_XMM0, REG_XMM1, REG_XMM2);
+
+ theEmitter->emitIns_R_R_R(INS_vpdpbuud, EA_16BYTE, REG_XMM0, REG_XMM1, REG_XMM2);
+ theEmitter->emitIns_R_R_R(INS_vpdpbuud, EA_32BYTE, REG_XMM0, REG_XMM1, REG_XMM2);
+ theEmitter->emitIns_R_R_R(INS_vpdpbuud, EA_64BYTE, REG_XMM0, REG_XMM1, REG_XMM2);
+ theEmitter->emitIns_R_R_R(INS_vpdpbuuds, EA_16BYTE, REG_XMM0, REG_XMM1, REG_XMM2);
+ theEmitter->emitIns_R_R_R(INS_vpdpbuuds, EA_32BYTE, REG_XMM0, REG_XMM1, REG_XMM2);
+ theEmitter->emitIns_R_R_R(INS_vpdpbuuds, EA_64BYTE, REG_XMM0, REG_XMM1, REG_XMM2);
+
+ // VMPSADBW
+ theEmitter->emitIns_R_R_R_I(INS_vmpsadbw, EA_64BYTE, REG_XMM0, REG_XMM1, REG_XMM2, 0); // zmm
+
+ // VCOMXSD
+ theEmitter->emitIns_R_R(INS_vcomxsd, EA_16BYTE, REG_XMM0, REG_XMM1);
+
+ // VCOMXSS
+ theEmitter->emitIns_R_R(INS_vcomxss, EA_16BYTE, REG_XMM0, REG_XMM1);
+
+ // VUCOMXSD
+ theEmitter->emitIns_R_R(INS_vucomxsd, EA_16BYTE, REG_XMM0, REG_XMM1);
+
+ // VUCOMXSS
+ theEmitter->emitIns_R_R(INS_vucomxss, EA_16BYTE, REG_XMM0, REG_XMM1);
+
+ // VMOVD
+ theEmitter->emitIns_R_R(INS_vmovd, EA_16BYTE, REG_XMM0, REG_XMM1);
+
+ // VMOVW
+ theEmitter->emitIns_R_R(INS_vmovw, EA_16BYTE, REG_XMM0, REG_XMM1);
+}
+
#endif // defined(DEBUG) && defined(TARGET_AMD64)
#ifdef PROFILING_SUPPORTED
diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp
index 185c7c323c6adb..33dda8c734ca1b 100644
--- a/src/coreclr/jit/compiler.cpp
+++ b/src/coreclr/jit/compiler.cpp
@@ -4571,7 +4571,7 @@ void Compiler::compCompile(void** methodCodePtr, uint32_t* methodCodeSize, JitFl
// Note: the importer is sensitive to block weights, so this has
// to happen before importation.
//
- activePhaseChecks |= PhaseChecks::CHECK_PROFILE;
+ activePhaseChecks |= PhaseChecks::CHECK_PROFILE | PhaseChecks::CHECK_PROFILE_FLAGS;
DoPhase(this, PHASE_INCPROFILE, &Compiler::fgIncorporateProfileData);
activePhaseChecks |= PhaseChecks::CHECK_FG_INIT_BLOCK;
diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h
index 956e05e9b71f00..5190c70c060b3a 100644
--- a/src/coreclr/jit/compiler.h
+++ b/src/coreclr/jit/compiler.h
@@ -1542,8 +1542,9 @@ enum class PhaseChecks : unsigned int
CHECK_LOOPS = 1 << 4, // loop integrity/canonicalization
CHECK_LIKELIHOODS = 1 << 5, // profile data likelihood integrity
CHECK_PROFILE = 1 << 6, // profile data full integrity
- CHECK_LINKED_LOCALS = 1 << 7, // check linked list of locals
- CHECK_FG_INIT_BLOCK = 1 << 8, // flow graph has an init block
+ CHECK_PROFILE_FLAGS = 1 << 7, // blocks with profile-derived weights have BBF_PROF_WEIGHT flag set
+ CHECK_LINKED_LOCALS = 1 << 8, // check linked list of locals
+ CHECK_FG_INIT_BLOCK = 1 << 9, // flow graph has an init block
};
inline constexpr PhaseChecks operator ~(PhaseChecks a)
@@ -1608,8 +1609,9 @@ enum class ProfileChecks : unsigned int
CHECK_HASLIKELIHOOD = 1 << 0, // check all FlowEdges for hasLikelihood
CHECK_LIKELIHOODSUM = 1 << 1, // check block succesor likelihoods sum to 1
CHECK_LIKELY = 1 << 2, // fully check likelihood based weights
- RAISE_ASSERT = 1 << 3, // assert on check failure
- CHECK_ALL_BLOCKS = 1 << 4, // check blocks even if bbHasProfileWeight is false
+ CHECK_FLAGS = 1 << 3, // check blocks with profile-derived weights have BBF_PROF_WEIGHT flag set
+ RAISE_ASSERT = 1 << 4, // assert on check failure
+ CHECK_ALL_BLOCKS = 1 << 5, // check blocks even if bbHasProfileWeight is false
};
inline constexpr ProfileChecks operator ~(ProfileChecks a)
@@ -2866,6 +2868,7 @@ class Compiler
bool bbInCatchHandlerILRange(BasicBlock* blk);
bool bbInFilterILRange(BasicBlock* blk);
+ bool bbInCatchHandlerBBRange(BasicBlock* blk);
bool bbInFilterBBRange(BasicBlock* blk);
bool bbInTryRegions(unsigned regionIndex, BasicBlock* blk);
bool bbInExnFlowRegions(unsigned regionIndex, BasicBlock* blk);
@@ -5223,15 +5226,13 @@ class Compiler
void impMarkInlineCandidate(GenTree* call,
CORINFO_CONTEXT_HANDLE exactContextHnd,
bool exactContextNeedsRuntimeLookup,
- CORINFO_CALL_INFO* callInfo,
- IL_OFFSET ilOffset);
+ CORINFO_CALL_INFO* callInfo);
void impMarkInlineCandidateHelper(GenTreeCall* call,
uint8_t candidateIndex,
CORINFO_CONTEXT_HANDLE exactContextHnd,
bool exactContextNeedsRuntimeLookup,
CORINFO_CALL_INFO* callInfo,
- IL_OFFSET ilOffset,
InlineResult* inlineResult);
bool impTailCallRetTypeCompatible(bool allowWidening,
diff --git a/src/coreclr/jit/emit.h b/src/coreclr/jit/emit.h
index dc0f977b608622..02461633f3c547 100644
--- a/src/coreclr/jit/emit.h
+++ b/src/coreclr/jit/emit.h
@@ -1607,36 +1607,36 @@ class emitter
bool idIsBound() const
{
- assert(!IsAvx512OrPriorInstruction(_idIns));
+ assert(!IsSimdInstruction(_idIns));
return _idBound != 0;
}
void idSetIsBound()
{
- assert(!IsAvx512OrPriorInstruction(_idIns));
+ assert(!IsSimdInstruction(_idIns));
_idBound = 1;
}
#ifndef TARGET_ARMARCH
bool idIsCallRegPtr() const
{
- assert(!IsAvx512OrPriorInstruction(_idIns));
+ assert(!IsSimdInstruction(_idIns));
return _idCallRegPtr != 0;
}
void idSetIsCallRegPtr()
{
- assert(!IsAvx512OrPriorInstruction(_idIns));
+ assert(!IsSimdInstruction(_idIns));
_idCallRegPtr = 1;
}
#endif // !TARGET_ARMARCH
bool idIsTlsGD() const
{
- assert(!IsAvx512OrPriorInstruction(_idIns));
+ assert(!IsSimdInstruction(_idIns));
return _idTlsGD != 0;
}
void idSetTlsGD()
{
- assert(!IsAvx512OrPriorInstruction(_idIns));
+ assert(!IsSimdInstruction(_idIns));
_idTlsGD = 1;
}
@@ -1645,12 +1645,12 @@ class emitter
// code, it is not necessary to generate GC info for a call so labeled.
bool idIsNoGC() const
{
- assert(!IsAvx512OrPriorInstruction(_idIns));
+ assert(!IsSimdInstruction(_idIns));
return _idNoGC != 0;
}
void idSetIsNoGC(bool val)
{
- assert(!IsAvx512OrPriorInstruction(_idIns));
+ assert(!IsSimdInstruction(_idIns));
_idNoGC = val;
}
@@ -1703,7 +1703,7 @@ class emitter
unsigned idGetEvexAaaContext() const
{
- assert(IsAvx512OrPriorInstruction(_idIns));
+ assert(IsSimdInstruction(_idIns));
return _idEvexAaaContext;
}
@@ -1719,7 +1719,7 @@ class emitter
bool idIsEvexZContextSet() const
{
- assert(IsAvx512OrPriorInstruction(_idIns));
+ assert(IsSimdInstruction(_idIns));
return _idEvexZContext != 0;
}
diff --git a/src/coreclr/jit/emitxarch.cpp b/src/coreclr/jit/emitxarch.cpp
index 77f8787a3e2457..ddec8af5e753f5 100644
--- a/src/coreclr/jit/emitxarch.cpp
+++ b/src/coreclr/jit/emitxarch.cpp
@@ -1417,7 +1417,9 @@ bool emitter::TakesRex2Prefix(const instrDesc* id) const
// - R, X, B, W - bits to express corresponding REX prefixes.Additionally, X combines with B to expand r/m to 32 SIMD
// registers
// - R' - combines with R to expand reg to 32 SIMD registers
-// - mm - lower 2 bits of m-mmmmm (5-bit) in corresponding VEX prefix
+// - mmm - Encodes the map number to which the instruction belongs to
+// mm - lower 2 bits of m-mmmmm (5-bit) in corresponding VEX prefix (For AVX10.1 and below)
+// mmm - map number to which the instruction belongs to (For AVX10.2 and above)
// - vvvv (4-bits) - register specifier in 1's complement form; must be 1111 if unused
// - pp (2-bits) - opcode extension providing equivalent functionality of a SIMD size prefix
// these prefixes are treated mandatory when used with escape opcode 0Fh for
@@ -1433,6 +1435,11 @@ bool emitter::TakesRex2Prefix(const instrDesc* id) const
// - V'- bit to extend vvvv
// - aaa - specifies mask register
// Rest - reserved for future use and usage of them will uresult in Undefined instruction exception.
+// - u - Bit to indicate YMM Embedded rounding.
+// Set to 1 for isas Avx10.1 and below
+// Needs to be set to 0 for AVX10.2 and above to indicate YMM embedded rounding
+// - B' - reserved as of now
+// set to 0 for future compatibility.
//
#define DEFAULT_BYTE_EVEX_PREFIX 0x62F07C0800000000ULL
@@ -1441,6 +1448,7 @@ bool emitter::TakesRex2Prefix(const instrDesc* id) const
#define LBIT_IN_BYTE_EVEX_PREFIX 0x0000002000000000ULL
#define LPRIMEBIT_IN_BYTE_EVEX_PREFIX 0x0000004000000000ULL
#define ZBIT_IN_BYTE_EVEX_PREFIX 0x0000008000000000ULL
+#define uBIT_IN_BYTE_EVEX_PREFIX 0x0000040000000000ULL
//------------------------------------------------------------------------
// AddEvexPrefix: Add default EVEX prefix with only LL' bits set.
@@ -1482,7 +1490,13 @@ emitter::code_t emitter::AddEvexPrefix(const instrDesc* id, code_t code, emitAtt
if (!id->idHasMem())
{
- // embedded rounding case.
+ // ymm embedded rounding case.
+ if (attr == EA_32BYTE)
+ {
+ assert(emitComp->compIsaSupportedDebugOnly(InstructionSet_AVX10v2));
+ code &= ~(uBIT_IN_BYTE_EVEX_PREFIX);
+ }
+
unsigned roundingMode = id->idGetEvexbContext();
if (roundingMode == 1)
{
@@ -1740,7 +1754,7 @@ bool emitter::TakesRexWPrefix(const instrDesc* id) const
}
}
- assert(!IsAvx512OrPriorInstruction(ins));
+ assert(!IsSimdInstruction(ins));
#ifdef TARGET_AMD64
// movsx should always sign extend out to 8 bytes just because we don't track
@@ -2220,8 +2234,14 @@ emitter::code_t emitter::emitExtractEvexPrefix(instruction ins, code_t& code) co
// check for a prefix in the 11 position
BYTE sizePrefix = (code >> 16) & 0xFF;
- if ((sizePrefix != 0) && isPrefix(sizePrefix))
+ if (sizePrefix == 0)
+ {
+ // no simd prefix for EVEX2 - AVX10.2 and above
+ assert(emitComp->compIsaSupportedDebugOnly(InstructionSet_AVX10v2));
+ }
+ else if (isPrefix(sizePrefix))
{
+ // EVEX1 - EVEX encoding before Avx10.2
// 'pp' bits in byte 1 of EVEX prefix allows us to encode SIMD size prefixes as two bits
//
// 00 - None (0F - packed float)
@@ -2256,37 +2276,49 @@ emitter::code_t emitter::emitExtractEvexPrefix(instruction ins, code_t& code) co
unreached();
}
}
+ }
+ else
+ {
+ unreached();
+ }
+ // Now the byte in the 22 position should be either of the below:
+ // 1. An escape byte 0F (For isa before AVX10.2)
+ // 2. A map number from 0 to 7 (For AVX10.2 and above)
+ leadingBytes = check;
+ assert(leadingBytes == 0x0F || (emitComp->compIsaSupportedDebugOnly(InstructionSet_AVX10v2) &&
+ leadingBytes >= 0x00 && leadingBytes <= 0x07));
- // Now the byte in the 22 position must be an escape byte 0F
- leadingBytes = check;
- assert(leadingBytes == 0x0F);
-
- // Get rid of both sizePrefix and escape byte
- code &= 0x0000FFFFLL;
+ // Get rid of both sizePrefix and escape byte
+ code &= 0x0000FFFFLL;
- // Check the byte in the 33 position to see if it is 3A or 38.
- // In such a case escape bytes must be 0x0F3A or 0x0F38
- check = code & 0xFF;
+ // Check the byte in the 33 position to see if it is 3A or 38.
+ // In such a case escape bytes must be 0x0F3A or 0x0F38
+ check = code & 0xFF;
- if ((check == 0x3A) || (check == 0x38))
- {
- leadingBytes = (leadingBytes << 8) | check;
- code &= 0x0000FF00LL;
- }
+ if ((check == 0x3A) || (check == 0x38))
+ {
+ leadingBytes = (leadingBytes << 8) | check;
+ code &= 0x0000FF00LL;
}
}
else
{
- // 2-byte opcode with the bytes ordered as 0x0011RM22
- // the byte in position 11 must be an escape byte.
+ // 2-byte opcode with the bytes ordered as 0x0011RM22. There are 2 posibilities here:
+ // 1. the byte in position 11 must be an escape byte.
+ // 2. the byte in position 11 must be a map number from 0 to 7.
leadingBytes = (code >> 16) & 0xFF;
- assert(leadingBytes == 0x0F || leadingBytes == 0x00);
+ assert(leadingBytes == 0x0F || (emitComp->compIsaSupportedDebugOnly(InstructionSet_AVX10v2) &&
+ leadingBytes >= 0x00 && leadingBytes <= 0x07));
code &= 0xFFFF;
}
- // If there is an escape byte it must be 0x0F or 0x0F3A or 0x0F38
- // mm bits in byte 0 of EVEX prefix allows us to encode these
- // implied leading bytes. They are identical to low two bits of VEX.mmmmm
+ // Encode the escape byte in the evex prefix using either of the below:
+ // 1. If there is an escape byte it must be 0x0F or 0x0F3A or 0x0F38
+ // mm bits in byte 0 of EVEX prefix allows us to encode these
+ // implied leading bytes. They are identical to low two bits of VEX.mmmmm
+ // 2. If there is no escape byte but a map number from 0 to 7,
+ // EVEX.mmm bits in byte 0 of EVEX prefix allows us to encode these
+ // map numbers
switch (leadingBytes)
{
@@ -2314,6 +2346,19 @@ emitter::code_t emitter::emitExtractEvexPrefix(instruction ins, code_t& code) co
break;
}
+ case 0x05:
+ {
+ assert(emitComp->compIsaSupportedDebugOnly(InstructionSet_AVX10v2));
+ evexPrefix |= (0x05 << 16);
+ break;
+ }
+
+ case 0x01:
+ case 0x02:
+ case 0x03:
+ case 0x04:
+ case 0x06:
+ case 0x07:
default:
{
assert(!"encountered unknown leading bytes");
@@ -3066,7 +3111,7 @@ bool emitter::emitInsCanOnlyWriteSSE2OrAVXReg(instrDesc* id)
{
instruction ins = id->idIns();
- if (!IsAvx512OrPriorInstruction(ins))
+ if (!IsSimdInstruction(ins))
{
return false;
}
@@ -3511,7 +3556,7 @@ bool emitter::EncodedBySSE38orSSE3A(instruction ins) const
size_t insCode = 0;
- if (!IsAvx512OrPriorInstruction(ins))
+ if (!IsSimdInstruction(ins))
{
return false;
}
@@ -4081,7 +4126,7 @@ inline UNATIVE_OFFSET emitter::emitInsSizeRR(instrDesc* id, code_t code, int val
}
else
{
- assert(!IsAvx512OrPriorInstruction(ins));
+ assert(!IsSimdInstruction(ins));
}
return valSize + emitInsSizeRR(id, code);
@@ -4130,7 +4175,7 @@ inline UNATIVE_OFFSET emitter::emitInsSizeRR(instrDesc* id)
if ((code & 0xFF00) != 0)
{
- sz += IsAvx512OrPriorInstruction(ins) ? emitInsSize(id, code, includeRexPrefixSize) : 5;
+ sz += IsSimdInstruction(ins) ? emitInsSize(id, code, includeRexPrefixSize) : 5;
}
else
{
@@ -4698,7 +4743,7 @@ inline UNATIVE_OFFSET emitter::emitInsSizeAM(instrDesc* id, code_t code, int val
}
else
{
- assert(!IsAvx512OrPriorInstruction(ins));
+ assert(!IsSimdInstruction(ins));
}
return valSize + emitInsSizeAM(id, code);
@@ -4757,7 +4802,7 @@ inline UNATIVE_OFFSET emitter::emitInsSizeCV(instrDesc* id, code_t code, int val
}
else
{
- assert(!IsAvx512OrPriorInstruction(ins));
+ assert(!IsSimdInstruction(ins));
}
return valSize + emitInsSizeCV(id, code);
@@ -6058,7 +6103,7 @@ void emitter::emitIns_R_I(instruction ins,
emitAttr size = EA_SIZE(attr);
// Allow emitting SSE2/AVX SIMD instructions of R_I form that can specify EA_16BYTE or EA_32BYTE
- assert(size <= EA_PTRSIZE || IsAvx512OrPriorInstruction(ins));
+ assert(size <= EA_PTRSIZE || IsSimdInstruction(ins));
noway_assert(emitVerifyEncodable(ins, size, reg));
@@ -6126,7 +6171,7 @@ void emitter::emitIns_R_I(instruction ins,
if (valInByte)
{
- if (IsAvx512OrPriorInstruction(ins))
+ if (IsSimdInstruction(ins))
{
sz = 1;
isSimdInsAndValInByte = true;
@@ -6142,7 +6187,7 @@ void emitter::emitIns_R_I(instruction ins,
}
else
{
- assert(!IsAvx512OrPriorInstruction(ins));
+ assert(!IsSimdInstruction(ins));
if (reg == REG_EAX && !instrIs3opImul(ins))
{
@@ -7079,7 +7124,7 @@ void emitter::emitIns_AR(instruction ins, emitAttr attr, regNumber base, int off
void emitter::emitIns_AR_R_R(
instruction ins, emitAttr attr, regNumber op2Reg, regNumber op3Reg, regNumber base, int offs, insOpts instOptions)
{
- assert(IsAvx512OrPriorInstruction(ins));
+ assert(IsSimdInstruction(ins));
assert(IsThreeOperandAVXInstruction(ins));
instrDesc* id = emitNewInstrAmd(attr, offs);
@@ -7126,7 +7171,7 @@ void emitter::emitIns_R_A_I(
instruction ins, emitAttr attr, regNumber reg1, GenTreeIndir* indir, int ival, insOpts instOptions)
{
noway_assert(emitVerifyEncodable(ins, EA_SIZE(attr), reg1));
- assert(IsAvx512OrPriorInstruction(ins));
+ assert(IsSimdInstruction(ins));
ssize_t offs = indir->Offset();
instrDesc* id = emitNewInstrAmdCns(attr, offs, ival);
@@ -7172,7 +7217,7 @@ void emitter::emitIns_R_C_I(instruction ins,
}
noway_assert(emitVerifyEncodable(ins, EA_SIZE(attr), reg1));
- assert(IsAvx512OrPriorInstruction(ins));
+ assert(IsSimdInstruction(ins));
instrDesc* id = emitNewInstrCnsDsp(attr, ival, offs);
@@ -7206,7 +7251,7 @@ void emitter::emitIns_R_S_I(
instruction ins, emitAttr attr, regNumber reg1, int varx, int offs, int ival, insOpts instOptions)
{
noway_assert(emitVerifyEncodable(ins, EA_SIZE(attr), reg1));
- assert(IsAvx512OrPriorInstruction(ins));
+ assert(IsSimdInstruction(ins));
instrDesc* id = emitNewInstrCns(attr, ival);
@@ -7243,7 +7288,7 @@ void emitter::emitIns_R_S_I(
void emitter::emitIns_R_R_A(
instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, GenTreeIndir* indir, insOpts instOptions)
{
- assert(IsAvx512OrPriorInstruction(ins));
+ assert(IsSimdInstruction(ins));
assert(IsThreeOperandAVXInstruction(ins));
ssize_t offs = indir->Offset();
@@ -7267,7 +7312,7 @@ void emitter::emitIns_R_R_A(
void emitter::emitIns_R_R_AR(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, regNumber base, int offs)
{
- assert(IsAvx512OrPriorInstruction(ins));
+ assert(IsSimdInstruction(ins));
assert(IsThreeOperandAVXInstruction(ins));
instrDesc* id = emitNewInstrAmd(attr, offs);
@@ -7363,7 +7408,7 @@ void emitter::emitIns_R_R_C(instruction ins,
int offs,
insOpts instOptions)
{
- assert(IsAvx512OrPriorInstruction(ins));
+ assert(IsSimdInstruction(ins));
assert(IsThreeOperandAVXInstruction(ins));
// Static always need relocs
@@ -7398,7 +7443,7 @@ void emitter::emitIns_R_R_C(instruction ins,
void emitter::emitIns_R_R_R(
instruction ins, emitAttr attr, regNumber targetReg, regNumber reg1, regNumber reg2, insOpts instOptions)
{
- assert(IsAvx512OrPriorInstruction(ins));
+ assert(IsSimdInstruction(ins));
assert(IsThreeOperandAVXInstruction(ins) || IsKInstruction(ins));
instrDesc* id = emitNewInstr(attr);
@@ -7426,7 +7471,7 @@ void emitter::emitIns_R_R_R(
void emitter::emitIns_R_R_S(
instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, int varx, int offs, insOpts instOptions)
{
- assert(IsAvx512OrPriorInstruction(ins));
+ assert(IsSimdInstruction(ins));
assert(IsThreeOperandAVXInstruction(ins));
instrDesc* id = emitNewInstr(attr);
@@ -7460,7 +7505,7 @@ void emitter::emitIns_R_R_A_I(instruction ins,
insFormat fmt,
insOpts instOptions)
{
- assert(IsAvx512OrPriorInstruction(ins));
+ assert(IsSimdInstruction(ins));
assert(IsThreeOperandAVXInstruction(ins));
ssize_t offs = indir->Offset();
@@ -7485,7 +7530,7 @@ void emitter::emitIns_R_R_A_I(instruction ins,
void emitter::emitIns_R_R_AR_I(
instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, regNumber base, int offs, int ival)
{
- assert(IsAvx512OrPriorInstruction(ins));
+ assert(IsSimdInstruction(ins));
assert(IsThreeOperandAVXInstruction(ins));
instrDesc* id = emitNewInstrAmdCns(attr, offs, ival);
@@ -7514,7 +7559,7 @@ void emitter::emitIns_R_R_C_I(instruction ins,
int ival,
insOpts instOptions)
{
- assert(IsAvx512OrPriorInstruction(ins));
+ assert(IsSimdInstruction(ins));
assert(IsThreeOperandAVXInstruction(ins));
// Static always need relocs
@@ -7557,7 +7602,7 @@ void emitter::emitIns_R_R_C_I(instruction ins,
void emitter::emitIns_R_R_R_I(
instruction ins, emitAttr attr, regNumber targetReg, regNumber reg1, regNumber reg2, int ival, insOpts instOptions)
{
- assert(IsAvx512OrPriorInstruction(ins));
+ assert(IsSimdInstruction(ins));
assert(IsThreeOperandAVXInstruction(ins));
instrDesc* id = emitNewInstrCns(attr, ival);
@@ -7580,7 +7625,7 @@ void emitter::emitIns_R_R_R_I(
void emitter::emitIns_R_R_S_I(
instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, int varx, int offs, int ival, insOpts instOptions)
{
- assert(IsAvx512OrPriorInstruction(ins));
+ assert(IsSimdInstruction(ins));
assert(IsThreeOperandAVXInstruction(ins));
instrDesc* id = emitNewInstrCns(attr, ival);
@@ -8285,7 +8330,7 @@ void emitter::emitIns_AR_R(instruction ins, emitAttr attr, regNumber reg, regNum
void emitter::emitIns_C_R_I(
instruction ins, emitAttr attr, CORINFO_FIELD_HANDLE fldHnd, int offs, regNumber reg, int ival)
{
- assert(IsAvx512OrPriorInstruction(ins));
+ assert(IsSimdInstruction(ins));
assert(reg != REG_NA);
// Static always need relocs
@@ -8322,7 +8367,7 @@ void emitter::emitIns_C_R_I(
//
void emitter::emitIns_S_R_I(instruction ins, emitAttr attr, int varNum, int offs, regNumber reg, int ival)
{
- assert(IsAvx512OrPriorInstruction(ins));
+ assert(IsSimdInstruction(ins));
assert(reg != REG_NA);
instrDesc* id = emitNewInstrAmdCns(attr, 0, ival);
@@ -8355,7 +8400,7 @@ void emitter::emitIns_S_R_I(instruction ins, emitAttr attr, int varNum, int offs
//
void emitter::emitIns_A_R_I(instruction ins, emitAttr attr, GenTreeIndir* indir, regNumber reg, int imm)
{
- assert(IsAvx512OrPriorInstruction(ins));
+ assert(IsSimdInstruction(ins));
assert(reg != REG_NA);
instrDesc* id = emitNewInstrAmdCns(attr, indir->Offset(), imm);
@@ -13289,7 +13334,7 @@ BYTE* emitter::emitOutputAM(BYTE* dst, instrDesc* id, code_t code, CnsVal* addc)
// SSE/AVX do not need to modify opcode
if ((signed char)cval == cval && addc->cnsReloc == false && ins != INS_mov && ins != INS_test)
{
- if (id->idInsFmt() != IF_ARW_SHF && !IsAvx512OrPriorInstruction(ins))
+ if (id->idInsFmt() != IF_ARW_SHF && !IsSimdInstruction(ins))
{
code |= 2;
}
@@ -13672,7 +13717,7 @@ BYTE* emitter::emitOutputAM(BYTE* dst, instrDesc* id, code_t code, CnsVal* addc)
#else
dst += emitOutputLong(dst, dsp);
#endif
- if (!IsAvx512OrPriorInstruction(ins) && id->idIsTlsGD())
+ if (!IsSimdInstruction(ins) && id->idIsTlsGD())
{
addlDelta = -4;
emitRecordRelocationWithAddlDelta((void*)(dst - sizeof(INT32)), (void*)dsp, IMAGE_REL_TLSGD,
@@ -14236,7 +14281,7 @@ BYTE* emitter::emitOutputSV(BYTE* dst, instrDesc* id, code_t code, CnsVal* addc)
if ((signed char)cval == cval && addc->cnsReloc == false && ins != INS_mov && ins != INS_test)
{
if ((id->idInsFmt() != IF_SRW_SHF) && (id->idInsFmt() != IF_RRW_SRD_CNS) &&
- (id->idInsFmt() != IF_RWR_RRD_SRD_CNS) && !IsAvx512OrPriorInstruction(ins))
+ (id->idInsFmt() != IF_RWR_RRD_SRD_CNS) && !IsSimdInstruction(ins))
{
code |= 2;
}
@@ -14736,7 +14781,7 @@ BYTE* emitter::emitOutputCV(BYTE* dst, instrDesc* id, code_t code, CnsVal* addc)
if ((signed char)cval == cval && addc->cnsReloc == false && ins != INS_mov && ins != INS_test)
{
// SSE/AVX do not need to modify opcode
- if (id->idInsFmt() != IF_MRW_SHF && !IsAvx512OrPriorInstruction(ins))
+ if (id->idInsFmt() != IF_MRW_SHF && !IsSimdInstruction(ins))
{
code |= 2;
}
@@ -15451,7 +15496,7 @@ BYTE* emitter::emitOutputRR(BYTE* dst, instrDesc* id)
assert(!id->idHasReg3());
- if (IsAvx512OrPriorInstruction(ins))
+ if (IsSimdInstruction(ins))
{
assert((ins != INS_movd) || (isFloatReg(reg1) != isFloatReg(reg2)));
@@ -15980,7 +16025,7 @@ BYTE* emitter::emitOutputRI(BYTE* dst, instrDesc* id)
noway_assert(emitVerifyEncodable(ins, size, reg));
- if (IsAvx512OrPriorInstruction(ins))
+ if (IsSimdInstruction(ins))
{
// Handle SSE2 instructions of the form "opcode reg, immed8"
@@ -17763,7 +17808,7 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp)
case IF_RWR_ARD_CNS:
case IF_RRW_ARD_CNS:
{
- assert(IsAvx512OrPriorInstruction(ins));
+ assert(IsSimdInstruction(ins));
emitGetInsAmdCns(id, &cnsVal);
if (hasCodeMI(ins))
@@ -17801,7 +17846,7 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp)
case IF_AWR_RRD_CNS:
case IF_ARW_RRD_CNS:
{
- assert(IsAvx512OrPriorInstruction(ins));
+ assert(IsSimdInstruction(ins));
emitGetInsAmdCns(id, &cnsVal);
dst = emitOutputAM(dst, id, insCodeMR(ins), &cnsVal);
sz = emitSizeOfInsDsc_AMD(id);
@@ -17848,7 +17893,7 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp)
case IF_RWR_RRD_ARD_CNS:
case IF_RWR_RRD_ARD_RRD:
{
- assert(IsAvx512OrPriorInstruction(ins));
+ assert(IsSimdInstruction(ins));
code = insCodeRM(ins);
emitGetInsAmdCns(id, &cnsVal);
@@ -17994,7 +18039,7 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp)
case IF_SWR_RRD_CNS:
case IF_SRW_RRD_CNS:
{
- assert(IsAvx512OrPriorInstruction(ins) || (ins == INS_shld) || (ins == INS_shrd));
+ assert(IsSimdInstruction(ins) || (ins == INS_shld) || (ins == INS_shrd));
emitGetInsAmdCns(id, &cnsVal);
dst = emitOutputSV(dst, id, insCodeMR(ins), &cnsVal);
sz = emitSizeOfInsDsc_CNS(id);
@@ -18005,7 +18050,7 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp)
case IF_RWR_SRD_CNS:
case IF_RRW_SRD_CNS:
{
- assert(IsAvx512OrPriorInstruction(ins));
+ assert(IsSimdInstruction(ins));
emitGetInsCns(id, &cnsVal);
if (hasCodeMI(ins))
@@ -18234,7 +18279,7 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp)
case IF_RWR_MRD_CNS:
case IF_RRW_MRD_CNS:
{
- assert(IsAvx512OrPriorInstruction(ins));
+ assert(IsSimdInstruction(ins));
emitGetInsDcmCns(id, &cnsVal);
if (hasCodeMI(ins))
@@ -19478,6 +19523,8 @@ emitter::insExecutionCharacteristics emitter::getInsExecutionCharacteristics(ins
case INS_vmovdqu8:
case INS_vmovdqu16:
case INS_vmovdqu64:
+ case INS_vmovd:
+ case INS_vmovw:
case INS_movaps:
case INS_movups:
case INS_movapd:
@@ -19619,6 +19666,10 @@ emitter::insExecutionCharacteristics emitter::getInsExecutionCharacteristics(ins
case INS_vrangeps:
case INS_vrangesd:
case INS_vrangess:
+ case INS_vminmaxsd:
+ case INS_vminmaxss:
+ case INS_vminmaxpd:
+ case INS_vminmaxps:
case INS_vreducepd:
case INS_vreduceps:
case INS_vreducesd:
@@ -19633,6 +19684,17 @@ emitter::insExecutionCharacteristics emitter::getInsExecutionCharacteristics(ins
break;
}
+ // TODO-XArch-AVX10.2: handle perf for AVX10.2 instructions
+ case INS_vcomxsd:
+ case INS_vcomxss:
+ case INS_vucomxsd:
+ case INS_vucomxss:
+ {
+ result.insThroughput = PERFSCORE_THROUGHPUT_2X;
+ result.insLatency += PERFSCORE_LATENCY_4C;
+ break;
+ }
+
case INS_vpermi2b:
case INS_vpermt2b:
{
@@ -19808,8 +19870,24 @@ emitter::insExecutionCharacteristics emitter::getInsExecutionCharacteristics(ins
case INS_vcvtusi2ss32:
case INS_vcvtusi2ss64:
case INS_vcvttsd2usi32:
+ case INS_vcvttsd2usis32:
case INS_vcvttsd2usi64:
+ case INS_vcvttsd2usis64:
case INS_vcvttss2usi32:
+ case INS_vcvttss2usis32:
+ case INS_vcvttsd2sis32:
+ case INS_vcvttsd2sis64:
+ case INS_vcvttss2sis32:
+ case INS_vcvttss2sis64:
+ case INS_vcvttss2usis64:
+ case INS_vcvttps2dqs:
+ case INS_vcvttps2udqs:
+ case INS_vcvttpd2qqs:
+ case INS_vcvttpd2uqqs:
+ case INS_vcvttps2ibs:
+ case INS_vcvttps2iubs:
+ case INS_vcvtps2ibs:
+ case INS_vcvtps2iubs:
result.insThroughput = PERFSCORE_THROUGHPUT_1C;
result.insLatency += PERFSCORE_LATENCY_7C;
break;
@@ -20246,6 +20324,7 @@ emitter::insExecutionCharacteristics emitter::getInsExecutionCharacteristics(ins
}
case INS_mpsadbw:
+ case INS_vmpsadbw:
result.insThroughput = PERFSCORE_THROUGHPUT_2C;
result.insLatency += PERFSCORE_LATENCY_4C;
break;
@@ -20259,9 +20338,21 @@ emitter::insExecutionCharacteristics emitter::getInsExecutionCharacteristics(ins
case INS_pmaddwd:
case INS_pmaddubsw:
case INS_vpdpbusd:
- case INS_vpdpwssd:
case INS_vpdpbusds:
+ case INS_vpdpbssd:
+ case INS_vpdpbssds:
+ case INS_vpdpbsud:
+ case INS_vpdpbsuds:
+ case INS_vpdpbuud:
+ case INS_vpdpbuuds:
case INS_vpdpwssds:
+ case INS_vpdpwssd:
+ case INS_vpdpwsud:
+ case INS_vpdpwsuds:
+ case INS_vpdpwusd:
+ case INS_vpdpwusds:
+ case INS_vpdpwuud:
+ case INS_vpdpwuuds:
case INS_gf2p8affineinvqb:
case INS_gf2p8affineqb:
case INS_gf2p8mulb:
diff --git a/src/coreclr/jit/fginline.cpp b/src/coreclr/jit/fginline.cpp
index ee75f8b13cd774..1761d79f8eca7f 100644
--- a/src/coreclr/jit/fginline.cpp
+++ b/src/coreclr/jit/fginline.cpp
@@ -1323,7 +1323,8 @@ void Compiler::fgInvokeInlineeCompiler(GenTreeCall* call, InlineResult* inlineRe
// (This could happen for example for a BBJ_THROW block fall through a BBJ_RETURN block which
// causes the BBJ_RETURN block not to be imported at all.)
// Fail the inlining attempt
- if ((inlineCandidateInfo->fncRetType != TYP_VOID) && (inlineCandidateInfo->retExpr->gtSubstExpr == nullptr))
+ if ((inlineCandidateInfo->methInfo.args.retType != CORINFO_TYPE_VOID) &&
+ (inlineCandidateInfo->retExpr->gtSubstExpr == nullptr))
{
#ifdef DEBUG
if (verbose)
@@ -1514,7 +1515,7 @@ void Compiler::fgInsertInlineeBlocks(InlineInfo* pInlineInfo)
noway_assert(!block->hasTryIndex());
noway_assert(!block->hasHndIndex());
block->copyEHRegion(iciBlock);
- block->CopyFlags(iciBlock, BBF_BACKWARD_JUMP);
+ block->CopyFlags(iciBlock, BBF_BACKWARD_JUMP | BBF_PROF_WEIGHT);
// Update block nums appropriately
//
diff --git a/src/coreclr/jit/fgprofile.cpp b/src/coreclr/jit/fgprofile.cpp
index 9cf332bf16c995..2a21e61f0d3a09 100644
--- a/src/coreclr/jit/fgprofile.cpp
+++ b/src/coreclr/jit/fgprofile.cpp
@@ -4571,6 +4571,12 @@ void Compiler::fgDebugCheckProfile(PhaseChecks checks)
else if (hasFlag(checks, PhaseChecks::CHECK_PROFILE))
{
ProfileChecks profileChecks = ProfileChecks::CHECK_LIKELY | ProfileChecks::RAISE_ASSERT;
+
+ if (hasFlag(checks, PhaseChecks::CHECK_PROFILE_FLAGS))
+ {
+ profileChecks |= ProfileChecks::CHECK_FLAGS;
+ }
+
fgDebugCheckProfileWeights(profileChecks);
}
else if (hasFlag(checks, PhaseChecks::CHECK_LIKELIHOODS))
@@ -4611,6 +4617,7 @@ bool Compiler::fgDebugCheckProfileWeights(ProfileChecks checks)
const bool verifyLikelyWeights = hasFlag(checks, ProfileChecks::CHECK_LIKELY);
const bool verifyHasLikelihood = hasFlag(checks, ProfileChecks::CHECK_HASLIKELIHOOD);
const bool verifyLikelihoodSum = hasFlag(checks, ProfileChecks::CHECK_LIKELIHOODSUM);
+ const bool checkProfileFlag = hasFlag(checks, ProfileChecks::CHECK_FLAGS) && fgIsUsingProfileWeights();
const bool assertOnFailure = hasFlag(checks, ProfileChecks::RAISE_ASSERT) && fgPgoConsistent;
const bool checkAllBlocks = hasFlag(checks, ProfileChecks::CHECK_ALL_BLOCKS);
@@ -4633,6 +4640,7 @@ bool Compiler::fgDebugCheckProfileWeights(ProfileChecks checks)
unsigned problemBlocks = 0;
unsigned unprofiledBlocks = 0;
unsigned profiledBlocks = 0;
+ unsigned unflaggedBlocks = 0;
bool entryProfiled = false;
bool exitProfiled = false;
bool hasTry = false;
@@ -4643,10 +4651,20 @@ bool Compiler::fgDebugCheckProfileWeights(ProfileChecks checks)
//
for (BasicBlock* const block : Blocks())
{
- if (!block->hasProfileWeight() && !checkAllBlocks)
+ if (!block->hasProfileWeight())
{
- unprofiledBlocks++;
- continue;
+ if (checkProfileFlag && (block->bbPreds != nullptr))
+ {
+ // Block has flow into it that isn't marked as profile-derived.
+ //
+ unflaggedBlocks++;
+ }
+
+ if (!checkAllBlocks)
+ {
+ unprofiledBlocks++;
+ continue;
+ }
}
// There is some profile data to check.
@@ -4831,6 +4849,12 @@ bool Compiler::fgDebugCheckProfileWeights(ProfileChecks checks)
}
}
+ if (unflaggedBlocks > 0)
+ {
+ JITDUMP("%d blocks are missing BBF_PROF_WEIGHT flag.\n", unflaggedBlocks);
+ assert(!"Missing BBF_PROF_WEIGHT flag");
+ }
+
return (problemBlocks == 0);
}
diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp
index 94293bdf4e6217..06854fa563b59c 100644
--- a/src/coreclr/jit/gentree.cpp
+++ b/src/coreclr/jit/gentree.cpp
@@ -20020,7 +20020,7 @@ bool GenTree::SupportsSettingZeroFlag()
}
#endif
#elif defined(TARGET_ARM64)
- if (OperIs(GT_AND))
+ if (OperIs(GT_AND, GT_AND_NOT))
{
return true;
}
@@ -27789,6 +27789,21 @@ bool GenTreeHWIntrinsic::OperIsEmbRoundingEnabled() const
case NI_AVX10v1_MultiplyScalar:
case NI_AVX10v1_SubtractScalar:
case NI_AVX10v1_SqrtScalar:
+ case NI_AVX10v2_Add:
+ case NI_AVX10v2_ConvertToVector128Int32:
+ case NI_AVX10v2_ConvertToVector128Single:
+ case NI_AVX10v2_ConvertToVector128UInt32:
+ case NI_AVX10v2_ConvertToVector256Double:
+ case NI_AVX10v2_ConvertToVector256Int32:
+ case NI_AVX10v2_ConvertToVector256Int64:
+ case NI_AVX10v2_ConvertToVector256Single:
+ case NI_AVX10v2_ConvertToVector256UInt32:
+ case NI_AVX10v2_ConvertToVector256UInt64:
+ case NI_AVX10v2_Divide:
+ case NI_AVX10v2_Multiply:
+ case NI_AVX10v2_Scale:
+ case NI_AVX10v2_Sqrt:
+ case NI_AVX10v2_Subtract:
{
return true;
}
@@ -27857,6 +27872,10 @@ bool GenTreeHWIntrinsic::OperIsEmbRoundingEnabled() const
case NI_AVX10v1_V512_ConvertToVector512Double:
case NI_AVX10v1_V512_ConvertToVector512Int64:
case NI_AVX10v1_V512_ConvertToVector512UInt64:
+ case NI_AVX10v2_ConvertToSByteWithSaturationAndZeroExtendToInt32:
+ case NI_AVX10v2_ConvertToByteWithSaturationAndZeroExtendToInt32:
+ case NI_AVX10v2_V512_ConvertToSByteWithSaturationAndZeroExtendToInt32:
+ case NI_AVX10v2_V512_ConvertToByteWithSaturationAndZeroExtendToInt32:
{
return numArgs == 2;
}
@@ -28232,6 +28251,7 @@ genTreeOps GenTreeHWIntrinsic::GetOperForHWIntrinsicId(NamedIntrinsic id, var_ty
case NI_AVX_Add:
case NI_AVX2_Add:
case NI_AVX512F_Add:
+ case NI_AVX10v2_Add:
case NI_AVX512BW_Add:
#elif defined(TARGET_ARM64)
case NI_AdvSimd_Add:
@@ -28268,6 +28288,7 @@ genTreeOps GenTreeHWIntrinsic::GetOperForHWIntrinsicId(NamedIntrinsic id, var_ty
case NI_SSE2_Divide:
case NI_AVX_Divide:
case NI_AVX512F_Divide:
+ case NI_AVX10v2_Divide:
#elif defined(TARGET_ARM64)
case NI_AdvSimd_Arm64_Divide:
#endif
@@ -28320,6 +28341,7 @@ genTreeOps GenTreeHWIntrinsic::GetOperForHWIntrinsicId(NamedIntrinsic id, var_ty
#if defined(TARGET_XARCH)
case NI_SSE2_Multiply:
case NI_AVX512F_Multiply:
+ case NI_AVX10v2_Multiply:
{
if (varTypeIsFloating(simdBaseType))
{
@@ -28485,6 +28507,7 @@ genTreeOps GenTreeHWIntrinsic::GetOperForHWIntrinsicId(NamedIntrinsic id, var_ty
case NI_AVX2_Subtract:
case NI_AVX512F_Subtract:
case NI_AVX512BW_Subtract:
+ case NI_AVX10v2_Subtract:
#elif defined(TARGET_ARM64)
case NI_AdvSimd_Subtract:
case NI_AdvSimd_Arm64_Subtract:
diff --git a/src/coreclr/jit/hwintrinsic.cpp b/src/coreclr/jit/hwintrinsic.cpp
index 553888bb996aa6..a00d57962d757b 100644
--- a/src/coreclr/jit/hwintrinsic.cpp
+++ b/src/coreclr/jit/hwintrinsic.cpp
@@ -807,8 +807,8 @@ static const HWIntrinsicIsaRange hwintrinsicIsaRangeArray[] = {
{ NI_Illegal, NI_Illegal }, // VectorT256
{ NI_Illegal, NI_Illegal }, // VectorT512
{ NI_Illegal, NI_Illegal }, // APX
- { NI_Illegal, NI_Illegal }, // AVX10v2
- { NI_Illegal, NI_Illegal }, // AVX10v2_V512
+ { FIRST_NI_AVX10v2, LAST_NI_AVX10v2 }, // AVX10v2
+ { FIRST_NI_AVX10v2_V512, LAST_NI_AVX10v2_V512 }, // AVX10v2_V512
{ FIRST_NI_GFNI, LAST_NI_GFNI },
{ FIRST_NI_GFNI_V256, LAST_NI_GFNI_V256 },
{ FIRST_NI_GFNI_V512, LAST_NI_GFNI_V512 },
diff --git a/src/coreclr/jit/hwintrinsiclistxarch.h b/src/coreclr/jit/hwintrinsiclistxarch.h
index b76781500c56fa..8a629436d25947 100644
--- a/src/coreclr/jit/hwintrinsiclistxarch.h
+++ b/src/coreclr/jit/hwintrinsiclistxarch.h
@@ -1432,6 +1432,56 @@ HARDWARE_INTRINSIC(AVX10v1_X64, ConvertToUInt64,
HARDWARE_INTRINSIC(AVX10v1_X64, ConvertToUInt64WithTruncation, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vcvttss2usi64, INS_vcvttsd2usi64}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialCodeGen)
#define LAST_NI_AVX10v1_X64 NI_AVX10v1_X64_ConvertToUInt64WithTruncation
+// ***************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
+// ISA Function name SIMD size NumArg Instructions Category Flags
+// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE}
+// ***************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
+// AVX10v2 Intrinsics
+#define FIRST_NI_AVX10v2 NI_AVX10v2_Add
+HARDWARE_INTRINSIC(AVX10v2, Add, 32, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_addps, INS_addpd}, HW_Category_SimpleSIMD, HW_Flag_Commutative |HW_Flag_EmbBroadcastCompatible|HW_Flag_EmbMaskingCompatible|HW_Flag_EmbRoundingCompatible)
+HARDWARE_INTRINSIC(AVX10v2, ConvertToByteWithSaturationAndZeroExtendToInt32, -1, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vcvtps2iubs, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_EmbBroadcastCompatible|HW_Flag_EmbMaskingCompatible|HW_Flag_EmbRoundingCompatible)
+HARDWARE_INTRINSIC(AVX10v2, ConvertToByteWithTruncatedSaturationAndZeroExtendToInt32, -1, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vcvttps2iubs, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_EmbBroadcastCompatible|HW_Flag_EmbMaskingCompatible)
+HARDWARE_INTRINSIC(AVX10v2, ConvertToSByteWithSaturationAndZeroExtendToInt32, -1, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vcvtps2ibs, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_EmbBroadcastCompatible|HW_Flag_EmbMaskingCompatible|HW_Flag_EmbRoundingCompatible)
+HARDWARE_INTRINSIC(AVX10v2, ConvertToSByteWithTruncatedSaturationAndZeroExtendToInt32, -1, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vcvttps2ibs, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_EmbBroadcastCompatible|HW_Flag_EmbMaskingCompatible)
+HARDWARE_INTRINSIC(AVX10v2, ConvertToVector128Int32, 32, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvtpd2dq}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_EmbBroadcastCompatible|HW_Flag_EmbMaskingCompatible|HW_Flag_EmbRoundingCompatible)
+HARDWARE_INTRINSIC(AVX10v2, ConvertToVector128Single, 32, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vcvtqq2ps, INS_vcvtuqq2ps, INS_invalid, INS_cvtpd2ps}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_EmbBroadcastCompatible|HW_Flag_EmbMaskingCompatible|HW_Flag_EmbRoundingCompatible)
+HARDWARE_INTRINSIC(AVX10v2, ConvertToVector128UInt32, 32, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vcvtpd2udq}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_EmbBroadcastCompatible|HW_Flag_EmbMaskingCompatible|HW_Flag_EmbRoundingCompatible)
+HARDWARE_INTRINSIC(AVX10v2, ConvertToVector256Double, 32, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vcvtqq2pd, INS_vcvtuqq2pd, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_EmbBroadcastCompatible|HW_Flag_EmbMaskingCompatible|HW_Flag_EmbRoundingCompatible)
+HARDWARE_INTRINSIC(AVX10v2, ConvertToVector256Int32, 32, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvtps2dq, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_EmbBroadcastCompatible|HW_Flag_EmbMaskingCompatible|HW_Flag_EmbRoundingCompatible)
+HARDWARE_INTRINSIC(AVX10v2, ConvertToVector256Int64, 32, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vcvtps2qq, INS_vcvtpd2qq}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_EmbBroadcastCompatible|HW_Flag_EmbMaskingCompatible|HW_Flag_EmbRoundingCompatible)
+HARDWARE_INTRINSIC(AVX10v2, ConvertToVector256Single, 32, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvtdq2ps, INS_vcvtudq2ps, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_EmbBroadcastCompatible|HW_Flag_EmbMaskingCompatible|HW_Flag_EmbRoundingCompatible)
+HARDWARE_INTRINSIC(AVX10v2, ConvertToVector256UInt32, 32, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vcvtps2udq, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_EmbBroadcastCompatible|HW_Flag_EmbMaskingCompatible|HW_Flag_EmbRoundingCompatible)
+HARDWARE_INTRINSIC(AVX10v2, ConvertToVector256UInt64, 32, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vcvtps2uqq, INS_vcvtpd2uqq}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_EmbBroadcastCompatible|HW_Flag_EmbMaskingCompatible|HW_Flag_EmbRoundingCompatible)
+HARDWARE_INTRINSIC(AVX10v2, ConvertToVectorInt32WithTruncationSaturation, -1, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vcvttps2dqs, INS_vcvttpd2dqs}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_EmbBroadcastCompatible|HW_Flag_EmbMaskingCompatible)
+HARDWARE_INTRINSIC(AVX10v2, ConvertToVectorInt64WithTruncationSaturation, -1, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vcvttps2qqs, INS_vcvttpd2qqs}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_EmbBroadcastCompatible|HW_Flag_EmbMaskingCompatible)
+HARDWARE_INTRINSIC(AVX10v2, ConvertToVectorUInt32WithTruncationSaturation, -1, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vcvttps2udqs, INS_vcvttpd2udqs}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_EmbBroadcastCompatible|HW_Flag_EmbMaskingCompatible)
+HARDWARE_INTRINSIC(AVX10v2, ConvertToVectorUInt64WithTruncationSaturation, -1, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vcvttps2uqqs, INS_vcvttpd2uqqs}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_EmbBroadcastCompatible|HW_Flag_EmbMaskingCompatible)
+HARDWARE_INTRINSIC(AVX10v2, Divide, 32, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_divps, INS_divpd}, HW_Category_SimpleSIMD, HW_Flag_EmbBroadcastCompatible|HW_Flag_EmbMaskingCompatible|HW_Flag_EmbRoundingCompatible)
+HARDWARE_INTRINSIC(AVX10v2, MinMax, -1, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vminmaxps, INS_vminmaxpd}, HW_Category_IMM, HW_Flag_BaseTypeFromFirstArg|HW_Flag_EmbBroadcastCompatible|HW_Flag_EmbMaskingCompatible)
+HARDWARE_INTRINSIC(AVX10v2, MinMaxScalar, -1, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vminmaxss, INS_vminmaxsd}, HW_Category_IMM, HW_Flag_BaseTypeFromFirstArg|HW_Flag_EmbBroadcastCompatible|HW_Flag_EmbMaskingCompatible)
+HARDWARE_INTRINSIC(AVX10v2, Multiply, 32, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_mulps, INS_mulpd}, HW_Category_SimpleSIMD, HW_Flag_Commutative |HW_Flag_EmbBroadcastCompatible|HW_Flag_EmbMaskingCompatible|HW_Flag_EmbRoundingCompatible)
+HARDWARE_INTRINSIC(AVX10v2, Scale, 32, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vscalefps, INS_vscalefpd}, HW_Category_SimpleSIMD, HW_Flag_EmbBroadcastCompatible|HW_Flag_EmbMaskingCompatible|HW_Flag_EmbRoundingCompatible)
+HARDWARE_INTRINSIC(AVX10v2, Sqrt, 32, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sqrtps, INS_sqrtpd}, HW_Category_SimpleSIMD, HW_Flag_EmbBroadcastCompatible|HW_Flag_EmbMaskingCompatible|HW_Flag_EmbRoundingCompatible)
+HARDWARE_INTRINSIC(AVX10v2, Subtract, 32, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_subps, INS_subpd}, HW_Category_SimpleSIMD, HW_Flag_EmbBroadcastCompatible|HW_Flag_EmbMaskingCompatible|HW_Flag_EmbRoundingCompatible)
+#define LAST_NI_AVX10v2 NI_AVX10v2_Subtract
+
+// ***************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
+// ISA Function name SIMD size NumArg Instructions Category Flags
+// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE}
+// ***************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
+// AVX10v2_V512 Intrinsics
+#define FIRST_NI_AVX10v2_V512 NI_AVX10v2_V512_ConvertToByteWithSaturationAndZeroExtendToInt32
+HARDWARE_INTRINSIC(AVX10v2_V512, ConvertToByteWithSaturationAndZeroExtendToInt32, 64, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vcvtps2iubs, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_EmbBroadcastCompatible|HW_Flag_EmbMaskingCompatible|HW_Flag_EmbRoundingCompatible)
+HARDWARE_INTRINSIC(AVX10v2_V512, ConvertToByteWithTruncatedSaturationAndZeroExtendToInt32, 64, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vcvttps2iubs, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_EmbBroadcastCompatible|HW_Flag_EmbMaskingCompatible)
+HARDWARE_INTRINSIC(AVX10v2_V512, ConvertToSByteWithSaturationAndZeroExtendToInt32, 64, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vcvtps2ibs, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_EmbBroadcastCompatible|HW_Flag_EmbMaskingCompatible|HW_Flag_EmbRoundingCompatible)
+HARDWARE_INTRINSIC(AVX10v2_V512, ConvertToSByteWithTruncatedSaturationAndZeroExtendToInt32, 64, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vcvttps2ibs, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_EmbBroadcastCompatible|HW_Flag_EmbMaskingCompatible)
+HARDWARE_INTRINSIC(AVX10v2_V512, ConvertToVectorInt32WithTruncationSaturation, 64, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vcvttps2dqs, INS_vcvttpd2dqs}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_EmbBroadcastCompatible|HW_Flag_EmbMaskingCompatible)
+HARDWARE_INTRINSIC(AVX10v2_V512, ConvertToVectorInt64WithTruncationSaturation, 64, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vcvttps2qqs, INS_vcvttpd2qqs}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_EmbBroadcastCompatible|HW_Flag_EmbMaskingCompatible)
+HARDWARE_INTRINSIC(AVX10v2_V512, ConvertToVectorUInt32WithTruncationSaturation, 64, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vcvttps2udqs, INS_vcvttpd2udqs}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_EmbBroadcastCompatible|HW_Flag_EmbMaskingCompatible)
+HARDWARE_INTRINSIC(AVX10v2_V512, ConvertToVectorUInt64WithTruncationSaturation, 64, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vcvttps2uqqs, INS_vcvttpd2uqqs}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_EmbBroadcastCompatible|HW_Flag_EmbMaskingCompatible)
+HARDWARE_INTRINSIC(AVX10v2_V512, MinMax, 64, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vminmaxps, INS_vminmaxpd}, HW_Category_IMM, HW_Flag_BaseTypeFromFirstArg|HW_Flag_EmbBroadcastCompatible|HW_Flag_EmbMaskingCompatible)
+HARDWARE_INTRINSIC(AVX10v2_V512, MultipleSumAbsoluteDifferences, 64, 3, {INS_invalid, INS_invalid, INS_invalid, INS_vmpsadbw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM|HW_Flag_EmbMaskingCompatible)
+#define LAST_NI_AVX10v2_V512 NI_AVX10v2_V512_MultipleSumAbsoluteDifferences
// ***************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
// ISA Function name SIMD size NumArg Instructions Category Flags
diff --git a/src/coreclr/jit/hwintrinsicxarch.cpp b/src/coreclr/jit/hwintrinsicxarch.cpp
index b8c8d43f787e0b..cc53c87ba7f712 100644
--- a/src/coreclr/jit/hwintrinsicxarch.cpp
+++ b/src/coreclr/jit/hwintrinsicxarch.cpp
@@ -50,6 +50,10 @@ static CORINFO_InstructionSet X64VersionOfIsa(CORINFO_InstructionSet isa)
return InstructionSet_AVX10v1_X64;
case InstructionSet_AVX10v1_V512:
return InstructionSet_AVX10v1_V512_X64;
+ case InstructionSet_AVX10v2:
+ return InstructionSet_AVX10v2_X64;
+ case InstructionSet_AVX10v2_V512:
+ return InstructionSet_AVX10v2_V512_X64;
case InstructionSet_AVXVNNI:
return InstructionSet_AVXVNNI_X64;
case InstructionSet_AES:
@@ -139,6 +143,10 @@ static CORINFO_InstructionSet V512VersionOfIsa(CORINFO_InstructionSet isa)
return InstructionSet_AVX10v1_V512;
case InstructionSet_AVX10v1_X64:
return InstructionSet_AVX10v1_V512_X64;
+ case InstructionSet_AVX10v2:
+ return InstructionSet_AVX10v2_V512;
+ case InstructionSet_AVX10v2_X64:
+ return InstructionSet_AVX10v2_V512_X64;
case InstructionSet_GFNI:
return InstructionSet_GFNI_V512;
case InstructionSet_PCLMULQDQ:
@@ -172,9 +180,16 @@ static CORINFO_InstructionSet lookupInstructionSet(const char* className)
{
return InstructionSet_AVX;
}
- else if (strcmp(className + 3, "10v1") == 0)
+ else if (strncmp(className + 3, "10v", 3) == 0)
{
- return InstructionSet_AVX10v1;
+ if (strcmp(className + 6, "1") == 0)
+ {
+ return InstructionSet_AVX10v1;
+ }
+ else if (strcmp(className + 6, "2") == 0)
+ {
+ return InstructionSet_AVX10v2;
+ }
}
else if (strcmp(className + 3, "2") == 0)
{
@@ -412,6 +427,9 @@ int HWIntrinsicInfo::lookupImmUpperBound(NamedIntrinsic id)
case NI_AVX_CompareScalar:
case NI_AVX512F_Compare:
case NI_EVEX_CompareMask:
+ case NI_AVX10v2_MinMaxScalar:
+ case NI_AVX10v2_MinMax:
+ case NI_AVX10v2_V512_MinMax:
{
assert(!HWIntrinsicInfo::HasFullRangeImm(id));
return 31; // enum FloatComparisonMode has 32 values
@@ -910,6 +928,10 @@ bool HWIntrinsicInfo::isFullyImplementedIsa(CORINFO_InstructionSet isa)
case InstructionSet_AVX10v1_X64:
case InstructionSet_AVX10v1_V512:
case InstructionSet_AVX10v1_V512_X64:
+ case InstructionSet_AVX10v2:
+ case InstructionSet_AVX10v2_X64:
+ case InstructionSet_AVX10v2_V512:
+ case InstructionSet_AVX10v2_V512_X64:
case InstructionSet_EVEX:
case InstructionSet_GFNI:
case InstructionSet_GFNI_X64:
@@ -3341,7 +3363,7 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic,
{
// Emulate NI_AVX512DQ_VL_MultiplyLow with SSE41 for SIMD16
}
- else
+ else if (simdSize != 64)
{
// Software fallback
break;
@@ -3399,7 +3421,7 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic,
{
// Emulate NI_AVX512DQ_VL_MultiplyLow with SSE41 for SIMD16
}
- else
+ else if (simdSize != 64)
{
// Software fallback
break;
diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp
index 5bd6e842daa119..0435ecf0b514e4 100644
--- a/src/coreclr/jit/importer.cpp
+++ b/src/coreclr/jit/importer.cpp
@@ -9548,6 +9548,21 @@ void Compiler::impImportBlockCode(BasicBlock* block)
{
indirFlags |= GTF_IND_TGT_HEAP;
}
+ else if ((lclTyp == TYP_STRUCT) && (fieldInfo.structType != NO_CLASS_HANDLE) &&
+ eeIsByrefLike(fieldInfo.structType))
+ {
+ // Field's type is a byref-like struct -> address is not on the heap.
+ indirFlags |= GTF_IND_TGT_NOT_HEAP;
+ }
+ else
+ {
+ // Field's owner is a byref-like struct -> address is not on the heap.
+ CORINFO_CLASS_HANDLE fldOwner = info.compCompHnd->getFieldClass(resolvedToken.hField);
+ if ((fldOwner != NO_CLASS_HANDLE) && eeIsByrefLike(fldOwner))
+ {
+ indirFlags |= GTF_IND_TGT_NOT_HEAP;
+ }
+ }
assert(varTypeIsI(op1));
op1 = (lclTyp == TYP_STRUCT) ? gtNewStoreBlkNode(layout, op1, op2, indirFlags)->AsIndir()
@@ -10981,7 +10996,7 @@ bool Compiler::impReturnInstruction(int prefixFlags, OPCODE& opcode)
// Make sure the type matches the original call.
var_types returnType = genActualType(op2->gtType);
- var_types originalCallType = inlCandInfo->fncRetType;
+ var_types originalCallType = genActualType(JITtype2varType(inlCandInfo->methInfo.args.retType));
if ((returnType != originalCallType) && (originalCallType == TYP_STRUCT))
{
originalCallType = impNormStructType(inlCandInfo->methInfo.args.retTypeClass);
diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp
index 6d737b4f59d10f..a90a23c405cc2d 100644
--- a/src/coreclr/jit/importercalls.cpp
+++ b/src/coreclr/jit/importercalls.cpp
@@ -1030,7 +1030,7 @@ var_types Compiler::impImportCall(OPCODE opcode,
INDEBUG(call->AsCall()->gtRawILOffset = rawILOffset);
// Is it an inline candidate?
- impMarkInlineCandidate(call, exactContextHnd, exactContextNeedsRuntimeLookup, callInfo, rawILOffset);
+ impMarkInlineCandidate(call, exactContextHnd, exactContextNeedsRuntimeLookup, callInfo);
}
// append the call node.
@@ -1240,7 +1240,7 @@ var_types Compiler::impImportCall(OPCODE opcode,
INDEBUG(call->AsCall()->gtRawILOffset = rawILOffset);
// Is it an inline candidate?
- impMarkInlineCandidate(call, exactContextHnd, exactContextNeedsRuntimeLookup, callInfo, rawILOffset);
+ impMarkInlineCandidate(call, exactContextHnd, exactContextNeedsRuntimeLookup, callInfo);
}
// Extra checks for tail calls and tail recursion.
@@ -7450,7 +7450,6 @@ void Compiler::addGuardedDevirtualizationCandidate(GenTreeCall* call,
// exactContextHnd -- context handle for inlining
// exactContextNeedsRuntimeLookup -- true if context required runtime lookup
// callInfo -- call info from VM
-// ilOffset -- the actual IL offset of the instruction that produced this inline candidate
//
// Notes:
// Mostly a wrapper for impMarkInlineCandidateHelper that also undoes
@@ -7460,8 +7459,7 @@ void Compiler::addGuardedDevirtualizationCandidate(GenTreeCall* call,
void Compiler::impMarkInlineCandidate(GenTree* callNode,
CORINFO_CONTEXT_HANDLE exactContextHnd,
bool exactContextNeedsRuntimeLookup,
- CORINFO_CALL_INFO* callInfo,
- IL_OFFSET ilOffset)
+ CORINFO_CALL_INFO* callInfo)
{
if (!opts.OptEnabled(CLFLG_INLINING))
{
@@ -7484,7 +7482,7 @@ void Compiler::impMarkInlineCandidate(GenTree* callNode,
// Do the actual evaluation
impMarkInlineCandidateHelper(call, candidateId, exactContextHnd, exactContextNeedsRuntimeLookup, callInfo,
- ilOffset, &inlineResult);
+ &inlineResult);
// Ignore non-inlineable candidates
// TODO: Consider keeping them to just devirtualize without inlining, at least for interface
// calls on NativeAOT, but that requires more changes elsewhere too.
@@ -7507,8 +7505,7 @@ void Compiler::impMarkInlineCandidate(GenTree* callNode,
const uint8_t candidatesCount = call->GetInlineCandidatesCount();
assert(candidatesCount <= 1);
InlineResult inlineResult(this, call, nullptr, "impMarkInlineCandidate");
- impMarkInlineCandidateHelper(call, 0, exactContextHnd, exactContextNeedsRuntimeLookup, callInfo, ilOffset,
- &inlineResult);
+ impMarkInlineCandidateHelper(call, 0, exactContextHnd, exactContextNeedsRuntimeLookup, callInfo, &inlineResult);
}
// If this call is an inline candidate or is not a guarded devirtualization
@@ -7541,7 +7538,6 @@ void Compiler::impMarkInlineCandidate(GenTree* callNode,
// exactContextHnd -- context handle for inlining
// exactContextNeedsRuntimeLookup -- true if context required runtime lookup
// callInfo -- call info from VM
-// ilOffset -- IL offset of instruction creating the inline candidate
//
// Notes:
// If callNode is an inline candidate, this method sets the flag
@@ -7558,7 +7554,6 @@ void Compiler::impMarkInlineCandidateHelper(GenTreeCall* call,
CORINFO_CONTEXT_HANDLE exactContextHnd,
bool exactContextNeedsRuntimeLookup,
CORINFO_CALL_INFO* callInfo,
- IL_OFFSET ilOffset,
InlineResult* inlineResult)
{
// Let the strategy know there's another call
@@ -7696,21 +7691,20 @@ void Compiler::impMarkInlineCandidateHelper(GenTreeCall* call,
if (!(methAttr & CORINFO_FLG_FORCEINLINE))
{
/* Don't bother inline blocks that are in the filter region */
- if (bbInCatchHandlerILRange(compCurBB))
+ if (bbInCatchHandlerBBRange(compCurBB))
{
#ifdef DEBUG
if (verbose)
{
printf("\nWill not inline blocks that are in the catch handler region\n");
}
-
#endif
inlineResult->NoteFatal(InlineObservation::CALLSITE_IS_WITHIN_CATCH);
return;
}
- if (bbInFilterILRange(compCurBB))
+ if (bbInFilterBBRange(compCurBB))
{
#ifdef DEBUG
if (verbose)
@@ -7767,7 +7761,6 @@ void Compiler::impMarkInlineCandidateHelper(GenTreeCall* call,
// The new value should not be null.
assert(inlineCandidateInfo != nullptr);
inlineCandidateInfo->exactContextNeedsRuntimeLookup = exactContextNeedsRuntimeLookup;
- inlineCandidateInfo->ilOffset = ilOffset;
// If we're in an inlinee compiler, and have a return spill temp, and this inline candidate
// is also a tail call candidate, it can use the same return spill temp.
@@ -9201,12 +9194,11 @@ void Compiler::impCheckCanInline(GenTreeCall* call,
CORINFO_CLASS_HANDLE clsHandle = compCompHnd->getMethodClass(ftn);
unsigned const clsAttr = compCompHnd->getClassAttribs(clsHandle);
+#ifdef DEBUG
// Return type
//
- var_types const fncRetType = pParam->call->TypeGet();
-
-#ifdef DEBUG
- var_types fncRealRetType = JITtype2varType(methInfo.args.retType);
+ var_types const fncRetType = pParam->call->gtReturnType;
+ var_types const fncRealRetType = JITtype2varType(methInfo.args.retType);
assert((genActualType(fncRealRetType) == genActualType(fncRetType)) ||
// VSW 288602
@@ -9250,7 +9242,6 @@ void Compiler::impCheckCanInline(GenTreeCall* call,
pInfo->clsAttr = clsAttr;
pInfo->methAttr = pParam->methAttr;
pInfo->initClassResult = initClassResult;
- pInfo->fncRetType = fncRetType;
pInfo->exactContextNeedsRuntimeLookup = false;
pInfo->inlinersContext = pParam->pThis->compInlineContext;
diff --git a/src/coreclr/jit/inline.h b/src/coreclr/jit/inline.h
index ce50b2cc93dba8..426e6575973d4c 100644
--- a/src/coreclr/jit/inline.h
+++ b/src/coreclr/jit/inline.h
@@ -622,10 +622,7 @@ struct InlineCandidateInfo : public HandleHistogramProfileCandidateInfo
unsigned clsAttr;
unsigned methAttr;
- // actual IL offset of instruction that resulted in this inline candidate
- IL_OFFSET ilOffset;
CorInfoInitClassResult initClassResult;
- var_types fncRetType;
bool exactContextNeedsRuntimeLookup;
InlineContext* inlinersContext;
};
diff --git a/src/coreclr/jit/instr.h b/src/coreclr/jit/instr.h
index 5ec40ea333973c..4f00ca62627966 100644
--- a/src/coreclr/jit/instr.h
+++ b/src/coreclr/jit/instr.h
@@ -85,7 +85,7 @@ enum instruction : uint32_t
};
//------------------------------------------------------------------------
-// IsAvx512OrPriorInstruction: Is this an Avx512 or Avx or Sse or K (opmask) instruction.
+// IsSimdInstruction: Is this an Avx512 or Avx or Sse or K (opmask) instruction.
// Technically, K instructions would be considered under the VEX encoding umbrella, but due to
// the instruction table encoding had to be pulled out with the rest of the `INST5` definitions.
//
@@ -95,10 +95,10 @@ enum instruction : uint32_t
// Returns:
// `true` if it is a sse or avx or avx512 instruction.
//
-inline bool IsAvx512OrPriorInstruction(instruction ins)
+inline bool IsSimdInstruction(instruction ins)
{
#if defined(TARGET_XARCH)
- return (ins >= INS_FIRST_SSE_INSTRUCTION) && (ins <= INS_LAST_AVX512_INSTRUCTION);
+ return (ins >= INS_FIRST_SSE_INSTRUCTION) && (ins <= INS_LAST_AVX10v2_INSTRUCTION);
#else
return false;
#endif // TARGET_XARCH
diff --git a/src/coreclr/jit/instrsxarch.h b/src/coreclr/jit/instrsxarch.h
index 3c6285405a0747..24be0ef3527b6a 100644
--- a/src/coreclr/jit/instrsxarch.h
+++ b/src/coreclr/jit/instrsxarch.h
@@ -172,6 +172,10 @@ INSTMUL(imul_15, "imul", IUM_RD, BAD_CODE, 0x4400003868,
#define PCKDBL(c) PACK3(0x66, 0x0f, c)
#define PCKFLT(c) PACK2(0x0f, c)
#define PCKMVB(c) PACK3(0x0F, 0x38, c)
+#define PCKDBLMAP(m, c) PACK3(0x66, m, c)
+#define PCKFLTMAP(m, c) PACK2(m, c)
+#define SSEDBLMAP(m, c) PACK3(0xf2, m, c)
+#define SSEFLTMAP(m, c) PACK3(0xf3, m, c)
// These macros encode extra byte that is implicit in the macro.
#define PACK4(byte1,byte2,byte3,byte4) (((byte1) << 16) | ((byte2) << 24) | (byte3) | ((byte4) << 8))
@@ -181,6 +185,7 @@ INSTMUL(imul_15, "imul", IUM_RD, BAD_CODE, 0x4400003868,
#define SSE38(c) PSSE38(0x66, c)
#define SSE3A(c) PSSE3A(0x66, c)
+#define AVX3A(c) PSSE3A(0xf3, c)
// VEX* encodes the implied leading opcode bytes in c1:
// 1: implied 0f, 2: implied 0f 38, 3: implied 0f 3a
@@ -884,6 +889,54 @@ INST3(vpmultishiftqb, "pmultishiftqb", IUM_WR, BAD_CODE, BAD_
INST3(LAST_AVX512_INSTRUCTION, "LAST_AVX512_INSTRUCTION", IUM_WR, BAD_CODE, BAD_CODE, BAD_CODE, INS_TT_NONE, INS_FLAGS_None)
+INST3(FIRST_AVX10v2_INSTRUCTION, "FIRST_AVX10v2_INSTRUCTION", IUM_WR, BAD_CODE, BAD_CODE, BAD_CODE, INS_TT_NONE, INS_FLAGS_None)
+INST3(vcomxsd, "comxsd", IUM_RD, BAD_CODE, BAD_CODE, SSEFLT(0x2f), INS_TT_TUPLE1_SCALAR, Input_64Bit | REX_W1 | Encoding_EVEX | Writes_OF | Writes_SF | Writes_ZF | Writes_PF | Writes_CF | Resets_AF) // Compare double precision floating point values and set flags
+INST3(vcomxss, "comxss", IUM_RD, BAD_CODE, BAD_CODE, SSEDBL(0x2f), INS_TT_TUPLE1_SCALAR, Input_32Bit | REX_W0 | Encoding_EVEX | Writes_OF | Writes_SF | Writes_ZF | Writes_PF | Writes_CF | Resets_AF) // Compare single precision floating point values and set flags
+INST3(vucomxsd, "ucomxsd", IUM_RD, BAD_CODE, BAD_CODE, SSEFLT(0x2f), INS_TT_TUPLE1_SCALAR, Input_64Bit | REX_W1 | Encoding_EVEX | Writes_OF | Writes_SF | Writes_ZF | Writes_PF | Writes_CF | Resets_AF) // Perform an unordered compare of double precision floating point values and set flags
+INST3(vucomxss, "ucomxss", IUM_RD, BAD_CODE, BAD_CODE, SSEDBL(0x2E), INS_TT_TUPLE1_SCALAR, Input_32Bit | REX_W0 | Encoding_EVEX | Writes_OF | Writes_SF | Writes_ZF | Writes_PF | Writes_CF | Resets_AF) // Perform an unordered compare of single precision floating point values and set flags
+INST3(vcvttps2dqs, "cvttps2dqs", IUM_WR, BAD_CODE, BAD_CODE, PCKFLTMAP(0x05, 0x6D), INS_TT_FULL, Input_32Bit | REX_W0 | Encoding_EVEX | INS_Flags_EmbeddedBroadcastSupported) // cvt with truncation/saturation packed singles to DWORDs
+INST3(vcvttps2udqs, "cvttps2udqs", IUM_WR, BAD_CODE, BAD_CODE, PCKFLTMAP(0x05, 0x6C), INS_TT_FULL, Input_32Bit | REX_W0 | Encoding_EVEX | INS_Flags_EmbeddedBroadcastSupported) // cvt with truncation/saturation packed singles to unsigned DWORDs
+INST3(vcvttps2qqs, "cvttps2qqs", IUM_WR, BAD_CODE, BAD_CODE, PCKDBLMAP(0x05, 0x6D), INS_TT_HALF, Input_32Bit | REX_W0 | Encoding_EVEX | INS_Flags_EmbeddedBroadcastSupported) // cvt with truncation/saturation packed singles to signed QWORDs
+INST3(vcvttps2uqqs, "cvttps2uqqs", IUM_WR, BAD_CODE, BAD_CODE, PCKDBLMAP(0x05, 0x6C), INS_TT_HALF, Input_32Bit | REX_W0 | Encoding_EVEX | INS_Flags_EmbeddedBroadcastSupported) // cvt with truncation/saturation packed singles to unsigned QWORDs
+INST3(vcvttpd2dqs, "cvttpd2dqs", IUM_WR, BAD_CODE, BAD_CODE, PCKFLTMAP(0x05, 0x6D), INS_TT_FULL, Input_64Bit | REX_W1 | Encoding_EVEX | INS_Flags_EmbeddedBroadcastSupported) // cvt with truncation/saturation packed doubles to DWORDs
+INST3(vcvttpd2udqs, "cvttpd2udqs", IUM_WR, BAD_CODE, BAD_CODE, PCKFLTMAP(0x05, 0x6C), INS_TT_FULL, Input_64Bit | REX_W1 | Encoding_EVEX | INS_Flags_EmbeddedBroadcastSupported) // cvt with truncation/saturation packed doubles to unsigned DWORDs
+INST3(vcvttpd2qqs, "cvttpd2qqs", IUM_WR, BAD_CODE, BAD_CODE, PCKDBLMAP(0x05, 0x6D), INS_TT_FULL, Input_64Bit | REX_W1 | Encoding_EVEX | INS_Flags_EmbeddedBroadcastSupported) // cvt with truncation/saturation packed doubles to signed QWORDs
+INST3(vcvttpd2uqqs, "cvttpd2uqqs", IUM_WR, BAD_CODE, BAD_CODE, PCKDBLMAP(0x05, 0x6C), INS_TT_FULL, Input_64Bit | REX_W1 | Encoding_EVEX | INS_Flags_EmbeddedBroadcastSupported) // cvt with truncation/saturation packed doubles to signed QWORDs
+INST3(vcvttsd2sis32, "cvttsd2sis", IUM_WR, BAD_CODE, BAD_CODE, SSEDBLMAP(0x05, 0x6D), INS_TT_TUPLE1_SCALAR, Input_64Bit | REX_W0 | Encoding_EVEX) // cvt with truncation/saturation scalar double to signed DWORDs
+INST3(vcvttsd2sis64, "cvttsd2sis", IUM_WR, BAD_CODE, BAD_CODE, SSEDBLMAP(0x05, 0x6D), INS_TT_TUPLE1_SCALAR, Input_64Bit | REX_W1 | Encoding_EVEX) // cvt with truncation/saturation scalar double to signed DWORDs
+INST3(vcvttsd2usis32, "cvttsd2usis", IUM_WR, BAD_CODE, BAD_CODE, SSEDBLMAP(0x05, 0x6C), INS_TT_TUPLE1_SCALAR, Input_64Bit | REX_W0 | Encoding_EVEX) // cvt with truncation/saturation scalar double to unsigned DWORD
+INST3(vcvttsd2usis64, "cvttsd2usis", IUM_WR, BAD_CODE, BAD_CODE, SSEDBLMAP(0x05, 0x6C), INS_TT_TUPLE1_SCALAR, Input_64Bit | REX_W1 | Encoding_EVEX) // cvt with truncation/saturation scalar double to unsigned QWORD
+INST3(vcvttss2sis32, "cvttss2sis", IUM_WR, BAD_CODE, BAD_CODE, SSEFLTMAP(0x05, 0x6D), INS_TT_TUPLE1_SCALAR, Input_32Bit | REX_W0 | Encoding_EVEX) // cvt with truncation/saturation scalar single to DWORD
+INST3(vcvttss2sis64, "cvttss2sis", IUM_WR, BAD_CODE, BAD_CODE, SSEFLTMAP(0x05, 0x6D), INS_TT_TUPLE1_SCALAR, Input_32Bit | REX_W1 | Encoding_EVEX) // cvt with truncation/saturation scalar single to DWORD
+INST3(vcvttss2usis32, "cvttss2usis", IUM_WR, BAD_CODE, BAD_CODE, SSEFLTMAP(0x05, 0x6C), INS_TT_TUPLE1_SCALAR, Input_32Bit | REX_W0 | Encoding_EVEX) // cvt with truncation/saturation scalar single to unsigned DWORD/QWORD
+INST3(vcvttss2usis64, "cvttss2usis", IUM_WR, BAD_CODE, BAD_CODE, SSEFLTMAP(0x05, 0x6C), INS_TT_TUPLE1_SCALAR, Input_32Bit | REX_W1 | Encoding_EVEX) // cvt with truncation/saturation scalar single to unsigned DWORD/QWORD
+
+INST3(vcvtps2ibs, "cvtps2ibs", IUM_WR, BAD_CODE, BAD_CODE, PCKDBLMAP(0x05, 0x69), INS_TT_FULL, Input_32Bit | REX_W0 | Encoding_EVEX)
+INST3(vcvtps2iubs, "cvtps2iubs", IUM_WR, BAD_CODE, BAD_CODE, PCKDBLMAP(0x05, 0x6B), INS_TT_FULL, Input_32Bit | REX_W0 | Encoding_EVEX) // cvt with truncation/saturation scalar single to unsigned DWORD/QWORD
+INST3(vcvttps2ibs, "cvttps2ibs", IUM_WR, BAD_CODE, BAD_CODE, PCKDBLMAP(0x05, 0x68), INS_TT_FULL, Input_32Bit | REX_W0 | Encoding_EVEX) // cvt with truncation/saturation scalar single to unsigned DWORD/QWORD
+INST3(vcvttps2iubs, "cvttps2iubs", IUM_WR, BAD_CODE, BAD_CODE, PCKDBLMAP(0x05, 0x6A), INS_TT_FULL, Input_32Bit | REX_W0 | Encoding_EVEX) // cvt with truncation/saturation scalar single to unsigned DWORD/QWORD
+INST3(vmpsadbw, "mpsadbw", IUM_WR, BAD_CODE, BAD_CODE, AVX3A(0x42), INS_TT_FULL, Input_8Bit | REX_W0 | Encoding_EVEX | INS_Flags_IsDstDstSrcAVXInstruction) // Compute Multiple Packed Sums of Absolute Difference
+
+INST3(vminmaxsd, "minmaxsd", IUM_WR, BAD_CODE, BAD_CODE, SSE3A(0x53), INS_TT_TUPLE1_SCALAR, Input_64Bit | REX_W1 | Encoding_EVEX | INS_Flags_IsDstSrcSrcAVXInstruction) // Return Minimum/Maximum scalar double
+INST3(vminmaxss, "minmaxss", IUM_WR, BAD_CODE, BAD_CODE, SSE3A(0x53), INS_TT_TUPLE1_SCALAR, Input_32Bit | REX_W0 | Encoding_EVEX | INS_Flags_IsDstSrcSrcAVXInstruction) // Return Minimum/Maximum scalar single
+INST3(vminmaxpd, "minmaxpd", IUM_WR, BAD_CODE, BAD_CODE, SSE3A(0x52), INS_TT_FULL, Input_64Bit | REX_W1 | Encoding_EVEX | INS_Flags_EmbeddedBroadcastSupported | INS_Flags_IsDstSrcSrcAVXInstruction) // Return Maximum packed doubles
+INST3(vminmaxps, "minmaxps", IUM_WR, BAD_CODE, BAD_CODE, SSE3A(0x52), INS_TT_FULL, Input_32Bit | REX_W0 | Encoding_EVEX | INS_Flags_EmbeddedBroadcastSupported | INS_Flags_IsDstSrcSrcAVXInstruction) // Return Maximum packed singles
+INST3(vmovd, "movd", IUM_WR, PCKDBL(0xD6), BAD_CODE, SSEFLT(0x7E), INS_TT_TUPLE1_SCALAR, Input_32Bit | REX_W0 | Encoding_EVEX) // Move DWORD between xmm regs <-> memory/xmm regs
+INST3(vmovw, "movw", IUM_WR, SSEFLTMAP(0x05, 0x7E), BAD_CODE, SSEFLTMAP(0x05, 0x6E), INS_TT_TUPLE1_SCALAR, Input_16Bit | REX_W0 | Encoding_EVEX) // Move WORD between xmm regs <-> memory/xmm regs
+INST3(vpdpwsud, "pdpwsud", IUM_WR, BAD_CODE, BAD_CODE, PSSE38(0xf3, 0xD2), INS_TT_FULL, Input_32Bit | REX_W0 | Encoding_EVEX | INS_Flags_EmbeddedBroadcastSupported | INS_Flags_IsDstSrcSrcAVXInstruction) // Multiply individual words of first source operand with individual words of second source operand and add the results
+INST3(vpdpwsuds, "pdpwsuds", IUM_WR, BAD_CODE, BAD_CODE, PSSE38(0xf3, 0xD3), INS_TT_FULL, Input_32Bit | REX_W0 | Encoding_EVEX | INS_Flags_EmbeddedBroadcastSupported | INS_Flags_IsDstSrcSrcAVXInstruction) // Multiply individual words of first source operand with individual words of second source operand and add the results
+INST3(vpdpwusd, "pdpwusd", IUM_WR, BAD_CODE, BAD_CODE, SSE38(0xD2), INS_TT_FULL, Input_32Bit | REX_W0 | Encoding_EVEX | INS_Flags_EmbeddedBroadcastSupported | INS_Flags_IsDstSrcSrcAVXInstruction) // Multiply individual words of first source operand with individual words of second source operand and add the results
+INST3(vpdpwusds, "pdpwusds", IUM_WR, BAD_CODE, BAD_CODE, SSE38(0xD3), INS_TT_FULL, Input_32Bit | REX_W0 | Encoding_EVEX | INS_Flags_EmbeddedBroadcastSupported | INS_Flags_IsDstSrcSrcAVXInstruction) // Multiply individual words of first source operand with individual words of second source operand and add the results
+INST3(vpdpwuud, "pdpwuud", IUM_WR, BAD_CODE, BAD_CODE, PSSE38(0x00, 0xD2), INS_TT_FULL, Input_32Bit | REX_W0 | Encoding_EVEX | INS_Flags_EmbeddedBroadcastSupported | INS_Flags_IsDstSrcSrcAVXInstruction) // Multiply individual words of first source operand with individual words of second source operand and add the results
+INST3(vpdpwuuds, "pdpwuuds", IUM_WR, BAD_CODE, BAD_CODE, PSSE38(0x00, 0xD3), INS_TT_FULL, Input_32Bit | REX_W0 | Encoding_EVEX | INS_Flags_EmbeddedBroadcastSupported | INS_Flags_IsDstSrcSrcAVXInstruction) // Multiply individual words of first source operand with individual words of second source operand and add the results
+INST3(vpdpbssd, "pdpbssd", IUM_WR, BAD_CODE, BAD_CODE, PSSE38(0xf2, 0x50), INS_TT_FULL, Input_8Bit | REX_W0 | Encoding_EVEX | INS_Flags_EmbeddedBroadcastSupported | INS_Flags_IsDstSrcSrcAVXInstruction) // Multiply individual bytes of first source operand with individual bytes of second source operand and add the results
+INST3(vpdpbssds, "pdpbssds", IUM_WR, BAD_CODE, BAD_CODE, PSSE38(0xf2, 0x51), INS_TT_FULL, Input_8Bit | REX_W0 | Encoding_EVEX | INS_Flags_EmbeddedBroadcastSupported | INS_Flags_IsDstSrcSrcAVXInstruction) // Multiply individual bytes of first source operand with individual bytes of second source operand and add the results
+INST3(vpdpbsud, "pdpbsud", IUM_WR, BAD_CODE, BAD_CODE, PSSE38(0xf3, 0x50), INS_TT_FULL, Input_8Bit | REX_W0 | Encoding_EVEX | INS_Flags_EmbeddedBroadcastSupported | INS_Flags_IsDstSrcSrcAVXInstruction) // Multiply individual bytes of first source operand with individual bytes of second source operand and add the results
+INST3(vpdpbsuds, "pdpbsuds", IUM_WR, BAD_CODE, BAD_CODE, PSSE38(0xf3, 0x51), INS_TT_FULL, Input_8Bit | REX_W0 | Encoding_EVEX | INS_Flags_EmbeddedBroadcastSupported | INS_Flags_IsDstSrcSrcAVXInstruction) // Multiply individual bytes of first source operand with individual bytes of second source operand and add the results
+INST3(vpdpbuud, "pdpbuud", IUM_WR, BAD_CODE, BAD_CODE, PSSE38(0x00, 0x50), INS_TT_FULL, Input_8Bit | REX_W0 | Encoding_EVEX | INS_Flags_EmbeddedBroadcastSupported | INS_Flags_IsDstSrcSrcAVXInstruction) // Multiply individual bytes of first source operand with individual bytes of second source operand and add the results
+INST3(vpdpbuuds, "pdpbuuds", IUM_WR, BAD_CODE, BAD_CODE, PSSE38(0x00, 0x51), INS_TT_FULL, Input_8Bit | REX_W0 | Encoding_EVEX | INS_Flags_EmbeddedBroadcastSupported | INS_Flags_IsDstSrcSrcAVXInstruction) // Multiply individual bytes of first source operand with individual bytes of second source operand and add the results
+INST3(LAST_AVX10v2_INSTRUCTION, "LAST_AVX10v2_INSTRUCTION", IUM_WR, BAD_CODE, BAD_CODE, BAD_CODE, INS_TT_NONE, INS_FLAGS_None)
+
// Scalar instructions in SSE4.2
INST3(crc32, "crc32", IUM_RW, BAD_CODE, BAD_CODE, PSSE38(0xF2, 0xF0), INS_TT_NONE, INS_FLAGS_None)
diff --git a/src/coreclr/jit/jiteh.cpp b/src/coreclr/jit/jiteh.cpp
index 703c615fcd6339..60c830aad8d592 100644
--- a/src/coreclr/jit/jiteh.cpp
+++ b/src/coreclr/jit/jiteh.cpp
@@ -354,6 +354,28 @@ bool Compiler::bbInFilterILRange(BasicBlock* blk)
return HBtab->InFilterRegionILRange(blk);
}
+//------------------------------------------------------------------------
+// bbInCatchHandlerBBRange:
+// Check if this block is part of a catch handler.
+//
+// Arguments:
+// blk - The block
+//
+// Return Value:
+// True if the block is part of a catch handler clause. Otherwise false.
+//
+bool Compiler::bbInCatchHandlerBBRange(BasicBlock* blk)
+{
+ EHblkDsc* HBtab = ehGetBlockHndDsc(blk);
+
+ if (HBtab == nullptr)
+ {
+ return false;
+ }
+
+ return HBtab->HasCatchHandler() && HBtab->InHndRegionBBRange(blk);
+}
+
//------------------------------------------------------------------------
// bbInFilterBBRange:
// Check if this block is part of a filter.
diff --git a/src/coreclr/jit/lowerarmarch.cpp b/src/coreclr/jit/lowerarmarch.cpp
index cc02a343cf67ed..471ec849686e92 100644
--- a/src/coreclr/jit/lowerarmarch.cpp
+++ b/src/coreclr/jit/lowerarmarch.cpp
@@ -304,6 +304,11 @@ bool Lowering::IsContainableUnaryOrBinaryOp(GenTree* parentNode, GenTree* childN
}
}
+ if (childNode->OperIs(GT_LSH, GT_RSH, GT_RSZ) && parentNode->OperIs(GT_AND_NOT))
+ {
+ return true;
+ }
+
// TODO: Handle CMN, NEG/NEGS, BIC/BICS, EON, MVN, ORN, TST
return false;
}
diff --git a/src/coreclr/jit/lowerxarch.cpp b/src/coreclr/jit/lowerxarch.cpp
index 8b38842d8e9fc0..2b0300ccd85d7c 100644
--- a/src/coreclr/jit/lowerxarch.cpp
+++ b/src/coreclr/jit/lowerxarch.cpp
@@ -9602,10 +9602,6 @@ void Lowering::TryFoldCnsVecForEmbeddedBroadcast(GenTreeHWIntrinsic* parentNode,
{
assert(!childNode->IsAllBitsSet());
assert(!childNode->IsZero());
- var_types simdType = parentNode->TypeGet();
- var_types simdBaseType = parentNode->GetSimdBaseType();
- CorInfoType simdBaseJitType = parentNode->GetSimdBaseJitType();
- bool isCreatedFromScalar = true;
if (!comp->canUseEmbeddedBroadcast())
{
@@ -9613,10 +9609,16 @@ void Lowering::TryFoldCnsVecForEmbeddedBroadcast(GenTreeHWIntrinsic* parentNode,
return;
}
- if (simdType == TYP_MASK)
- {
- simdType = Compiler::getSIMDTypeForSize(parentNode->GetSimdSize());
- }
+ // We use the child node's size for the broadcast node, because the parent may consume more than its own size.
+ // The containment check has already validated that the child is sufficiently large.
+ //
+ // We use the parent node's base type, because we must ensure that the constant repeats correctly for that size,
+ // regardless of how the constant vector was created.
+
+ var_types simdType = childNode->TypeGet();
+ var_types simdBaseType = parentNode->GetSimdBaseType();
+ CorInfoType simdBaseJitType = parentNode->GetSimdBaseJitType();
+ bool isCreatedFromScalar = true;
if (varTypeIsSmall(simdBaseType))
{
@@ -10971,6 +10973,10 @@ void Lowering::ContainCheckHWIntrinsic(GenTreeHWIntrinsic* node)
case NI_AVX10v1_V512_InsertVector128:
case NI_AVX10v1_V512_InsertVector256:
case NI_AVX10v1_V512_Range:
+ case NI_AVX10v2_MinMaxScalar:
+ case NI_AVX10v2_MinMax:
+ case NI_AVX10v2_V512_MinMax:
+ case NI_AVX10v2_V512_MultipleSumAbsoluteDifferences:
case NI_GFNI_GaloisFieldAffineTransform:
case NI_GFNI_GaloisFieldAffineTransformInverse:
case NI_GFNI_V256_GaloisFieldAffineTransform:
diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp
index a7071e4ec4de9c..31785e2e052e49 100644
--- a/src/coreclr/jit/morph.cpp
+++ b/src/coreclr/jit/morph.cpp
@@ -7755,14 +7755,23 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac, bool* optA
break;
case GT_STOREIND:
- if (op1->OperIs(GT_FIELD_ADDR) && varTypeIsGC(tree))
+ if (varTypeIsGC(tree))
{
- CORINFO_FIELD_HANDLE fieldHandle = op1->AsFieldAddr()->gtFldHnd;
- if (eeIsByrefLike(info.compCompHnd->getFieldClass(fieldHandle)))
+ GenTree* addr = op1;
+ // If we're storing a reference to a field (GT_FIELD_ADDR), let's check if the field's owner is a
+ // byref-like struct.
+ while ((addr != nullptr) && addr->OperIs(GT_FIELD_ADDR))
{
- JITDUMP("Marking [%06u] STOREIND as GTF_IND_TGT_NOT_HEAP: field's owner is a byref-like struct\n",
+ CORINFO_FIELD_HANDLE fieldHandle = addr->AsFieldAddr()->gtFldHnd;
+ if (eeIsByrefLike(info.compCompHnd->getFieldClass(fieldHandle)))
+ {
+ JITDUMP(
+ "Marking [%06u] STOREIND as GTF_IND_TGT_NOT_HEAP: field's owner is a byref-like struct\n",
dspTreeID(tree));
- tree->gtFlags |= GTF_IND_TGT_NOT_HEAP;
+ tree->gtFlags |= GTF_IND_TGT_NOT_HEAP;
+ break;
+ }
+ addr = addr->AsFieldAddr()->GetFldObj();
}
}
break;
diff --git a/src/coreclr/jit/morphblock.cpp b/src/coreclr/jit/morphblock.cpp
index 4b81ca7d79eaa3..c5ab836fdc2281 100644
--- a/src/coreclr/jit/morphblock.cpp
+++ b/src/coreclr/jit/morphblock.cpp
@@ -1363,6 +1363,10 @@ GenTree* MorphCopyBlockHelper::CopyFieldByField()
if (m_store->OperIs(GT_STORE_BLK, GT_STOREIND))
{
indirFlags = m_store->gtFlags & (GTF_IND_TGT_NOT_HEAP | GTF_IND_TGT_HEAP);
+ if (m_store->OperIs(GT_STORE_BLK) && m_store->AsBlk()->GetLayout()->IsStackOnly(m_comp))
+ {
+ indirFlags |= GTF_IND_TGT_NOT_HEAP;
+ }
}
dstFldStore = m_comp->gtNewStoreIndNode(srcType, fldAddr, srcFld, indirFlags);
}
diff --git a/src/coreclr/jit/objectalloc.cpp b/src/coreclr/jit/objectalloc.cpp
index 8a18a39015c74e..7736f0b9aaf161 100644
--- a/src/coreclr/jit/objectalloc.cpp
+++ b/src/coreclr/jit/objectalloc.cpp
@@ -392,6 +392,7 @@ bool ObjectAllocator::MorphAllocObjNodes()
bool didStackAllocate = false;
m_PossiblyStackPointingPointers = BitVecOps::MakeEmpty(&m_bitVecTraits);
m_DefinitelyStackPointingPointers = BitVecOps::MakeEmpty(&m_bitVecTraits);
+ const bool isReadyToRun = comp->opts.IsReadyToRun() && !comp->IsTargetAbi(CORINFO_NATIVEAOT_ABI);
for (BasicBlock* const block : comp->Blocks())
{
@@ -419,7 +420,7 @@ bool ObjectAllocator::MorphAllocObjNodes()
{
allocType = OAT_NEWOBJ;
}
- else if (!comp->opts.IsReadyToRun() && data->IsHelperCall())
+ else if (!isReadyToRun && data->IsHelperCall())
{
switch (data->AsCall()->GetHelperNum())
{
@@ -471,7 +472,7 @@ bool ObjectAllocator::MorphAllocObjNodes()
// R2R not yet supported
//
- assert(!comp->opts.IsReadyToRun());
+ assert(!isReadyToRun);
//------------------------------------------------------------------------
// We expect the following expression tree at this point
diff --git a/src/coreclr/jit/optimizer.cpp b/src/coreclr/jit/optimizer.cpp
index c0049564371ebf..f427e3fc068d07 100644
--- a/src/coreclr/jit/optimizer.cpp
+++ b/src/coreclr/jit/optimizer.cpp
@@ -40,9 +40,20 @@ DataFlow::DataFlow(Compiler* pCompiler)
PhaseStatus Compiler::optSetBlockWeights()
{
noway_assert(opts.OptimizationEnabled());
+ assert(m_dfsTree != nullptr);
+ const bool usingProfileWeights = fgIsUsingProfileWeights();
+
+ // Rely on profile synthesis to propagate weights when we have PGO data.
+ // TODO: Replace optSetBlockWeights with profile synthesis entirely.
+ if (usingProfileWeights)
+ {
+ // Leave breadcrumb for loop alignment
+ fgHasLoops = m_dfsTree->HasCycle();
+ return PhaseStatus::MODIFIED_NOTHING;
+ }
+
bool madeChanges = false;
- assert(m_dfsTree != nullptr);
if (m_domTree == nullptr)
{
m_domTree = FlowGraphDominatorTree::Build(m_dfsTree);
@@ -59,8 +70,7 @@ PhaseStatus Compiler::optSetBlockWeights()
optFindAndScaleGeneralLoopBlocks();
}
- bool firstBBDominatesAllReturns = true;
- const bool usingProfileWeights = fgIsUsingProfileWeights();
+ bool firstBBDominatesAllReturns = true;
fgComputeReturnBlocks();
diff --git a/src/coreclr/jit/promotiondecomposition.cpp b/src/coreclr/jit/promotiondecomposition.cpp
index cde869becbe2b5..b7538acddbf2f3 100644
--- a/src/coreclr/jit/promotiondecomposition.cpp
+++ b/src/coreclr/jit/promotiondecomposition.cpp
@@ -523,16 +523,21 @@ class DecompositionPlan
target_ssize_t addrBaseOffs = 0;
FieldSeq* addrBaseOffsFldSeq = nullptr;
GenTreeFlags indirFlags = GTF_EMPTY;
-
+ GenTreeFlags flagsToPropagate = GTF_IND_COPYABLE_FLAGS;
if (m_store->OperIs(GT_STORE_BLK))
{
+ flagsToPropagate |= GTF_IND_TGT_NOT_HEAP | GTF_IND_TGT_HEAP;
addr = m_store->AsIndir()->Addr();
- indirFlags = m_store->gtFlags & GTF_IND_COPYABLE_FLAGS;
+ indirFlags = m_store->gtFlags & flagsToPropagate;
+ if (m_store->AsBlk()->GetLayout()->IsStackOnly(m_compiler))
+ {
+ indirFlags |= GTF_IND_TGT_NOT_HEAP;
+ }
}
else if (m_src->OperIs(GT_BLK))
{
addr = m_src->AsIndir()->Addr();
- indirFlags = m_src->gtFlags & GTF_IND_COPYABLE_FLAGS;
+ indirFlags = m_src->gtFlags & flagsToPropagate;
}
int numAddrUses = 0;
diff --git a/src/coreclr/jit/redundantbranchopts.cpp b/src/coreclr/jit/redundantbranchopts.cpp
index 7fae5edd0dd07a..3d028bbc764d65 100644
--- a/src/coreclr/jit/redundantbranchopts.cpp
+++ b/src/coreclr/jit/redundantbranchopts.cpp
@@ -417,8 +417,10 @@ void Compiler::optRelopImpliesRelop(RelopImplicationInfo* rii)
const ValueNum relatedVN = vnStore->GetRelatedRelop(rii->domCmpNormVN, vnRelation);
if ((relatedVN != ValueNumStore::NoVN) && (relatedVN == rii->treeNormVN))
{
- rii->canInfer = true;
- rii->vnRelation = vnRelation;
+ rii->canInfer = true;
+ rii->vnRelation = vnRelation;
+ rii->reverseSense = (rii->vnRelation == ValueNumStore::VN_RELATION_KIND::VRK_Reverse) ||
+ (rii->vnRelation == ValueNumStore::VN_RELATION_KIND::VRK_SwapReverse);
return;
}
}
@@ -543,21 +545,40 @@ void Compiler::optRelopImpliesRelop(RelopImplicationInfo* rii)
// If dom predicate is wrapped in EQ(*,0) then a true dom
// predicate implies a false branch outcome, and vice versa.
//
- // And if the dom predicate is GT_NOT we reverse yet again.
- //
- rii->reverseSense = (oper == GT_EQ) ^ (predOper == GT_NOT);
+ rii->reverseSense = (rii->vnRelation == ValueNumStore::VN_RELATION_KIND::VRK_Reverse) ||
+ (rii->vnRelation == ValueNumStore::VN_RELATION_KIND::VRK_SwapReverse);
- // We only get partial knowledge in these cases.
+ // We only get partial knowledge in the AND/OR cases.
//
// AND(p1,p2) = true ==> both p1 and p2 must be true
// AND(p1,p2) = false ==> don't know p1 or p2
// OR(p1,p2) = true ==> don't know p1 or p2
// OR(p1,p2) = false ==> both p1 and p2 must be false
//
- if (predOper != GT_NOT)
+ if (predOper == GT_AND)
+ {
+ // EQ(AND, 0) false ==> AND true ==> AND operands true
+ rii->canInferFromFalse = (oper == GT_EQ);
+ // NE(AND, 0) true ==> AND true ==> AND operands true
+ rii->canInferFromTrue = (oper == GT_NE);
+ rii->reverseSense ^= (oper == GT_EQ);
+ }
+ else if (predOper == GT_OR)
{
- rii->canInferFromFalse = rii->reverseSense ^ (predOper == GT_OR);
- rii->canInferFromTrue = rii->reverseSense ^ (predOper == GT_AND);
+ // NE(OR, 0) false ==> OR false ==> OR operands false
+ rii->canInferFromFalse = (oper == GT_NE);
+ // EQ(OR, 0) true ==> OR false ==> OR operands false
+ rii->canInferFromTrue = (oper == GT_EQ);
+ rii->reverseSense ^= (oper == GT_EQ);
+ }
+ else
+ {
+ assert(predOper == GT_NOT);
+ // NE(NOT(x), 0) ==> NOT(X)
+ // EQ(NOT(x), 0) ==> X
+ rii->canInferFromTrue = true;
+ rii->canInferFromFalse = true;
+ rii->reverseSense ^= (oper == GT_NE);
}
JITDUMP("Inferring predicate value from %s\n", GenTree::OpName(predOper));
@@ -660,19 +681,21 @@ bool Compiler::optRelopTryInferWithOneEqualOperand(const VNFuncApp& domApp,
// BB4:
// return;
- // Check whether the dominating compare being "false" implies the dominated compare is known
+ // Check whether the dominating compare being "true" or false" implies the dominated compare is known
// to be either "true" or "false".
- RelopResult treeOperStatus = IsCmp2ImpliedByCmp1(GenTree::ReverseRelop(domOper), domCns, treeOper, treeCns);
- if (treeOperStatus == RelopResult::Unknown)
+ RelopResult ifTrueStatus = IsCmp2ImpliedByCmp1(domOper, domCns, treeOper, treeCns);
+ RelopResult ifFalseStatus = IsCmp2ImpliedByCmp1(GenTree::ReverseRelop(domOper), domCns, treeOper, treeCns);
+
+ if ((ifTrueStatus == RelopResult::Unknown) && (ifFalseStatus == RelopResult::Unknown))
{
return false;
}
rii->canInfer = true;
rii->vnRelation = ValueNumStore::VN_RELATION_KIND::VRK_Inferred;
- rii->canInferFromTrue = false;
- rii->canInferFromFalse = true;
- rii->reverseSense = treeOperStatus == RelopResult::AlwaysTrue;
+ rii->canInferFromTrue = (ifTrueStatus != RelopResult::Unknown);
+ rii->canInferFromFalse = (ifFalseStatus != RelopResult::Unknown);
+ rii->reverseSense = (ifFalseStatus == RelopResult::AlwaysTrue) || (ifTrueStatus == RelopResult::AlwaysFalse);
return true;
}
@@ -811,10 +834,12 @@ bool Compiler::optRedundantBranch(BasicBlock* const block)
//
if (domIsInferredRelop)
{
- // This inference should be one-sided
+ // We used to assert rii.canInferFromTrue ^ rii.canInferFromFalse here.
//
- assert(rii.canInferFromTrue ^ rii.canInferFromFalse);
- JITDUMP("\nDominator " FMT_BB " of " FMT_BB " has same VN operands but different relop\n",
+ // But now we can find fully redundant compares with different relops,
+ // eg LT x, 47 dominating LE x, 46. The second relop's value is equal to the first.
+ //
+ JITDUMP("\nDominator " FMT_BB " of " FMT_BB " can infer value of dominated relop\n",
domBlock->bbNum, block->bbNum);
}
else
@@ -826,9 +851,6 @@ bool Compiler::optRedundantBranch(BasicBlock* const block)
JITDUMP(" Redundant compare; current relop:\n");
DISPTREE(tree);
- const bool domIsSameRelop = (rii.vnRelation == ValueNumStore::VN_RELATION_KIND::VRK_Same) ||
- (rii.vnRelation == ValueNumStore::VN_RELATION_KIND::VRK_Swap);
-
BasicBlock* const trueSuccessor = domBlock->GetTrueTarget();
BasicBlock* const falseSuccessor = domBlock->GetFalseTarget();
@@ -851,7 +873,7 @@ bool Compiler::optRedundantBranch(BasicBlock* const block)
// However we may be able to update the flow from block's predecessors so they
// bypass block and instead transfer control to jump's successors (aka jump threading).
//
- const bool wasThreaded = optJumpThreadDom(block, domBlock, domIsSameRelop);
+ const bool wasThreaded = optJumpThreadDom(block, domBlock, !rii.reverseSense);
if (wasThreaded)
{
@@ -862,7 +884,7 @@ bool Compiler::optRedundantBranch(BasicBlock* const block)
{
// True path in dominator reaches, false path doesn't; relop must be true/false.
//
- const bool relopIsTrue = rii.reverseSense ^ (domIsSameRelop | domIsInferredRelop);
+ const bool relopIsTrue = !rii.reverseSense;
JITDUMP("True successor " FMT_BB " of " FMT_BB " reaches, relop [%06u] must be %s\n",
domBlock->GetTrueTarget()->bbNum, domBlock->bbNum, dspTreeID(tree),
relopIsTrue ? "true" : "false");
@@ -873,7 +895,7 @@ bool Compiler::optRedundantBranch(BasicBlock* const block)
{
// False path from dominator reaches, true path doesn't; relop must be false/true.
//
- const bool relopIsFalse = rii.reverseSense ^ (domIsSameRelop | domIsInferredRelop);
+ const bool relopIsFalse = !rii.reverseSense;
JITDUMP("False successor " FMT_BB " of " FMT_BB " reaches, relop [%06u] must be %s\n",
domBlock->GetFalseTarget()->bbNum, domBlock->bbNum, dspTreeID(tree),
relopIsFalse ? "false" : "true");
diff --git a/src/coreclr/jit/scev.cpp b/src/coreclr/jit/scev.cpp
index a91a8f32ac58ba..94e75dc22a35af 100644
--- a/src/coreclr/jit/scev.cpp
+++ b/src/coreclr/jit/scev.cpp
@@ -1559,22 +1559,18 @@ RelopEvaluationResult ScalarEvolutionContext::EvaluateRelop(ValueNum vn)
continue;
}
- bool domIsInferredRelop = (rii.vnRelation == ValueNumStore::VN_RELATION_KIND::VRK_Inferred);
- bool domIsSameRelop = (rii.vnRelation == ValueNumStore::VN_RELATION_KIND::VRK_Same) ||
- (rii.vnRelation == ValueNumStore::VN_RELATION_KIND::VRK_Swap);
-
bool trueReaches = m_comp->optReachable(idom->GetTrueTarget(), m_loop->GetHeader(), idom);
bool falseReaches = m_comp->optReachable(idom->GetFalseTarget(), m_loop->GetHeader(), idom);
if (trueReaches && !falseReaches && rii.canInferFromTrue)
{
- bool relopIsTrue = rii.reverseSense ^ (domIsSameRelop | domIsInferredRelop);
+ bool relopIsTrue = !rii.reverseSense;
return relopIsTrue ? RelopEvaluationResult::True : RelopEvaluationResult::False;
}
if (falseReaches && !trueReaches && rii.canInferFromFalse)
{
- bool relopIsFalse = rii.reverseSense ^ (domIsSameRelop | domIsInferredRelop);
+ bool relopIsFalse = !rii.reverseSense;
return relopIsFalse ? RelopEvaluationResult::False : RelopEvaluationResult::True;
}
}
diff --git a/src/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/Amd64/GcInfo.cs b/src/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/Amd64/GcInfo.cs
index 860a18b73565a2..a64ae72b6cd4e0 100644
--- a/src/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/Amd64/GcInfo.cs
+++ b/src/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/Amd64/GcInfo.cs
@@ -381,8 +381,8 @@ private List EnumerateInterruptibleRanges(byte[] image, int
uint normRangeStartOffset = normLastinterruptibleRangeStopOffset + normStartDelta;
uint normRangeStopOffset = normRangeStartOffset + normStopDelta;
- uint rangeStartOffset = _gcInfoTypes.DenormalizeCodeOffset(normRangeStopOffset);
- uint rangeStopOffset = _gcInfoTypes.DenormalizeCodeOffset(normRangeStartOffset);
+ uint rangeStartOffset = _gcInfoTypes.DenormalizeCodeOffset(normRangeStartOffset);
+ uint rangeStopOffset = _gcInfoTypes.DenormalizeCodeOffset(normRangeStopOffset);
ranges.Add(new InterruptibleRange(i, rangeStartOffset, rangeStopOffset));
normLastinterruptibleRangeStopOffset = normRangeStopOffset;
diff --git a/src/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/Amd64/GcTransition.cs b/src/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/Amd64/GcTransition.cs
index 68e4385e1992d9..749f7e48f22e2f 100644
--- a/src/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/Amd64/GcTransition.cs
+++ b/src/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/Amd64/GcTransition.cs
@@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics;
using System.Reflection.PortableExecutable;
using System.Text;
@@ -16,6 +17,7 @@ public struct InterruptibleRange
public InterruptibleRange(uint index, uint start, uint stop)
{
Index = index;
+ Debug.Assert(start <= stop);
StartOffset = start;
StopOffset = stop;
}
diff --git a/src/libraries/Common/tests/System/Security/Cryptography/X509Certificates/TestData.cs b/src/libraries/Common/tests/System/Security/Cryptography/X509Certificates/TestData.cs
index 3c78b73ca5d9e0..20fb1159cd966b 100644
--- a/src/libraries/Common/tests/System/Security/Cryptography/X509Certificates/TestData.cs
+++ b/src/libraries/Common/tests/System/Security/Cryptography/X509Certificates/TestData.cs
@@ -2398,53 +2398,54 @@ internal struct ECDsaCngKeyValues
"-----END CERTIFICATE REQUEST-----";
internal static byte[] EmptySubjectCertificate = (
- "308202A73082018FA003020102020103300D06092A864886F70D01010B050030" +
- "1F311D301B06035504031314456D707479205375626A65637420497373756572" +
- "301E170D3138303631353134343030365A170D3333303631353134323030365A" +
- "300030820122300D06092A864886F70D01010105000382010F003082010A0282" +
- "0101008BFA2727E0D93BEF2A992E912A829FF7A374992F2BD910291BF2BD747D" +
- "5CCCF997276ABC2F1CACEAD3F964333F5FF9D7F116A0AC392E711866CCEB0E48" +
- "80716367613E4ABD26FCB946E0A2C6AB84ABFD1EF377CD4F6C497D49D9B99CBE" +
- "DA878CA4E962307DE110345D2B22CB95A2CC3E0AB94D505CF43FA3B0343B4957" +
- "AF361E3604507732150254D77162909887509D5990499C039E5C3871326E09C2" +
- "DE132786032B4CD9F460CE35DD0650BE77B0AD9963BC498773CAC858AD15000E" +
- "A97793A906D5052A381AA2EE84BF2734833BF12DE932CF67A6D567E627898D96" +
- "2FEA2B4F55DE992C205DD67B5B2A59CDD25C04070363D48C8ED854BE013C5D1E" +
- "3E57FF0203010001A30D300B30090603551D1304023000300D06092A864886F7" +
- "0D01010B0500038201010001BF6D51DA7C45965CB2B6B889E0B1875DFEFDBAC1" +
- "558978A53E37BB796E10CBA9AFB698168F55DBD2EC4D26E9FABB7D40D55A2FCA" +
- "57F7BBC8509D1B88EB753468F3B57A42718081F00430115A48035CE72CBF9294" +
- "2837DF2C2FDC38CE213F2258C5E071A4E18ED70DFC281CD376E84ADC92922416" +
- "43389C87098AFAD976F811AA95B48B69DAF7CB31C79953BBFD1C96839561CE12" +
- "435F83CEA9F2CB9A94235B0B21FB0D591CDC41676FE927E41CC3A776FAF97146" +
- "BF14B08041CB1A90AC7339E7BD1DAF9A600479754F42C88D418B5449F5D34050" +
- "4E543013489C47297C83440C3EEF49C9A9D96E398949F03ACB0D5F72E7B4E9D3" +
- "895D82CAB526DB74AC5629").HexToByteArray();
+ "308202D1308201B9A003020102020A258B80E19011363C8AE6300D06092A8648" +
+ "86F70D01010B0500301F311D301B06035504031314456D707479205375626A65" +
+ "637420497373756572301E170D3235303131393030303330375A170D34343031" +
+ "31393030303330375A300030820122300D06092A864886F70D01010105000382" +
+ "010F003082010A0282010100D9E161DE2C29CABD97ABC3E0D246C46A061E74E1" +
+ "D947DCC3D8E0B536185DF3206FCFE24F3CBA7AD351FEE031A3771D95DC6C53A0" +
+ "3E5D6EEE6A25E2AD9FE1BEA7AF95E6FB9E309B7E954780DC9EDA2EC6E765534F" +
+ "DCF8FAB09D8C00617E5FDE07A95FB855738513CA4386419D3C61F3BAD16EB92B" +
+ "9039D42377C12851B4CA8A7A3076A8F000F416EF3DAA69F2EB776BF63FA1FE93" +
+ "AA83806EC85AB0FF0F0A1EB5598AD904D3A9687C53E05FD21967053428D7A502" +
+ "18F47E00F770B8ED8C393D876F926BC2B1D1E46F54E48F60E0DB67E33755FA4C" +
+ "724B081D59128A6D014720654ADC0714D344788BF0DB5A8E2955C90F99326FEE" +
+ "ABDA354C6F923815F9C586590203010001A32E302C301F0603551D110101FF04" +
+ "15301382116D6963726F736F66742E6578616D706C6530090603551D13040230" +
+ "00300D06092A864886F70D01010B050003820101005ABEB15466AC8775278E18" +
+ "811D00F16FE1E4FDD7A3BFBED0D5578859F258018CD2D84657D1B1C71F8077A5" +
+ "C3DF29E907E737E8F2129644F98F0FBA47A1C2480DF4DE4767850841412036B0" +
+ "0AD2B21728DCAF463EBBA803CD0FB9A55F8579A895E339733561319767213EF0" +
+ "7265BED608FD22ECCDD207E970C0386F21E8A04354B5BD43F7D394C461B9A109" +
+ "0C8113D86CA437AEC5B1014A06D3A8EB57D2D214EF2E9FA864831803DCEEED8E" +
+ "01C60EA4E85F7983F55A2C0BED6B3A5BC37EC01584D67CFC53B2C6D54AE963D0" +
+ "4F99BB8CAB6E2C941BF7F0DAA3AD25AC9F16377295DF744B6281C53954137EC3" +
+ "1D4B90590E0E0E39CD7B2F574951C4178D9DC5D4C3").HexToByteArray();
internal static byte[] EmptySubjectIssuerCertificate = (
- "308202D4308201BCA003020102020900F68AD256DB542CF9300D06092A864886" +
- "F70D01010B0500301F311D301B06035504031314456D707479205375626A6563" +
- "7420497373756572301E170D3137303631353134343030365A170D3333303631" +
- "353134343030365A301F311D301B06035504031314456D707479205375626A65" +
- "63742049737375657230820122300D06092A864886F70D01010105000382010F" +
- "003082010A0282010100A67F5898CCA5FC235EEB2FF14BF0BF490BB507C4D552" +
- "76E0D86CAA72BFDBDE7E7F38EC3184B18D32AEA7F5A1EEF0D2D24B7B8ED340F5" +
- "00703D3758B7E3824848CD9A4CDF15F73EBB1D4A02ED8182673138822C148463" +
- "B6126D14BE03C9A4DF62D35109BF7A8CDDFF6AE5A55C75496C13376C9B0096A0" +
- "5F398703FFBB6B69F7EA79B1F1F955F07CEBDAF3FB87D6E6F9C33678C49EC5E5" +
- "7EF10AEB14E009C83DC3DD3A2707F36D1A8723849DCD020CFBB0D38972B15F12" +
- "53209E015915A2275ADFB0164DB5A6C79BA53EA5782B001D92764D21694E5992" +
- "33B4D2C7FE260F925194C372EE473812B4F82381B4027E1F7F52E72A6ECC5BEE" +
- "656FE161E7681A06A9BF0203010001A3133011300F0603551D130101FF040530" +
- "030101FF300D06092A864886F70D01010B050003820101008D239025B8266EFF" +
- "AEB1B76EA159ED7BF6A6F2E5A23266DF07767DEDF26B43983EC8717AC2E6B99E" +
- "A21625D787D39BF94110D5A9B37CF0E6FB3062090D280B889A0E8DA5952E46D5" +
- "107F9BE829119282ADD53414CE0BA47C1E04D82BCC50118BB9CB3905E22FADD5" +
- "1905F23373D7F5E9E32C5C7D27B68CD15D1E079153B66B3DBE148D4DF2BF8EA1" +
- "8E68D838BE1C86E68E4CAF09A90F7428A4A50922BCB01010A1B585227930CEE0" +
- "027D561804C2F023AEBAA63F312F49A37B74BED2DB8B6D8AA1A6E60320589EB5" +
- "B14EB93CC47DAF7F07D67C25FD275493C0AF0CC23E8AED47963DCCE7C2ADFD56" +
- "5B8A77118C2978E15D1511572C4496CD1180094D43AE50FD").HexToByteArray();
+ "308202D3308201BBA00302010202083875DCB8D7B865B5300D06092A864886F7" +
+ "0D01010B0500301F311D301B06035504031314456D707479205375626A656374" +
+ "20497373756572301E170D3235303131383030303330375A170D343530313139" +
+ "3030303330375A301F311D301B06035504031314456D707479205375626A6563" +
+ "742049737375657230820122300D06092A864886F70D01010105000382010F00" +
+ "3082010A0282010100DC1542882EF660F49EFCB483151A9D9AC1E7801A3BA4A2" +
+ "176427F0F6A59137687C096CB59B2D9398A1E3FC3AE11D0301D343D3206B8EF2" +
+ "F558025889B84BAAA7337750C5E878E278132A53AD8DCBA3061D241B44008772" +
+ "4BED8E6875BD509EB6C2D920F2E74529609F02E1639FF6839E5E18D5F4A7BB6C" +
+ "021848274EBB4E1207A5C18873EB9A171FFAD2A0F5CC3B82E60B1CF06F7C482C" +
+ "3555CC45D011245C242D33FD989953383F6F7E9D5B6246DAE7D241C0575E7872" +
+ "06329A58151E97232C510E5609745D84EB3768A82C350CAB0230C522963B93E0" +
+ "5025FBC4B0865705310F35A8BA589D8D3B794765BD0F4D34BE9A057AA7CEF98F" +
+ "46125C50A4856766D90203010001A3133011300F0603551D130101FF04053003" +
+ "0101FF300D06092A864886F70D01010B0500038201010042940334A754ACA256" +
+ "C27BD14FD05FEC3730DC6633C5DF5DAD7323CD8FB9C01473DF129A7D4F03751B" +
+ "2A9B53C8E954770090BD5153991A43DAD8ED9602AB93DFEFFF4D651354775CE8" +
+ "2A105B5653EB6F2A6E369BC1D98361699F6CD2AB0418C6E57C18647895D77F3F" +
+ "402909F85085037F13C6BEF847A4218B4F8FBC8823BFA9C4491CA3F510423A8C" +
+ "BF192CAEE3C190C15D367067F91E235835A502C9219499A443833E40AC660DC6" +
+ "268CB44411AA2482CB11087BD4DBED936FB564367FB85903BDE2B778CE64D976" +
+ "28C17EA2B73F84C6D7D6BBF387F4484DCE45ECEE3495530103F37AE656DC0602" +
+ "22DCE1EB7F2DC5E0B1DF67B62FBA8C705A3D4838662E8D").HexToByteArray();
internal static byte[] T61StringCertificate = (
"2d2d2d2d2d424547494e2043455254494649434154452d2d2d2d2d0a4d494943" +
diff --git a/src/libraries/Common/tests/TestUtilities/System/AssertExtensions.cs b/src/libraries/Common/tests/TestUtilities/System/AssertExtensions.cs
index cdab35da2b134b..4fe7c4821a2aa8 100644
--- a/src/libraries/Common/tests/TestUtilities/System/AssertExtensions.cs
+++ b/src/libraries/Common/tests/TestUtilities/System/AssertExtensions.cs
@@ -813,9 +813,11 @@ static string ToStringPadded(Half value)
/// Verifies that two values are equal, within the .
/// The expected value
/// The value to be compared against
- /// The total variance allowed between the expected and actual results.
+ /// The total variance allowed between the expected and actual results.
+ /// The banner to show; if null, then the standard
+ /// banner of "Values differ" will be used
/// Thrown when the values are not equal
- public static void Equal(double expected, double actual, double variance)
+ public static void Equal(double expected, double actual, double variance, string? banner = null)
{
if (double.IsNaN(expected))
{
@@ -824,11 +826,11 @@ public static void Equal(double expected, double actual, double variance)
return;
}
- throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual));
+ throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual), banner);
}
else if (double.IsNaN(actual))
{
- throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual));
+ throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual), banner);
}
if (double.IsNegativeInfinity(expected))
@@ -838,11 +840,11 @@ public static void Equal(double expected, double actual, double variance)
return;
}
- throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual));
+ throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual), banner);
}
else if (double.IsNegativeInfinity(actual))
{
- throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual));
+ throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual), banner);
}
if (double.IsPositiveInfinity(expected))
@@ -852,11 +854,11 @@ public static void Equal(double expected, double actual, double variance)
return;
}
- throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual));
+ throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual), banner);
}
else if (double.IsPositiveInfinity(actual))
{
- throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual));
+ throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual), banner);
}
if (IsNegativeZero(expected))
@@ -868,7 +870,7 @@ public static void Equal(double expected, double actual, double variance)
if (IsPositiveZero(variance) || IsNegativeZero(variance))
{
- throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual));
+ throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual), banner);
}
// When the variance is not +-0.0, then we are handling a case where
@@ -879,7 +881,7 @@ public static void Equal(double expected, double actual, double variance)
{
if (IsPositiveZero(variance) || IsNegativeZero(variance))
{
- throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual));
+ throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual), banner);
}
// When the variance is not +-0.0, then we are handling a case where
@@ -896,7 +898,7 @@ public static void Equal(double expected, double actual, double variance)
if (IsPositiveZero(variance) || IsNegativeZero(variance))
{
- throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual));
+ throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual), banner);
}
// When the variance is not +-0.0, then we are handling a case where
@@ -907,7 +909,7 @@ public static void Equal(double expected, double actual, double variance)
{
if (IsPositiveZero(variance) || IsNegativeZero(variance))
{
- throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual));
+ throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual), banner);
}
// When the variance is not +-0.0, then we are handling a case where
@@ -919,7 +921,7 @@ public static void Equal(double expected, double actual, double variance)
if (delta > variance)
{
- throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual));
+ throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual), banner);
}
}
@@ -927,8 +929,10 @@ public static void Equal(double expected, double actual, double variance)
/// The expected value
/// The value to be compared against
/// The total variance allowed between the expected and actual results.
+ /// The banner to show; if null, then the standard
+ /// banner of "Values differ" will be used
/// Thrown when the values are not equal
- public static void Equal(float expected, float actual, float variance)
+ public static void Equal(float expected, float actual, float variance, string? banner = null)
{
if (float.IsNaN(expected))
{
@@ -937,11 +941,11 @@ public static void Equal(float expected, float actual, float variance)
return;
}
- throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual));
+ throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual), banner);
}
else if (float.IsNaN(actual))
{
- throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual));
+ throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual), banner);
}
if (float.IsNegativeInfinity(expected))
@@ -951,11 +955,11 @@ public static void Equal(float expected, float actual, float variance)
return;
}
- throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual));
+ throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual), banner);
}
else if (float.IsNegativeInfinity(actual))
{
- throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual));
+ throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual), banner);
}
if (float.IsPositiveInfinity(expected))
@@ -965,11 +969,11 @@ public static void Equal(float expected, float actual, float variance)
return;
}
- throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual));
+ throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual), banner);
}
else if (float.IsPositiveInfinity(actual))
{
- throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual));
+ throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual), banner);
}
if (IsNegativeZero(expected))
@@ -981,7 +985,7 @@ public static void Equal(float expected, float actual, float variance)
if (IsPositiveZero(variance) || IsNegativeZero(variance))
{
- throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual));
+ throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual), banner);
}
// When the variance is not +-0.0, then we are handling a case where
@@ -992,7 +996,7 @@ public static void Equal(float expected, float actual, float variance)
{
if (IsPositiveZero(variance) || IsNegativeZero(variance))
{
- throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual));
+ throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual), banner);
}
// When the variance is not +-0.0, then we are handling a case where
@@ -1009,7 +1013,7 @@ public static void Equal(float expected, float actual, float variance)
if (IsPositiveZero(variance) || IsNegativeZero(variance))
{
- throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual));
+ throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual), banner);
}
// When the variance is not +-0.0, then we are handling a case where
@@ -1020,7 +1024,7 @@ public static void Equal(float expected, float actual, float variance)
{
if (IsPositiveZero(variance) || IsNegativeZero(variance))
{
- throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual));
+ throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual), banner);
}
// When the variance is not +-0.0, then we are handling a case where
@@ -1032,7 +1036,7 @@ public static void Equal(float expected, float actual, float variance)
if (delta > variance)
{
- throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual));
+ throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual), banner);
}
}
@@ -1041,8 +1045,10 @@ public static void Equal(float expected, float actual, float variance)
/// The expected value
/// The value to be compared against
/// The total variance allowed between the expected and actual results.
+ /// The banner to show; if null, then the standard
+ /// banner of "Values differ" will be used
/// Thrown when the values are not equal
- public static void Equal(Half expected, Half actual, Half variance)
+ public static void Equal(Half expected, Half actual, Half variance, string? banner = null)
{
if (Half.IsNaN(expected))
{
@@ -1051,11 +1057,11 @@ public static void Equal(Half expected, Half actual, Half variance)
return;
}
- throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual));
+ throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual), banner);
}
else if (Half.IsNaN(actual))
{
- throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual));
+ throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual), banner);
}
if (Half.IsNegativeInfinity(expected))
@@ -1065,11 +1071,11 @@ public static void Equal(Half expected, Half actual, Half variance)
return;
}
- throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual));
+ throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual), banner);
}
else if (Half.IsNegativeInfinity(actual))
{
- throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual));
+ throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual), banner);
}
if (Half.IsPositiveInfinity(expected))
@@ -1079,11 +1085,11 @@ public static void Equal(Half expected, Half actual, Half variance)
return;
}
- throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual));
+ throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual), banner);
}
else if (Half.IsPositiveInfinity(actual))
{
- throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual));
+ throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual), banner);
}
if (IsNegativeZero(expected))
@@ -1095,7 +1101,7 @@ public static void Equal(Half expected, Half actual, Half variance)
if (IsPositiveZero(variance) || IsNegativeZero(variance))
{
- throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual));
+ throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual), banner);
}
// When the variance is not +-0.0, then we are handling a case where
@@ -1106,7 +1112,7 @@ public static void Equal(Half expected, Half actual, Half variance)
{
if (IsPositiveZero(variance) || IsNegativeZero(variance))
{
- throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual));
+ throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual), banner);
}
// When the variance is not +-0.0, then we are handling a case where
@@ -1123,7 +1129,7 @@ public static void Equal(Half expected, Half actual, Half variance)
if (IsPositiveZero(variance) || IsNegativeZero(variance))
{
- throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual));
+ throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual), banner);
}
// When the variance is not +-0.0, then we are handling a case where
@@ -1134,7 +1140,7 @@ public static void Equal(Half expected, Half actual, Half variance)
{
if (IsPositiveZero(variance) || IsNegativeZero(variance))
{
- throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual));
+ throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual), banner);
}
// When the variance is not +-0.0, then we are handling a case where
@@ -1146,7 +1152,7 @@ public static void Equal(Half expected, Half actual, Half variance)
if (delta > variance)
{
- throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual));
+ throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual), banner);
}
}
#endif
diff --git a/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.Unix.cs b/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.Unix.cs
index f0924cdedf5fdb..59c0b9a29d3932 100644
--- a/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.Unix.cs
+++ b/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.Unix.cs
@@ -51,9 +51,10 @@ public static partial class PlatformDetection
throw new PlatformNotSupportedException();
private static readonly Version s_openssl3Version = new Version(3, 0, 0);
- public static bool IsOpenSsl3 => !IsApplePlatform && !IsWindows && !IsAndroid && !IsBrowser ?
- GetOpenSslVersion() >= s_openssl3Version :
- false;
+ private static readonly Version s_openssl3_4Version = new Version(3, 4, 0);
+
+ public static bool IsOpenSsl3 => IsOpenSslVersionAtLeast(s_openssl3Version);
+ public static bool IsOpenSsl3_4 => IsOpenSslVersionAtLeast(s_openssl3_4Version);
///
/// If gnulibc is available, returns the release, such as "stable".
@@ -140,6 +141,18 @@ private static Version GetOpenSslVersion()
return s_opensslVersion;
}
+ // The "IsOpenSsl" properties answer false on Apple, even if OpenSSL is present for lightup,
+ // as they are answering the question "is OpenSSL the primary crypto provider".
+ private static bool IsOpenSslVersionAtLeast(Version minVersion)
+ {
+ if (IsApplePlatform || IsWindows || IsAndroid || IsBrowser)
+ {
+ return false;
+ }
+
+ return GetOpenSslVersion() >= minVersion;
+ }
+
private static Version ToVersion(string versionString)
{
// In some distros/versions we cannot discover the distro version; return something valid.
diff --git a/src/libraries/Microsoft.Extensions.Caching.Memory/src/MemoryCache.cs b/src/libraries/Microsoft.Extensions.Caching.Memory/src/MemoryCache.cs
index 0c95499694451a..90b6931ba88acd 100644
--- a/src/libraries/Microsoft.Extensions.Caching.Memory/src/MemoryCache.cs
+++ b/src/libraries/Microsoft.Extensions.Caching.Memory/src/MemoryCache.cs
@@ -2,11 +2,13 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System;
+using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
@@ -81,15 +83,7 @@ public MemoryCache(IOptions optionsAccessor, ILoggerFactory
/// Gets an enumerable of the all the keys in the .
///
public IEnumerable
@@ -21,4 +22,8 @@
+
+
+
+
diff --git a/src/libraries/Microsoft.Extensions.Caching.Memory/tests/MemoryCacheSetAndRemoveTests.cs b/src/libraries/Microsoft.Extensions.Caching.Memory/tests/MemoryCacheSetAndRemoveTests.cs
index cebc0a374b3102..57c3f56913b60d 100644
--- a/src/libraries/Microsoft.Extensions.Caching.Memory/tests/MemoryCacheSetAndRemoveTests.cs
+++ b/src/libraries/Microsoft.Extensions.Caching.Memory/tests/MemoryCacheSetAndRemoveTests.cs
@@ -850,6 +850,21 @@ public async Task GetOrCreateAsyncWithCacheEntryOptions()
Assert.False(cache.TryGetValue(cacheKey, out _));
}
+ [Fact]
+ public void MixedKeysUsage()
+ {
+ // keys are split internally into 2 separate chunks
+ var cache = CreateCache();
+ var typed = Assert.IsType(cache);
+ object key0 = 123.45M, key1 = "123.45";
+ cache.Set(key0, "string value");
+ cache.Set(key1, "decimal value");
+
+ Assert.Equal(2, typed.Count);
+ Assert.Equal("string value", cache.Get(key0));
+ Assert.Equal("decimal value", cache.Get(key1));
+ }
+
private class TestKey
{
public override bool Equals(object obj) => true;
diff --git a/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchiveEntry.cs b/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchiveEntry.cs
index cdb8551bffdca4..93250857111adf 100644
--- a/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchiveEntry.cs
+++ b/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchiveEntry.cs
@@ -1212,14 +1212,14 @@ private void WriteDataDescriptor()
BinaryPrimitives.WriteInt64LittleEndian(dataDescriptor[ZipLocalFileHeader.Zip64DataDescriptor.FieldLocations.CompressedSize..], _compressedSize);
BinaryPrimitives.WriteInt64LittleEndian(dataDescriptor[ZipLocalFileHeader.Zip64DataDescriptor.FieldLocations.UncompressedSize..], _uncompressedSize);
- bytesToWrite = ZipLocalFileHeader.Zip64DataDescriptor.FieldLocations.CompressedSize + ZipLocalFileHeader.Zip64DataDescriptor.FieldLengths.UncompressedSize;
+ bytesToWrite = ZipLocalFileHeader.Zip64DataDescriptor.FieldLocations.UncompressedSize + ZipLocalFileHeader.Zip64DataDescriptor.FieldLengths.UncompressedSize;
}
else
{
BinaryPrimitives.WriteUInt32LittleEndian(dataDescriptor[ZipLocalFileHeader.ZipDataDescriptor.FieldLocations.CompressedSize..], (uint)_compressedSize);
BinaryPrimitives.WriteUInt32LittleEndian(dataDescriptor[ZipLocalFileHeader.ZipDataDescriptor.FieldLocations.UncompressedSize..], (uint)_uncompressedSize);
- bytesToWrite = ZipLocalFileHeader.ZipDataDescriptor.FieldLocations.CompressedSize + ZipLocalFileHeader.ZipDataDescriptor.FieldLengths.UncompressedSize;
+ bytesToWrite = ZipLocalFileHeader.ZipDataDescriptor.FieldLocations.UncompressedSize + ZipLocalFileHeader.ZipDataDescriptor.FieldLengths.UncompressedSize;
}
_archive.ArchiveStream.Write(dataDescriptor[..bytesToWrite]);
diff --git a/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipBlocks.cs b/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipBlocks.cs
index a4567fe6769abf..6365fafab66b96 100644
--- a/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipBlocks.cs
+++ b/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipBlocks.cs
@@ -340,28 +340,33 @@ public static void RemoveZip64Blocks(List extraFields)
public void WriteBlock(Stream stream)
{
Span extraFieldData = stackalloc byte[TotalSize];
+ int startOffset = ZipGenericExtraField.FieldLocations.DynamicData;
BinaryPrimitives.WriteUInt16LittleEndian(extraFieldData[FieldLocations.Tag..], TagConstant);
BinaryPrimitives.WriteUInt16LittleEndian(extraFieldData[FieldLocations.Size..], _size);
if (_uncompressedSize != null)
{
- BinaryPrimitives.WriteInt64LittleEndian(extraFieldData[FieldLocations.UncompressedSize..], _uncompressedSize.Value);
+ BinaryPrimitives.WriteInt64LittleEndian(extraFieldData[startOffset..], _uncompressedSize.Value);
+ startOffset += FieldLengths.UncompressedSize;
}
if (_compressedSize != null)
{
- BinaryPrimitives.WriteInt64LittleEndian(extraFieldData[FieldLocations.CompressedSize..], _compressedSize.Value);
+ BinaryPrimitives.WriteInt64LittleEndian(extraFieldData[startOffset..], _compressedSize.Value);
+ startOffset += FieldLengths.CompressedSize;
}
if (_localHeaderOffset != null)
{
- BinaryPrimitives.WriteInt64LittleEndian(extraFieldData[FieldLocations.LocalHeaderOffset..], _localHeaderOffset.Value);
+ BinaryPrimitives.WriteInt64LittleEndian(extraFieldData[startOffset..], _localHeaderOffset.Value);
+ startOffset += FieldLengths.LocalHeaderOffset;
}
if (_startDiskNumber != null)
{
- BinaryPrimitives.WriteUInt32LittleEndian(extraFieldData[FieldLocations.StartDiskNumber..], _startDiskNumber.Value);
+ BinaryPrimitives.WriteUInt32LittleEndian(extraFieldData[startOffset..], _startDiskNumber.Value);
+ startOffset += FieldLengths.StartDiskNumber;
}
stream.Write(extraFieldData);
diff --git a/src/libraries/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs b/src/libraries/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs
index e485b71f87639e..09126f59f097eb 100644
--- a/src/libraries/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs
+++ b/src/libraries/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs
@@ -77,7 +77,9 @@ public partial struct Matrix4x4 : System.IEquatable
public System.Numerics.Vector3 Translation { readonly get { throw null; } set { } }
public static System.Numerics.Matrix4x4 Add(System.Numerics.Matrix4x4 value1, System.Numerics.Matrix4x4 value2) { throw null; }
public static System.Numerics.Matrix4x4 CreateBillboard(System.Numerics.Vector3 objectPosition, System.Numerics.Vector3 cameraPosition, System.Numerics.Vector3 cameraUpVector, System.Numerics.Vector3 cameraForwardVector) { throw null; }
+ public static System.Numerics.Matrix4x4 CreateBillboardLeftHanded(System.Numerics.Vector3 objectPosition, System.Numerics.Vector3 cameraPosition, System.Numerics.Vector3 cameraUpVector, System.Numerics.Vector3 cameraForwardVector) { throw null; }
public static System.Numerics.Matrix4x4 CreateConstrainedBillboard(System.Numerics.Vector3 objectPosition, System.Numerics.Vector3 cameraPosition, System.Numerics.Vector3 rotateAxis, System.Numerics.Vector3 cameraForwardVector, System.Numerics.Vector3 objectForwardVector) { throw null; }
+ public static System.Numerics.Matrix4x4 CreateConstrainedBillboardLeftHanded(System.Numerics.Vector3 objectPosition, System.Numerics.Vector3 cameraPosition, System.Numerics.Vector3 rotateAxis, System.Numerics.Vector3 cameraForwardVector, System.Numerics.Vector3 objectForwardVector) { throw null; }
public static System.Numerics.Matrix4x4 CreateFromAxisAngle(System.Numerics.Vector3 axis, float angle) { throw null; }
public static System.Numerics.Matrix4x4 CreateFromQuaternion(System.Numerics.Quaternion quaternion) { throw null; }
public static System.Numerics.Matrix4x4 CreateFromYawPitchRoll(float yaw, float pitch, float roll) { throw null; }
diff --git a/src/libraries/System.Numerics.Vectors/tests/Matrix4x4Tests.cs b/src/libraries/System.Numerics.Vectors/tests/Matrix4x4Tests.cs
index 2107bcf184f8d9..fa52f037b22cd5 100644
--- a/src/libraries/System.Numerics.Vectors/tests/Matrix4x4Tests.cs
+++ b/src/libraries/System.Numerics.Vectors/tests/Matrix4x4Tests.cs
@@ -9,7 +9,7 @@ namespace System.Numerics.Tests
{
public sealed class Matrix4x4Tests
{
- static Matrix4x4 GenerateIncrementalMatrixNumber(float value = 0.0f)
+ private static Matrix4x4 GenerateIncrementalMatrixNumber(float value = 0.0f)
{
Matrix4x4 a = new Matrix4x4();
a.M11 = value + 1.0f;
@@ -31,7 +31,7 @@ static Matrix4x4 GenerateIncrementalMatrixNumber(float value = 0.0f)
return a;
}
- static Matrix4x4 GenerateTestMatrix()
+ private static Matrix4x4 GenerateTestMatrix()
{
Matrix4x4 m =
Matrix4x4.CreateRotationX(MathHelper.ToRadians(30.0f)) *
@@ -41,6 +41,57 @@ static Matrix4x4 GenerateTestMatrix()
return m;
}
+ private static Matrix4x4 DefaultVarianceMatrix = GenerateFilledMatrix(1e-5f);
+
+ private static Matrix4x4 GenerateFilledMatrix(float value) => new Matrix4x4
+ {
+ M11 = value,
+ M12 = value,
+ M13 = value,
+ M14 = value,
+ M21 = value,
+ M22 = value,
+ M23 = value,
+ M24 = value,
+ M31 = value,
+ M32 = value,
+ M33 = value,
+ M34 = value,
+ M41 = value,
+ M42 = value,
+ M43 = value,
+ M44 = value
+ };
+
+ private static Vector3 InverseHandedness(Vector3 vector) => new Vector3(vector.X, vector.Y, -vector.Z);
+
+ // The handedness-swapped matrix of matrix M is B^-1 * M * B where B is the change of handedness matrix.
+ // Since only the Z coordinate is flipped when changing handedness,
+ //
+ // B = [ 1 0 0 0
+ // 0 1 0 0
+ // 0 0 -1 0
+ // 0 0 0 1 ]
+ //
+ // and B is its own inverse. So the handedness swap can be simplified to
+ //
+ // B^-1 * M * B = [ m11 m12 -m13 m14
+ // m21 m22 -m23 m24
+ // -m31 -m32 m33 -m34
+ // m41 m42 -m43 m44 ]
+ private static Matrix4x4 InverseHandedness(Matrix4x4 matrix) => new Matrix4x4(
+ matrix.M11, matrix.M12, -matrix.M13, matrix.M14,
+ matrix.M21, matrix.M22, -matrix.M23, matrix.M24,
+ -matrix.M31, -matrix.M32, matrix.M33, -matrix.M34,
+ matrix.M41, matrix.M42, -matrix.M43, matrix.M44);
+
+ private static void AssertEqual(Matrix4x4 expected, Matrix4x4 actual, Matrix4x4 variance)
+ {
+ for (var r = 0; r < 4; r++)
+ for (var c = 0; c < 4; c++)
+ AssertExtensions.Equal(expected[r, c], actual[r, c], variance[r, c], $"Values differ at Matrix4x4.M{r + 1}{c + 1}");
+ }
+
[Theory]
[InlineData(0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f)]
[InlineData(1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f)]
@@ -2137,13 +2188,25 @@ public void Matrix4x4SubtractTest()
Assert.Equal(expected, actual);
}
- private void CreateBillboardFact(Vector3 placeDirection, Vector3 cameraUpVector, Matrix4x4 expectedRotation)
+ private void CreateBillboardFact(Vector3 placeDirection, Vector3 cameraUpVector, Matrix4x4 expectedRotationRightHanded, Matrix4x4 expectedRotationLeftHanded)
{
Vector3 cameraPosition = new Vector3(3.0f, 4.0f, 5.0f);
Vector3 objectPosition = cameraPosition + placeDirection * 10.0f;
- Matrix4x4 expected = expectedRotation * Matrix4x4.CreateTranslation(objectPosition);
- Matrix4x4 actual = Matrix4x4.CreateBillboard(objectPosition, cameraPosition, cameraUpVector, new Vector3(0, 0, -1));
- Assert.True(MathHelper.Equal(expected, actual), "Matrix4x4.CreateBillboard did not return the expected value.");
+ Matrix4x4 expected = expectedRotationRightHanded * Matrix4x4.CreateTranslation(objectPosition);
+ Matrix4x4 actualRH = Matrix4x4.CreateBillboard(objectPosition, cameraPosition, cameraUpVector, new Vector3(0, 0, -1));
+ Assert.True(MathHelper.Equal(expected, actualRH), "Matrix4x4.CreateBillboard did not return the expected value.");
+
+ placeDirection = InverseHandedness(placeDirection);
+ cameraUpVector = InverseHandedness(cameraUpVector);
+
+ cameraPosition = new Vector3(3.0f, 4.0f, -5.0f);
+ objectPosition = cameraPosition + placeDirection * 10.0f;
+ expected = expectedRotationLeftHanded * Matrix4x4.CreateTranslation(objectPosition);
+ Matrix4x4 actualLH = Matrix4x4.CreateBillboardLeftHanded(objectPosition, cameraPosition, cameraUpVector, Vector3.UnitZ);
+ Assert.True(MathHelper.Equal(expected, actualLH), "Matrix4x4.CreateBillboardLeftHanded did not return the expected value.");
+
+ AssertEqual(actualRH, InverseHandedness(actualLH), DefaultVarianceMatrix);
+ AssertEqual(InverseHandedness(actualRH), actualLH, DefaultVarianceMatrix);
}
// A test for CreateBillboard (Vector3f, Vector3f, Vector3f, Vector3f?)
@@ -2152,7 +2215,11 @@ private void CreateBillboardFact(Vector3 placeDirection, Vector3 cameraUpVector,
public void Matrix4x4CreateBillboardTest01()
{
// Object placed at Forward of camera. result must be same as 180 degrees rotate along y-axis.
- CreateBillboardFact(new Vector3(0, 0, -1), new Vector3(0, 1, 0), Matrix4x4.CreateRotationY(MathHelper.ToRadians(180.0f)));
+ CreateBillboardFact(
+ new Vector3(0, 0, -1),
+ Vector3.UnitY,
+ Matrix4x4.CreateRotationY(MathHelper.ToRadians(180.0f)),
+ Matrix4x4.CreateRotationY(MathHelper.ToRadians(180.0f)));
}
// A test for CreateBillboard (Vector3f, Vector3f, Vector3f, Vector3f?)
@@ -2161,7 +2228,11 @@ public void Matrix4x4CreateBillboardTest01()
public void Matrix4x4CreateBillboardTest02()
{
// Object placed at Backward of camera. This result must be same as 0 degrees rotate along y-axis.
- CreateBillboardFact(new Vector3(0, 0, 1), new Vector3(0, 1, 0), Matrix4x4.CreateRotationY(MathHelper.ToRadians(0)));
+ CreateBillboardFact(
+ Vector3.UnitZ,
+ Vector3.UnitY,
+ Matrix4x4.CreateRotationY(MathHelper.ToRadians(0)),
+ Matrix4x4.CreateRotationY(MathHelper.ToRadians(0)));
}
// A test for CreateBillboard (Vector3f, Vector3f, Vector3f, Vector3f?)
@@ -2170,7 +2241,11 @@ public void Matrix4x4CreateBillboardTest02()
public void Matrix4x4CreateBillboardTest03()
{
// Place object at Right side of camera. This result must be same as 90 degrees rotate along y-axis.
- CreateBillboardFact(new Vector3(1, 0, 0), new Vector3(0, 1, 0), Matrix4x4.CreateRotationY(MathHelper.ToRadians(90)));
+ CreateBillboardFact(
+ Vector3.UnitX,
+ Vector3.UnitY,
+ Matrix4x4.CreateRotationY(MathHelper.ToRadians(90)),
+ Matrix4x4.CreateRotationY(MathHelper.ToRadians(-90)));
}
// A test for CreateBillboard (Vector3f, Vector3f, Vector3f, Vector3f?)
@@ -2179,7 +2254,11 @@ public void Matrix4x4CreateBillboardTest03()
public void Matrix4x4CreateBillboardTest04()
{
// Place object at Left side of camera. This result must be same as -90 degrees rotate along y-axis.
- CreateBillboardFact(new Vector3(-1, 0, 0), new Vector3(0, 1, 0), Matrix4x4.CreateRotationY(MathHelper.ToRadians(-90)));
+ CreateBillboardFact(
+ new Vector3(-1, 0, 0),
+ Vector3.UnitY,
+ Matrix4x4.CreateRotationY(MathHelper.ToRadians(-90)),
+ Matrix4x4.CreateRotationY(MathHelper.ToRadians(90)));
}
// A test for CreateBillboard (Vector3f, Vector3f, Vector3f, Vector3f?)
@@ -2188,8 +2267,11 @@ public void Matrix4x4CreateBillboardTest04()
public void Matrix4x4CreateBillboardTest05()
{
// Place object at Up side of camera. result must be same as 180 degrees rotate along z-axis after 90 degrees rotate along x-axis.
- CreateBillboardFact(new Vector3(0, 1, 0), new Vector3(0, 0, 1),
- Matrix4x4.CreateRotationX(MathHelper.ToRadians(90.0f)) * Matrix4x4.CreateRotationZ(MathHelper.ToRadians(180)));
+ CreateBillboardFact(
+ Vector3.UnitY,
+ Vector3.UnitZ,
+ Matrix4x4.CreateRotationX(MathHelper.ToRadians(90.0f)) * Matrix4x4.CreateRotationZ(MathHelper.ToRadians(180)),
+ Matrix4x4.CreateRotationX(MathHelper.ToRadians(-90.0f)) * Matrix4x4.CreateRotationZ(MathHelper.ToRadians(180)));
}
// A test for CreateBillboard (Vector3f, Vector3f, Vector3f, Vector3f?)
@@ -2198,8 +2280,11 @@ public void Matrix4x4CreateBillboardTest05()
public void Matrix4x4CreateBillboardTest06()
{
// Place object at Down side of camera. result must be same as 0 degrees rotate along z-axis after 90 degrees rotate along x-axis.
- CreateBillboardFact(new Vector3(0, -1, 0), new Vector3(0, 0, 1),
- Matrix4x4.CreateRotationX(MathHelper.ToRadians(90.0f)) * Matrix4x4.CreateRotationZ(MathHelper.ToRadians(0)));
+ CreateBillboardFact(
+ new Vector3(0, -1, 0),
+ Vector3.UnitZ,
+ Matrix4x4.CreateRotationX(MathHelper.ToRadians(90.0f)) * Matrix4x4.CreateRotationZ(MathHelper.ToRadians(0)),
+ Matrix4x4.CreateRotationX(MathHelper.ToRadians(-90.0f)) * Matrix4x4.CreateRotationZ(MathHelper.ToRadians(0)));
}
// A test for CreateBillboard (Vector3f, Vector3f, Vector3f, Vector3f?)
@@ -2208,8 +2293,11 @@ public void Matrix4x4CreateBillboardTest06()
public void Matrix4x4CreateBillboardTest07()
{
// Place object at Right side of camera. result must be same as 90 degrees rotate along z-axis after 90 degrees rotate along x-axis.
- CreateBillboardFact(new Vector3(1, 0, 0), new Vector3(0, 0, 1),
- Matrix4x4.CreateRotationX(MathHelper.ToRadians(90.0f)) * Matrix4x4.CreateRotationZ(MathHelper.ToRadians(90.0f)));
+ CreateBillboardFact(
+ Vector3.UnitX,
+ Vector3.UnitZ,
+ Matrix4x4.CreateRotationX(MathHelper.ToRadians(90.0f)) * Matrix4x4.CreateRotationZ(MathHelper.ToRadians(90.0f)),
+ Matrix4x4.CreateRotationX(MathHelper.ToRadians(-90.0f)) * Matrix4x4.CreateRotationZ(MathHelper.ToRadians(90.0f)));
}
// A test for CreateBillboard (Vector3f, Vector3f, Vector3f, Vector3f?)
@@ -2218,8 +2306,11 @@ public void Matrix4x4CreateBillboardTest07()
public void Matrix4x4CreateBillboardTest08()
{
// Place object at Left side of camera. result must be same as -90 degrees rotate along z-axis after 90 degrees rotate along x-axis.
- CreateBillboardFact(new Vector3(-1, 0, 0), new Vector3(0, 0, 1),
- Matrix4x4.CreateRotationX(MathHelper.ToRadians(90.0f)) * Matrix4x4.CreateRotationZ(MathHelper.ToRadians(-90.0f)));
+ CreateBillboardFact(
+ new Vector3(-1, 0, 0),
+ Vector3.UnitZ,
+ Matrix4x4.CreateRotationX(MathHelper.ToRadians(90.0f)) * Matrix4x4.CreateRotationZ(MathHelper.ToRadians(-90.0f)),
+ Matrix4x4.CreateRotationX(MathHelper.ToRadians(-90.0f)) * Matrix4x4.CreateRotationZ(MathHelper.ToRadians(-90.0f)));
}
// A test for CreateBillboard (Vector3f, Vector3f, Vector3f, Vector3f?)
@@ -2228,8 +2319,11 @@ public void Matrix4x4CreateBillboardTest08()
public void Matrix4x4CreateBillboardTest09()
{
// Place object at Up side of camera. result must be same as -90 degrees rotate along x-axis after 90 degrees rotate along z-axis.
- CreateBillboardFact(new Vector3(0, 1, 0), new Vector3(-1, 0, 0),
- Matrix4x4.CreateRotationZ(MathHelper.ToRadians(90.0f)) * Matrix4x4.CreateRotationX(MathHelper.ToRadians(-90.0f)));
+ CreateBillboardFact(
+ Vector3.UnitY,
+ new Vector3(-1, 0, 0),
+ Matrix4x4.CreateRotationZ(MathHelper.ToRadians(90.0f)) * Matrix4x4.CreateRotationX(MathHelper.ToRadians(-90.0f)),
+ Matrix4x4.CreateRotationZ(MathHelper.ToRadians(90.0f)) * Matrix4x4.CreateRotationX(MathHelper.ToRadians(90.0f)));
}
// A test for CreateBillboard (Vector3f, Vector3f, Vector3f, Vector3f?)
@@ -2238,8 +2332,11 @@ public void Matrix4x4CreateBillboardTest09()
public void Matrix4x4CreateBillboardTest10()
{
// Place object at Down side of camera. result must be same as 90 degrees rotate along x-axis after 90 degrees rotate along z-axis.
- CreateBillboardFact(new Vector3(0, -1, 0), new Vector3(-1, 0, 0),
- Matrix4x4.CreateRotationZ(MathHelper.ToRadians(90.0f)) * Matrix4x4.CreateRotationX(MathHelper.ToRadians(90.0f)));
+ CreateBillboardFact(
+ new Vector3(0, -1, 0),
+ new Vector3(-1, 0, 0),
+ Matrix4x4.CreateRotationZ(MathHelper.ToRadians(90.0f)) * Matrix4x4.CreateRotationX(MathHelper.ToRadians(90.0f)),
+ Matrix4x4.CreateRotationZ(MathHelper.ToRadians(90.0f)) * Matrix4x4.CreateRotationX(MathHelper.ToRadians(-90.0f)));
}
// A test for CreateBillboard (Vector3f, Vector3f, Vector3f, Vector3f?)
@@ -2248,7 +2345,10 @@ public void Matrix4x4CreateBillboardTest10()
public void Matrix4x4CreateBillboardTest11()
{
// Place object at Forward side of camera. result must be same as 180 degrees rotate along x-axis after 90 degrees rotate along z-axis.
- CreateBillboardFact(new Vector3(0, 0, -1), new Vector3(-1, 0, 0),
+ CreateBillboardFact(
+ new Vector3(0, 0, -1),
+ new Vector3(-1, 0, 0),
+ Matrix4x4.CreateRotationZ(MathHelper.ToRadians(90.0f)) * Matrix4x4.CreateRotationX(MathHelper.ToRadians(180.0f)),
Matrix4x4.CreateRotationZ(MathHelper.ToRadians(90.0f)) * Matrix4x4.CreateRotationX(MathHelper.ToRadians(180.0f)));
}
@@ -2258,7 +2358,10 @@ public void Matrix4x4CreateBillboardTest11()
public void Matrix4x4CreateBillboardTest12()
{
// Place object at Backward side of camera. result must be same as 0 degrees rotate along x-axis after 90 degrees rotate along z-axis.
- CreateBillboardFact(new Vector3(0, 0, 1), new Vector3(-1, 0, 0),
+ CreateBillboardFact(
+ Vector3.UnitZ,
+ new Vector3(-1, 0, 0),
+ Matrix4x4.CreateRotationZ(MathHelper.ToRadians(90.0f)) * Matrix4x4.CreateRotationX(MathHelper.ToRadians(0.0f)),
Matrix4x4.CreateRotationZ(MathHelper.ToRadians(90.0f)) * Matrix4x4.CreateRotationX(MathHelper.ToRadians(0.0f)));
}
@@ -2269,12 +2372,23 @@ public void Matrix4x4CreateBillboardTooCloseTest1()
{
Vector3 objectPosition = new Vector3(3.0f, 4.0f, 5.0f);
Vector3 cameraPosition = objectPosition;
- Vector3 cameraUpVector = new Vector3(0, 1, 0);
+ Vector3 cameraUpVector = Vector3.UnitY;
// Doesn't pass camera face direction. CreateBillboard uses new Vector3f(0, 0, -1) direction. Result must be same as 180 degrees rotate along y-axis.
Matrix4x4 expected = Matrix4x4.CreateRotationY(MathHelper.ToRadians(180.0f)) * Matrix4x4.CreateTranslation(objectPosition);
- Matrix4x4 actual = Matrix4x4.CreateBillboard(objectPosition, cameraPosition, cameraUpVector, new Vector3(0, 0, 1));
- Assert.True(MathHelper.Equal(expected, actual), "Matrix4x4.CreateBillboard did not return the expected value.");
+ Matrix4x4 actualRH = Matrix4x4.CreateBillboard(objectPosition, cameraPosition, cameraUpVector, Vector3.UnitZ);
+ Assert.True(MathHelper.Equal(expected, actualRH), "Matrix4x4.CreateBillboard did not return the expected value.");
+
+ objectPosition = new Vector3(3.0f, 4.0f, -5.0f);
+ cameraPosition = objectPosition;
+ cameraUpVector = Vector3.UnitY;
+
+ expected = Matrix4x4.CreateRotationY(MathHelper.ToRadians(180.0f)) * Matrix4x4.CreateTranslation(objectPosition);
+ Matrix4x4 actualLH = Matrix4x4.CreateBillboardLeftHanded(objectPosition, cameraPosition, cameraUpVector, new Vector3(0, 0, -1));
+ Assert.True(MathHelper.Equal(expected, actualLH), "Matrix4x4.CreateBillboardLeftHanded did not return the expected value.");
+
+ AssertEqual(actualRH, InverseHandedness(actualLH), DefaultVarianceMatrix);
+ AssertEqual(InverseHandedness(actualRH), actualLH, DefaultVarianceMatrix);
}
// A test for CreateBillboard (Vector3f, Vector3f, Vector3f, Vector3f?)
@@ -2284,30 +2398,65 @@ public void Matrix4x4CreateBillboardTooCloseTest2()
{
Vector3 objectPosition = new Vector3(3.0f, 4.0f, 5.0f);
Vector3 cameraPosition = objectPosition;
- Vector3 cameraUpVector = new Vector3(0, 1, 0);
+ Vector3 cameraUpVector = Vector3.UnitY;
// Passes Vector3f.Right as camera face direction. Result must be same as -90 degrees rotate along y-axis.
Matrix4x4 expected = Matrix4x4.CreateRotationY(MathHelper.ToRadians(-90.0f)) * Matrix4x4.CreateTranslation(objectPosition);
- Matrix4x4 actual = Matrix4x4.CreateBillboard(objectPosition, cameraPosition, cameraUpVector, new Vector3(1, 0, 0));
- Assert.True(MathHelper.Equal(expected, actual), "Matrix4x4.CreateBillboard did not return the expected value.");
+ Matrix4x4 actualRH = Matrix4x4.CreateBillboard(objectPosition, cameraPosition, cameraUpVector, Vector3.UnitX);
+ Assert.True(MathHelper.Equal(expected, actualRH), "Matrix4x4.CreateBillboard did not return the expected value.");
+
+ objectPosition = new Vector3(3.0f, 4.0f, -5.0f);
+ cameraPosition = objectPosition;
+ cameraUpVector = Vector3.UnitY;
+
+ expected = Matrix4x4.CreateRotationY(MathHelper.ToRadians(90.0f)) * Matrix4x4.CreateTranslation(objectPosition);
+ Matrix4x4 actualLH = Matrix4x4.CreateBillboardLeftHanded(objectPosition, cameraPosition, cameraUpVector, Vector3.UnitX);
+ Assert.True(MathHelper.Equal(expected, actualLH), "Matrix4x4.CreateBillboardLeftHanded did not return the expected value.");
}
- private void CreateConstrainedBillboardFact(Vector3 placeDirection, Vector3 rotateAxis, Matrix4x4 expectedRotation)
+ private void CreateConstrainedBillboardFact(Vector3 placeDirection, Vector3 rotateAxis, Matrix4x4 expectedRotationRightHanded, Matrix4x4 expectedRotationLeftHanded)
{
Vector3 cameraPosition = new Vector3(3.0f, 4.0f, 5.0f);
Vector3 objectPosition = cameraPosition + placeDirection * 10.0f;
- Matrix4x4 expected = expectedRotation * Matrix4x4.CreateTranslation(objectPosition);
- Matrix4x4 actual = Matrix4x4.CreateConstrainedBillboard(objectPosition, cameraPosition, rotateAxis, new Vector3(0, 0, -1), new Vector3(0, 0, -1));
- Assert.True(MathHelper.Equal(expected, actual), "Matrix4x4.CreateConstrainedBillboard did not return the expected value.");
+ Matrix4x4 expected = expectedRotationRightHanded * Matrix4x4.CreateTranslation(objectPosition);
+ Matrix4x4 actualRH = Matrix4x4.CreateConstrainedBillboard(objectPosition, cameraPosition, rotateAxis, new Vector3(0, 0, -1), new Vector3(0, 0, -1));
+ Assert.True(MathHelper.Equal(expected, actualRH), $"{nameof(Matrix4x4.CreateConstrainedBillboard)} did not return the expected value.");
+
+ // When you move camera along rotateAxis, result must be same.
+ cameraPosition += rotateAxis * 10.0f;
+ Matrix4x4 actualTranslatedUpRH = Matrix4x4.CreateConstrainedBillboard(objectPosition, cameraPosition, rotateAxis, new Vector3(0, 0, -1), new Vector3(0, 0, -1));
+ Assert.True(MathHelper.Equal(expected, actualTranslatedUpRH), $"{nameof(Matrix4x4.CreateConstrainedBillboard)} did not return the expected value.");
+
+ cameraPosition -= rotateAxis * 30.0f;
+ Matrix4x4 actualTranslatedDownRH = Matrix4x4.CreateConstrainedBillboard(objectPosition, cameraPosition, rotateAxis, new Vector3(0, 0, -1), new Vector3(0, 0, -1));
+ Assert.True(MathHelper.Equal(expected, actualTranslatedDownRH), $"{nameof(Matrix4x4.CreateConstrainedBillboard)} did not return the expected value.");
+
+ placeDirection = InverseHandedness(placeDirection);
+ rotateAxis = InverseHandedness(rotateAxis);
+
+ cameraPosition = new Vector3(3.0f, 4.0f, -5.0f);
+ objectPosition = cameraPosition + placeDirection * 10.0f;
+ expected = expectedRotationLeftHanded * Matrix4x4.CreateTranslation(objectPosition);
+ Matrix4x4 actualLH = Matrix4x4.CreateConstrainedBillboardLeftHanded(objectPosition, cameraPosition, rotateAxis, new Vector3(0, 0, -1), Vector3.UnitZ);
+ Assert.True(MathHelper.Equal(expected, actualLH), $"{nameof(Matrix4x4.CreateConstrainedBillboardLeftHanded)} did not return the expected value.");
// When you move camera along rotateAxis, result must be same.
cameraPosition += rotateAxis * 10.0f;
- actual = Matrix4x4.CreateConstrainedBillboard(objectPosition, cameraPosition, rotateAxis, new Vector3(0, 0, -1), new Vector3(0, 0, -1));
- Assert.True(MathHelper.Equal(expected, actual), "Matrix4x4.CreateConstrainedBillboard did not return the expected value.");
+ Matrix4x4 actualTranslatedUpLH = Matrix4x4.CreateConstrainedBillboardLeftHanded(objectPosition, cameraPosition, rotateAxis, new Vector3(0, 0, -1), Vector3.UnitZ);
+ Assert.True(MathHelper.Equal(expected, actualTranslatedUpLH), $"{nameof(Matrix4x4.CreateConstrainedBillboardLeftHanded)} did not return the expected value.");
cameraPosition -= rotateAxis * 30.0f;
- actual = Matrix4x4.CreateConstrainedBillboard(objectPosition, cameraPosition, rotateAxis, new Vector3(0, 0, -1), new Vector3(0, 0, -1));
- Assert.True(MathHelper.Equal(expected, actual), "Matrix4x4.CreateConstrainedBillboard did not return the expected value.");
+ Matrix4x4 actualTranslatedDownLH = Matrix4x4.CreateConstrainedBillboardLeftHanded(objectPosition, cameraPosition, rotateAxis, new Vector3(0, 0, -1), Vector3.UnitZ);
+ Assert.True(MathHelper.Equal(expected, actualTranslatedDownLH), $"{nameof(Matrix4x4.CreateConstrainedBillboardLeftHanded)} did not return the expected value.");
+
+ AssertEqual(actualRH, InverseHandedness(actualLH), DefaultVarianceMatrix);
+ AssertEqual(InverseHandedness(actualRH), actualLH, DefaultVarianceMatrix);
+
+ AssertEqual(actualTranslatedUpRH, InverseHandedness(actualTranslatedUpLH), DefaultVarianceMatrix);
+ AssertEqual(InverseHandedness(actualTranslatedUpRH), actualTranslatedUpLH, DefaultVarianceMatrix);
+
+ AssertEqual(actualTranslatedDownRH, InverseHandedness(actualTranslatedDownLH), DefaultVarianceMatrix);
+ AssertEqual(InverseHandedness(actualTranslatedDownRH), actualTranslatedDownLH, DefaultVarianceMatrix);
}
// A test for CreateConstrainedBillboard (Vector3f, Vector3f, Vector3f, Vector3f?)
@@ -2316,7 +2465,11 @@ private void CreateConstrainedBillboardFact(Vector3 placeDirection, Vector3 rota
public void Matrix4x4CreateConstrainedBillboardTest01()
{
// Object placed at Forward of camera. result must be same as 180 degrees rotate along y-axis.
- CreateConstrainedBillboardFact(new Vector3(0, 0, -1), new Vector3(0, 1, 0), Matrix4x4.CreateRotationY(MathHelper.ToRadians(180.0f)));
+ CreateConstrainedBillboardFact(
+ new Vector3(0, 0, -1),
+ Vector3.UnitY,
+ Matrix4x4.CreateRotationY(MathHelper.ToRadians(180.0f)),
+ Matrix4x4.CreateRotationY(MathHelper.ToRadians(180.0f)));
}
// A test for CreateConstrainedBillboard (Vector3f, Vector3f, Vector3f, Vector3f?)
@@ -2325,7 +2478,11 @@ public void Matrix4x4CreateConstrainedBillboardTest01()
public void Matrix4x4CreateConstrainedBillboardTest02()
{
// Object placed at Backward of camera. This result must be same as 0 degrees rotate along y-axis.
- CreateConstrainedBillboardFact(new Vector3(0, 0, 1), new Vector3(0, 1, 0), Matrix4x4.CreateRotationY(MathHelper.ToRadians(0)));
+ CreateConstrainedBillboardFact(
+ Vector3.UnitZ,
+ Vector3.UnitY,
+ Matrix4x4.CreateRotationY(MathHelper.ToRadians(0)),
+ Matrix4x4.CreateRotationY(MathHelper.ToRadians(0)));
}
// A test for CreateConstrainedBillboard (Vector3f, Vector3f, Vector3f, Vector3f?)
@@ -2334,7 +2491,11 @@ public void Matrix4x4CreateConstrainedBillboardTest02()
public void Matrix4x4CreateConstrainedBillboardTest03()
{
// Place object at Right side of camera. This result must be same as 90 degrees rotate along y-axis.
- CreateConstrainedBillboardFact(new Vector3(1, 0, 0), new Vector3(0, 1, 0), Matrix4x4.CreateRotationY(MathHelper.ToRadians(90)));
+ CreateConstrainedBillboardFact(
+ Vector3.UnitX,
+ Vector3.UnitY,
+ Matrix4x4.CreateRotationY(MathHelper.ToRadians(90)),
+ Matrix4x4.CreateRotationY(MathHelper.ToRadians(-90)));
}
// A test for CreateConstrainedBillboard (Vector3f, Vector3f, Vector3f, Vector3f?)
@@ -2343,7 +2504,11 @@ public void Matrix4x4CreateConstrainedBillboardTest03()
public void Matrix4x4CreateConstrainedBillboardTest04()
{
// Place object at Left side of camera. This result must be same as -90 degrees rotate along y-axis.
- CreateConstrainedBillboardFact(new Vector3(-1, 0, 0), new Vector3(0, 1, 0), Matrix4x4.CreateRotationY(MathHelper.ToRadians(-90)));
+ CreateConstrainedBillboardFact(
+ new Vector3(-1, 0, 0),
+ Vector3.UnitY,
+ Matrix4x4.CreateRotationY(MathHelper.ToRadians(-90)),
+ Matrix4x4.CreateRotationY(MathHelper.ToRadians(90)));
}
// A test for CreateConstrainedBillboard (Vector3f, Vector3f, Vector3f, Vector3f?)
@@ -2352,8 +2517,11 @@ public void Matrix4x4CreateConstrainedBillboardTest04()
public void Matrix4x4CreateConstrainedBillboardTest05()
{
// Place object at Up side of camera. result must be same as 180 degrees rotate along z-axis after 90 degrees rotate along x-axis.
- CreateConstrainedBillboardFact(new Vector3(0, 1, 0), new Vector3(0, 0, 1),
- Matrix4x4.CreateRotationX(MathHelper.ToRadians(90.0f)) * Matrix4x4.CreateRotationZ(MathHelper.ToRadians(180)));
+ CreateConstrainedBillboardFact(
+ Vector3.UnitY,
+ Vector3.UnitZ,
+ Matrix4x4.CreateRotationX(MathHelper.ToRadians(90.0f)) * Matrix4x4.CreateRotationZ(MathHelper.ToRadians(180)),
+ Matrix4x4.CreateRotationX(MathHelper.ToRadians(-90.0f)) * Matrix4x4.CreateRotationZ(MathHelper.ToRadians(180)));
}
// A test for CreateConstrainedBillboard (Vector3f, Vector3f, Vector3f, Vector3f?)
@@ -2362,8 +2530,11 @@ public void Matrix4x4CreateConstrainedBillboardTest05()
public void Matrix4x4CreateConstrainedBillboardTest06()
{
// Place object at Down side of camera. result must be same as 0 degrees rotate along z-axis after 90 degrees rotate along x-axis.
- CreateConstrainedBillboardFact(new Vector3(0, -1, 0), new Vector3(0, 0, 1),
- Matrix4x4.CreateRotationX(MathHelper.ToRadians(90.0f)) * Matrix4x4.CreateRotationZ(MathHelper.ToRadians(0)));
+ CreateConstrainedBillboardFact(
+ new Vector3(0, -1, 0),
+ Vector3.UnitZ,
+ Matrix4x4.CreateRotationX(MathHelper.ToRadians(90.0f)) * Matrix4x4.CreateRotationZ(MathHelper.ToRadians(0)),
+ Matrix4x4.CreateRotationX(MathHelper.ToRadians(-90.0f)) * Matrix4x4.CreateRotationZ(MathHelper.ToRadians(0)));
}
// A test for CreateConstrainedBillboard (Vector3f, Vector3f, Vector3f, Vector3f?)
@@ -2372,8 +2543,11 @@ public void Matrix4x4CreateConstrainedBillboardTest06()
public void Matrix4x4CreateConstrainedBillboardTest07()
{
// Place object at Right side of camera. result must be same as 90 degrees rotate along z-axis after 90 degrees rotate along x-axis.
- CreateConstrainedBillboardFact(new Vector3(1, 0, 0), new Vector3(0, 0, 1),
- Matrix4x4.CreateRotationX(MathHelper.ToRadians(90.0f)) * Matrix4x4.CreateRotationZ(MathHelper.ToRadians(90.0f)));
+ CreateConstrainedBillboardFact(
+ Vector3.UnitX,
+ Vector3.UnitZ,
+ Matrix4x4.CreateRotationX(MathHelper.ToRadians(90.0f)) * Matrix4x4.CreateRotationZ(MathHelper.ToRadians(90.0f)),
+ Matrix4x4.CreateRotationX(MathHelper.ToRadians(-90.0f)) * Matrix4x4.CreateRotationZ(MathHelper.ToRadians(90.0f)));
}
// A test for CreateConstrainedBillboard (Vector3f, Vector3f, Vector3f, Vector3f?)
@@ -2382,8 +2556,11 @@ public void Matrix4x4CreateConstrainedBillboardTest07()
public void Matrix4x4CreateConstrainedBillboardTest08()
{
// Place object at Left side of camera. result must be same as -90 degrees rotate along z-axis after 90 degrees rotate along x-axis.
- CreateConstrainedBillboardFact(new Vector3(-1, 0, 0), new Vector3(0, 0, 1),
- Matrix4x4.CreateRotationX(MathHelper.ToRadians(90.0f)) * Matrix4x4.CreateRotationZ(MathHelper.ToRadians(-90.0f)));
+ CreateConstrainedBillboardFact(
+ new Vector3(-1, 0, 0),
+ Vector3.UnitZ,
+ Matrix4x4.CreateRotationX(MathHelper.ToRadians(90.0f)) * Matrix4x4.CreateRotationZ(MathHelper.ToRadians(-90.0f)),
+ Matrix4x4.CreateRotationX(MathHelper.ToRadians(-90.0f)) * Matrix4x4.CreateRotationZ(MathHelper.ToRadians(-90.0f)));
}
// A test for CreateConstrainedBillboard (Vector3f, Vector3f, Vector3f, Vector3f?)
@@ -2392,8 +2569,11 @@ public void Matrix4x4CreateConstrainedBillboardTest08()
public void Matrix4x4CreateConstrainedBillboardTest09()
{
// Place object at Up side of camera. result must be same as -90 degrees rotate along x-axis after 90 degrees rotate along z-axis.
- CreateConstrainedBillboardFact(new Vector3(0, 1, 0), new Vector3(-1, 0, 0),
- Matrix4x4.CreateRotationZ(MathHelper.ToRadians(90.0f)) * Matrix4x4.CreateRotationX(MathHelper.ToRadians(-90.0f)));
+ CreateConstrainedBillboardFact(
+ Vector3.UnitY,
+ new Vector3(-1, 0, 0),
+ Matrix4x4.CreateRotationZ(MathHelper.ToRadians(90.0f)) * Matrix4x4.CreateRotationX(MathHelper.ToRadians(-90.0f)),
+ Matrix4x4.CreateRotationZ(MathHelper.ToRadians(90.0f)) * Matrix4x4.CreateRotationX(MathHelper.ToRadians(90.0f)));
}
// A test for CreateConstrainedBillboard (Vector3f, Vector3f, Vector3f, Vector3f?)
@@ -2402,8 +2582,11 @@ public void Matrix4x4CreateConstrainedBillboardTest09()
public void Matrix4x4CreateConstrainedBillboardTest10()
{
// Place object at Down side of camera. result must be same as 90 degrees rotate along x-axis after 90 degrees rotate along z-axis.
- CreateConstrainedBillboardFact(new Vector3(0, -1, 0), new Vector3(-1, 0, 0),
- Matrix4x4.CreateRotationZ(MathHelper.ToRadians(90.0f)) * Matrix4x4.CreateRotationX(MathHelper.ToRadians(90.0f)));
+ CreateConstrainedBillboardFact(
+ new Vector3(0, -1, 0),
+ new Vector3(-1, 0, 0),
+ Matrix4x4.CreateRotationZ(MathHelper.ToRadians(90.0f)) * Matrix4x4.CreateRotationX(MathHelper.ToRadians(90.0f)),
+ Matrix4x4.CreateRotationZ(MathHelper.ToRadians(90.0f)) * Matrix4x4.CreateRotationX(MathHelper.ToRadians(-90.0f)));
}
// A test for CreateConstrainedBillboard (Vector3f, Vector3f, Vector3f, Vector3f?)
@@ -2412,7 +2595,10 @@ public void Matrix4x4CreateConstrainedBillboardTest10()
public void Matrix4x4CreateConstrainedBillboardTest11()
{
// Place object at Forward side of camera. result must be same as 180 degrees rotate along x-axis after 90 degrees rotate along z-axis.
- CreateConstrainedBillboardFact(new Vector3(0, 0, -1), new Vector3(-1, 0, 0),
+ CreateConstrainedBillboardFact(
+ new Vector3(0, 0, -1),
+ new Vector3(-1, 0, 0),
+ Matrix4x4.CreateRotationZ(MathHelper.ToRadians(90.0f)) * Matrix4x4.CreateRotationX(MathHelper.ToRadians(180.0f)),
Matrix4x4.CreateRotationZ(MathHelper.ToRadians(90.0f)) * Matrix4x4.CreateRotationX(MathHelper.ToRadians(180.0f)));
}
@@ -2422,7 +2608,10 @@ public void Matrix4x4CreateConstrainedBillboardTest11()
public void Matrix4x4CreateConstrainedBillboardTest12()
{
// Place object at Backward side of camera. result must be same as 0 degrees rotate along x-axis after 90 degrees rotate along z-axis.
- CreateConstrainedBillboardFact(new Vector3(0, 0, 1), new Vector3(-1, 0, 0),
+ CreateConstrainedBillboardFact(
+ Vector3.UnitZ,
+ new Vector3(-1, 0, 0),
+ Matrix4x4.CreateRotationZ(MathHelper.ToRadians(90.0f)) * Matrix4x4.CreateRotationX(MathHelper.ToRadians(0.0f)),
Matrix4x4.CreateRotationZ(MathHelper.ToRadians(90.0f)) * Matrix4x4.CreateRotationX(MathHelper.ToRadians(0.0f)));
}
@@ -2433,12 +2622,23 @@ public void Matrix4x4CreateConstrainedBillboardTooCloseTest1()
{
Vector3 objectPosition = new Vector3(3.0f, 4.0f, 5.0f);
Vector3 cameraPosition = objectPosition;
- Vector3 cameraUpVector = new Vector3(0, 1, 0);
+ Vector3 cameraUpVector = Vector3.UnitY;
// Doesn't pass camera face direction. CreateConstrainedBillboard uses new Vector3f(0, 0, -1) direction. Result must be same as 180 degrees rotate along y-axis.
Matrix4x4 expected = Matrix4x4.CreateRotationY(MathHelper.ToRadians(180.0f)) * Matrix4x4.CreateTranslation(objectPosition);
- Matrix4x4 actual = Matrix4x4.CreateConstrainedBillboard(objectPosition, cameraPosition, cameraUpVector, new Vector3(0, 0, 1), new Vector3(0, 0, -1));
- Assert.True(MathHelper.Equal(expected, actual), "Matrix4x4.CreateConstrainedBillboard did not return the expected value.");
+ Matrix4x4 actualRH = Matrix4x4.CreateConstrainedBillboard(objectPosition, cameraPosition, cameraUpVector, Vector3.UnitZ, new Vector3(0, 0, -1));
+ Assert.True(MathHelper.Equal(expected, actualRH), $"{nameof(Matrix4x4.CreateConstrainedBillboard)} did not return the expected value.");
+
+ objectPosition = new Vector3(3.0f, 4.0f, -5.0f);
+ cameraPosition = objectPosition;
+ cameraUpVector = Vector3.UnitY;
+
+ expected = Matrix4x4.CreateRotationY(MathHelper.ToRadians(180.0f)) * Matrix4x4.CreateTranslation(objectPosition);
+ Matrix4x4 actualLH = Matrix4x4.CreateConstrainedBillboardLeftHanded(objectPosition, cameraPosition, cameraUpVector, new Vector3(0, 0, -1), Vector3.UnitZ);
+ Assert.True(MathHelper.Equal(expected, actualLH), $"{nameof(Matrix4x4.CreateConstrainedBillboardLeftHanded)} did not return the expected value.");
+
+ AssertEqual(actualRH, InverseHandedness(actualLH), DefaultVarianceMatrix);
+ AssertEqual(InverseHandedness(actualRH), actualLH, DefaultVarianceMatrix);
}
// A test for CreateConstrainedBillboard (Vector3f, Vector3f, Vector3f, Vector3f?)
@@ -2448,28 +2648,60 @@ public void Matrix4x4CreateConstrainedBillboardTooCloseTest2()
{
Vector3 objectPosition = new Vector3(3.0f, 4.0f, 5.0f);
Vector3 cameraPosition = objectPosition;
- Vector3 cameraUpVector = new Vector3(0, 1, 0);
+ Vector3 cameraUpVector = Vector3.UnitY;
// Passes Vector3f.Right as camera face direction. Result must be same as -90 degrees rotate along y-axis.
Matrix4x4 expected = Matrix4x4.CreateRotationY(MathHelper.ToRadians(-90.0f)) * Matrix4x4.CreateTranslation(objectPosition);
- Matrix4x4 actual = Matrix4x4.CreateConstrainedBillboard(objectPosition, cameraPosition, cameraUpVector, new Vector3(1, 0, 0), new Vector3(0, 0, -1));
- Assert.True(MathHelper.Equal(expected, actual), "Matrix4x4.CreateConstrainedBillboard did not return the expected value.");
+ Matrix4x4 actualRH = Matrix4x4.CreateConstrainedBillboard(objectPosition, cameraPosition, cameraUpVector, Vector3.UnitX, new Vector3(0, 0, -1));
+ Assert.True(MathHelper.Equal(expected, actualRH), $"{nameof(Matrix4x4.CreateConstrainedBillboard)} did not return the expected value.");
+
+ objectPosition = new Vector3(3.0f, 4.0f, -5.0f);
+ cameraPosition = objectPosition;
+ cameraUpVector = Vector3.UnitY;
+
+ expected = Matrix4x4.CreateRotationY(MathHelper.ToRadians(90.0f)) * Matrix4x4.CreateTranslation(objectPosition);
+ Matrix4x4 actualLH = Matrix4x4.CreateConstrainedBillboardLeftHanded(objectPosition, cameraPosition, cameraUpVector, Vector3.UnitX, Vector3.UnitZ);
+ Assert.True(MathHelper.Equal(expected, actualLH), $"{nameof(Matrix4x4.CreateConstrainedBillboardLeftHanded)} did not return the expected value.");
+
+ AssertEqual(actualRH, InverseHandedness(actualLH), DefaultVarianceMatrix);
+ AssertEqual(InverseHandedness(actualRH), actualLH, DefaultVarianceMatrix);
}
- // A test for CreateConstrainedBillboard (Vector3f, Vector3f, Vector3f, Vector3f?)
- // Angle between rotateAxis and camera to object vector is too small. And use doesn't passed objectForwardVector parameter.
- [Fact]
- public void Matrix4x4CreateConstrainedBillboardAlongAxisTest1()
+ private static void Matrix4x4CreateConstrainedBillboardAlongAxisFact(Vector3 rotateAxis, Vector3 cameraForward, Vector3 objectForward, Matrix4x4 expectedRotationRightHanded, Matrix4x4 expectedRotationLeftHanded)
{
// Place camera at up side of object.
Vector3 objectPosition = new Vector3(3.0f, 4.0f, 5.0f);
- Vector3 rotateAxis = new Vector3(0, 1, 0);
Vector3 cameraPosition = objectPosition + rotateAxis * 10.0f;
+ Matrix4x4 expected = expectedRotationRightHanded * Matrix4x4.CreateTranslation(objectPosition);
+ Matrix4x4 actualLH = Matrix4x4.CreateConstrainedBillboard(objectPosition, cameraPosition, rotateAxis, cameraForward, objectForward);
+ Assert.True(MathHelper.Equal(expected, actualLH), $"{nameof(Matrix4x4.CreateConstrainedBillboard)} did not return the expected value.");
+
+ rotateAxis = InverseHandedness(rotateAxis);
+ cameraForward = InverseHandedness(cameraForward);
+ objectForward = InverseHandedness(objectForward);
+
+ objectPosition = new Vector3(3.0f, 4.0f, -5.0f);
+ cameraPosition = objectPosition + rotateAxis * 10.0f;
+
+ expected = expectedRotationLeftHanded * Matrix4x4.CreateTranslation(objectPosition);
+ Matrix4x4 actualRH = Matrix4x4.CreateConstrainedBillboardLeftHanded(objectPosition, cameraPosition, rotateAxis, cameraForward, objectForward);
+ Assert.True(MathHelper.Equal(expected, actualRH), $"{nameof(Matrix4x4.CreateConstrainedBillboardLeftHanded)} did not return the expected value.");
+
+ AssertEqual(actualRH, InverseHandedness(actualLH), DefaultVarianceMatrix);
+ AssertEqual(InverseHandedness(actualRH), actualLH, DefaultVarianceMatrix);
+ }
+
+ // A test for CreateConstrainedBillboard (Vector3f, Vector3f, Vector3f, Vector3f?)
+ // Angle between rotateAxis and camera to object vector is too small. And use doesn't passed objectForwardVector parameter.
+ [Fact]
+ public void Matrix4x4CreateConstrainedBillboardAlongAxisTest1()
+ {
// In this case, CreateConstrainedBillboard picks new Vector3f(0, 0, -1) as object forward vector.
- Matrix4x4 expected = Matrix4x4.CreateRotationY(MathHelper.ToRadians(180.0f)) * Matrix4x4.CreateTranslation(objectPosition);
- Matrix4x4 actual = Matrix4x4.CreateConstrainedBillboard(objectPosition, cameraPosition, rotateAxis, new Vector3(0, 0, -1), new Vector3(0, 0, -1));
- Assert.True(MathHelper.Equal(expected, actual), "Matrix4x4.CreateConstrainedBillboard did not return the expected value.");
+ Matrix4x4CreateConstrainedBillboardAlongAxisFact(
+ Vector3.UnitY, new Vector3(0, 0, -1), new Vector3(0, 0, -1),
+ Matrix4x4.CreateRotationY(MathHelper.ToRadians(180.0f)),
+ Matrix4x4.CreateRotationY(MathHelper.ToRadians(180.0f)));
}
// A test for CreateConstrainedBillboard (Vector3f, Vector3f, Vector3f, Vector3f?)
@@ -2477,15 +2709,11 @@ public void Matrix4x4CreateConstrainedBillboardAlongAxisTest1()
[Fact]
public void Matrix4x4CreateConstrainedBillboardAlongAxisTest2()
{
- // Place camera at up side of object.
- Vector3 objectPosition = new Vector3(3.0f, 4.0f, 5.0f);
- Vector3 rotateAxis = new Vector3(0, 0, -1);
- Vector3 cameraPosition = objectPosition + rotateAxis * 10.0f;
-
// In this case, CreateConstrainedBillboard picks new Vector3f(1, 0, 0) as object forward vector.
- Matrix4x4 expected = Matrix4x4.CreateRotationX(MathHelper.ToRadians(-90.0f)) * Matrix4x4.CreateRotationZ(MathHelper.ToRadians(-90.0f)) * Matrix4x4.CreateTranslation(objectPosition);
- Matrix4x4 actual = Matrix4x4.CreateConstrainedBillboard(objectPosition, cameraPosition, rotateAxis, new Vector3(0, 0, -1), new Vector3(0, 0, -1));
- Assert.True(MathHelper.Equal(expected, actual), "Matrix4x4.CreateConstrainedBillboard did not return the expected value.");
+ Matrix4x4CreateConstrainedBillboardAlongAxisFact(
+ new Vector3(0, 0, -1), new Vector3(0, 0, -1), new Vector3(0, 0, -1),
+ Matrix4x4.CreateRotationX(MathHelper.ToRadians(-90.0f)) * Matrix4x4.CreateRotationZ(MathHelper.ToRadians(-90.0f)),
+ Matrix4x4.CreateRotationX(MathHelper.ToRadians(90.0f)) * Matrix4x4.CreateRotationZ(MathHelper.ToRadians(-90.0f)));
}
// A test for CreateConstrainedBillboard (Vector3f, Vector3f, Vector3f, Vector3f?)
@@ -2493,15 +2721,11 @@ public void Matrix4x4CreateConstrainedBillboardAlongAxisTest2()
[Fact]
public void Matrix4x4CreateConstrainedBillboardAlongAxisTest3()
{
- // Place camera at up side of object.
- Vector3 objectPosition = new Vector3(3.0f, 4.0f, 5.0f);
- Vector3 rotateAxis = new Vector3(0, 1, 0);
- Vector3 cameraPosition = objectPosition + rotateAxis * 10.0f;
-
// User passes correct objectForwardVector.
- Matrix4x4 expected = Matrix4x4.CreateRotationY(MathHelper.ToRadians(180.0f)) * Matrix4x4.CreateTranslation(objectPosition);
- Matrix4x4 actual = Matrix4x4.CreateConstrainedBillboard(objectPosition, cameraPosition, rotateAxis, new Vector3(0, 0, -1), new Vector3(0, 0, -1));
- Assert.True(MathHelper.Equal(expected, actual), "Matrix4x4.CreateConstrainedBillboard did not return the expected value.");
+ Matrix4x4CreateConstrainedBillboardAlongAxisFact(
+ Vector3.UnitY, new Vector3(0, 0, -1), new Vector3(0, 0, -1),
+ Matrix4x4.CreateRotationY(MathHelper.ToRadians(180.0f)),
+ Matrix4x4.CreateRotationY(MathHelper.ToRadians(180.0f)));
}
// A test for CreateConstrainedBillboard (Vector3f, Vector3f, Vector3f, Vector3f?)
@@ -2509,15 +2733,11 @@ public void Matrix4x4CreateConstrainedBillboardAlongAxisTest3()
[Fact]
public void Matrix4x4CreateConstrainedBillboardAlongAxisTest4()
{
- // Place camera at up side of object.
- Vector3 objectPosition = new Vector3(3.0f, 4.0f, 5.0f);
- Vector3 rotateAxis = new Vector3(0, 1, 0);
- Vector3 cameraPosition = objectPosition + rotateAxis * 10.0f;
-
// User passes correct objectForwardVector.
- Matrix4x4 expected = Matrix4x4.CreateRotationY(MathHelper.ToRadians(180.0f)) * Matrix4x4.CreateTranslation(objectPosition);
- Matrix4x4 actual = Matrix4x4.CreateConstrainedBillboard(objectPosition, cameraPosition, rotateAxis, new Vector3(0, 0, -1), new Vector3(0, 1, 0));
- Assert.True(MathHelper.Equal(expected, actual), "Matrix4x4.CreateConstrainedBillboard did not return the expected value.");
+ Matrix4x4CreateConstrainedBillboardAlongAxisFact(
+ Vector3.UnitY, new Vector3(0, 0, -1), Vector3.UnitY,
+ Matrix4x4.CreateRotationY(MathHelper.ToRadians(180.0f)),
+ Matrix4x4.CreateRotationY(MathHelper.ToRadians(180.0f)));
}
// A test for CreateConstrainedBillboard (Vector3f, Vector3f, Vector3f, Vector3f?)
@@ -2525,15 +2745,11 @@ public void Matrix4x4CreateConstrainedBillboardAlongAxisTest4()
[Fact]
public void Matrix4x4CreateConstrainedBillboardAlongAxisTest5()
{
- // Place camera at up side of object.
- Vector3 objectPosition = new Vector3(3.0f, 4.0f, 5.0f);
- Vector3 rotateAxis = new Vector3(0, 0, -1);
- Vector3 cameraPosition = objectPosition + rotateAxis * 10.0f;
-
// In this case, CreateConstrainedBillboard picks Vector3f.Right as object forward vector.
- Matrix4x4 expected = Matrix4x4.CreateRotationX(MathHelper.ToRadians(-90.0f)) * Matrix4x4.CreateRotationZ(MathHelper.ToRadians(-90.0f)) * Matrix4x4.CreateTranslation(objectPosition);
- Matrix4x4 actual = Matrix4x4.CreateConstrainedBillboard(objectPosition, cameraPosition, rotateAxis, new Vector3(0, 0, -1), new Vector3(0, 0, -1));
- Assert.True(MathHelper.Equal(expected, actual), "Matrix4x4.CreateConstrainedBillboard did not return the expected value.");
+ Matrix4x4CreateConstrainedBillboardAlongAxisFact(
+ new Vector3(0, 0, -1), new Vector3(0, 0, -1), new Vector3(0, 0, -1),
+ Matrix4x4.CreateRotationX(MathHelper.ToRadians(-90.0f)) * Matrix4x4.CreateRotationZ(MathHelper.ToRadians(-90.0f)),
+ Matrix4x4.CreateRotationX(MathHelper.ToRadians(90.0f)) * Matrix4x4.CreateRotationZ(MathHelper.ToRadians(-90.0f)));
}
// A test for CreateScale (Vector3f)
diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
index 61d304184b2865..064e2579bdca3c 100644
--- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
+++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
@@ -2608,6 +2608,7 @@
+
@@ -2640,6 +2641,7 @@
+
diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Stopwatch.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Stopwatch.cs
index 33f5998a96248c..c73d407b1c7f5c 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Stopwatch.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Stopwatch.cs
@@ -3,10 +3,6 @@
namespace System.Diagnostics
{
- // This class uses high-resolution performance counter if the installed
- // hardware supports it. Otherwise, the class will fall back to DateTime
- // and uses ticks as a measurement.
-
[DebuggerDisplay("{DebuggerDisplay,nq}")]
public partial class Stopwatch
{
@@ -14,21 +10,15 @@ public partial class Stopwatch
private long _startTimeStamp;
private bool _isRunning;
- // "Frequency" stores the frequency of the high-resolution performance counter,
- // if one exists. Otherwise it will store TicksPerSecond.
- // The frequency cannot change while the system is running,
- // so we only need to initialize it once.
public static readonly long Frequency = QueryPerformanceFrequency();
public static readonly bool IsHighResolution = true;
// performance-counter frequency, in counts per ticks.
- // This can speed up conversion from high frequency performance-counter
- // to ticks.
+ // This can speed up conversion to ticks.
private static readonly double s_tickFrequency = (double)TimeSpan.TicksPerSecond / Frequency;
public Stopwatch()
{
- Reset();
}
public void Start()
@@ -43,7 +33,7 @@ public void Start()
public static Stopwatch StartNew()
{
- Stopwatch s = new Stopwatch();
+ Stopwatch s = new();
s.Start();
return s;
}
@@ -53,29 +43,16 @@ public void Stop()
// Calling stop on a stopped Stopwatch is a no-op.
if (_isRunning)
{
- long endTimeStamp = GetTimestamp();
- long elapsedThisPeriod = endTimeStamp - _startTimeStamp;
- _elapsed += elapsedThisPeriod;
+ _elapsed += GetTimestamp() - _startTimeStamp;
_isRunning = false;
-
- if (_elapsed < 0)
- {
- // When measuring small time periods the Stopwatch.Elapsed*
- // properties can return negative values. This is due to
- // bugs in the basic input/output system (BIOS) or the hardware
- // abstraction layer (HAL) on machines with variable-speed CPUs
- // (e.g. Intel SpeedStep).
-
- _elapsed = 0;
- }
}
}
public void Reset()
{
_elapsed = 0;
- _isRunning = false;
_startTimeStamp = 0;
+ _isRunning = false;
}
// Convenience method for replacing {sw.Reset(); sw.Start();} with a single sw.Restart()
@@ -94,32 +71,30 @@ public void Restart()
///
public override string ToString() => Elapsed.ToString();
- public bool IsRunning
- {
- get { return _isRunning; }
- }
+ public bool IsRunning => _isRunning;
- public TimeSpan Elapsed
- {
- get { return new TimeSpan(GetElapsedDateTimeTicks()); }
- }
+ public TimeSpan Elapsed => new(ElapsedTimeSpanTicks);
- public long ElapsedMilliseconds
- {
- get { return GetElapsedDateTimeTicks() / TimeSpan.TicksPerMillisecond; }
- }
+ public long ElapsedMilliseconds => ElapsedTimeSpanTicks / TimeSpan.TicksPerMillisecond;
public long ElapsedTicks
{
- get { return GetRawElapsedTicks(); }
- }
+ get
+ {
+ long timeElapsed = _elapsed;
- public static long GetTimestamp()
- {
- Debug.Assert(IsHighResolution);
- return QueryPerformanceCounter();
+ // If the Stopwatch is running, add elapsed time since the Stopwatch is started last time.
+ if (_isRunning)
+ {
+ timeElapsed += GetTimestamp() - _startTimeStamp;
+ }
+
+ return timeElapsed;
+ }
}
+ public static long GetTimestamp() => QueryPerformanceCounter();
+
/// Gets the elapsed time since the value retrieved using .
/// The timestamp marking the beginning of the time period.
/// A for the elapsed time between the starting timestamp and the time of this call.
@@ -131,31 +106,9 @@ public static TimeSpan GetElapsedTime(long startingTimestamp) =>
/// The timestamp marking the end of the time period.
/// A for the elapsed time between the starting and ending timestamps.
public static TimeSpan GetElapsedTime(long startingTimestamp, long endingTimestamp) =>
- new TimeSpan((long)((endingTimestamp - startingTimestamp) * s_tickFrequency));
-
- // Get the elapsed ticks.
- private long GetRawElapsedTicks()
- {
- long timeElapsed = _elapsed;
+ new((long)((endingTimestamp - startingTimestamp) * s_tickFrequency));
- if (_isRunning)
- {
- // If the Stopwatch is running, add elapsed time since
- // the Stopwatch is started last time.
- long currentTimeStamp = GetTimestamp();
- long elapsedUntilNow = currentTimeStamp - _startTimeStamp;
- timeElapsed += elapsedUntilNow;
- }
- return timeElapsed;
- }
-
- // Get the elapsed ticks.
- private long GetElapsedDateTimeTicks()
- {
- Debug.Assert(IsHighResolution);
- // convert high resolution perf counter to DateTime ticks
- return unchecked((long)(GetRawElapsedTicks() * s_tickFrequency));
- }
+ private long ElapsedTimeSpanTicks => (long)(ElapsedTicks * s_tickFrequency);
private string DebuggerDisplay => $"{Elapsed} (IsRunning = {_isRunning})";
}
diff --git a/src/libraries/System.Private.CoreLib/src/System/Marvin.cs b/src/libraries/System.Private.CoreLib/src/System/Marvin.cs
index 098ebb5260dc9d..31c1b696a68017 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Marvin.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Marvin.cs
@@ -6,6 +6,12 @@
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
+#if SYSTEM_PRIVATE_CORELIB
+using static System.Numerics.BitOperations;
+#else
+using System.Security.Cryptography;
+#endif
+
namespace System
{
internal static partial class Marvin
@@ -204,7 +210,7 @@ public static int ComputeHash32(ref byte data, uint count, uint p0, uint p1)
else
{
partialResult |= (uint)Unsafe.ReadUnaligned(ref data);
- partialResult = BitOperations.RotateLeft(partialResult, 16);
+ partialResult = RotateLeft(partialResult, 16);
}
}
@@ -221,16 +227,16 @@ private static void Block(ref uint rp0, ref uint rp1)
uint p1 = rp1;
p1 ^= p0;
- p0 = BitOperations.RotateLeft(p0, 20);
+ p0 = RotateLeft(p0, 20);
p0 += p1;
- p1 = BitOperations.RotateLeft(p1, 9);
+ p1 = RotateLeft(p1, 9);
p1 ^= p0;
- p0 = BitOperations.RotateLeft(p0, 27);
+ p0 = RotateLeft(p0, 27);
p0 += p1;
- p1 = BitOperations.RotateLeft(p1, 19);
+ p1 = RotateLeft(p1, 19);
rp0 = p0;
rp1 = p1;
@@ -241,8 +247,29 @@ private static void Block(ref uint rp0, ref uint rp1)
private static unsafe ulong GenerateSeed()
{
ulong seed;
+#if SYSTEM_PRIVATE_CORELIB
Interop.GetRandomBytes((byte*)&seed, sizeof(ulong));
+#else
+ byte[] seedBytes = new byte[sizeof(ulong)];
+ using (RandomNumberGenerator rng = RandomNumberGenerator.Create())
+ {
+ rng.GetBytes(seedBytes);
+ fixed (byte* b = seedBytes)
+ {
+ seed = *(ulong*)b;
+ }
+ }
+#endif
return seed;
}
+
+#if !SYSTEM_PRIVATE_CORELIB
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static uint RotateLeft(uint value, int shift)
+ {
+ // This is expected to be optimized into a single rol (or ror with negated shift value) instruction
+ return (value << shift) | (value >> (32 - shift));
+ }
+#endif
}
}
diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Matrix4x4.Impl.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Matrix4x4.Impl.cs
index 889311ca073028..5ca3cfeb40cc6b 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Matrix4x4.Impl.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Matrix4x4.Impl.cs
@@ -214,8 +214,12 @@ public Vector3 Translation
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Impl CreateBillboard(in Vector3 objectPosition, in Vector3 cameraPosition, in Vector3 cameraUpVector, in Vector3 cameraForwardVector)
{
+ // In a right-handed coordinate system, the object's positive z-axis is in the opposite direction as its forward vector,
+ // and spherical billboards by construction always face the camera.
Vector3 axisZ = objectPosition - cameraPosition;
+ // When object and camera position are approximately the same, the object should just face the
+ // same direction as the camera is facing.
if (axisZ.LengthSquared() < BillboardEpsilon)
{
axisZ = -cameraForwardVector;
@@ -232,7 +236,38 @@ public static Impl CreateBillboard(in Vector3 objectPosition, in Vector3 cameraP
result.X = axisX.AsVector4();
result.Y = axisY.AsVector4();
- result.Z = axisZ.AsVector4();;
+ result.Z = axisZ.AsVector4();
+ result.W = Vector4.Create(objectPosition, 1);
+
+ return result;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Impl CreateBillboardLeftHanded(in Vector3 objectPosition, in Vector3 cameraPosition, in Vector3 cameraUpVector, in Vector3 cameraForwardVector)
+ {
+ // In a left-handed coordinate system, the object's positive z-axis is in the same direction as its forward vector,
+ // and spherical billboards by construction always face the camera.
+ Vector3 axisZ = cameraPosition - objectPosition;
+
+ // When object and camera position are approximately the same, the object should just face the
+ // same direction as the camera is facing.
+ if (axisZ.LengthSquared() < BillboardEpsilon)
+ {
+ axisZ = cameraForwardVector;
+ }
+ else
+ {
+ axisZ = Vector3.Normalize(axisZ);
+ }
+
+ Vector3 axisX = Vector3.Normalize(Vector3.Cross(cameraUpVector, axisZ));
+ Vector3 axisY = Vector3.Cross(axisZ, axisX);
+
+ Impl result;
+
+ result.X = axisX.AsVector4();
+ result.Y = axisY.AsVector4();
+ result.Z = axisZ.AsVector4();
result.W = Vector4.Create(objectPosition, 1);
return result;
@@ -241,9 +276,12 @@ public static Impl CreateBillboard(in Vector3 objectPosition, in Vector3 cameraP
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Impl CreateConstrainedBillboard(in Vector3 objectPosition, in Vector3 cameraPosition, in Vector3 rotateAxis, in Vector3 cameraForwardVector, in Vector3 objectForwardVector)
{
- // Treat the case when object and camera positions are too close.
+ // First find the Z-axis of the spherical/unconstrained rotation. We call this faceDir and in a right-handed coordinate system
+ // it will be in the opposite direction as from the object to the camera.
Vector3 faceDir = objectPosition - cameraPosition;
+ // When object and camera position are approximately the same this indicates that the object should also just face the
+ // same direction as the camera is facing.
if (faceDir.LengthSquared() < BillboardEpsilon)
{
faceDir = -cameraForwardVector;
@@ -255,18 +293,30 @@ public static Impl CreateConstrainedBillboard(in Vector3 objectPosition, in Vect
Vector3 axisY = rotateAxis;
- // Treat the case when angle between faceDir and rotateAxis is too close to 0.
float dot = Vector3.Dot(axisY, faceDir);
+ // Generally the approximation for small angles is cos theta = 1 - theta^2 / 2,
+ // but it seems that here we are using cos theta = 1 - theta. Letting theta be the angle
+ // between the rotate axis and the faceDir,
+ //
+ // dot = cos theta ~ 1 - theta > 1 - .1 * pi/180 = 1 - (.1 degree) => theta < .1 degree
+ //
+ // So this condition checks if the faceDir is approximately the same as the rotate axis
+ // by checking if the angle between them is less than .1 degree.
if (float.Abs(dot) > BillboardMinAngle)
{
+ // If the faceDir is approximately the same as the rotate axis, then fallback to using object forward vector
+ // as the faceDir.
faceDir = objectForwardVector;
- // Make sure passed values are useful for compute.
dot = Vector3.Dot(axisY, faceDir);
+ // Similar to before, check if the faceDir is still is approximately the rotate axis.
+ // If so, then use either -UnitZ or UnitX as the fallback faceDir.
if (float.Abs(dot) > BillboardMinAngle)
{
+ // |axisY.Z| = |dot(axisY, -UnitZ)|, so this is checking if the rotate axis is approximately the same as -UnitZ.
+ // If is, then use UnitX as the fallback.
faceDir = (float.Abs(axisY.Z) > BillboardMinAngle) ? Vector3.UnitX : Vector3.Create(0, 0, -1);
}
}
@@ -284,6 +334,66 @@ public static Impl CreateConstrainedBillboard(in Vector3 objectPosition, in Vect
return result;
}
+ public static Impl CreateConstrainedBillboardLeftHanded(in Vector3 objectPosition, in Vector3 cameraPosition, in Vector3 rotateAxis, in Vector3 cameraForwardVector, in Vector3 objectForwardVector)
+ {
+ // First find the Z-axis of the spherical/unconstrained rotation. We call this faceDir and in a left-handed coordinate system
+ // it will be in the same direction as from the object to the camera.
+ Vector3 faceDir = cameraPosition - objectPosition;
+
+ // When object and camera position are approximately the same this indicates that the object should also just face the
+ // same direction as the camera is facing.
+ if (faceDir.LengthSquared() < BillboardEpsilon)
+ {
+ faceDir = cameraForwardVector;
+ }
+ else
+ {
+ faceDir = Vector3.Normalize(faceDir);
+ }
+
+ Vector3 axisY = rotateAxis;
+
+ float dot = Vector3.Dot(axisY, faceDir);
+
+ // Generally the approximation for small angles is cos theta = 1 - theta^2 / 2,
+ // but it seems that here we are using cos theta = 1 - theta. Letting theta be the angle
+ // between the rotate axis and the faceDir,
+ //
+ // dot = cos theta ~ 1 - theta > 1 - .1 * pi/180 = 1 - (.1 degree) => theta < .1 degree
+ //
+ // So this condition checks if the faceDir is approximately the same as the rotate axis
+ // by checking if the angle between them is less than .1 degree.
+ if (float.Abs(dot) > BillboardMinAngle)
+ {
+ // If the faceDir is approximately the same as the rotate axis, then fallback to using object forward vector
+ // as the faceDir.
+ faceDir = -objectForwardVector;
+
+ dot = Vector3.Dot(axisY, faceDir);
+
+ // Similar to before, check if the faceDir is still is approximately the rotate axis.
+ // If so, then use either -UnitZ or -UnitX as the fallback faceDir.
+ if (float.Abs(dot) > BillboardMinAngle)
+ {
+ // |axisY.Z| = |dot(axisY, -UnitZ)|, so this is checking if the rotate axis is approximately the same as -UnitZ.
+ // If is, then use -UnitX as the fallback.
+ faceDir = (float.Abs(axisY.Z) > BillboardMinAngle) ? Vector3.Create(-1, 0, 0) : Vector3.Create(0, 0, -1);
+ }
+ }
+
+ Vector3 axisX = Vector3.Normalize(Vector3.Cross(axisY, faceDir));
+ Vector3 axisZ = Vector3.Normalize(Vector3.Cross(axisX, axisY));
+
+ Impl result;
+
+ result.X = axisX.AsVector4();
+ result.Y = axisY.AsVector4();
+ result.Z = axisZ.AsVector4();
+ result.W = Vector4.Create(objectPosition, 1);
+
+ return result;
+ }
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Impl CreateFromAxisAngle(in Vector3 axis, float angle)
{
diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Matrix4x4.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Matrix4x4.cs
index 22774a5b3a10cc..7e92e304ef9c2b 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Matrix4x4.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Matrix4x4.cs
@@ -224,7 +224,7 @@ public Vector3 Translation
public static Matrix4x4 Add(Matrix4x4 value1, Matrix4x4 value2)
=> (value1.AsImpl() + value2.AsImpl()).AsM4x4();
- /// Creates a spherical billboard that rotates around a specified object position.
+ /// Creates a right-handed spherical billboard matrix that rotates around a specified object position.
/// The position of the object that the billboard will rotate around.
/// The position of the camera.
/// The up vector of the camera.
@@ -233,7 +233,16 @@ public static Matrix4x4 Add(Matrix4x4 value1, Matrix4x4 value2)
public static Matrix4x4 CreateBillboard(Vector3 objectPosition, Vector3 cameraPosition, Vector3 cameraUpVector, Vector3 cameraForwardVector)
=> Impl.CreateBillboard(in objectPosition, in cameraPosition, in cameraUpVector, in cameraForwardVector).AsM4x4();
- /// Creates a cylindrical billboard that rotates around a specified axis.
+ /// Creates a left-handed spherical billboard matrix that rotates around a specified object position.
+ /// The position of the object that the billboard will rotate around.
+ /// The position of the camera.
+ /// The up vector of the camera.
+ /// The forward vector of the camera.
+ /// The created billboard.
+ public static Matrix4x4 CreateBillboardLeftHanded(Vector3 objectPosition, Vector3 cameraPosition, Vector3 cameraUpVector, Vector3 cameraForwardVector)
+ => Impl.CreateBillboardLeftHanded(in objectPosition, in cameraPosition, in cameraUpVector, in cameraForwardVector).AsM4x4();
+
+ /// Creates a right-handed cylindrical billboard matrix that rotates around a specified axis.
/// The position of the object that the billboard will rotate around.
/// The position of the camera.
/// The axis to rotate the billboard around.
@@ -243,6 +252,16 @@ public static Matrix4x4 CreateBillboard(Vector3 objectPosition, Vector3 cameraPo
public static Matrix4x4 CreateConstrainedBillboard(Vector3 objectPosition, Vector3 cameraPosition, Vector3 rotateAxis, Vector3 cameraForwardVector, Vector3 objectForwardVector)
=> Impl.CreateConstrainedBillboard(in objectPosition, in cameraPosition, in rotateAxis, in cameraForwardVector, in objectForwardVector).AsM4x4();
+ /// Creates a left-handed cylindrical billboard matrix that rotates around a specified axis.
+ /// The position of the object that the billboard will rotate around.
+ /// The position of the camera.
+ /// The axis to rotate the billboard around.
+ /// The forward vector of the camera.
+ /// The forward vector of the object.
+ /// The billboard matrix.
+ public static Matrix4x4 CreateConstrainedBillboardLeftHanded(Vector3 objectPosition, Vector3 cameraPosition, Vector3 rotateAxis, Vector3 cameraForwardVector, Vector3 objectForwardVector)
+ => Impl.CreateConstrainedBillboardLeftHanded(in objectPosition, in cameraPosition, in rotateAxis, in cameraForwardVector, in objectForwardVector).AsM4x4();
+
/// Creates a matrix that rotates around an arbitrary vector.
/// The axis to rotate around.
/// The angle to rotate around , in radians.
diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/Avx10v2.PlatformNotSupported.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/Avx10v2.PlatformNotSupported.cs
new file mode 100644
index 00000000000000..bea42e51167f55
--- /dev/null
+++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/Avx10v2.PlatformNotSupported.cs
@@ -0,0 +1,327 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.CompilerServices;
+using System.Runtime.Intrinsics;
+
+namespace System.Runtime.Intrinsics.X86
+{
+ /// Provides access to X86 Avx10.2 hardware instructions via intrinsics.
+ [CLSCompliant(false)]
+ public abstract class Avx10v2 : Avx10v1
+ {
+ internal Avx10v2() { }
+
+ /// Gets a value that indicates whether the APIs in this class are supported.
+ /// if the APIs are supported; otherwise, .
+ /// A value of indicates that the APIs will throw .
+ public static new bool IsSupported { [Intrinsic] get { return false; } }
+
+ ///
+ /// VMINMAXPD xmm1{k1}{z}, xmm2, xmm3/m128/m64bcst, imm8
+ ///
+ public static Vector128 MinMax(Vector128 left, Vector128 right, [ConstantExpected] byte control) { throw new PlatformNotSupportedException(); }
+
+ ///
+ /// VMINMAXPD ymm1{k1}{z}, ymm2, ymm3/m256/m64bcst {sae}, imm8
+ ///
+ public static Vector256 MinMax(Vector256 left, Vector256 right, [ConstantExpected] byte control) { throw new PlatformNotSupportedException(); }
+
+ ///
+ /// VMINMAXPS xmm1{k1}{z}, xmm2, xmm3/m128/m32bcst, imm8
+ ///
+ public static Vector128 MinMax(Vector128 left, Vector128 right, [ConstantExpected] byte control) { throw new PlatformNotSupportedException(); }
+
+ ///
+ /// VMINMAXPS ymm1{k1}{z}, ymm2, ymm3/m256/m32bcst {sae}, imm8
+ ///
+ public static Vector256 MinMax(Vector256 left, Vector256 right, [ConstantExpected] byte control) { throw new PlatformNotSupportedException(); }
+
+ ///
+ /// VMINMAXSD xmm1{k1}{z}, xmm2, xmm3/m64 {sae}, imm8
+ ///
+ public static Vector128 MinMaxScalar(Vector128 left, Vector128 right, [ConstantExpected] byte control) { throw new PlatformNotSupportedException(); }
+
+ ///
+ /// VMINMAXSS xmm1{k1}{z}, xmm2, xmm3/m32 {sae}, imm8
+ ///
+ public static Vector128 MinMaxScalar(Vector128 left, Vector128 right, [ConstantExpected] byte control) { throw new PlatformNotSupportedException(); }
+
+ ///
+ /// VADDPD ymm1{k1}{z}, ymm2, ymm3/m256/m64bcst {er}
+ ///
+ public static Vector256 Add(Vector256 left, Vector256 right, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) { throw new PlatformNotSupportedException(); }
+
+ ///
+ /// VADDPS ymm1{k1}{z}, ymm2, ymm3/m256/m32bcst {er}
+ ///
+ public static Vector256 Add(Vector256 left, Vector256 right, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) { throw new PlatformNotSupportedException(); }
+
+ ///
+ /// VDIVPD ymm1{k1}{z}, ymm2, ymm3/m256/m64bcst {er}
+ ///
+ public static Vector256 Divide(Vector256 left, Vector256 right, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) { throw new PlatformNotSupportedException(); }
+
+ ///
+ /// VDIVPS ymm1{k1}{z}, ymm2, ymm3/m256/m32bcst {er}
+ ///
+ public static Vector256 Divide(Vector256 left, Vector256 right, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) { throw new PlatformNotSupportedException(); }
+
+ ///
+ /// VCVTPS2IBS xmm1{k1}{z}, xmm2/m128/m32bcst
+ ///
+ public static Vector128 ConvertToSByteWithSaturationAndZeroExtendToInt32(Vector128 value) { throw new PlatformNotSupportedException(); }
+
+ ///
+ /// VCVTPS2IBS ymm1{k1}{z}, ymm2/m256/m32bcst {er}
+ ///
+ public static Vector256 ConvertToSByteWithSaturationAndZeroExtendToInt32(Vector256 value) { throw new PlatformNotSupportedException(); }
+
+ ///
+ /// VCVTPS2IBS ymm1{k1}{z}, ymm2/m256/m32bcst {er}
+ ///
+ public static Vector256 ConvertToSByteWithSaturationAndZeroExtendToInt32(Vector256 value, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) { throw new PlatformNotSupportedException(); }
+
+ ///
+ /// VCVTPS2IUBS xmm1{k1}{z}, xmm2/m128/m32bcst
+ ///
+ public static Vector128 ConvertToByteWithSaturationAndZeroExtendToInt32(Vector128 value) { throw new PlatformNotSupportedException(); }
+
+ ///
+ /// VCVTPS2IUBS ymm1{k1}{z}, ymm2/m256/m32bcst {er}
+ ///
+ public static Vector256 ConvertToByteWithSaturationAndZeroExtendToInt32(Vector256 value) { throw new PlatformNotSupportedException(); }
+
+ ///
+ /// VCVTPS2IUBS ymm1{k1}{z}, ymm2/m256/m32bcst {er}
+ ///
+ public static Vector256 ConvertToByteWithSaturationAndZeroExtendToInt32(Vector256 value, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) { throw new PlatformNotSupportedException(); }
+
+ ///
+ /// VCVTTPS2IBS xmm1{k1}{z}, xmm2/m128/m32bcst
+ ///
+ public static Vector128 ConvertToSByteWithTruncatedSaturationAndZeroExtendToInt32(Vector128 value) { throw new PlatformNotSupportedException(); }
+
+ ///
+ /// VCVTTPS2IBS ymm1{k1}{z}, ymm2/m256/m32bcst {sae}
+ ///
+ public static Vector256 ConvertToSByteWithTruncatedSaturationAndZeroExtendToInt32(Vector256 value) { throw new PlatformNotSupportedException(); }
+
+ ///
+ /// VCVTTPS2IUBS xmm1{k1}{z}, xmm2/m128/m32bcst
+ ///
+ public static Vector128 ConvertToByteWithTruncatedSaturationAndZeroExtendToInt32(Vector128 value) { throw new PlatformNotSupportedException(); }
+
+ ///
+ /// VCVTTPS2IUBS ymm1{k1}{z}, ymm2/m256/m32bcst {sae}
+ ///
+ public static Vector256 ConvertToByteWithTruncatedSaturationAndZeroExtendToInt32(Vector256 value) { throw new PlatformNotSupportedException(); }
+
+ ///
+ /// VMOVD xmm1, xmm2/m32
+ ///
+ public static Vector128 ConvertToVector128UInt32(Vector128 value) { throw new PlatformNotSupportedException(); }
+
+ ///
+ /// VMOVW xmm1, xmm2/m16
+ ///
+ public static Vector128 ConvertToVector128UInt16(Vector128 value) { throw new PlatformNotSupportedException(); }
+
+ ///
+ /// VCVTDQ2PS ymm1{k1}{z}, ymm2/m256/m32bcst {er}
+ ///
+ public static Vector256 ConvertToVector256Single(Vector256 value, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) { throw new PlatformNotSupportedException(); }
+
+ ///
+ /// VCVTPD2DQ xmm1{k1}{z}, ymm2/m256/m64bcst {er}
+ ///
+ public static Vector128 ConvertToVector128Int32(Vector256 value, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) { throw new PlatformNotSupportedException(); }
+
+ ///
+ /// VCVTPD2PS xmm1{k1}{z}, ymm2/m256/m64bcst {er}
+ ///
+ public static Vector128 ConvertToVector128Single(Vector256 value, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) { throw new PlatformNotSupportedException(); }
+
+ ///
+ /// VCVTPD2QQ ymm1{k1}{z}, ymm2/m256/m64bcst {er}
+ ///
+ public static Vector256 ConvertToVector256Int64(Vector256 value, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) { throw new PlatformNotSupportedException(); }
+
+ ///
+ /// VCVTPD2UDQ xmm1{k1}{z}, ymm2/m256/m64bcst {er}
+ ///
+ public static Vector128 ConvertToVector128UInt32(Vector256 value, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) { throw new PlatformNotSupportedException(); }
+
+ ///
+ /// VCVTPD2UQQ ymm1{k1}{z}, ymm2/m256/m64bcst {er}
+ ///
+ public static Vector256 ConvertToVector256UInt64(Vector256 value, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) { throw new PlatformNotSupportedException(); }
+
+ ///
+ /// VCVTPS2DQ ymm1{k1}{z}, ymm2/m256/m32bcst {er}
+ ///
+ public static Vector256 ConvertToVector256Int32(Vector256 value, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) { throw new PlatformNotSupportedException(); }
+
+ ///
+ /// VCVTPS2QQ ymm1{k1}{z}, xmm2/m128/m32bcst {er}
+ ///
+ public static Vector256 ConvertToVector256Int64(Vector128 value, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) { throw new PlatformNotSupportedException(); }
+
+ ///
+ /// VCVTPS2UDQ ymm1{k1}{z}, ymm2/m256/m32bcst {er}
+ ///
+ public static Vector256 ConvertToVector256UInt32(Vector256 value, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) { throw new PlatformNotSupportedException(); }
+
+ ///
+ /// VCVTPS2UQQ ymm1{k1}{z}, xmm2/m128/m32bcst {er}
+ ///
+ public static Vector256 ConvertToVector256UInt64(Vector128 value, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) { throw new PlatformNotSupportedException(); }
+
+ ///
+ /// VCVTQQ2PS xmm1{k1}{z}, ymm2/m256/m64bcst {er}
+ ///
+ public static Vector128 ConvertToVector128Single(Vector256 value, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) { throw new PlatformNotSupportedException(); }
+
+ ///
+ /// VCVTQQ2PD ymm1{k1}{z}, ymm2/m256/m64bcst {er}
+ ///
+ public static Vector256 ConvertToVector256Double(Vector256 value, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) { throw new PlatformNotSupportedException(); }
+
+ ///
+ /// VCVTUDQ2PS ymm1{k1}{z}, ymm2/m256/m32bcst {er}
+ ///
+ public static Vector256 ConvertToVector256Single(Vector256 value, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) { throw new PlatformNotSupportedException(); }
+
+ ///
+ /// VCVTUQQ2PS xmm1{k1}{z}, ymm2/m256/m64bcst {er}
+ ///
+ public static Vector128 ConvertToVector128Single(Vector256 value, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) { throw new PlatformNotSupportedException(); }
+
+ ///
+ /// VCVTUQQ2PD ymm1{k1}{z}, ymm2/m256/m64bcst {er}
+ ///
+ public static Vector256 ConvertToVector256Double(Vector256 value, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) { throw new PlatformNotSupportedException(); }
+
+ ///
+ /// VMULPD ymm1{k1}{z}, ymm2, ymm3/m256/m64bcst {er}
+ ///
+ public static Vector256 Multiply(Vector256 left, Vector256 right, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) { throw new PlatformNotSupportedException(); }
+
+ ///
+ /// VMULPS ymm1{k1}{z}, ymm2, ymm3/m256/m32bcst {er}
+ ///
+ public static Vector256 Multiply(Vector256 left, Vector256 right, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) { throw new PlatformNotSupportedException(); }
+
+ ///
+ /// VSCALEFPD ymm1{k1}{z}, ymm2, ymm3/m256/m64bcst {er}
+ ///
+ public static Vector256 Scale(Vector256 left, Vector256 right, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) { throw new PlatformNotSupportedException(); }
+
+ ///
+ /// VSCALEFPS ymm1{k1}{z}, ymm2, ymm3/m256/m32bcst {er}
+ ///
+ public static Vector256 Scale(Vector256 left, Vector256 right, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) { throw new PlatformNotSupportedException(); }
+
+ ///
+ /// VSQRTPD ymm1{k1}{z}, ymm2/m256/m64bcst {er}
+ ///
+ public static Vector256 Sqrt(Vector256 value, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) { throw new PlatformNotSupportedException(); }
+
+ ///
+ /// VSQRTPS ymm1{k1}{z}, ymm2/m256/m32bcst {er}
+ ///
+ public static Vector256 Sqrt(Vector256 value, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) { throw new PlatformNotSupportedException(); }
+
+ ///
+ /// VSUBPD ymm1{k1}{z}, ymm2, ymm3/m256/m64bcst {er}
+ ///
+ public static Vector256 Subtract(Vector256 left, Vector256 right, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) { throw new PlatformNotSupportedException(); }
+
+ ///
+ /// VSUBPS ymm1{k1}{z}, ymm2, ymm3/m256/m32bcst {er}
+ ///
+ public static Vector256 Subtract(Vector256 left, Vector256 right, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) { throw new PlatformNotSupportedException(); }
+
+ /// Provides access to the x86 AVX10.2 hardware instructions, that are only available to 64-bit processes, via intrinsics.
+ public new abstract class X64 : Avx10v1.X64
+ {
+ internal X64() { }
+
+ /// Gets a value that indicates whether the APIs in this class are supported.
+ /// if the APIs are supported; otherwise, .
+ /// A value of indicates that the APIs will throw .
+ public static new bool IsSupported { [Intrinsic] get { return false; } }
+
+ }
+
+ /// Provides access to the x86 AVX10.2/512 hardware instructions via intrinsics.
+ public new abstract class V512 : Avx10v1.V512
+ {
+ internal V512() { }
+
+ /// Gets a value that indicates whether the APIs in this class are supported.
+ /// if the APIs are supported; otherwise, .
+ /// A value of indicates that the APIs will throw .
+ public static new bool IsSupported { [Intrinsic] get { return false; } }
+
+ ///
+ /// VMINMAXPD zmm1{k1}{z}, zmm2, zmm3/m512/m64bcst {sae}, imm8
+ ///
+ public static Vector512 MinMax(Vector512 left, Vector512 right, [ConstantExpected] byte control) { throw new PlatformNotSupportedException(); }
+
+ ///
+ /// VMINMAXPS zmm1{k1}{z}, zmm2, zmm3/m512/m32bcst {sae}, imm8
+ ///
+ public static Vector512 MinMax(Vector512 left, Vector512 right, [ConstantExpected] byte control) { throw new PlatformNotSupportedException(); }
+
+ ///
+ /// VCVTPS2IBS zmm1{k1}{z}, zmm2/m512/m32bcst {er}
+ ///
+ public static Vector512 ConvertToSByteWithSaturationAndZeroExtendToInt32(Vector512 value) { throw new PlatformNotSupportedException(); }
+
+ ///
+ /// VCVTPS2IBS zmm1{k1}{z}, zmm2/m512/m32bcst {er}
+ ///
+ public static Vector512 ConvertToSByteWithSaturationAndZeroExtendToInt32(Vector512 value, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) { throw new PlatformNotSupportedException(); }
+
+ ///
+ /// VCVTPS2IUBS zmm1{k1}{z}, zmm2/m512/m32bcst {er}
+ ///
+ public static Vector512 ConvertToByteWithSaturationAndZeroExtendToInt32(Vector512 value) { throw new PlatformNotSupportedException(); }
+
+ ///
+ /// VCVTPS2IUBS zmm1{k1}{z}, zmm2/m512/m32bcst {er}
+ ///
+ public static Vector512 ConvertToByteWithSaturationAndZeroExtendToInt32(Vector512 value, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) { throw new PlatformNotSupportedException(); }
+
+ ///
+ /// VCVTTPS2IUBS zmm1{k1}{z}, zmm2/m512/m32bcst {sae}
+ ///
+ public static Vector512 ConvertToSByteWithTruncatedSaturationAndZeroExtendToInt32(Vector512 value) { throw new PlatformNotSupportedException(); }
+
+ ///
+ /// VCVTTPS2IUBS zmm1{k1}{z}, zmm2/m512/m32bcst {sae}
+ ///
+ public static Vector512 ConvertToByteWithTruncatedSaturationAndZeroExtendToInt32(Vector512 value) { throw new PlatformNotSupportedException(); }
+
+ ///
+ /// VMPSADBW zmm1{k1}{z}, zmm2, zmm3/m512, imm8
+ ///
+ public static Vector512 MultipleSumAbsoluteDifferences(Vector512 left, Vector512 right, [ConstantExpected] byte mask) { throw new PlatformNotSupportedException(); }
+
+ /// Provides access to the x86 AVX10.1/512 hardware instructions, that are only available to 64-bit processes, via intrinsics.
+ [Intrinsic]
+ public new abstract class X64 : Avx10v1.V512.X64
+ {
+ internal X64() { }
+
+ /// Gets a value that indicates whether the APIs in this class are supported.
+ /// if the APIs are supported; otherwise, .
+ /// A value of indicates that the APIs will throw .
+ public static new bool IsSupported { [Intrinsic] get { return false; } }
+ }
+ }
+ }
+}
diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/Avx10v2.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/Avx10v2.cs
new file mode 100644
index 00000000000000..5c9cba0625fd5c
--- /dev/null
+++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/Avx10v2.cs
@@ -0,0 +1,327 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.CompilerServices;
+
+namespace System.Runtime.Intrinsics.X86
+{
+ /// Provides access to X86 AVX10.2 hardware instructions via intrinsics
+ [Intrinsic]
+ [CLSCompliant(false)]
+ public abstract class Avx10v2 : Avx10v1
+ {
+ internal Avx10v2() { }
+
+ /// Gets a value that indicates whether the APIs in this class are supported.
+ /// if the APIs are supported; otherwise, .
+ /// A value of indicates that the APIs will throw .
+ public static new bool IsSupported { get => IsSupported; }
+
+ ///
+ /// VMINMAXPD xmm1{k1}{z}, xmm2, xmm3/m128/m64bcst, imm8
+ ///
+ public static Vector128 MinMax(Vector128 left, Vector128 right, [ConstantExpected] byte control) => MinMax(left, right, control);
+
+ ///
+ /// VMINMAXPD ymm1{k1}{z}, ymm2, ymm3/m256/m64bcst {sae}, imm8
+ ///
+ public static Vector256 MinMax(Vector256 left, Vector256 right, [ConstantExpected] byte control) => MinMax(left, right, control);
+
+ ///
+ /// VMINMAXPS xmm1{k1}{z}, xmm2, xmm3/m128/m32bcst, imm8
+ ///
+ public static Vector128 MinMax(Vector128 left, Vector128 right, [ConstantExpected] byte control) => MinMax(left, right, control);
+
+ ///
+ /// VMINMAXPS ymm1{k1}{z}, ymm2, ymm3/m256/m32bcst {sae}, imm8
+ ///
+ public static Vector256 MinMax(Vector256 left, Vector256 right, [ConstantExpected] byte control) => MinMax(left, right, control);
+
+ ///
+ /// VMINMAXSD xmm1{k1}{z}, xmm2, xmm3/m64 {sae}, imm8
+ ///
+ public static Vector128 MinMaxScalar(Vector128 left, Vector128 right, [ConstantExpected] byte control) => MinMaxScalar(left, right, control);
+
+ ///
+ /// VMINMAXSS xmm1{k1}{z}, xmm2, xmm3/m32 {sae}, imm8
+ ///
+ public static Vector128 MinMaxScalar(Vector128 left, Vector128 right, [ConstantExpected] byte control) => MinMaxScalar(left, right, control);
+
+ ///
+ /// VCVTPS2IBS xmm1{k1}{z}, xmm2/m128/m32bcst
+ ///
+ public static Vector128 ConvertToSByteWithSaturationAndZeroExtendToInt32(Vector128 value) => ConvertToSByteWithSaturationAndZeroExtendToInt32(value);
+
+ ///
+ /// VCVTPS2IBS ymm1{k1}{z}, ymm2/m256/m32bcst {er}
+ ///
+ public static Vector256 ConvertToSByteWithSaturationAndZeroExtendToInt32(Vector256 value) => ConvertToSByteWithSaturationAndZeroExtendToInt32(value);
+
+ ///
+ /// VCVTPS2IBS ymm1{k1}{z}, ymm2/m256/m32bcst {er}
+ ///
+ public static Vector256 ConvertToSByteWithSaturationAndZeroExtendToInt32(Vector256 value, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) => ConvertToSByteWithSaturationAndZeroExtendToInt32(value, mode);
+
+ ///
+ /// VCVTPS2IUBS xmm1{k1}{z}, xmm2/m128/m32bcst
+ ///
+ public static Vector128 ConvertToByteWithSaturationAndZeroExtendToInt32(Vector128 value) => ConvertToByteWithSaturationAndZeroExtendToInt32(value);
+
+ ///
+ /// VCVTPS2IUBS ymm1{k1}{z}, ymm2/m256/m32bcst {er}
+ ///
+ public static Vector256 ConvertToByteWithSaturationAndZeroExtendToInt32(Vector256 value) => ConvertToByteWithSaturationAndZeroExtendToInt32(value);
+
+ ///
+ /// VCVTPS2IUBS ymm1{k1}{z}, ymm2/m256/m32bcst {er}
+ ///
+ public static Vector256 ConvertToByteWithSaturationAndZeroExtendToInt32(Vector256 value, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) => ConvertToByteWithSaturationAndZeroExtendToInt32(value, mode);
+
+ ///
+ /// VCVTTPS2IBS xmm1{k1}{z}, xmm2/m128/m32bcst
+ ///
+ public static Vector128 ConvertToSByteWithTruncatedSaturationAndZeroExtendToInt32(Vector128 value) => ConvertToSByteWithTruncatedSaturationAndZeroExtendToInt32(value);
+
+ ///
+ /// VCVTTPS2IBS ymm1{k1}{z}, ymm2/m256/m32bcst {sae}
+ ///
+ public static Vector256 ConvertToSByteWithTruncatedSaturationAndZeroExtendToInt32(Vector256 value) => ConvertToSByteWithTruncatedSaturationAndZeroExtendToInt32(value);
+
+ ///
+ /// VCVTTPS2IUBS xmm1{k1}{z}, xmm2/m128/m32bcst
+ ///
+ public static Vector128 ConvertToByteWithTruncatedSaturationAndZeroExtendToInt32(Vector128 value) => ConvertToByteWithTruncatedSaturationAndZeroExtendToInt32(value);
+
+ ///
+ /// VCVTTPS2IUBS ymm1{k1}{z}, ymm2/m256/m32bcst {sae}
+ ///
+ public static Vector256 ConvertToByteWithTruncatedSaturationAndZeroExtendToInt32(Vector256 value) => ConvertToByteWithTruncatedSaturationAndZeroExtendToInt32(value);
+
+ ///
+ /// VMOVD xmm1, xmm2/m32
+ ///
+ public static Vector128 ConvertToVector128UInt32(Vector128 value) => ConvertToVector128UInt32(value);
+
+ ///
+ /// VMOVW xmm1, xmm2/m16
+ ///
+ public static Vector128 ConvertToVector128UInt16(Vector128 value) => ConvertToVector128UInt16(value);
+
+ ///
+ /// VADDPD ymm1{k1}{z}, ymm2, ymm3/m256/m64bcst {er}
+ ///
+ public static Vector256 Add(Vector256 left, Vector256 right, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) => Add(left, right, mode);
+
+ ///
+ /// VADDPS ymm1{k1}{z}, ymm2, ymm3/m256/m32bcst {er}
+ ///
+ public static Vector256 Add(Vector256 left, Vector256 right, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) => Add(left, right, mode);
+
+ ///
+ /// VDIVPD ymm1{k1}{z}, ymm2, ymm3/m256/m64bcst {er}
+ ///
+ public static Vector256 Divide(Vector256 left, Vector256 right, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) => Divide(left, right, mode);
+
+ ///
+ /// VDIVPS ymm1{k1}{z}, ymm2, ymm3/m256/m32bcst {er}
+ ///
+ public static Vector256 Divide(Vector256 left, Vector256 right, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) => Divide(left, right, mode);
+
+ ///
+ /// VCVTDQ2PS ymm1{k1}{z}, ymm2/m256/m32bcst {er}
+ ///
+ public static Vector256 ConvertToVector256Single(Vector256 value, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) => ConvertToVector256Single(value, mode);
+
+ ///
+ /// VCVTPD2DQ xmm1{k1}{z}, ymm2/m256/m64bcst {er}
+ ///
+ public static Vector128 ConvertToVector128Int32(Vector256 value, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) => ConvertToVector128Int32(value, mode);
+
+ ///
+ /// VCVTPD2PS xmm1{k1}{z}, ymm2/m256/m64bcst {er}
+ ///
+ public static Vector128 ConvertToVector128Single(Vector256 value, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) => ConvertToVector128Single(value, mode);
+
+ ///
+ /// VCVTPD2QQ ymm1{k1}{z}, ymm2/m256/m64bcst {er}
+ ///
+ public static Vector256 ConvertToVector256Int64(Vector256 value, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) => ConvertToVector256Int64(value, mode);
+
+ ///
+ /// VCVTPD2UDQ xmm1{k1}{z}, ymm2/m256/m64bcst {er}
+ ///
+ public static Vector128 ConvertToVector128UInt32(Vector256 value, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) => ConvertToVector128UInt32(value, mode);
+
+ ///
+ /// VCVTPD2UQQ ymm1{k1}{z}, ymm2/m256/m64bcst {er}
+ ///
+ public static Vector256 ConvertToVector256UInt64(Vector256 value, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) => ConvertToVector256UInt64(value, mode);
+
+ ///
+ /// VCVTPS2DQ ymm1{k1}{z}, ymm2/m256/m32bcst {er}
+ ///
+ public static Vector256 ConvertToVector256Int32(Vector256 value, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) => ConvertToVector256Int32(value, mode);
+
+ ///
+ /// VCVTPS2QQ ymm1{k1}{z}, xmm2/m128/m32bcst {er}
+ ///
+ public static Vector256 ConvertToVector256Int64(Vector128 value, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) => ConvertToVector256Int64(value, mode);
+
+ ///
+ /// VCVTPS2UDQ ymm1{k1}{z}, ymm2/m256/m32bcst {er}
+ ///
+ public static Vector256 ConvertToVector256UInt32(Vector256 value, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) => ConvertToVector256UInt32(value, mode);
+
+ ///
+ /// VCVTPS2UQQ ymm1{k1}{z}, xmm2/m128/m32bcst {er}
+ ///
+ public static Vector256 ConvertToVector256UInt64(Vector128 value, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) => ConvertToVector256UInt64(value, mode);
+
+ ///
+ /// VCVTQQ2PS xmm1{k1}{z}, ymm2/m256/m64bcst {er}
+ ///
+ public static Vector128 ConvertToVector128Single(Vector256 value, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) => ConvertToVector128Single(value, mode);
+
+ ///
+ /// VCVTQQ2PD ymm1{k1}{z}, ymm2/m256/m64bcst {er}
+ ///
+ public static Vector256 ConvertToVector256Double(Vector256 value, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) => ConvertToVector256Double(value, mode);
+
+ ///
+ /// VCVTUDQ2PS ymm1{k1}{z}, ymm2/m256/m32bcst {er}
+ ///
+ public static Vector256 ConvertToVector256Single(Vector256 value, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) => ConvertToVector256Single(value, mode);
+
+ ///
+ /// VCVTUQQ2PS xmm1{k1}{z}, ymm2/m256/m64bcst {er}
+ ///
+ public static Vector128 ConvertToVector128Single(Vector256 value, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) => ConvertToVector128Single(value, mode);
+
+ ///
+ /// VCVTUQQ2PD ymm1{k1}{z}, ymm2/m256/m64bcst {er}
+ ///
+ public static Vector256 ConvertToVector256Double(Vector256 value, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) => ConvertToVector256Double(value, mode);
+
+ ///
+ /// VMULPD ymm1{k1}{z}, ymm2, ymm3/m256/m64bcst {er}
+ ///
+ public static Vector256 Multiply(Vector256 left, Vector256 right, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) => Multiply(left, right, mode);
+
+ ///
+ /// VMULPS ymm1{k1}{z}, ymm2, ymm3/m256/m32bcst {er}
+ ///
+ public static Vector256 Multiply(Vector256 left, Vector256 right, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) => Multiply(left, right, mode);
+
+ ///
+ /// VSCALEFPD ymm1{k1}{z}, ymm2, ymm3/m256/m64bcst {er}
+ ///
+ public static Vector256 Scale(Vector256 left, Vector256 right, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) => Scale(left, right, mode);
+
+ ///
+ /// VSCALEFPS ymm1{k1}{z}, ymm2, ymm3/m256/m32bcst {er}
+ ///
+ public static Vector256 Scale(Vector256 left, Vector256 right, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) => Scale(left, right, mode);
+
+ ///
+ /// VSQRTPD ymm1{k1}{z}, ymm2/m256/m64bcst {er}
+ ///
+ public static Vector256 Sqrt(Vector256 value, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) => Sqrt(value, mode);
+
+ ///
+ /// VSQRTPS ymm1{k1}{z}, ymm2/m256/m32bcst {er}
+ ///
+ public static Vector256 Sqrt(Vector256 value, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) => Sqrt(value, mode);
+
+ ///
+ /// VSUBPD ymm1{k1}{z}, ymm2, ymm3/m256/m64bcst {er}
+ ///
+ public static Vector256 Subtract(Vector256 left, Vector256 right, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) => Subtract(left, right, mode);
+
+ ///
+ /// VSUBPS ymm1{k1}{z}, ymm2, ymm3/m256/m32bcst {er}
+ ///
+ public static Vector256 Subtract(Vector256 left, Vector256 right, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) => Subtract(left, right, mode);
+
+ /// Provides access to the x86 AVX10.2 hardware instructions, that are only available to 64-bit processes, via intrinsics.
+ [Intrinsic]
+ public new abstract class X64 : Avx10v1.X64
+ {
+ internal X64() { }
+
+ /// Gets a value that indicates whether the APIs in this class are supported.
+ /// if the APIs are supported; otherwise, .
+ /// A value of indicates that the APIs will throw .
+ public static new bool IsSupported { get => IsSupported; }
+ }
+
+ /// Provides access to the x86 AVX10.2/512 hardware instructions via intrinsics.
+ [Intrinsic]
+ public new abstract class V512 : Avx10v1.V512
+ {
+ internal V512() { }
+
+ /// Gets a value that indicates whether the APIs in this class are supported.
+ /// if the APIs are supported; otherwise, .
+ /// A value of indicates that the APIs will throw .
+ public static new bool IsSupported { get => IsSupported; }
+
+ ///
+ /// VMINMAXPD zmm1{k1}{z}, zmm2, zmm3/m512/m64bcst {sae}, imm8
+ ///
+ public static Vector512 MinMax(Vector512 left, Vector512 right, [ConstantExpected] byte control) => MinMax(left, right, control);
+
+ ///
+ /// VMINMAXPS zmm1{k1}{z}, zmm2, zmm3/m512/m32bcst {sae}, imm8
+ ///
+ public static Vector512 MinMax(Vector512 left, Vector512 right, [ConstantExpected] byte control) => MinMax(left, right, control);
+
+ ///
+ /// VCVTPS2IBS zmm1{k1}{z}, zmm2/m512/m32bcst {er}
+ ///
+ public static Vector512 ConvertToSByteWithSaturationAndZeroExtendToInt32(Vector512 value) => ConvertToSByteWithSaturationAndZeroExtendToInt32(value);
+
+ ///
+ /// VCVTPS2IBS zmm1{k1}{z}, zmm2/m512/m32bcst {er}
+ ///
+ public static Vector512 ConvertToSByteWithSaturationAndZeroExtendToInt32(Vector512 value, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) => ConvertToSByteWithSaturationAndZeroExtendToInt32(value, mode);
+
+ ///
+ /// VCVTPS2IUBS zmm1{k1}{z}, zmm2/m512/m32bcst {er}
+ ///
+ public static Vector512 ConvertToByteWithSaturationAndZeroExtendToInt32(Vector512 value) => ConvertToByteWithSaturationAndZeroExtendToInt32(value);
+
+ ///
+ /// VCVTPS2IUBS zmm1{k1}{z}, zmm2/m512/m32bcst {er}
+ ///
+ public static Vector512 ConvertToByteWithSaturationAndZeroExtendToInt32(Vector512 value, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) => ConvertToByteWithSaturationAndZeroExtendToInt32(value, mode);
+
+ ///