Skip to content

Commit

Permalink
Adding support for vector constants via GenTreeVecCon (#68874)
Browse files Browse the repository at this point in the history
* Adding support for vector constants via GenTreeVecCon

* Responding to PR feedback

* Support tracking the underlying simdBaseJitType for GenTreeVecCon

* Applying formatting patch

* Handle the scenario where TYP_SIMD8 is retyped to TYP_LONG or TYP_DOUBLE

* Ensure GenTreeVecCon tracks the simdSize so that TYP_SIMD8 ABI retyping still works

* Ensure the create call and not the cloned local is lowered

* Resolving PR feedback

* Ensure morph and rationalize check `OBJ(ADDR(CNS_VEC))`

* Update src/coreclr/jit/gentree.cpp

Co-authored-by: SingleAccretion <[email protected]>

Co-authored-by: SingleAccretion <[email protected]>
  • Loading branch information
tannergooding and SingleAccretion authored May 31, 2022
1 parent 2631413 commit 187bb1f
Show file tree
Hide file tree
Showing 45 changed files with 2,495 additions and 1,487 deletions.
52 changes: 40 additions & 12 deletions src/coreclr/jit/assertionprop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2958,8 +2958,8 @@ GenTree* Compiler::optVNConstantPropOnTree(BasicBlock* block, GenTree* tree)
ValueNumPair vnPair = tree->gtVNPair;
ValueNum vnCns = vnStore->VNConservativeNormalValue(vnPair);

// Check if node evaluates to a constant or Vector.Zero.
if (!vnStore->IsVNConstant(vnCns) && !vnStore->IsVNVectorZero(vnCns))
// Check if node evaluates to a constant
if (!vnStore->IsVNConstant(vnCns))
{
return nullptr;
}
Expand Down Expand Up @@ -3118,23 +3118,52 @@ GenTree* Compiler::optVNConstantPropOnTree(BasicBlock* block, GenTree* tree)
}
break;

#if FEATURE_HW_INTRINSICS
#if FEATURE_SIMD
case TYP_SIMD8:
{
simd8_t value = vnStore->ConstantValue<simd8_t>(vnCns);

GenTreeVecCon* vecCon = gtNewVconNode(tree->TypeGet(), CORINFO_TYPE_FLOAT);
vecCon->gtSimd8Val = value;

conValTree = vecCon;
break;
}

case TYP_SIMD12:
{
simd12_t value = vnStore->ConstantValue<simd12_t>(vnCns);

GenTreeVecCon* vecCon = gtNewVconNode(tree->TypeGet(), CORINFO_TYPE_FLOAT);
vecCon->gtSimd12Val = value;

conValTree = vecCon;
break;
}

case TYP_SIMD16:
{
simd16_t value = vnStore->ConstantValue<simd16_t>(vnCns);

GenTreeVecCon* vecCon = gtNewVconNode(tree->TypeGet(), CORINFO_TYPE_FLOAT);
vecCon->gtSimd16Val = value;

conValTree = vecCon;
break;
}

case TYP_SIMD32:
{
assert(vnStore->IsVNVectorZero(vnCns));
VNSimdTypeInfo vnInfo = vnStore->GetVectorZeroSimdTypeOfVN(vnCns);
simd32_t value = vnStore->ConstantValue<simd32_t>(vnCns);

assert(vnInfo.m_simdBaseJitType != CORINFO_TYPE_UNDEF);
assert(vnInfo.m_simdSize != 0);
assert(getSIMDTypeForSize(vnInfo.m_simdSize) == vnStore->TypeOfVN(vnCns));
GenTreeVecCon* vecCon = gtNewVconNode(tree->TypeGet(), CORINFO_TYPE_FLOAT);
vecCon->gtSimd32Val = value;

conValTree = gtNewSimdZeroNode(tree->TypeGet(), vnInfo.m_simdBaseJitType, vnInfo.m_simdSize, true);
conValTree = vecCon;
break;
}
break;
#endif
#endif // FEATURE_SIMD

