Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
68 changes: 68 additions & 0 deletions src/coreclr/jit/assertionprop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,68 @@ static Range GetRange(Compiler* comp, GenTree* tree, BasicBlock* block, ASSERT_V
return Limit(Limit::keUnknown);
}

#if defined(FEATURE_HW_INTRINSICS) && defined(TARGET_ARM64)
//----------------------------------------------------------------------------------------------
// optAssertionProp_HWIntrinsic: Propagate VN-derived facts to local var metadata.
//
// Arguments:
// comp - The compiler instance
// tree - The hwintrinsic node
//
static void optAssertionProp_HWIntrinsic(Compiler* comp, GenTreeHWIntrinsic* tree)
{
NamedIntrinsic intrinsic = tree->GetHWIntrinsicId();

if ((intrinsic != NI_Vector64_ExtractMostSignificantBits) && (intrinsic != NI_Vector128_ExtractMostSignificantBits))
{
return;
}

assert(tree->GetOperandCount() == 1);

GenTree* op1 = tree->Op(1);

if (!op1->OperIs(GT_LCL_VAR))
{
return;
}

LclVarDsc* varDsc = comp->lvaGetDesc(op1->AsLclVar());

if (!varDsc->lvSingleDef)
{
return;
}

ValueNum op1VN = comp->vnStore->VNConservativeNormalValue(op1->gtVNPair);

auto vnVisitor = [comp, tree](ValueNum vn) -> ValueNumStore::VNVisit {
if (vn == ValueNumStore::NoVN)
{
return ValueNumStore::VNVisit::Abort;
}

vn = comp->vnStore->VNNormalValue(vn);
var_types type = comp->vnStore->TypeOfVN(vn);
unsigned simdSize = tree->GetSimdSize();

if (!varTypeIsSIMD(type) || (genTypeSize(type) != simdSize))
{
return ValueNumStore::VNVisit::Abort;
}

return comp->vnStore->IsVectorPerElementMask(vn, tree->GetSimdBaseType(), simdSize)
? ValueNumStore::VNVisit::Continue
: ValueNumStore::VNVisit::Abort;
};

if (comp->vnStore->VNVisitReachingVNs(op1VN, vnVisitor) == ValueNumStore::VNVisit::Continue)
{
varDsc->SetIsVectorPerElementMask(tree->GetSimdBaseType());
}
}
#endif // FEATURE_HW_INTRINSICS && TARGET_ARM64

//------------------------------------------------------------------------
// SymbolicToRealValue: Convert a symbolic value to a 64-bit signed integer.
//
Expand Down Expand Up @@ -5822,6 +5884,12 @@ GenTree* Compiler::optAssertionProp(ASSERT_VALARG_TP assertions, GenTree* tree,
case GT_CALL:
return optAssertionProp_Call(assertions, tree->AsCall(), stmt);

#if defined(FEATURE_HW_INTRINSICS) && defined(TARGET_ARM64)
case GT_HWINTRINSIC:
optAssertionProp_HWIntrinsic(this, tree->AsHWIntrinsic());
return nullptr;
#endif // FEATURE_HW_INTRINSICS && TARGET_ARM64

case GT_EQ:
case GT_NE:
case GT_LT:
Expand Down
57 changes: 56 additions & 1 deletion src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -668,6 +668,9 @@ class LclVarDsc

unsigned char lvIsSpan : 1; // The local is a Span<T>

unsigned char lvIsVectorPerElementMask : 1; // The local is known to be a per-element mask
unsigned char lvVectorPerElementMaskElemSizeLog2 : 2; // Maximum log2(element size) for the local mask

public:
union
{
Expand Down Expand Up @@ -869,6 +872,58 @@ class LclVarDsc
lvIsSpan = value;
}

#ifdef FEATURE_HW_INTRINSICS
// Is this local a per-element mask compatible with the given base type?
bool IsVectorPerElementMask(var_types simdBaseType) const
{
return lvIsVectorPerElementMask &&
(GetVectorPerElementMaskElemSizeLog2(simdBaseType) <= lvVectorPerElementMaskElemSizeLog2);
}

// Mark this local as a per-element mask with the given base type.
void SetIsVectorPerElementMask(var_types simdBaseType)
{
unsigned elemSizeLog2 = GetVectorPerElementMaskElemSizeLog2(simdBaseType);

if (!lvIsVectorPerElementMask || (elemSizeLog2 > lvVectorPerElementMaskElemSizeLog2))
{
lvVectorPerElementMaskElemSizeLog2 = static_cast<unsigned char>(elemSizeLog2);
}

lvIsVectorPerElementMask = true;
}

private:
static unsigned GetVectorPerElementMaskElemSizeLog2(var_types simdBaseType)
{
switch (simdBaseType)
{
case TYP_BYTE:
case TYP_UBYTE:
return 0;

case TYP_SHORT:
case TYP_USHORT:
return 1;

case TYP_INT:
case TYP_UINT:
case TYP_FLOAT:
return 2;

case TYP_LONG:
case TYP_ULONG:
case TYP_DOUBLE:
return 3;

default:
unreached();
}
}

public:
#endif // FEATURE_HW_INTRINSICS

/////////////////////

regNumber GetArgInitReg() const
Expand Down Expand Up @@ -10409,7 +10464,7 @@ class Compiler
return simdType;
}

