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
160 changes: 113 additions & 47 deletions src/coreclr/jit/assertionprop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -236,18 +236,28 @@ bool IntegralRange::Contains(int64_t value) const
}

case GT_CNS_INT:
case GT_CNS_LNG:
{
if (node->IsIntegralConst(0) || node->IsIntegralConst(1))
{
return {SymbolicIntegerValue::Zero, SymbolicIntegerValue::One};
}

int64_t constValue = node->AsIntCon()->IntegralValue();
int64_t constValue = node->AsIntConCommon()->IntegralValue();

if (FitsIn<int32_t>(constValue))
{
rangeType = TYP_INT;
}
else if (FitsIn<uint32_t>(constValue))
{
rangeType = TYP_UINT;
}

if (constValue >= 0)
{
return {SymbolicIntegerValue::Zero, UpperBoundForType(rangeType)};
}

break;
}

Expand All @@ -260,94 +270,150 @@ bool IntegralRange::Contains(int64_t value) const

#if defined(FEATURE_HW_INTRINSICS)
case GT_HWINTRINSIC:
switch (node->AsHWIntrinsic()->GetHWIntrinsicId())
{
GenTreeHWIntrinsic* hwintrinsic = node->AsHWIntrinsic();

switch (hwintrinsic->GetHWIntrinsicId())
{
#if defined(TARGET_XARCH)
case NI_Vector128_op_Equality:
case NI_Vector128_op_Inequality:
case NI_Vector256_ExtractMostSignificantBits:
case NI_Vector512_ExtractMostSignificantBits:
case NI_X86Base_MoveMask:
case NI_AVX_MoveMask:
case NI_AVX2_MoveMask:
case NI_AVX512_MoveMask:
#elif defined(TARGET_ARM64)
case NI_Vector64_ExtractMostSignificantBits:
#endif
case NI_Vector128_ExtractMostSignificantBits:
{
// We have 1 bit per element, remaining upper bits are 0

size_t elementSize = genTypeSize(hwintrinsic->GetSimdBaseType());
size_t elementCount = hwintrinsic->GetSimdSize() / elementSize;

if (elementCount <= 8)
{
rangeType = TYP_UBYTE;
}
else if (elementCount <= 16)
{
rangeType = TYP_USHORT;
}
break;
}

#if defined(TARGET_XARCH)
case NI_Vector256_op_Equality:
case NI_Vector256_op_Inequality:
case NI_Vector512_op_Equality:
case NI_Vector512_op_Inequality:
case NI_X86Base_CompareScalarOrderedEqual:
case NI_X86Base_CompareScalarOrderedNotEqual:
case NI_X86Base_CompareScalarOrderedLessThan:
case NI_X86Base_CompareScalarOrderedLessThanOrEqual:
case NI_X86Base_CompareScalarOrderedGreaterThan:
case NI_X86Base_CompareScalarOrderedGreaterThanOrEqual:
case NI_X86Base_CompareScalarOrderedLessThan:
case NI_X86Base_CompareScalarOrderedLessThanOrEqual:
case NI_X86Base_CompareScalarOrderedNotEqual:
case NI_X86Base_CompareScalarUnorderedEqual:
case NI_X86Base_CompareScalarUnorderedNotEqual:
case NI_X86Base_CompareScalarUnorderedLessThanOrEqual:
case NI_X86Base_CompareScalarUnorderedLessThan:
case NI_X86Base_CompareScalarUnorderedGreaterThanOrEqual:
case NI_X86Base_CompareScalarUnorderedGreaterThan:
case NI_X86Base_CompareScalarUnorderedGreaterThanOrEqual:
case NI_X86Base_CompareScalarUnorderedLessThan:
case NI_X86Base_CompareScalarUnorderedLessThanOrEqual:
case NI_X86Base_CompareScalarUnorderedNotEqual:
case NI_X86Base_TestC:
case NI_X86Base_TestZ:
case NI_X86Base_TestNotZAndNotC:
case NI_X86Base_TestZ:
case NI_AVX_TestC:
case NI_AVX_TestZ:
case NI_AVX_TestNotZAndNotC:
case NI_AVX_TestZ:
#elif defined(TARGET_ARM64)
case NI_Vector64_op_Equality:
case NI_Vector64_op_Inequality:
#endif
case NI_Vector128_op_Equality:
case NI_Vector128_op_Inequality:
{
// A boolean [0, 1]
return {SymbolicIntegerValue::Zero, SymbolicIntegerValue::One};
}

case NI_X86Base_Extract:
case NI_X86Base_X64_Extract:
case NI_Vector128_ToScalar:
#if defined(TARGET_XARCH)
case NI_Vector256_GetElement:
case NI_Vector256_ToScalar:
case NI_Vector512_GetElement:
case NI_Vector512_ToScalar:
case NI_X86Base_Extract:
case NI_X86Base_X64_Extract:
#elif defined(TARGET_ARM64)
case NI_Vector64_GetElement:
case NI_Vector64_ToScalar:
case NI_AdvSimd_Extract:
#endif
case NI_Vector128_GetElement:
case NI_Vector256_GetElement:
case NI_Vector512_GetElement:
if (varTypeIsSmall(node->AsHWIntrinsic()->GetSimdBaseType()))
case NI_Vector128_ToScalar:
{
// We are extracting a value of the base types width and sign
var_types simdBaseType = hwintrinsic->GetSimdBaseType();

if (varTypeIsSmall(simdBaseType))
{
return ForType(node->AsHWIntrinsic()->GetSimdBaseType());
rangeType = simdBaseType;
}
break;
}

#if defined(TARGET_XARCH)
case NI_AVX2_LeadingZeroCount:
case NI_AVX2_TrailingZeroCount:
case NI_AVX2_X64_LeadingZeroCount:
case NI_AVX2_X64_TrailingZeroCount:
case NI_X86Base_PopCount:
case NI_X86Base_X64_PopCount:
// Note: No advantage in using a precise range for IntegralRange.
// Example: IntCns = 42 gives [0..127] with a non -precise range, [42,42] with a precise range.
return {SymbolicIntegerValue::Zero, SymbolicIntegerValue::ByteMax};
#elif defined(TARGET_ARM64)
case NI_Vector64_op_Equality:
case NI_Vector64_op_Inequality:
case NI_Vector128_op_Equality:
case NI_Vector128_op_Inequality:
return {SymbolicIntegerValue::Zero, SymbolicIntegerValue::One};

case NI_AdvSimd_Extract:
case NI_Vector64_ToScalar:
case NI_Vector128_ToScalar:
case NI_Vector64_GetElement:
case NI_Vector128_GetElement:
if (varTypeIsSmall(node->AsHWIntrinsic()->GetSimdBaseType()))
{
return ForType(node->AsHWIntrinsic()->GetSimdBaseType());
}
break;

case NI_AdvSimd_PopCount:
case NI_AdvSimd_LeadingZeroCount:
case NI_AdvSimd_LeadingSignCount:
case NI_ArmBase_LeadingZeroCount:
case NI_ArmBase_Arm64_LeadingZeroCount:
case NI_ArmBase_Arm64_LeadingSignCount:
// Note: No advantage in using a precise range for IntegralRange.
// Example: IntCns = 42 gives [0..127] with a non -precise range, [42,42] with a precise range.
return {SymbolicIntegerValue::Zero, SymbolicIntegerValue::ByteMax};
#else
#error Unsupported platform
#endif
{
// The actual range is [0..32] or [0..64]
return {SymbolicIntegerValue::Zero, SymbolicIntegerValue::ByteMax};
}

// TODO-SVE: Various intrinsics extract scalars or test patterns and return bool

default:
break;
}
break;
}
#endif // defined(FEATURE_HW_INTRINSICS)

