Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit 3f115ef

Browse files
committed
Adding support for the SSE Set, SetAll, and SetZero intrinsics
1 parent c09ad38 commit 3f115ef

File tree

7 files changed

+196
-16
lines changed

7 files changed

+196
-16
lines changed

src/jit/compiler.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2057,10 +2057,22 @@ class Compiler
20572057
#endif
20582058

20592059
#if FEATURE_HW_INTRINSICS
2060+
GenTreeHWIntrinsic* gtNewSimdHWIntrinsicNode(var_types type,
2061+
NamedIntrinsic hwIntrinsicID,
2062+
var_types baseType,
2063+
unsigned size);
20602064
GenTreeHWIntrinsic* gtNewSimdHWIntrinsicNode(
20612065
var_types type, GenTree* op1, NamedIntrinsic hwIntrinsicID, var_types baseType, unsigned size);
20622066
GenTreeHWIntrinsic* gtNewSimdHWIntrinsicNode(
20632067
var_types type, GenTree* op1, GenTree* op2, NamedIntrinsic hwIntrinsicID, var_types baseType, unsigned size);
2068+
GenTreeHWIntrinsic* gtNewSimdHWIntrinsicNode(var_types type,
2069+
GenTree* op1,
2070+
GenTree* op2,
2071+
GenTree* op3,
2072+
GenTree* op4,
2073+
NamedIntrinsic hwIntrinsicID,
2074+
var_types baseType,
2075+
unsigned size);
20642076
GenTreeHWIntrinsic* gtNewScalarHWIntrinsicNode(var_types type, GenTree* op1, NamedIntrinsic hwIntrinsicID);
20652077
GenTreeHWIntrinsic* gtNewScalarHWIntrinsicNode(var_types type,
20662078
GenTree* op1,
@@ -2088,6 +2100,7 @@ class Compiler
20882100
GenTreeArgList* gtNewArgList(GenTreePtr op);
20892101
GenTreeArgList* gtNewArgList(GenTreePtr op1, GenTreePtr op2);
20902102
GenTreeArgList* gtNewArgList(GenTreePtr op1, GenTreePtr op2, GenTreePtr op3);
2103+
GenTreeArgList* gtNewArgList(GenTreePtr op1, GenTreePtr op2, GenTreePtr op3, GenTreePtr op4);
20912104

20922105
static fgArgTabEntryPtr gtArgEntryByArgNum(GenTreeCall* call, unsigned argNum);
20932106
static fgArgTabEntryPtr gtArgEntryByNode(GenTreeCall* call, GenTreePtr node);

src/jit/compiler.hpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4891,6 +4891,19 @@ void GenTree::VisitOperands(TVisitor visitor)
48914891
return;
48924892
#endif // FEATURE_SIMD
48934893

4894+
#if FEATURE_HW_INTRINSICS
4895+
case GT_HWIntrinsic:
4896+
if ((this->AsHWIntrinsic()->gtOp1 != nullptr) && this->AsHWIntrinsic()->gtOp1->OperIsList())
4897+
{
4898+
this->AsHWIntrinsic()->gtOp1->VisitListOperands(visitor);
4899+
}
4900+
else
4901+
{
4902+
VisitBinOpOperands<TVisitor>(visitor);
4903+
}
4904+
return;
4905+
#endif // FEATURE_HW_INTRINSICS
4906+
48944907
// Special nodes
48954908
case GT_CMPXCHG:
48964909
{

src/jit/gentree.cpp

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5671,6 +5671,16 @@ bool GenTree::TryGetUse(GenTree* def, GenTree*** use)
56715671
return TryGetUseBinOp(def, use);
56725672
#endif // FEATURE_SIMD
56735673

5674+
#ifdef FEATURE_HW_INTRINSICS
5675+
case GT_HWIntrinsic:
5676+
if ((this->AsHWIntrinsic()->gtOp1 != nullptr) && this->AsHWIntrinsic()->gtOp1->OperIsList())
5677+
{
5678+
return this->AsHWIntrinsic()->gtOp1->TryGetUseList(def, use);
5679+
}
5680+
5681+
return TryGetUseBinOp(def, use);
5682+
#endif // FEATURE_HW_INTRINSICS
5683+
56745684
// Special nodes
56755685
case GT_CMPXCHG:
56765686
{
@@ -6788,6 +6798,16 @@ GenTreeArgList* Compiler::gtNewArgList(GenTreePtr arg1, GenTreePtr arg2, GenTree
67886798
return new (this, GT_LIST) GenTreeArgList(arg1, gtNewArgList(arg2, arg3));
67896799
}
67906800

6801+
/*****************************************************************************
6802+
*
6803+
* Create a list out of the three values.
6804+
*/
6805+
6806+
GenTreeArgList* Compiler::gtNewArgList(GenTreePtr arg1, GenTreePtr arg2, GenTreePtr arg3, GenTreePtr arg4)
6807+
{
6808+
return new (this, GT_LIST) GenTreeArgList(arg1, gtNewArgList(arg2, arg3, arg4));
6809+
}
6810+
67916811
/*****************************************************************************
67926812
*
67936813
* Given a GT_CALL node, access the fgArgInfo and find the entry
@@ -9211,6 +9231,24 @@ GenTreeUseEdgeIterator::GenTreeUseEdgeIterator(GenTree* node)
92119231
return;
92129232
#endif // FEATURE_SIMD
92139233

9234+
#if FEATURE_HW_INTRINSICS
9235+
case GT_HWIntrinsic:
9236+
if (m_node->AsHWIntrinsic()->gtOp1 == nullptr)
9237+
{
9238+
assert(m_node->NullOp1Legal());
9239+
m_state = -1;
9240+
}
9241+
else if (m_node->AsHWIntrinsic()->gtOp1->OperIsList())
9242+
{
9243+
SetEntryStateForList(m_node->AsHWIntrinsic()->gtOp1);
9244+
}
9245+
else
9246+
{
9247+
SetEntryStateForBinOp();
9248+
}
9249+
return;
9250+
#endif // FEATURE_HW_INTRINSICS
9251+
92149252
// LEA, which may have no first operand
92159253
case GT_LEA:
92169254
if (m_node->AsAddrMode()->gtOp1 == nullptr)
@@ -17863,6 +17901,14 @@ bool GenTree::isCommutativeSIMDIntrinsic()
1786317901
#endif // FEATURE_SIMD
1786417902

1786517903
#if FEATURE_HW_INTRINSICS
17904+
GenTreeHWIntrinsic* Compiler::gtNewSimdHWIntrinsicNode(var_types type,
17905+
NamedIntrinsic hwIntrinsicID,
17906+
var_types baseType,
17907+
unsigned size)
17908+
{
17909+
return new (this, GT_HWIntrinsic) GenTreeHWIntrinsic(type, hwIntrinsicID, baseType, size);
17910+
}
17911+
1786617912
GenTreeHWIntrinsic* Compiler::gtNewSimdHWIntrinsicNode(
1786717913
var_types type, GenTree* op1, NamedIntrinsic hwIntrinsicID, var_types baseType, unsigned size)
1786817914
{
@@ -17875,6 +17921,19 @@ GenTreeHWIntrinsic* Compiler::gtNewSimdHWIntrinsicNode(
1787517921
return new (this, GT_HWIntrinsic) GenTreeHWIntrinsic(type, op1, op2, hwIntrinsicID, baseType, size);
1787617922
}
1787717923

17924+
GenTreeHWIntrinsic* Compiler::gtNewSimdHWIntrinsicNode(var_types type,
17925+
GenTree* op1,
17926+
GenTree* op2,
17927+
GenTree* op3,
17928+
GenTree* op4,
17929+
NamedIntrinsic hwIntrinsicID,
17930+
var_types baseType,
17931+
unsigned size)
17932+
{
17933+
return new (this, GT_HWIntrinsic)
17934+
GenTreeHWIntrinsic(type, gtNewArgList(op1, op2, op3, op4), hwIntrinsicID, baseType, size);
17935+
}
17936+
1787817937
GenTreeHWIntrinsic* Compiler::gtNewScalarHWIntrinsicNode(var_types type, GenTree* op1, NamedIntrinsic hwIntrinsicID)
1787917938
{
1788017939
return new (this, GT_HWIntrinsic) GenTreeHWIntrinsic(type, op1, hwIntrinsicID, TYP_UNKNOWN, 0);

src/jit/gentree.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1663,6 +1663,9 @@ struct GenTree
16631663
case GT_LEA:
16641664
case GT_RETFILT:
16651665
case GT_NOP:
1666+
#if FEATURE_HW_INTRINSICS
1667+
case GT_HWIntrinsic:
1668+
#endif // FEATURE_HW_INTRINSICS
16661669
return true;
16671670
case GT_RETURN:
16681671
return gtType == TYP_VOID;
@@ -4225,6 +4228,11 @@ struct GenTreeHWIntrinsic : public GenTreeJitIntrinsic
42254228
{
42264229
NamedIntrinsic gtHWIntrinsicId;
42274230

4231+
GenTreeHWIntrinsic(var_types type, NamedIntrinsic hwIntrinsicID, var_types baseType, unsigned size)
4232+
: GenTreeJitIntrinsic(GT_HWIntrinsic, type, nullptr, nullptr, baseType, size), gtHWIntrinsicId(hwIntrinsicID)
4233+
{
4234+
}
4235+
42284236
GenTreeHWIntrinsic(var_types type, GenTree* op1, NamedIntrinsic hwIntrinsicID, var_types baseType, unsigned size)
42294237
: GenTreeJitIntrinsic(GT_HWIntrinsic, type, op1, nullptr, baseType, size), gtHWIntrinsicId(hwIntrinsicID)
42304238
{

src/jit/hwintrinsiccodegenxarch.cpp

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,16 +193,24 @@ void CodeGen::genSSEIntrinsic(GenTreeHWIntrinsic* node)
193193
NamedIntrinsic intrinsicID = node->gtHWIntrinsicId;
194194
GenTree* op1 = node->gtGetOp1();
195195
GenTree* op2 = node->gtGetOp2();
196+
GenTree* op3 = nullptr;
197+
GenTree* op4 = nullptr;
196198
regNumber targetReg = node->gtRegNum;
197199
var_types targetType = node->TypeGet();
198200
var_types baseType = node->gtSIMDBaseType;
199201
instruction ins = INS_invalid;
200202

201-
regNumber op1Reg = op1->gtRegNum;
203+
regNumber op1Reg = REG_NA;
202204
regNumber op2Reg = REG_NA;
205+
regNumber op3Reg = REG_NA;
206+
regNumber op4Reg = REG_NA;
203207
emitter* emit = getEmitter();
204208

205-
genConsumeOperands(node);
209+
if ((op1 != nullptr) && !op1->OperIsList())
210+
{
211+
op1Reg = op1->gtRegNum;
212+
genConsumeOperands(node);
213+
}
206214

207215
switch (intrinsicID)
208216
{
@@ -332,6 +340,19 @@ void CodeGen::genSSEIntrinsic(GenTreeHWIntrinsic* node)
332340
emit->emitIns_SIMD_R_R(INS_rsqrtps, targetReg, op1Reg, TYP_SIMD16);
333341
break;
334342

343+
case NI_SSE_SetAllVector128:
344+
assert(baseType == TYP_FLOAT);
345+
assert(op2 == nullptr);
346+
emit->emitIns_SIMD_R_R_R_I(INS_shufps, targetReg, op1Reg, op1Reg, 0, TYP_SIMD16);
347+
break;
348+
349+
case NI_SSE_SetZeroVector128:
350+
assert(baseType == TYP_FLOAT);
351+
assert(op1 == nullptr);
352+
assert(op2 == nullptr);
353+
emit->emitIns_SIMD_R_R_R(INS_xorps, targetReg, targetReg, targetReg, TYP_SIMD16);
354+
break;
355+
335356
case NI_SSE_Sqrt:
336357
assert(baseType == TYP_FLOAT);
337358
assert(op2 == nullptr);

src/jit/hwintrinsicxarch.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -450,8 +450,29 @@ GenTree* Compiler::impSSEIntrinsic(NamedIntrinsic intrinsic,
450450
GenTree* retNode = nullptr;
451451
GenTree* op1 = nullptr;
452452
GenTree* op2 = nullptr;
453+
GenTree* op3 = nullptr;
454+
GenTree* op4 = nullptr;
455+
453456
switch (intrinsic)
454457
{
458+
case NI_SSE_SetVector128:
459+
{
460+
assert(sig->numArgs == 4);
461+
assert(getBaseTypeOfSIMDType(sig->retTypeSigClass) == TYP_FLOAT);
462+
463+
op4 = impPopStack().val;
464+
op3 = impPopStack().val;
465+
op2 = impPopStack().val;
466+
op1 = impPopStack().val;
467+
468+
GenTree* left = gtNewSimdHWIntrinsicNode(TYP_SIMD16, op4, op3, NI_SSE_UnpackLow, TYP_FLOAT, 16);
469+
GenTree* right = gtNewSimdHWIntrinsicNode(TYP_SIMD16, op2, op1, NI_SSE_UnpackLow, TYP_FLOAT, 16);
470+
GenTree* control = gtNewIconNode(68, TYP_UBYTE);
471+
472+
retNode = gtNewSimdHWIntrinsicNode(TYP_SIMD16, left, right, control, NI_SSE_Shuffle, TYP_FLOAT, 16);
473+
break;
474+
}
475+
455476
case NI_SSE_Add:
456477
case NI_SSE_And:
457478
case NI_SSE_AndNot:
@@ -485,6 +506,13 @@ GenTree* Compiler::impSSEIntrinsic(NamedIntrinsic intrinsic,
485506
retNode = gtNewSimdHWIntrinsicNode(TYP_SIMD16, op1, op2, intrinsic, TYP_FLOAT, 16);
486507
break;
487508

509+
case NI_SSE_SetAllVector128:
510+
assert(sig->numArgs == 1);
511+
assert(getBaseTypeOfSIMDType(sig->retTypeSigClass) == TYP_FLOAT);
512+
op1 = impPopStack().val;
513+
retNode = gtNewSimdHWIntrinsicNode(TYP_SIMD16, op1, intrinsic, TYP_FLOAT, 16);
514+
break;
515+
488516
case NI_SSE_Reciprocal:
489517
case NI_SSE_ReciprocalSqrt:
490518
case NI_SSE_Sqrt:
@@ -494,6 +522,12 @@ GenTree* Compiler::impSSEIntrinsic(NamedIntrinsic intrinsic,
494522
retNode = gtNewSimdHWIntrinsicNode(TYP_SIMD16, op1, intrinsic, TYP_FLOAT, 16);
495523
break;
496524

525+
case NI_SSE_SetZeroVector128:
526+
assert(sig->numArgs == 0);
527+
assert(getBaseTypeOfSIMDType(sig->retTypeSigClass) == TYP_FLOAT);
528+
retNode = gtNewSimdHWIntrinsicNode(TYP_SIMD16, intrinsic, TYP_FLOAT, 16);
529+
break;
530+
497531
default:
498532
JITDUMP("Not implemented hardware intrinsic");
499533
break;

src/jit/lsraxarch.cpp

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2505,31 +2505,63 @@ void LinearScan::TreeNodeInfoInitHWIntrinsic(GenTreeHWIntrinsic* intrinsicTree,
25052505
{
25062506
NamedIntrinsic intrinsicID = intrinsicTree->gtHWIntrinsicId;
25072507
InstructionSet isa = compiler->isaOfHWIntrinsic(intrinsicID);
2508+
25082509
if (isa == InstructionSet_AVX || isa == InstructionSet_AVX2)
25092510
{
25102511
SetContainsAVXFlags(true, 32);
25112512
}
2512-
info->srcCount += GetOperandInfo(intrinsicTree->gtOp.gtOp1);
2513-
if (intrinsicTree->gtGetOp2IfPresent() != nullptr)
2513+
2514+
GenTree* op1 = intrinsicTree->gtOp.gtOp1;
2515+
GenTree* op2 = intrinsicTree->gtOp.gtOp2;
2516+
info->srcCount = 0;
2517+
2518+
if (op1 != nullptr)
2519+
{
2520+
if (op1->OperIsList())
2521+
{
2522+
int srcCount = 0;
2523+
2524+
for (GenTreeArgList* list = op1->AsArgList(); list != nullptr; list = list->Rest())
2525+
{
2526+
GenTree* listItem = list->Current();
2527+
srcCount += GetOperandInfo(listItem);
2528+
}
2529+
2530+
info->srcCount += srcCount;
2531+
}
2532+
else
2533+
{
2534+
info->srcCount += GetOperandInfo(op1);
2535+
}
2536+
}
2537+
if (op2 != nullptr)
25142538
{
2515-
info->srcCount += GetOperandInfo(intrinsicTree->gtOp.gtOp2);
2539+
info->srcCount += GetOperandInfo(op2);
25162540
}
25172541

2518-
#ifdef _TARGET_X86_
2519-
if (intrinsicTree->gtHWIntrinsicId == NI_SSE42_Crc32)
2542+
switch (intrinsicID)
25202543
{
2521-
// CRC32 may operate over "byte" but on x86 only RBM_BYTE_REGS can be used as byte registers.
2522-
//
2523-
// TODO - currently we use the BaseType to bring the type of the second argument
2524-
// to the code generator. May encode the overload info in other way.
2525-
var_types srcType = intrinsicTree->gtSIMDBaseType;
2526-
if (varTypeIsByte(srcType))
2544+
#ifdef _TARGET_X86_
2545+
case NI_SSE42_Crc32:
25272546
{
2528-
LocationInfoListNode* op2Info = useList.GetSecond(INDEBUG(intrinsicTree->gtGetOp2()));
2529-
op2Info->info.setSrcCandidates(this, RBM_BYTE_REGS);
2547+
// CRC32 may operate over "byte" but on x86 only RBM_BYTE_REGS can be used as byte registers.
2548+
//
2549+
// TODO - currently we use the BaseType to bring the type of the second argument
2550+
// to the code generator. May encode the overload info in other way.
2551+
var_types srcType = intrinsicTree->gtSIMDBaseType;
2552+
if (varTypeIsByte(srcType))
2553+
{
2554+
LocationInfoListNode* op2Info = useList.GetSecond(INDEBUG(intrinsicTree->gtGetOp2()));
2555+
op2Info->info.setSrcCandidates(this, RBM_BYTE_REGS);
2556+
}
2557+
break;
25302558
}
2559+
#endif // _TARGET_X86_
2560+
2561+
default:
2562+
assert((intrinsicID > NI_HW_INTRINSIC_START) && (intrinsicID < NI_HW_INTRINSIC_END));
2563+
break;
25312564
}
2532-
#endif
25332565
}
25342566
#endif
25352567

0 commit comments

Comments
 (0)