Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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