case GT_INTRINSIC:
{
switch (node->AsIntrinsic()->gtIntrinsicName)
{
case NI_PRIMITIVE_LeadingZeroCount:
case NI_PRIMITIVE_Log2:
case NI_PRIMITIVE_PopCount:
case NI_PRIMITIVE_TrailingZeroCount:
{
// The actual range is [0..32] or [0..64]
return {SymbolicIntegerValue::Zero, SymbolicIntegerValue::ByteMax};
}

case NI_System_Runtime_CompilerServices_RuntimeHelpers_IsKnownConstant:
{
return {SymbolicIntegerValue::Zero, SymbolicIntegerValue::One};
}

default:
break;
}
break;
}

default:
break;
}
Expand Down
98 changes: 96 additions & 2 deletions src/coreclr/jit/rangecheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -902,6 +902,97 @@ Range RangeCheck::GetRangeFromAssertionsWorker(
}

#if defined(FEATURE_HW_INTRINSICS)
#if defined(TARGET_XARCH)
case VNF_HWI_Vector256_ExtractMostSignificantBits:
case VNF_HWI_Vector512_ExtractMostSignificantBits:
case VNF_HWI_X86Base_MoveMask:
case VNF_HWI_AVX_MoveMask:
case VNF_HWI_AVX2_MoveMask:
case VNF_HWI_AVX512_MoveMask:
#elif defined(TARGET_ARM64)
case VNF_HWI_Vector64_ExtractMostSignificantBits:
#endif
case VNF_HWI_Vector128_ExtractMostSignificantBits:
{
// We have 1 bit per element, remaining upper bits are 0

var_types simdBaseType;
uint32_t simdSize = comp->vnStore->GetVNHWIntrinsicSizeAndBaseType(funcApp, &simdBaseType);

size_t elementSize = genTypeSize(simdBaseType);
size_t elementCount = simdSize / elementSize;

if (elementCount <= 16)
{
result.lLimit = Limit(Limit::keConstant, 0);
result.uLimit = Limit(Limit::keConstant, (1 << elementCount) - 1);
}
break;
}

