Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Stop using LIST nodes for SIMD operand lists #1141

Closed
wants to merge 14 commits into from
Closed
71 changes: 37 additions & 34 deletions src/coreclr/src/jit/codegenarm64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4080,13 +4080,13 @@ void CodeGen::genSIMDIntrinsicInit(GenTreeSIMD* simdNode)
{
assert(simdNode->gtSIMDIntrinsicID == SIMDIntrinsicInit);

GenTree* op1 = simdNode->gtGetOp1();
GenTree* op1 = simdNode->GetOp(0);
var_types baseType = simdNode->gtSIMDBaseType;
regNumber targetReg = simdNode->GetRegNum();
assert(targetReg != REG_NA);
var_types targetType = simdNode->TypeGet();

genConsumeOperands(simdNode);
genConsumeRegs(op1);
regNumber op1Reg = op1->IsIntegralConst(0) ? REG_ZR : op1->GetRegNum();

// TODO-ARM64-CQ Add LD1R to allow SIMDIntrinsicInit from contained memory
Expand Down Expand Up @@ -4149,14 +4149,11 @@ void CodeGen::genSIMDIntrinsicInitN(GenTreeSIMD* simdNode)
// and record the registers.
regNumber operandRegs[FP_REGSIZE_BYTES];
unsigned initCount = 0;
for (GenTree* list = simdNode->gtGetOp1(); list != nullptr; list = list->gtGetOp2())
{
assert(list->OperGet() == GT_LIST);
GenTree* listItem = list->gtGetOp1();
assert(listItem->TypeGet() == baseType);
assert(!listItem->isContained());
regNumber operandReg = genConsumeReg(listItem);
operandRegs[initCount] = operandReg;
for (GenTreeSIMD::Use& use : simdNode->Uses())
{
assert(use.GetNode()->TypeGet() == baseType);
assert(!use.GetNode()->isContained());
operandRegs[initCount] = genConsumeReg(use.GetNode());
initCount++;
}

Expand Down Expand Up @@ -4209,13 +4206,13 @@ void CodeGen::genSIMDIntrinsicUnOp(GenTreeSIMD* simdNode)
simdNode->gtSIMDIntrinsicID == SIMDIntrinsicConvertToDouble ||
simdNode->gtSIMDIntrinsicID == SIMDIntrinsicConvertToInt64);

GenTree* op1 = simdNode->gtGetOp1();
GenTree* op1 = simdNode->GetOp(0);
var_types baseType = simdNode->gtSIMDBaseType;
regNumber targetReg = simdNode->GetRegNum();
assert(targetReg != REG_NA);
var_types targetType = simdNode->TypeGet();

genConsumeOperands(simdNode);
genConsumeRegs(op1);
regNumber op1Reg = op1->GetRegNum();

assert(genIsValidFloatReg(op1Reg));
Expand Down Expand Up @@ -4244,13 +4241,13 @@ void CodeGen::genSIMDIntrinsicWiden(GenTreeSIMD* simdNode)
assert((simdNode->gtSIMDIntrinsicID == SIMDIntrinsicWidenLo) ||
(simdNode->gtSIMDIntrinsicID == SIMDIntrinsicWidenHi));

GenTree* op1 = simdNode->gtGetOp1();
GenTree* op1 = simdNode->GetOp(0);
var_types baseType = simdNode->gtSIMDBaseType;
regNumber targetReg = simdNode->GetRegNum();
assert(targetReg != REG_NA);
var_types simdType = simdNode->TypeGet();

genConsumeOperands(simdNode);
genConsumeRegs(op1);
regNumber op1Reg = op1->GetRegNum();
regNumber srcReg = op1Reg;
emitAttr emitSize = emitActualTypeSize(simdType);
Expand Down Expand Up @@ -4286,15 +4283,16 @@ void CodeGen::genSIMDIntrinsicNarrow(GenTreeSIMD* simdNode)
{
assert(simdNode->gtSIMDIntrinsicID == SIMDIntrinsicNarrow);

GenTree* op1 = simdNode->gtGetOp1();
GenTree* op2 = simdNode->gtGetOp2();
GenTree* op1 = simdNode->GetOp(0);
GenTree* op2 = simdNode->GetOp(1);
var_types baseType = simdNode->gtSIMDBaseType;
regNumber targetReg = simdNode->GetRegNum();
assert(targetReg != REG_NA);
var_types simdType = simdNode->TypeGet();
emitAttr emitSize = emitTypeSize(simdType);

genConsumeOperands(simdNode);
genConsumeRegs(op1);
genConsumeRegs(op2);
regNumber op1Reg = op1->GetRegNum();
regNumber op2Reg = op2->GetRegNum();

Expand Down Expand Up @@ -4372,14 +4370,15 @@ void CodeGen::genSIMDIntrinsicBinOp(GenTreeSIMD* simdNode)
simdNode->gtSIMDIntrinsicID == SIMDIntrinsicLessThanOrEqual ||
simdNode->gtSIMDIntrinsicID == SIMDIntrinsicGreaterThanOrEqual);

GenTree* op1 = simdNode->gtGetOp1();
GenTree* op2 = simdNode->gtGetOp2();
GenTree* op1 = simdNode->GetOp(0);
GenTree* op2 = simdNode->GetOp(1);
var_types baseType = simdNode->gtSIMDBaseType;
regNumber targetReg = simdNode->GetRegNum();
assert(targetReg != REG_NA);
var_types targetType = simdNode->TypeGet();

genConsumeOperands(simdNode);
genConsumeRegs(op1);
genConsumeRegs(op2);
regNumber op1Reg = op1->GetRegNum();
regNumber op2Reg = op2->GetRegNum();

Expand Down Expand Up @@ -4413,13 +4412,14 @@ void CodeGen::genSIMDIntrinsicRelOp(GenTreeSIMD* simdNode)
assert(simdNode->gtSIMDIntrinsicID == SIMDIntrinsicOpEquality ||
simdNode->gtSIMDIntrinsicID == SIMDIntrinsicOpInEquality);

GenTree* op1 = simdNode->gtGetOp1();
GenTree* op2 = simdNode->gtGetOp2();
GenTree* op1 = simdNode->GetOp(0);
GenTree* op2 = simdNode->GetOp(1);
var_types baseType = simdNode->gtSIMDBaseType;
regNumber targetReg = simdNode->GetRegNum();
var_types targetType = simdNode->TypeGet();

genConsumeOperands(simdNode);
genConsumeRegs(op1);
genConsumeRegs(op2);
regNumber op1Reg = op1->GetRegNum();
regNumber op2Reg = op2->GetRegNum();
regNumber otherReg = op2Reg;
Expand Down Expand Up @@ -4470,8 +4470,8 @@ void CodeGen::genSIMDIntrinsicDotProduct(GenTreeSIMD* simdNode)
{
assert(simdNode->gtSIMDIntrinsicID == SIMDIntrinsicDotProduct);

GenTree* op1 = simdNode->gtGetOp1();
GenTree* op2 = simdNode->gtGetOp2();
GenTree* op1 = simdNode->GetOp(0);
GenTree* op2 = simdNode->GetOp(1);
var_types baseType = simdNode->gtSIMDBaseType;
var_types simdType = op1->TypeGet();

Expand All @@ -4481,7 +4481,8 @@ void CodeGen::genSIMDIntrinsicDotProduct(GenTreeSIMD* simdNode)
var_types targetType = simdNode->TypeGet();
assert(targetType == baseType);

genConsumeOperands(simdNode);
genConsumeRegs(op1);
genConsumeRegs(op2);
regNumber op1Reg = op1->GetRegNum();
regNumber op2Reg = op2->GetRegNum();
regNumber tmpReg = targetReg;
Expand Down Expand Up @@ -4554,8 +4555,8 @@ void CodeGen::genSIMDIntrinsicGetItem(GenTreeSIMD* simdNode)
{
assert(simdNode->gtSIMDIntrinsicID == SIMDIntrinsicGetItem);

GenTree* op1 = simdNode->gtGetOp1();
GenTree* op2 = simdNode->gtGetOp2();
GenTree* op1 = simdNode->GetOp(0);
GenTree* op2 = simdNode->GetOp(1);
var_types simdType = op1->TypeGet();
assert(varTypeIsSIMD(simdType));

Expand All @@ -4574,7 +4575,8 @@ void CodeGen::genSIMDIntrinsicGetItem(GenTreeSIMD* simdNode)
// GetItem has 2 operands:
// - the source of SIMD type (op1)
// - the index of the value to be returned.
genConsumeOperands(simdNode);
genConsumeRegs(op1);
genConsumeRegs(op2);

emitAttr baseTypeSize = emitTypeSize(baseType);
unsigned baseTypeScale = genLog2(EA_SIZE_IN_BYTES(baseTypeSize));
Expand Down Expand Up @@ -4739,8 +4741,8 @@ void CodeGen::genSIMDIntrinsicSetItem(GenTreeSIMD* simdNode)

// op1 is the SIMD vector
// op2 is the value to be set
GenTree* op1 = simdNode->gtGetOp1();
GenTree* op2 = simdNode->gtGetOp2();
GenTree* op1 = simdNode->GetOp(0);
GenTree* op2 = simdNode->GetOp(1);

var_types baseType = simdNode->gtSIMDBaseType;
regNumber targetReg = simdNode->GetRegNum();
Expand All @@ -4751,7 +4753,8 @@ void CodeGen::genSIMDIntrinsicSetItem(GenTreeSIMD* simdNode)
assert(op2->TypeGet() == baseType);
assert(simdNode->gtSIMDSize >= ((index + 1) * genTypeSize(baseType)));

genConsumeOperands(simdNode);
genConsumeRegs(op1);
genConsumeRegs(op2);
regNumber op1Reg = op1->GetRegNum();
regNumber op2Reg = op2->GetRegNum();

Expand Down Expand Up @@ -4799,7 +4802,7 @@ void CodeGen::genSIMDIntrinsicUpperSave(GenTreeSIMD* simdNode)
{
assert(simdNode->gtSIMDIntrinsicID == SIMDIntrinsicUpperSave);

GenTree* op1 = simdNode->gtGetOp1();
GenTree* op1 = simdNode->GetOp(0);
assert(op1->IsLocal());
assert(emitTypeSize(op1->TypeGet()) == 16);
regNumber targetReg = simdNode->GetRegNum();
Expand Down Expand Up @@ -4848,7 +4851,7 @@ void CodeGen::genSIMDIntrinsicUpperRestore(GenTreeSIMD* simdNode)
{
assert(simdNode->gtSIMDIntrinsicID == SIMDIntrinsicUpperRestore);

GenTree* op1 = simdNode->gtGetOp1();
GenTree* op1 = simdNode->GetOp(0);
assert(op1->IsLocal());
assert(emitTypeSize(op1->TypeGet()) == 16);
regNumber srcReg = simdNode->GetRegNum();
Expand Down
39 changes: 37 additions & 2 deletions src/coreclr/src/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -2553,9 +2553,15 @@ class Compiler

#ifdef FEATURE_SIMD
GenTreeSIMD* gtNewSIMDNode(
var_types type, GenTree* op1, SIMDIntrinsicID simdIntrinsicID, var_types baseType, unsigned size);
var_types type, SIMDIntrinsicID simdIntrinsicID, var_types baseType, unsigned size, GenTree* op1);
GenTreeSIMD* gtNewSIMDNode(
var_types type, GenTree* op1, GenTree* op2, SIMDIntrinsicID simdIntrinsicID, var_types baseType, unsigned size);
var_types type, SIMDIntrinsicID simdIntrinsicID, var_types baseType, unsigned size, GenTree* op1, GenTree* op2);
GenTreeSIMD* gtNewSIMDNode(var_types type,
SIMDIntrinsicID simdIntrinsicID,
var_types baseType,
unsigned size,
unsigned numOps,
GenTree** ops);
void SetOpLclRelatedToSIMDIntrinsic(GenTree* op);
#endif

Expand Down Expand Up @@ -10011,6 +10017,35 @@ class GenTreeVisitor
}
break;

#ifdef FEATURE_SIMD
case GT_SIMD:
if (TVisitor::UseExecutionOrder && node->AsSIMD()->IsBinary() && node->IsReverseOp())
{
result = WalkTree(&node->AsSIMD()->GetUse(1).NodeRef(), node);
if (result == fgWalkResult::WALK_ABORT)
{
return result;
}
result = WalkTree(&node->AsSIMD()->GetUse(0).NodeRef(), node);
if (result == fgWalkResult::WALK_ABORT)
{
return result;
}
}
else
{
for (GenTreeSIMD::Use& use : node->AsSIMD()->Uses())
{
result = WalkTree(&use.NodeRef(), node);
if (result == fgWalkResult::WALK_ABORT)
{
return result;
}
}
}
break;
#endif

case GT_CMPXCHG:
{
GenTreeCmpXchg* const cmpXchg = node->AsCmpXchg();
Expand Down
26 changes: 12 additions & 14 deletions src/coreclr/src/jit/compiler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4280,20 +4280,6 @@ void GenTree::VisitOperands(TVisitor visitor)
return;

// Variadic nodes
#ifdef FEATURE_SIMD
case GT_SIMD:
if (this->AsSIMD()->gtSIMDIntrinsicID == SIMDIntrinsicInitN)
{
assert(this->AsSIMD()->gtOp1 != nullptr);
this->AsSIMD()->gtOp1->VisitListOperands(visitor);
}
else
{
VisitBinOpOperands<TVisitor>(visitor);
}
return;
#endif // FEATURE_SIMD

#ifdef FEATURE_HW_INTRINSICS
case GT_HWINTRINSIC:
if ((this->AsHWIntrinsic()->gtOp1 != nullptr) && this->AsHWIntrinsic()->gtOp1->OperIsList())
Expand Down Expand Up @@ -4328,6 +4314,18 @@ void GenTree::VisitOperands(TVisitor visitor)
}
return;

#ifdef FEATURE_SIMD
case GT_SIMD:
for (GenTreeSIMD::Use& use : AsSIMD()->Uses())
{
if (visitor(use.GetNode()) == VisitResult::Abort)
{
break;
}
}
return;
#endif // FEATURE_SIMD

case GT_CMPXCHG:
{
GenTreeCmpXchg* const cmpXchg = this->AsCmpXchg();
Expand Down
20 changes: 10 additions & 10 deletions src/coreclr/src/jit/decomposelongs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1701,17 +1701,17 @@ GenTree* DecomposeLongs::DecomposeSimdGetItem(LIR::Use& use)
assert(simdTree->gtSIMDIntrinsicID == SIMDIntrinsicGetItem);
assert(varTypeIsLong(baseType));
assert(varTypeIsLong(simdTree));
assert(varTypeIsSIMD(simdTree->AsOp()->gtOp1->gtType));
assert(simdTree->AsOp()->gtOp2->gtType == TYP_INT);
assert(varTypeIsSIMD(simdTree->GetOp(0)->TypeGet()));
assert(simdTree->GetOp(1)->TypeGet() == TYP_INT);

bool indexIsConst = simdTree->AsOp()->gtOp2->IsCnsIntOrI();
bool indexIsConst = simdTree->GetOp(1)->IsCnsIntOrI();
ssize_t index = 0;
if (indexIsConst)
{
index = simdTree->AsOp()->gtOp2->AsIntCon()->gtIconVal;
index = simdTree->GetOp(1)->AsIntCon()->gtIconVal;
}

GenTree* simdTmpVar = RepresentOpAsLocalVar(simdTree->AsOp()->gtOp1, simdTree, &simdTree->AsOp()->gtOp1);
GenTree* simdTmpVar = RepresentOpAsLocalVar(simdTree->GetOp(0), simdTree, &simdTree->GetUse(0).NodeRef());
unsigned simdTmpVarNum = simdTmpVar->AsLclVarCommon()->GetLclNum();
JITDUMP("[DecomposeSimdGetItem]: Saving op1 tree to a temp var:\n");
DISPTREERANGE(Range(), simdTmpVar);
Expand All @@ -1721,7 +1721,7 @@ GenTree* DecomposeLongs::DecomposeSimdGetItem(LIR::Use& use)
unsigned indexTmpVarNum = 0;
if (!indexIsConst)
{
indexTmpVar = RepresentOpAsLocalVar(simdTree->AsOp()->gtOp2, simdTree, &simdTree->AsOp()->gtOp2);
indexTmpVar = RepresentOpAsLocalVar(simdTree->GetOp(1), simdTree, &simdTree->GetUse(1).NodeRef());
indexTmpVarNum = indexTmpVar->AsLclVarCommon()->GetLclNum();
JITDUMP("[DecomposeSimdGetItem]: Saving op2 tree to a temp var:\n");
DISPTREERANGE(Range(), indexTmpVar);
Expand All @@ -1737,7 +1737,7 @@ GenTree* DecomposeLongs::DecomposeSimdGetItem(LIR::Use& use)
if (indexIsConst)
{
// Reuse the existing index constant node.
indexTimesTwo1 = simdTree->AsOp()->gtOp2;
indexTimesTwo1 = simdTree->GetOp(1);
Range().Remove(indexTimesTwo1);
indexTimesTwo1->AsIntCon()->gtIconVal = index * 2;

Expand All @@ -1752,13 +1752,13 @@ GenTree* DecomposeLongs::DecomposeSimdGetItem(LIR::Use& use)
}

GenTree* loResult =
m_compiler->gtNewSIMDNode(TYP_INT, simdTmpVar1, indexTimesTwo1, SIMDIntrinsicGetItem, TYP_INT, simdSize);
m_compiler->gtNewSIMDNode(TYP_INT, SIMDIntrinsicGetItem, TYP_INT, simdSize, simdTmpVar1, indexTimesTwo1);
Range().InsertBefore(simdTree, loResult);

// Create:
// hiResult = GT_SIMD{get_item}[int](tmp_simd_var, index * 2 + 1)

GenTree* simdTmpVar2 = m_compiler->gtNewLclLNode(simdTmpVarNum, simdTree->AsOp()->gtOp1->gtType);
GenTree* simdTmpVar2 = m_compiler->gtNewLclLNode(simdTmpVarNum, simdTree->GetOp(0)->TypeGet());
GenTree* indexTimesTwoPlusOne;

if (indexIsConst)
Expand All @@ -1778,7 +1778,7 @@ GenTree* DecomposeLongs::DecomposeSimdGetItem(LIR::Use& use)
}

GenTree* hiResult =
m_compiler->gtNewSIMDNode(TYP_INT, simdTmpVar2, indexTimesTwoPlusOne, SIMDIntrinsicGetItem, TYP_INT, simdSize);
m_compiler->gtNewSIMDNode(TYP_INT, SIMDIntrinsicGetItem, TYP_INT, simdSize, simdTmpVar2, indexTimesTwoPlusOne);
Range().InsertBefore(simdTree, hiResult);

// Done with the original tree; remove it.
Expand Down
Loading