Skip to content

Commit f69972f

Browse files
Expose various new Create and conversion APIs for the Vector types (#103462)
* Expose various new Create and conversion APIs for the Vector types * Remove simdashwintrinsic handling for Vector2/3 * Apply formatting patch * Ensure creation from a span checks the right element count for Vector2/3 * Ensure that we create more correct WithElement nodes * Ensure that Vector128.AsVector128Unsafe preserves the fact it produces TYP_SIMD16
1 parent de709b1 commit f69972f

40 files changed

+947
-1346
lines changed

src/coreclr/System.Private.CoreLib/src/System/Math.CoreCLR.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ public static partial class Math
9292
[MethodImpl(MethodImplOptions.InternalCall)]
9393
public static extern double Sin(double a);
9494

95+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
9596
public static unsafe (double Sin, double Cos) SinCos(double x)
9697
{
9798
double sin, cos;

src/coreclr/System.Private.CoreLib/src/System/MathF.CoreCLR.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ public static partial class MathF
8989
[MethodImpl(MethodImplOptions.InternalCall)]
9090
public static extern float Sin(float x);
9191

92+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
9293
public static unsafe (float Sin, float Cos) SinCos(float x)
9394
{
9495
float sin, cos;

src/coreclr/jit/compiler.h

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4562,8 +4562,7 @@ class Compiler
45624562
GenTreeLclVarCommon* data, WCHAR* cns, int len, int dataOffset, StringComparison cmpMode);
45634563
GenTreeStrCon* impGetStrConFromSpan(GenTree* span);
45644564

4565-
GenTree* impIntrinsic(GenTree* newobjThis,
4566-
CORINFO_CLASS_HANDLE clsHnd,
4565+
GenTree* impIntrinsic(CORINFO_CLASS_HANDLE clsHnd,
45674566
CORINFO_METHOD_HANDLE method,
45684567
CORINFO_SIG_INFO* sig,
45694568
unsigned methodFlags,
@@ -4628,7 +4627,6 @@ class Compiler
46284627
CORINFO_CLASS_HANDLE clsHnd,
46294628
CORINFO_METHOD_HANDLE method,
46304629
CORINFO_SIG_INFO* sig,
4631-
GenTree* newobjThis,
46324630
bool mustExpand);
46334631

46344632
protected:
@@ -4640,7 +4638,6 @@ class Compiler
46404638
var_types retType,
46414639
CorInfoType simdBaseJitType,
46424640
unsigned simdSize,
4643-
GenTree* newobjThis,
46444641
bool mustExpand);
46454642

46464643
GenTree* impSpecialIntrinsic(NamedIntrinsic intrinsic,
@@ -4653,10 +4650,7 @@ class Compiler
46534650
unsigned simdSize,
46544651
bool mustExpand);
46554652

4656-
GenTree* getArgForHWIntrinsic(var_types argType,
4657-
CORINFO_CLASS_HANDLE argClass,
4658-
bool expectAddr = false,
4659-
GenTree* newobjThis = nullptr);
4653+
GenTree* getArgForHWIntrinsic(var_types argType, CORINFO_CLASS_HANDLE argClass);
46604654
GenTree* impNonConstFallback(NamedIntrinsic intrinsic, var_types simdType, CorInfoType simdBaseJitType);
46614655
GenTree* addRangeCheckIfNeeded(
46624656
NamedIntrinsic intrinsic, GenTree* immOp, bool mustExpand, int immLowerBound, int immUpperBound);

src/coreclr/jit/fgbasic.cpp

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1395,15 +1395,10 @@ void Compiler::fgFindJumpTargets(const BYTE* codeAddr, IL_OFFSET codeSize, Fixed
13951395
case NI_Vector64_CreateScalar:
13961396
case NI_Vector64_CreateScalarUnsafe:
13971397
#endif // TARGET_ARM64
1398-
case NI_Vector2_Create:
1399-
case NI_Vector2_CreateBroadcast:
1400-
case NI_Vector3_Create:
1401-
case NI_Vector3_CreateBroadcast:
1402-
case NI_Vector3_CreateFromVector2:
14031398
case NI_Vector128_Create:
14041399
case NI_Vector128_CreateScalar:
14051400
case NI_Vector128_CreateScalarUnsafe:
1406-
case NI_VectorT_CreateBroadcast:
1401+
case NI_VectorT_Create:
14071402
#if defined(TARGET_XARCH)
14081403
case NI_BMI1_TrailingZeroCount:
14091404
case NI_BMI1_X64_TrailingZeroCount:

src/coreclr/jit/gentree.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27176,6 +27176,7 @@ GenTree* Compiler::gtNewSimdWithElementNode(
2717627176

2717727177
assert(varTypeIsArithmetic(simdBaseType));
2717827178
assert(op2->IsCnsIntOrI());
27179+
assert(varTypeIsArithmetic(op3));
2717927180

2718027181
ssize_t imm8 = op2->AsIntCon()->IconValue();
2718127182
ssize_t count = simdSize / genTypeSize(simdBaseType);

src/coreclr/jit/hwintrinsic.cpp

Lines changed: 4 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -745,16 +745,11 @@ bool HWIntrinsicInfo::isImmOp(NamedIntrinsic id, const GenTree* op)
745745
// Arguments:
746746
// argType -- the required type of argument
747747
// argClass -- the class handle of argType
748-
// expectAddr -- if true indicates we are expecting type stack entry to be a TYP_BYREF.
749-
// newobjThis -- For CEE_NEWOBJ, this is the temp grabbed for the allocated uninitialized object.
750748
//
751749
// Return Value:
752750
// the validated argument
753751
//
754-
GenTree* Compiler::getArgForHWIntrinsic(var_types argType,
755-
CORINFO_CLASS_HANDLE argClass,
756-
bool expectAddr,
757-
GenTree* newobjThis)
752+
GenTree* Compiler::getArgForHWIntrinsic(var_types argType, CORINFO_CLASS_HANDLE argClass)
758753
{
759754
GenTree* arg = nullptr;
760755

@@ -768,31 +763,12 @@ GenTree* Compiler::getArgForHWIntrinsic(var_types argType,
768763
}
769764
assert(varTypeIsSIMD(argType));
770765

771-
if (newobjThis == nullptr)
772-
{
773-
if (expectAddr)
774-
{
775-
arg = gtNewLoadValueNode(argType, impPopStack().val);
776-
}
777-
else
778-
{
779-
arg = impSIMDPopStack();
780-
}
781-
assert(varTypeIsSIMDOrMask(arg));
782-
}
783-
else
784-
{
785-
assert(newobjThis->IsLclVarAddr());
786-
arg = newobjThis;
787-
788-
// push newobj result on type stack
789-
unsigned lclNum = arg->AsLclVarCommon()->GetLclNum();
790-
impPushOnStack(gtNewLclvNode(lclNum, lvaGetRealType(lclNum)), verMakeTypeInfo(argClass));
791-
}
766+
arg = impSIMDPopStack();
767+
assert(varTypeIsSIMDOrMask(arg));
792768
}
793769
else
794770
{
795-
assert(varTypeIsArithmetic(argType) || ((argType == TYP_BYREF) && (newobjThis == nullptr)));
771+
assert(varTypeIsArithmetic(argType) || (argType == TYP_BYREF));
796772

797773
arg = impPopStack().val;
798774
assert(varTypeIsArithmetic(arg->TypeGet()) || ((argType == TYP_BYREF) && arg->TypeIs(TYP_BYREF)));

src/coreclr/jit/hwintrinsicarm64.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -721,6 +721,18 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic,
721721
break;
722722
}
723723

724+
case NI_Vector128_AsVector128Unsafe:
725+
{
726+
assert(sig->numArgs == 1);
727+
assert(retType == TYP_SIMD16);
728+
assert(simdBaseJitType == CORINFO_TYPE_FLOAT);
729+
assert((simdSize == 8) || (simdSize == 12));
730+
731+
op1 = impSIMDPopStack();
732+
retNode = gtNewSimdHWIntrinsicNode(retType, op1, NI_Vector128_AsVector128Unsafe, simdBaseJitType, simdSize);
733+
break;
734+
}
735+
724736
case NI_Vector64_op_BitwiseAnd:
725737
case NI_Vector128_op_BitwiseAnd:
726738
{

src/coreclr/jit/hwintrinsicxarch.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1279,6 +1279,18 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic,
12791279
break;
12801280
}
12811281

1282+
case NI_Vector128_AsVector128Unsafe:
1283+
{
1284+
assert(sig->numArgs == 1);
1285+
assert(retType == TYP_SIMD16);
1286+
assert(simdBaseJitType == CORINFO_TYPE_FLOAT);
1287+
assert((simdSize == 8) || (simdSize == 12));
1288+
1289+
op1 = impSIMDPopStack();
1290+
retNode = gtNewSimdHWIntrinsicNode(retType, op1, NI_Vector128_AsVector128Unsafe, simdBaseJitType, simdSize);
1291+
break;
1292+
}
1293+
12821294
case NI_Vector256_AsVector:
12831295
case NI_Vector256_AsVector256:
12841296
{

src/coreclr/jit/importercalls.cpp

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ var_types Compiler::impImportCall(OPCODE opcode,
242242
}
243243
#endif // FEATURE_READYTORUN
244244

245-
call = impIntrinsic(newobjThis, clsHnd, methHnd, sig, mflags, pResolvedToken, isReadonlyCall, isTailCall,
245+
call = impIntrinsic(clsHnd, methHnd, sig, mflags, pResolvedToken, isReadonlyCall, isTailCall,
246246
opcode == CEE_CALLVIRT, pConstrainedResolvedToken,
247247
callInfo->thisTransform R2RARG(&entryPoint), &ni, &isSpecialIntrinsic);
248248

@@ -2818,7 +2818,6 @@ GenTree* Compiler::impCreateSpanIntrinsic(CORINFO_SIG_INFO* sig)
28182818
// impIntrinsic: possibly expand intrinsic call into alternate IR sequence
28192819
//
28202820
// Arguments:
2821-
// newobjThis - for constructor calls, the tree for the newly allocated object
28222821
// clsHnd - handle for the intrinsic method's class
28232822
// method - handle for the intrinsic method
28242823
// sig - signature of the intrinsic method
@@ -2861,8 +2860,7 @@ GenTree* Compiler::impCreateSpanIntrinsic(CORINFO_SIG_INFO* sig)
28612860
// identified as "must expand" if they are invoked from within their
28622861
// own method bodies.
28632862
//
2864-
GenTree* Compiler::impIntrinsic(GenTree* newobjThis,
2865-
CORINFO_CLASS_HANDLE clsHnd,
2863+
GenTree* Compiler::impIntrinsic(CORINFO_CLASS_HANDLE clsHnd,
28662864
CORINFO_METHOD_HANDLE method,
28672865
CORINFO_SIG_INFO* sig,
28682866
unsigned methodFlags,
@@ -3088,7 +3086,7 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis,
30883086

30893087
if (isIntrinsic)
30903088
{
3091-
GenTree* hwintrinsic = impSimdAsHWIntrinsic(ni, clsHnd, method, sig, newobjThis, mustExpand);
3089+
GenTree* hwintrinsic = impSimdAsHWIntrinsic(ni, clsHnd, method, sig, mustExpand);
30923090

30933091
if (hwintrinsic == nullptr)
30943092
{

src/coreclr/jit/lclmorph.cpp

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1307,9 +1307,10 @@ class LocalAddressVisitor final : public GenTreeVisitor<LocalAddressVisitor>
13071307
break;
13081308

13091309
#ifdef FEATURE_HW_INTRINSICS
1310-
// We have two cases we want to handle:
1311-
// 1. Vector2/3/4 and Quaternion where we have 4x float fields
1310+
// We have three cases we want to handle:
1311+
// 1. Vector2/3/4 and Quaternion where we have 2-4x float fields
13121312
// 2. Plane where we have 1x Vector3 and 1x float field
1313+
// 3. Accesses of halves of larger SIMD types
13131314

13141315
case IndirTransform::GetElement:
13151316
{
@@ -1321,24 +1322,29 @@ class LocalAddressVisitor final : public GenTreeVisitor<LocalAddressVisitor>
13211322
{
13221323
case TYP_FLOAT:
13231324
{
1325+
// Handle case 1 or the float field of case 2
13241326
GenTree* indexNode = m_compiler->gtNewIconNode(offset / genTypeSize(elementType));
13251327
hwiNode = m_compiler->gtNewSimdGetElementNode(elementType, lclNode, indexNode,
13261328
CORINFO_TYPE_FLOAT, genTypeSize(varDsc));
13271329
break;
13281330
}
1331+
13291332
case TYP_SIMD12:
13301333
{
1334+
// Handle the Vector3 field of case 2
13311335
assert(genTypeSize(varDsc) == 16);
13321336
hwiNode = m_compiler->gtNewSimdHWIntrinsicNode(elementType, lclNode, NI_Vector128_AsVector3,
13331337
CORINFO_TYPE_FLOAT, 16);
13341338
break;
13351339
}
1340+
13361341
case TYP_SIMD8:
13371342
#if defined(FEATURE_SIMD) && defined(TARGET_XARCH)
13381343
case TYP_SIMD16:
13391344
case TYP_SIMD32:
13401345
#endif
13411346
{
1347+
// Handle case 3
13421348
assert(genTypeSize(elementType) * 2 == genTypeSize(varDsc));
13431349
if (offset == 0)
13441350
{
@@ -1374,29 +1380,44 @@ class LocalAddressVisitor final : public GenTreeVisitor<LocalAddressVisitor>
13741380
{
13751381
case TYP_FLOAT:
13761382
{
1383+
// Handle case 1 or the float field of case 2
13771384
GenTree* indexNode = m_compiler->gtNewIconNode(offset / genTypeSize(elementType));
13781385
hwiNode =
13791386
m_compiler->gtNewSimdWithElementNode(varDsc->TypeGet(), simdLclNode, indexNode, elementNode,
13801387
CORINFO_TYPE_FLOAT, genTypeSize(varDsc));
13811388
break;
13821389
}
1390+
13831391
case TYP_SIMD12:
13841392
{
1393+
// Handle the Vector3 field of case 2
13851394
assert(varDsc->TypeGet() == TYP_SIMD16);
13861395

1387-
// We inverse the operands here and take elementNode as the main value and simdLclNode[3] as the
1388-
// new value. This gives us a new TYP_SIMD16 with all elements in the right spots
1389-
GenTree* indexNode = m_compiler->gtNewIconNode(3, TYP_INT);
1390-
hwiNode = m_compiler->gtNewSimdWithElementNode(TYP_SIMD16, elementNode, indexNode, simdLclNode,
1396+
// We effectively inverse the operands here and take elementNode as the main value and
1397+
// simdLclNode[3] as the new value. This gives us a new TYP_SIMD16 with all elements in the
1398+
// right spots
1399+
1400+
elementNode = m_compiler->gtNewSimdHWIntrinsicNode(TYP_SIMD16, elementNode,
1401+
NI_Vector128_AsVector128Unsafe,
1402+
CORINFO_TYPE_FLOAT, 12);
1403+
1404+
GenTree* indexNode1 = m_compiler->gtNewIconNode(3, TYP_INT);
1405+
simdLclNode = m_compiler->gtNewSimdGetElementNode(TYP_FLOAT, simdLclNode, indexNode1,
1406+
CORINFO_TYPE_FLOAT, 16);
1407+
1408+
GenTree* indexNode2 = m_compiler->gtNewIconNode(3, TYP_INT);
1409+
hwiNode = m_compiler->gtNewSimdWithElementNode(TYP_SIMD16, elementNode, indexNode2, simdLclNode,
13911410
CORINFO_TYPE_FLOAT, 16);
13921411
break;
13931412
}
1413+
13941414
case TYP_SIMD8:
13951415
#if defined(FEATURE_SIMD) && defined(TARGET_XARCH)
13961416
case TYP_SIMD16:
13971417
case TYP_SIMD32:
13981418
#endif
13991419
{
1420+
// Handle case 3
14001421
assert(genTypeSize(elementType) * 2 == genTypeSize(varDsc));
14011422
if (offset == 0)
14021423
{
@@ -1412,6 +1433,7 @@ class LocalAddressVisitor final : public GenTreeVisitor<LocalAddressVisitor>
14121433

14131434
break;
14141435
}
1436+
14151437
default:
14161438
unreached();
14171439
}
@@ -1541,7 +1563,7 @@ class LocalAddressVisitor final : public GenTreeVisitor<LocalAddressVisitor>
15411563
if (varTypeIsSIMD(varDsc))
15421564
{
15431565
// We have three cases we want to handle:
1544-
// 1. Vector2/3/4 and Quaternion where we have 4x float fields
1566+
// 1. Vector2/3/4 and Quaternion where we have 2-4x float fields
15451567
// 2. Plane where we have 1x Vector3 and 1x float field
15461568
// 3. Accesses of halves of larger SIMD types
15471569

src/coreclr/jit/lower.cpp

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1752,18 +1752,23 @@ void Lowering::LowerArg(GenTreeCall* call, CallArg* callArg, bool late)
17521752
}
17531753
else if (arg->OperIs(GT_HWINTRINSIC))
17541754
{
1755-
GenTreeJitIntrinsic* jitIntrinsic = reinterpret_cast<GenTreeJitIntrinsic*>(arg);
1755+
GenTreeHWIntrinsic* hwintrinsic = arg->AsHWIntrinsic();
17561756

17571757
// For HWIntrinsic, there are some intrinsics like ExtractVector128 which have
1758-
// a gtType of TYP_SIMD16 but a SimdSize of 32, so we need to include that in
1759-
// the assert below.
1758+
// a gtType of TYP_SIMD16 but a SimdSize of 32, so we can't necessarily assert
1759+
// the simd size
17601760

1761-
assert((jitIntrinsic->GetSimdSize() == 12) || (jitIntrinsic->GetSimdSize() == 16) ||
1762-
(jitIntrinsic->GetSimdSize() == 32) || (jitIntrinsic->GetSimdSize() == 64));
1763-
1764-
if (jitIntrinsic->GetSimdSize() == 12)
1761+
if (hwintrinsic->GetSimdSize() == 12)
17651762
{
1766-
type = TYP_SIMD12;
1763+
if (hwintrinsic->GetHWIntrinsicId() != NI_Vector128_AsVector128Unsafe)
1764+
{
1765+
// Most nodes that have a simdSize of 12 are actually producing a TYP_SIMD12
1766+
// and have been massaged to TYP_SIMD16 to match the actual product size. This
1767+
// is not the case for NI_Vector128_AsVector128Unsafe which is explicitly taking
1768+
// a TYP_SIMD12 and producing a TYP_SIMD16.
1769+
1770+
type = TYP_SIMD12;
1771+
}
17671772
}
17681773
}
17691774
}

0 commit comments

Comments
 (0)