#if defined(TARGET_XARCH)
case VNF_HWI_Vector256_op_Equality:
case VNF_HWI_Vector256_op_Inequality:
case VNF_HWI_Vector512_op_Equality:
case VNF_HWI_Vector512_op_Inequality:
case VNF_HWI_X86Base_CompareScalarOrderedEqual:
case VNF_HWI_X86Base_CompareScalarOrderedGreaterThan:
case VNF_HWI_X86Base_CompareScalarOrderedGreaterThanOrEqual:
case VNF_HWI_X86Base_CompareScalarOrderedLessThan:
case VNF_HWI_X86Base_CompareScalarOrderedLessThanOrEqual:
case VNF_HWI_X86Base_CompareScalarOrderedNotEqual:
case VNF_HWI_X86Base_CompareScalarUnorderedEqual:
case VNF_HWI_X86Base_CompareScalarUnorderedGreaterThan:
case VNF_HWI_X86Base_CompareScalarUnorderedGreaterThanOrEqual:
case VNF_HWI_X86Base_CompareScalarUnorderedLessThan:
case VNF_HWI_X86Base_CompareScalarUnorderedLessThanOrEqual:
case VNF_HWI_X86Base_CompareScalarUnorderedNotEqual:
case VNF_HWI_X86Base_TestC:
case VNF_HWI_X86Base_TestNotZAndNotC:
case VNF_HWI_X86Base_TestZ:
case VNF_HWI_AVX_TestC:
case VNF_HWI_AVX_TestNotZAndNotC:
case VNF_HWI_AVX_TestZ:
#elif defined(TARGET_ARM64)
case VNF_HWI_Vector64_op_Equality:
case VNF_HWI_Vector64_op_Inequality:
#endif
case VNF_HWI_Vector128_op_Equality:
case VNF_HWI_Vector128_op_Inequality:
{
// A boolean [0, 1]
result.lLimit = Limit(Limit::keConstant, 0);
result.uLimit = Limit(Limit::keConstant, 1);
break;
}

#if defined(TARGET_XARCH)
case VNF_HWI_Vector256_GetElement:
case VNF_HWI_Vector256_ToScalar:
case VNF_HWI_Vector512_GetElement:
case VNF_HWI_Vector512_ToScalar:
case VNF_HWI_X86Base_Extract:
case VNF_HWI_X86Base_X64_Extract:
#elif defined(TARGET_ARM64)
case VNF_HWI_Vector64_GetElement:
case VNF_HWI_Vector64_ToScalar:
case VNF_HWI_AdvSimd_Extract:
#endif
case VNF_HWI_Vector128_GetElement:
case VNF_HWI_Vector128_ToScalar:
{
// We are extracting a value of the base types width and sign

var_types simdBaseType;
uint32_t simdSize = comp->vnStore->GetVNHWIntrinsicSizeAndBaseType(funcApp, &simdBaseType);

if (varTypeIsSmall(simdBaseType))
{
result = GetRangeFromType(simdBaseType);
}
break;
}

#if defined(TARGET_XARCH)
case VNF_HWI_AVX2_LeadingZeroCount:
case VNF_HWI_AVX2_TrailingZeroCount:
Expand All @@ -912,15 +1003,18 @@ Range RangeCheck::GetRangeFromAssertionsWorker(
#elif defined(TARGET_ARM64)
case VNF_HWI_ArmBase_LeadingZeroCount:
case VNF_HWI_ArmBase_Arm64_LeadingZeroCount:
case VNF_HWI_ArmBase_Arm64_LeadingSignCount:
#endif
#endif
case VNF_LeadingZeroCount:
case VNF_TrailingZeroCount:
case VNF_PopCount:
{
Comment thread
tannergooding marked this conversation as resolved.
// We can be a bit more precise here if we want to
// The actual range is [0..32] or [0..64]
var_types baseType = comp->vnStore->TypeOfVN(funcApp.GetArg(0));

result.lLimit = Limit(Limit::keConstant, 0);
result.uLimit = Limit(Limit::keConstant, 64);
result.uLimit = Limit(Limit::keConstant, varTypeIsLong(baseType) ? 64 : 32);
Comment thread
tannergooding marked this conversation as resolved.
break;
}

Expand Down
Loading
Loading