static var_types getIndexTypeForShuffle(var_types simdBaseType)
static var_types getUnsignedSimdBaseType(var_types simdBaseType)
{
switch (simdBaseType)
{
Expand Down
33 changes: 25 additions & 8 deletions src/coreclr/jit/gentree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27342,7 +27342,7 @@ GenTree* Compiler::gtNewSimdZipNode(
}

GenTreeVecCon* shuffle = gtNewVconNode(type);
var_types indexBaseType = getIndexTypeForShuffle(simdBaseType);
var_types indexBaseType = getUnsignedSimdBaseType(simdBaseType);
uint32_t start = upper ? (simdCount / 2) : 0;

for (uint32_t index = 0; index < simdCount; index++)
Expand Down Expand Up @@ -27450,7 +27450,7 @@ GenTree* Compiler::gtNewSimdUnzipNode(
#elif defined(TARGET_XARCH)

unsigned elementSize = genTypeSize(simdBaseType);
var_types indexBaseType = getIndexTypeForShuffle(simdBaseType);
var_types indexBaseType = getUnsignedSimdBaseType(simdBaseType);

if (simdSize == 16)
{
Expand Down Expand Up @@ -27605,7 +27605,7 @@ GenTree* Compiler::gtNewSimdReverseNode(var_types type, GenTree* op1, var_types
// return Shuffle(op1, indices);

GenTreeVecCon* shuffle = gtNewVconNode(type);
var_types indexBaseType = getIndexTypeForShuffle(simdBaseType);
var_types indexBaseType = getUnsignedSimdBaseType(simdBaseType);

for (uint32_t index = 0; index < simdCount; index++)
{
Expand Down Expand Up @@ -33767,22 +33767,34 @@ bool GenTree::IsInvariant() const
// True if this node is a per-element mask compatible with simdBaseType and simdSize
//
bool GenTree::IsVectorPerElementMask(var_types simdBaseType, unsigned simdSize) const
{
return IsVectorPerElementMask(nullptr, simdBaseType, simdSize);
}

bool GenTree::IsVectorPerElementMask(Compiler* comp, var_types simdBaseType, unsigned simdSize) const
{
#ifdef FEATURE_SIMD
// This should be kept in sync with ValueNumStore::IsVectorPerElementMask

var_types simdType = TypeGet();
unsigned elementCount = GenTreeVecCon::ElementCount(simdSize, simdBaseType);

assert(varTypeIsSIMD(simdType));
assert(genTypeSize(simdType) == simdSize);
if (!varTypeIsSIMD(simdType) || (genTypeSize(simdType) != simdSize))
{
return false;
}

if (IsCnsVec())
{
const GenTreeVecCon* vecCon = AsVecCon();
return ElementsAreAllBitsSetOrZero(&vecCon->gtSimdVal, simdBaseType, elementCount);
}

if ((comp != nullptr) && OperIs(GT_LCL_VAR))
{
return comp->lvaGetDesc(AsLclVar())->IsVectorPerElementMask(simdBaseType);
}

if (!OperIsHWIntrinsic())
{
return false;
Expand Down Expand Up @@ -33821,6 +33833,11 @@ bool GenTree::IsVectorPerElementMask(var_types simdBaseType, unsigned simdSize)
bool isScalar = false;
genTreeOps oper = GenTreeHWIntrinsic::GetOperForHWIntrinsicId(intrinsicId, simdBaseType, &isScalar);

if (!isScalar && GenTree::OperIsCmpCompare(oper))
{
return genTypeSize(intrinsicSimdBaseType) >= genTypeSize(simdBaseType);
}

switch (oper)
{
case GT_AND:
Expand All @@ -33836,14 +33853,14 @@ bool GenTree::IsVectorPerElementMask(var_types simdBaseType, unsigned simdSize)
// there isn't any way to statically determine this for non-constants and
// the constant cases should've already been folded.

return intrinsic->Op(1)->IsVectorPerElementMask(simdBaseType, simdSize) &&
intrinsic->Op(2)->IsVectorPerElementMask(simdBaseType, simdSize);
return intrinsic->Op(1)->IsVectorPerElementMask(comp, simdBaseType, simdSize) &&
intrinsic->Op(2)->IsVectorPerElementMask(comp, simdBaseType, simdSize);
}

case GT_NOT:
{
// We are a unary bitwise operation where the input is a per-element mask
return intrinsic->Op(1)->IsVectorPerElementMask(simdBaseType, simdSize);
return intrinsic->Op(1)->IsVectorPerElementMask(comp, simdBaseType, simdSize);
}

default:
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/jit/gentree.h
Original file line number Diff line number Diff line change
Expand Up @@ -2537,6 +2537,7 @@ struct GenTree

bool IsInvariant() const;
bool IsVectorPerElementMask(var_types simdBaseType, unsigned simdSize) const;
bool IsVectorPerElementMask(class Compiler* comp, var_types simdBaseType, unsigned simdSize) const;

bool IsNeverNegative(Compiler* comp) const;
bool IsNeverNegativeOne(Compiler* comp) const;
Expand Down
Loading
Loading