case TYP_BYREF:
// Do not support const byref optimization.
Expand Down Expand Up @@ -5608,8 +5637,7 @@ struct VNAssertionPropVisitorInfo
//
GenTree* Compiler::optExtractSideEffListFromConst(GenTree* tree)
{
assert(vnStore->IsVNConstant(vnStore->VNConservativeNormalValue(tree->gtVNPair)) ||
vnStore->IsVNVectorZero(vnStore->VNConservativeNormalValue(tree->gtVNPair)));
assert(vnStore->IsVNConstant(vnStore->VNConservativeNormalValue(tree->gtVNPair)));

GenTree* sideEffList = nullptr;

Expand Down
3 changes: 3 additions & 0 deletions src/coreclr/jit/clrjit.natvis
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ Documentation for VS debugger format specifiers: https://docs.microsoft.com/en-u
<Type Name="GenTreeStrCon">
<DisplayString>CNS_STR</DisplayString>
</Type>
<Type Name="GenTreeVecCon">
<DisplayString>CNS_VEC</DisplayString>
</Type>
<Type Name="GenTreeLngCon">
<DisplayString>{gtTreeID, d}: [[LngCon={((GenTreeLngCon*)this)-&gt;gtLconVal, l}]</DisplayString>
</Type>
Expand Down
5 changes: 5 additions & 0 deletions src/coreclr/jit/codegenarm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,11 @@ void CodeGen::genSetRegToConst(regNumber targetReg, var_types targetType, GenTre
}
break;

case GT_CNS_VEC:
{
unreached();
}

default:
unreached();
}
Expand Down
93 changes: 86 additions & 7 deletions src/coreclr/jit/codegenarm64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2314,6 +2314,77 @@ void CodeGen::genSetRegToConst(regNumber targetReg, var_types targetType, GenTre
}
break;

case GT_CNS_VEC:
{
GenTreeVecCon* vecCon = tree->AsVecCon();

emitter* emit = GetEmitter();
emitAttr attr = emitTypeSize(targetType);

switch (tree->TypeGet())
{
#if defined(FEATURE_SIMD)
case TYP_LONG:
case TYP_DOUBLE:
case TYP_SIMD8:
{
// TODO-1stClassStructs: do not retype SIMD nodes

if (vecCon->IsAllBitsSet())
{
emit->emitIns_R_I(INS_mvni, attr, targetReg, 0, INS_OPTS_2S);
}
else if (vecCon->IsZero())
{
emit->emitIns_R_I(INS_movi, attr, targetReg, 0, INS_OPTS_2S);
}
else
{
// Get a temp integer register to compute long address.
regNumber addrReg = tree->GetSingleTempReg();

simd8_t constValue = vecCon->gtSimd8Val;
CORINFO_FIELD_HANDLE hnd = emit->emitSimd8Const(constValue);

emit->emitIns_R_C(INS_ldr, attr, targetReg, addrReg, hnd, 0);
}
break;
}

case TYP_SIMD12:
case TYP_SIMD16:
{
if (vecCon->IsAllBitsSet())
{
emit->emitIns_R_I(INS_mvni, attr, targetReg, 0, INS_OPTS_4S);
}
else if (vecCon->IsZero())
{
emit->emitIns_R_I(INS_movi, attr, targetReg, 0, INS_OPTS_4S);
}
else
{
// Get a temp integer register to compute long address.
regNumber addrReg = tree->GetSingleTempReg();

simd16_t constValue = vecCon->gtSimd16Val;
CORINFO_FIELD_HANDLE hnd = emit->emitSimd16Const(constValue);

emit->emitIns_R_C(INS_ldr, attr, targetReg, addrReg, hnd, 0);
}
break;
}
#endif // FEATURE_SIMD

default:
{
unreached();
}
}

break;
}

default:
unreached();
}
Expand Down Expand Up @@ -2548,10 +2619,18 @@ void CodeGen::genCodeForStoreLclFld(GenTreeLclFld* tree)
}
else if (data->isContained())
{
assert(data->OperIs(GT_BITCAST));
const GenTree* bitcastSrc = data->AsUnOp()->gtGetOp1();
assert(!bitcastSrc->isContained());
dataReg = bitcastSrc->GetRegNum();
if (data->IsCnsVec())
{
assert(data->AsVecCon()->IsZero());
dataReg = REG_ZR;
}
else
{
assert(data->OperIs(GT_BITCAST));
const GenTree* bitcastSrc = data->AsUnOp()->gtGetOp1();
assert(!bitcastSrc->isContained());
dataReg = bitcastSrc->GetRegNum();
}
}
else
{
Expand Down Expand Up @@ -2629,7 +2708,7 @@ void CodeGen::genCodeForStoreLclVar(GenTreeLclVar* lclNode)
if (data->isContained())
{
// This is only possible for a zero-init or bitcast.
const bool zeroInit = (data->IsIntegralConst(0) || data->IsSIMDZero());
const bool zeroInit = (data->IsIntegralConst(0) || data->IsVectorZero());
assert(zeroInit || data->OperIs(GT_BITCAST));

if (zeroInit && varTypeIsSIMD(targetType))
Expand Down Expand Up @@ -4249,7 +4328,7 @@ void CodeGen::genCodeForCompare(GenTreeOp* tree)
assert(!op1->isContained());
assert(op1Type == op2Type);

if (op2->IsFPZero())
if (op2->IsFloatPositiveZero())
{
assert(op2->isContained());
emit->emitIns_R_F(INS_fcmp, cmpSize, op1->GetRegNum(), 0.0);
Expand Down Expand Up @@ -5088,7 +5167,7 @@ void CodeGen::genStoreLclTypeSIMD12(GenTree* treeNode)
if (op1->isContained())
{
// This is only possible for a zero-init.
assert(op1->IsIntegralConst(0) || op1->IsSIMDZero());
assert(op1->IsIntegralConst(0) || op1->IsVectorZero());

// store lower 8 bytes
GetEmitter()->emitIns_S_R(ins_Store(TYP_DOUBLE), EA_8BYTE, REG_ZR, varNum, offs);
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/jit/codegenarmarch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ void CodeGen::genCodeForTreeNode(GenTree* treeNode)

case GT_CNS_INT:
case GT_CNS_DBL:
case GT_CNS_VEC:
genSetRegToConst(targetReg, targetType, treeNode);
genProduceReg(treeNode);
break;
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/jit/codegenlinear.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1660,7 +1660,7 @@ void CodeGen::genConsumeRegs(GenTree* tree)
#ifdef FEATURE_SIMD
// (In)Equality operation that produces bool result, when compared
// against Vector zero, marks its Vector Zero operand as contained.
assert(tree->OperIsLeaf() || tree->IsSIMDZero() || tree->IsVectorZero());
assert(tree->OperIsLeaf() || tree->IsVectorZero());
#else
assert(tree->OperIsLeaf());
#endif
Expand Down
84 changes: 81 additions & 3 deletions src/coreclr/jit/codegenxarch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -451,8 +451,8 @@ void CodeGen::instGen_Set_Reg_To_Imm(emitAttr size,
/***********************************************************************************
*
* Generate code to set a register 'targetReg' of type 'targetType' to the constant
* specified by the constant (GT_CNS_INT or GT_CNS_DBL) in 'tree'. This does not call
* genProduceReg() on the target register.
* specified by the constant (GT_CNS_INT, GT_CNS_DBL, or GT_CNS_VEC) in 'tree'. This
* does not call genProduceReg() on the target register.
*/
void CodeGen::genSetRegToConst(regNumber targetReg, var_types targetType, GenTree* tree)
{
Expand Down Expand Up @@ -507,6 +507,78 @@ void CodeGen::genSetRegToConst(regNumber targetReg, var_types targetType, GenTre
}
break;

case GT_CNS_VEC:
{
GenTreeVecCon* vecCon = tree->AsVecCon();

emitter* emit = GetEmitter();
emitAttr attr = emitTypeSize(targetType);

if (vecCon->IsAllBitsSet())
{
#if defined(FEATURE_SIMD)
emit->emitIns_SIMD_R_R_R(INS_pcmpeqd, attr, targetReg, targetReg, targetReg);
#else
emit->emitIns_R_R(INS_pcmpeqd, attr, targetReg, targetReg);
#endif // FEATURE_SIMD
break;
}

if (vecCon->IsZero())
{
#if defined(FEATURE_SIMD)
emit->emitIns_SIMD_R_R_R(INS_xorps, attr, targetReg, targetReg, targetReg);
#else
emit->emitIns_R_R(INS_xorps, attr, targetReg, targetReg);
#endif // FEATURE_SIMD
break;
}

switch (tree->TypeGet())
{
#if defined(FEATURE_SIMD)
case TYP_LONG:
case TYP_DOUBLE:
case TYP_SIMD8:
{
// TODO-1stClassStructs: do not retype SIMD nodes

simd8_t constValue = vecCon->gtSimd8Val;
CORINFO_FIELD_HANDLE hnd = emit->emitSimd8Const(constValue);

emit->emitIns_R_C(ins_Load(targetType), attr, targetReg, hnd, 0);
break;
}

case TYP_SIMD12:
case TYP_SIMD16:
{
simd16_t constValue = vecCon->gtSimd16Val;
CORINFO_FIELD_HANDLE hnd = emit->emitSimd16Const(constValue);

emit->emitIns_R_C(ins_Load(targetType), attr, targetReg, hnd, 0);
break;
}

case TYP_SIMD32:
{
simd32_t constValue = vecCon->gtSimd32Val;
CORINFO_FIELD_HANDLE hnd = emit->emitSimd32Const(constValue);

emit->emitIns_R_C(ins_Load(targetType), attr, targetReg, hnd, 0);
break;
}
#endif // FEATURE_SIMD

default:
{
unreached();
}
}

break;
}

default:
unreached();
}
Expand Down Expand Up @@ -1495,6 +1567,11 @@ void CodeGen::genCodeForTreeNode(GenTree* treeNode)
genProduceReg(treeNode);
break;

case GT_CNS_VEC:
genSetRegToConst(targetReg, targetType, treeNode);
genProduceReg(treeNode);
break;

case GT_NOT:
case GT_NEG:
genCodeForNegNot(treeNode);
Expand Down Expand Up @@ -4858,7 +4935,8 @@ void CodeGen::genCodeForStoreLclVar(GenTreeLclVar* lclNode)
// zero in the target register, because an xor is smaller than a copy. Note that we could
// potentially handle this in the register allocator, but we can't always catch it there
// because the target may not have a register allocated for it yet.
if (op1->isUsedFromReg() && (op1->GetRegNum() != targetReg) && (op1->IsIntegralConst(0) || op1->IsFPZero()))
if (op1->isUsedFromReg() && (op1->GetRegNum() != targetReg) &&
(op1->IsIntegralConst(0) || op1->IsFloatPositiveZero()))
{
op1->SetRegNum(REG_NA);
op1->ResetReuseRegVal();
Expand Down
Loading

0 comments on commit 187bb1f

Please sign in to comment.