Skip to content

Commit c375121

Browse files
committed
Update fgMorphHWIntrinsic to more closely follow fgMorphSmpOp
1 parent f124c0e commit c375121

File tree

2 files changed

+137
-68
lines changed

2 files changed

+137
-68
lines changed

src/coreclr/jit/compiler.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6691,6 +6691,8 @@ class Compiler
66916691
GenTree* fgOptimizeRelationalComparisonWithFullRangeConst(GenTreeOp* cmp);
66926692
#if defined(FEATURE_HW_INTRINSICS)
66936693
GenTree* fgMorphHWIntrinsic(GenTreeHWIntrinsic* tree);
6694+
GenTree* fgMorphHWIntrinsicRequired(GenTreeHWIntrinsic* tree);
6695+
GenTree* fgMorphHWIntrinsicOptional(GenTreeHWIntrinsic* tree);
66946696
GenTree* fgOptimizeHWIntrinsic(GenTreeHWIntrinsic* node);
66956697
GenTree* fgOptimizeHWIntrinsicAssociative(GenTreeHWIntrinsic* node);
66966698
#if defined(FEATURE_MASKED_HW_INTRINSICS)

src/coreclr/jit/morph.cpp

Lines changed: 135 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -10938,6 +10938,20 @@ GenTree* Compiler::fgMorphSmpOpOptional(GenTreeOp* tree, bool* optAssertionPropD
1093810938
//
1093910939
GenTree* Compiler::fgMorphHWIntrinsic(GenTreeHWIntrinsic* tree)
1094010940
{
10941+
// It is important that this follows the general flow of fgMorphSmpOp
10942+
// * Perform required preorder processing
10943+
// * Process the operands, in order, if any
10944+
// * Perform required postorder morphing
10945+
// * Perform optional postorder morphing if optimizing
10946+
//
10947+
// It is also important that similar checks be done where relevant, so
10948+
// if fgMorphSmpOp does a check for fgGlobalMorph or OptimizationEnabled
10949+
// so should this method.
10950+
10951+
// ------------------------------------------------------------------------
10952+
// First do any PRE-ORDER processing
10953+
//
10954+
1094110955
bool allArgsAreConst = true;
1094210956
bool canBenefitFromConstantProp = false;
1094310957
bool hasImmediateOperand = false;
@@ -10955,6 +10969,18 @@ GenTree* Compiler::fgMorphHWIntrinsic(GenTreeHWIntrinsic* tree)
1095510969
hasImmediateOperand = true;
1095610970
}
1095710971

10972+
#ifdef TARGET_XARCH
10973+
if (intrinsicId == NI_Vector128_op_Division || intrinsicId == NI_Vector256_op_Division)
10974+
{
10975+
fgAddCodeRef(compCurBB, SCK_DIV_BY_ZERO);
10976+
fgAddCodeRef(compCurBB, SCK_OVERFLOW);
10977+
}
10978+
#endif // TARGET_XARCH
10979+
10980+
// ------------------------------------------------------------------------
10981+
// Process the operands, if any
10982+
//
10983+
1095810984
for (GenTree** use : tree->UseEdges())
1095910985
{
1096010986
*use = fgMorphTree(*use);
@@ -11004,102 +11030,143 @@ GenTree* Compiler::fgMorphHWIntrinsic(GenTreeHWIntrinsic* tree)
1100411030
tree->AddAllEffectsFlags(operand);
1100511031
}
1100611032

11007-
#ifdef TARGET_XARCH
11008-
if (intrinsicId == NI_Vector128_op_Division || intrinsicId == NI_Vector256_op_Division)
11033+
// ------------------------------------------------------------------------
11034+
// Now do POST-ORDER processing
11035+
//
11036+
11037+
var_types retType = tree->TypeGet();
11038+
CorInfoType simdBaseJitType = tree->GetSimdBaseJitType();
11039+
var_types simdBaseType = tree->GetSimdBaseType();
11040+
unsigned simdSize = tree->GetSimdSize();
11041+
11042+
// Try to fold it, maybe we get lucky,
11043+
GenTree* morphedTree = gtFoldExpr(tree);
11044+
11045+
if ((morphedTree != tree) || !morphedTree->OperIsHWIntrinsic())
1100911046
{
11010-
fgAddCodeRef(compCurBB, SCK_DIV_BY_ZERO);
11011-
fgAddCodeRef(compCurBB, SCK_OVERFLOW);
11047+
assert(!fgIsCommaThrow(morphedTree));
11048+
morphedTree->SetMorphed(this);
1101211049
}
11013-
#endif // TARGET_XARCH
11014-
11015-
if (opts.OptimizationEnabled())
11050+
else
1101611051
{
11017-
var_types retType = tree->TypeGet();
11018-
CorInfoType simdBaseJitType = tree->GetSimdBaseJitType();
11019-
var_types simdBaseType = tree->GetSimdBaseType();
11020-
unsigned simdSize = tree->GetSimdSize();
11021-
11022-
if (tree->isCommutativeHWIntrinsic())
11052+
if (allArgsAreConst && tree->IsVectorCreate())
1102311053
{
11024-
assert(tree->GetOperandCount() == 2);
11025-
GenTree*& op1 = tree->Op(1);
11054+
// Avoid unexpected CSE for constant arguments for Vector_.Create
11055+
// but only if all arguments are constants.
1102611056

11027-
if (op1->IsCnsVec())
11057+
for (GenTree* arg : tree->Operands())
1102811058
{
11029-
// Move constant vectors from op1 to op2 for commutative operations
11030-
std::swap(op1, tree->Op(2));
11059+
arg->SetDoNotCSE();
1103111060
}
1103211061
}
11033-
else
11034-
{
11035-
bool isScalar = false;
11036-
genTreeOps oper = tree->GetOperForHWIntrinsicId(&isScalar);
1103711062

11038-
// We can't handle scalar operations since they can copy upper bits from op1
11039-
if (GenTree::OperIsCompare(oper) && !isScalar)
11040-
{
11041-
assert(tree->GetOperandCount() == 2);
11063+
// ------------------------------------------------------------------------
11064+
// Perform the required oper-specific postorder morphing
11065+
//
1104211066

11043-
GenTree* op1 = tree->Op(1);
11044-
GenTree* op2 = tree->Op(2);
11067+
morphedTree = fgMorphHWIntrinsicRequired(tree);
1104511068

11046-
if (op1->IsCnsVec())
11047-
{
11048-
// Move constant vectors from op1 to op2 for comparison operations
11069+
// ------------------------------------------------------------------------
11070+
// Optional morphing is done if tree transformations is permitted
11071+
//
1104911072

11050-
genTreeOps newOper = GenTree::SwapRelop(oper);
11051-
var_types lookupType =
11052-
GenTreeHWIntrinsic::GetLookupTypeForCmpOp(this, newOper, retType, simdBaseType, simdSize);
11053-
NamedIntrinsic newId =
11054-
GenTreeHWIntrinsic::GetHWIntrinsicIdForCmpOp(this, newOper, retType, op2, op1, simdBaseType,
11055-
simdSize, false);
11073+
if ((opts.compFlags & CLFLG_TREETRANS) != 0)
11074+
{
11075+
morphedTree = fgMorphHWIntrinsicOptional(morphedTree->AsHWIntrinsic());
11076+
}
11077+
}
1105611078

11057-
if (newId != NI_Illegal)
11058-
{
11059-
tree->ResetHWIntrinsicId(newId, op2, op1);
11079+
if (retType != morphedTree->TypeGet())
11080+
{
11081+
assert(varTypeIsMask(morphedTree));
11082+
morphedTree = gtNewSimdCvtMaskToVectorNode(retType, morphedTree, simdBaseJitType, simdSize);
11083+
morphedTree = gtFoldExpr(morphedTree);
11084+
}
11085+
return morphedTree;
11086+
}
1106011087

11061-
if (lookupType != retType)
11062-
{
11063-
assert(varTypeIsMask(lookupType));
11064-
tree->gtType = lookupType;
11065-
}
11066-
}
11067-
}
11068-
}
11069-
}
11088+
//------------------------------------------------------------------------
11089+
// fgMorphHWIntrinsicRequired: Perform required postorder morphing of a GenTreeHWIntrinsic tree.
11090+
//
11091+
// Arguments:
11092+
// tree - The tree to morph
11093+
//
11094+
// Return Value:
11095+
// The morphed tree.
11096+
//
11097+
GenTree* Compiler::fgMorphHWIntrinsicRequired(GenTreeHWIntrinsic* tree)
11098+
{
11099+
var_types retType = tree->TypeGet();
11100+
CorInfoType simdBaseJitType = tree->GetSimdBaseJitType();
11101+
var_types simdBaseType = tree->GetSimdBaseType();
11102+
unsigned simdSize = tree->GetSimdSize();
1107011103

11071-
// Try to fold it, maybe we get lucky,
11072-
GenTree* morphedTree = gtFoldExpr(tree);
11104+
if (tree->isCommutativeHWIntrinsic())
11105+
{
11106+
assert(tree->GetOperandCount() == 2);
11107+
GenTree*& op1 = tree->Op(1);
1107311108

11074-
if ((morphedTree != tree) || !morphedTree->OperIsHWIntrinsic())
11109+
if (op1->OperIsConst())
1107511110
{
11076-
morphedTree->SetMorphed(this);
11111+
// Move constants from op1 to op2 for commutative operations
11112+
std::swap(op1, tree->Op(2));
1107711113
}
11078-
else
11114+
}
11115+
else
11116+
{
11117+
bool isScalar = false;
11118+
genTreeOps oper = tree->GetOperForHWIntrinsicId(&isScalar);
11119+
11120+
// We can't handle scalar operations since they can copy upper bits from op1
11121+
if (GenTree::OperIsCompare(oper) && !isScalar)
1107911122
{
11080-
if (allArgsAreConst && tree->IsVectorCreate())
11123+
assert(tree->GetOperandCount() == 2);
11124+
11125+
GenTree* op1 = tree->Op(1);
11126+
GenTree* op2 = tree->Op(2);
11127+
11128+
if (op1->IsCnsVec())
1108111129
{
11082-
// Avoid unexpected CSE for constant arguments for Vector_.Create
11083-
// but only if all arguments are constants.
11130+
// Move constant vectors from op1 to op2 for comparison operations
11131+
11132+
genTreeOps newOper = GenTree::SwapRelop(oper);
11133+
var_types lookupType =
11134+
GenTreeHWIntrinsic::GetLookupTypeForCmpOp(this, newOper, retType, simdBaseType, simdSize);
11135+
NamedIntrinsic newId = GenTreeHWIntrinsic::GetHWIntrinsicIdForCmpOp(this, newOper, retType, op2, op1,
11136+
simdBaseType, simdSize, false);
1108411137

11085-
for (GenTree* arg : tree->Operands())
11138+
if (newId != NI_Illegal)
1108611139
{
11087-
arg->SetDoNotCSE();
11140+
tree->ResetHWIntrinsicId(newId, op2, op1);
11141+
11142+
if (lookupType != retType)
11143+
{
11144+
assert(varTypeIsMask(lookupType));
11145+
tree->gtType = lookupType;
11146+
}
1108811147
}
1108911148
}
11090-
11091-
morphedTree = fgOptimizeHWIntrinsic(tree);
1109211149
}
11150+
}
1109311151

11094-
if (retType != morphedTree->TypeGet())
11095-
{
11096-
assert(varTypeIsMask(morphedTree));
11097-
morphedTree = gtNewSimdCvtMaskToVectorNode(retType, morphedTree, simdBaseJitType, simdSize);
11098-
morphedTree = gtFoldExpr(morphedTree);
11099-
}
11100-
return morphedTree;
11152+
if (opts.OptimizationEnabled())
11153+
{
11154+
return fgOptimizeHWIntrinsic(tree);
1110111155
}
11156+
return tree;
11157+
}
1110211158

11159+
//------------------------------------------------------------------------
11160+
// fgMorphHWIntrinsicOptional: Perform optional postorder morphing of a GenTreeHWIntrinsic tree.
11161+
//
11162+
// Arguments:
11163+
// tree - The tree to morph
11164+
//
11165+
// Return Value:
11166+
// The morphed tree.
11167+
//
11168+
GenTree* Compiler::fgMorphHWIntrinsicOptional(GenTreeHWIntrinsic* tree)
11169+
{
1110311170
return tree;
1110411171
}
1110511172
#endif // FEATURE_HW_INTRINSICS

0 commit comments

Comments
 (0)