@@ -718,18 +718,16 @@ uint8_t TernaryLogicInfo::GetTernaryControlByte(const TernaryLogicInfo& info, ui
718718//
719719// Arguments:
720720// intrinsic -- id of the intrinsic function.
721- // clsHnd -- class handle containing the intrinsic function.
722721// method -- method handle of the intrinsic function.
723722// sig -- signature of the intrinsic call.
724723// simdBaseJitType -- Predetermined simdBaseJitType, could be CORINFO_TYPE_UNDEF
725724//
726725// Return Value:
727726// The basetype of intrinsic of it can be fetched from 1st or 2nd argument, else return baseType unmodified.
728727//
729- CorInfoType Compiler::getBaseJitTypeFromArgIfNeeded (NamedIntrinsic intrinsic,
730- CORINFO_CLASS_HANDLE clsHnd,
731- CORINFO_SIG_INFO* sig,
732- CorInfoType simdBaseJitType)
728+ CorInfoType Compiler::getBaseJitTypeFromArgIfNeeded (NamedIntrinsic intrinsic,
729+ CORINFO_SIG_INFO* sig,
730+ CorInfoType simdBaseJitType)
733731{
734732 if (HWIntrinsicInfo::BaseTypeFromSecondArg (intrinsic) || HWIntrinsicInfo::BaseTypeFromFirstArg (intrinsic))
735733 {
@@ -1332,29 +1330,26 @@ GenTree* Compiler::getArgForHWIntrinsic(var_types argType, CORINFO_CLASS_HANDLE
13321330// Arguments:
13331331// intrinsic -- intrinsic ID
13341332// immOp -- the immediate operand of the intrinsic
1335- // mustExpand -- true if the compiler is compiling the fallback(GT_CALL) of this intrinsics
13361333// immLowerBound -- lower incl. bound for a value of the immediate operand (for a non-full-range imm-intrinsic)
13371334// immUpperBound -- upper incl. bound for a value of the immediate operand (for a non-full-range imm-intrinsic)
13381335//
13391336// Return Value:
13401337// add a GT_BOUNDS_CHECK node for non-full-range imm-intrinsic, which would throw ArgumentOutOfRangeException
13411338// when the imm-argument is not in the valid range
13421339//
1343- GenTree* Compiler::addRangeCheckIfNeeded (
1344- NamedIntrinsic intrinsic, GenTree* immOp, bool mustExpand, int immLowerBound, int immUpperBound)
1340+ GenTree* Compiler::addRangeCheckIfNeeded (NamedIntrinsic intrinsic, GenTree* immOp, int immLowerBound, int immUpperBound)
13451341{
13461342 assert (immOp != nullptr );
13471343 // Full-range imm-intrinsics do not need the range-check
13481344 // because the imm-parameter of the intrinsic method is a byte.
13491345 // AVX2 Gather intrinsics no not need the range-check
13501346 // because their imm-parameter have discrete valid values that are handle by managed code
1351- if (mustExpand && HWIntrinsicInfo::isImmOp (intrinsic, immOp)
1347+ if (!immOp-> IsCnsIntOrI () && HWIntrinsicInfo::isImmOp (intrinsic, immOp)
13521348#ifdef TARGET_XARCH
13531349 && !HWIntrinsicInfo::isAVX2GatherIntrinsic (intrinsic) && !HWIntrinsicInfo::HasFullRangeImm (intrinsic)
13541350#endif
13551351 )
13561352 {
1357- assert (!immOp->IsCnsIntOrI ());
13581353 assert (varTypeIsIntegral (immOp));
13591354
13601355 return addRangeCheckForHWIntrinsic (immOp, immLowerBound, immUpperBound);
@@ -1596,7 +1591,6 @@ bool Compiler::CheckHWIntrinsicImmRange(NamedIntrinsic intrinsic,
15961591
15971592 if (immOutOfRange)
15981593 {
1599- assert (!mustExpand);
16001594 // The imm-HWintrinsics that do not accept all imm8 values may throw
16011595 // ArgumentOutOfRangeException when the imm argument is not in the valid range,
16021596 // unless the intrinsic can be transformed into one that does accept all imm8 values
@@ -1764,7 +1758,8 @@ GenTree* Compiler::impHWIntrinsic(NamedIntrinsic intrinsic,
17641758 }
17651759 }
17661760
1767- simdBaseJitType = getBaseJitTypeFromArgIfNeeded (intrinsic, clsHnd, sig, simdBaseJitType);
1761+ simdBaseJitType = getBaseJitTypeFromArgIfNeeded (intrinsic, sig, simdBaseJitType);
1762+ unsigned simdSize = 0 ;
17681763
17691764 if (simdBaseJitType == CORINFO_TYPE_UNDEF)
17701765 {
@@ -1783,7 +1778,7 @@ GenTree* Compiler::impHWIntrinsic(NamedIntrinsic intrinsic,
17831778
17841779 simdBaseJitType = getBaseJitTypeAndSizeOfSIMDType (clsHnd, &sizeBytes);
17851780
1786- #if defined( TARGET_ARM64)
1781+ #ifdef TARGET_ARM64
17871782 if (simdBaseJitType == CORINFO_TYPE_UNDEF && HWIntrinsicInfo::HasScalarInputVariant (intrinsic))
17881783 {
17891784 // Did not find a valid vector type. The intrinsic has alternate scalar version. Switch to that.
@@ -1799,12 +1794,40 @@ GenTree* Compiler::impHWIntrinsic(NamedIntrinsic intrinsic,
17991794 assert (simdBaseJitType != CORINFO_TYPE_VALUECLASS);
18001795 }
18011796 else
1802- #endif
1797+ #endif // TARGET_ARM64
18031798 {
18041799 assert ((category == HW_Category_Special) || (category == HW_Category_Helper) || (sizeBytes != 0 ));
18051800 }
18061801 }
18071802 }
1803+ #ifdef TARGET_ARM64
1804+ else if ((simdBaseJitType == CORINFO_TYPE_VALUECLASS) && (HWIntrinsicInfo::BaseTypeFromValueTupleArg (intrinsic)))
1805+ {
1806+ // If HW_Flag_BaseTypeFromValueTupleArg is set, one of the base type position flags must be set.
1807+ // There is no point to using this flag if the SIMD size is known at compile-time.
1808+ assert (HWIntrinsicInfo::BaseTypeFromFirstArg (intrinsic) || HWIntrinsicInfo::BaseTypeFromSecondArg (intrinsic));
1809+ assert (!HWIntrinsicInfo::tryLookupSimdSize (intrinsic, &simdSize));
1810+
1811+ CORINFO_ARG_LIST_HANDLE arg = sig->args ;
1812+
1813+ if (HWIntrinsicInfo::BaseTypeFromSecondArg (intrinsic))
1814+ {
1815+ arg = info.compCompHnd ->getArgNext (arg);
1816+ }
1817+
1818+ CORINFO_CLASS_HANDLE argClass = info.compCompHnd ->getArgClass (sig, arg);
1819+ INDEBUG (unsigned fieldCount = info.compCompHnd ->getClassNumInstanceFields (argClass));
1820+ assert (fieldCount > 1 );
1821+
1822+ CORINFO_CLASS_HANDLE classHnd;
1823+ CORINFO_FIELD_HANDLE fieldHandle = info.compCompHnd ->getFieldInClass (argClass, 0 );
1824+ CorInfoType fieldType = info.compCompHnd ->getFieldType (fieldHandle, &classHnd);
1825+ assert (isIntrinsicType (classHnd));
1826+
1827+ simdBaseJitType = getBaseJitTypeAndSizeOfSIMDType (classHnd, &simdSize);
1828+ assert (simdSize > 0 );
1829+ }
1830+ #endif // TARGET_ARM64
18081831
18091832 // Immediately return if the category is other than scalar/special and this is not a supported base type.
18101833 if ((category != HW_Category_Special) && (category != HW_Category_Scalar) && !HWIntrinsicInfo::isScalarIsa (isa) &&
@@ -1827,7 +1850,9 @@ GenTree* Compiler::impHWIntrinsic(NamedIntrinsic intrinsic,
18271850#endif // TARGET_XARCH
18281851 }
18291852
1830- const unsigned simdSize = HWIntrinsicInfo::lookupSimdSize (this , intrinsic, sig);
1853+ // We may have already determined simdSize for intrinsics that require special handling.
1854+ // If so, skip the lookup.
1855+ simdSize = (simdSize == 0 ) ? HWIntrinsicInfo::lookupSimdSize (this , intrinsic, sig) : simdSize;
18311856
18321857 HWIntrinsicSignatureReader sigReader;
18331858 sigReader.Read (info.compCompHnd , sig);
@@ -1859,15 +1884,30 @@ GenTree* Compiler::impHWIntrinsic(NamedIntrinsic intrinsic,
18591884 {
18601885 return impNonConstFallback (intrinsic, retType, simdBaseJitType);
18611886 }
1862- else if (!opts. OptimizationEnabled ())
1887+ else if (immOp2-> IsCnsIntOrI ())
18631888 {
1864- // Only enable late stage rewriting if optimizations are enabled
1865- // as we won't otherwise encounter a constant at the later point
1866- return nullptr ;
1889+ // If we know the immediate is out-of-range,
1890+ // convert the intrinsic into a user call (or throw if we must expand)
1891+ return impUnsupportedNamedIntrinsic (CORINFO_HELP_THROW_ARGUMENTOUTOFRANGEEXCEPTION, method, sig,
1892+ mustExpand);
18671893 }
18681894 else
18691895 {
1870- setMethodHandle = true ;
1896+ // The immediate is unknown, and we aren't using a fallback intrinsic.
1897+ // In this case, CheckHWIntrinsicImmRange should not return false for intrinsics that must expand.
1898+ assert (!mustExpand);
1899+
1900+ if (opts.OptimizationEnabled ())
1901+ {
1902+ // Only enable late stage rewriting if optimizations are enabled
1903+ // as we won't otherwise encounter a constant at the later point
1904+ setMethodHandle = true ;
1905+ }
1906+ else
1907+ {
1908+ // Just convert to a user call
1909+ return nullptr ;
1910+ }
18711911 }
18721912 }
18731913 }
@@ -1896,15 +1936,30 @@ GenTree* Compiler::impHWIntrinsic(NamedIntrinsic intrinsic,
18961936 {
18971937 return impNonConstFallback (intrinsic, retType, simdBaseJitType);
18981938 }
1899- else if (!opts. OptimizationEnabled ())
1939+ else if (immOp1-> IsCnsIntOrI ())
19001940 {
1901- // Only enable late stage rewriting if optimizations are enabled
1902- // as we won't otherwise encounter a constant at the later point
1903- return nullptr ;
1941+ // If we know the immediate is out-of-range,
1942+ // convert the intrinsic into a user call (or throw if we must expand)
1943+ return impUnsupportedNamedIntrinsic (CORINFO_HELP_THROW_ARGUMENTOUTOFRANGEEXCEPTION, method, sig,
1944+ mustExpand);
19041945 }
19051946 else
19061947 {
1907- setMethodHandle = true ;
1948+ // The immediate is unknown, and we aren't using a fallback intrinsic.
1949+ // In this case, CheckHWIntrinsicImmRange should not return false for intrinsics that must expand.
1950+ assert (!mustExpand);
1951+
1952+ if (opts.OptimizationEnabled ())
1953+ {
1954+ // Only enable late stage rewriting if optimizations are enabled
1955+ // as we won't otherwise encounter a constant at the later point
1956+ setMethodHandle = true ;
1957+ }
1958+ else
1959+ {
1960+ // Just convert to a user call
1961+ return nullptr ;
1962+ }
19081963 }
19091964 }
19101965 }
@@ -1960,7 +2015,7 @@ GenTree* Compiler::impHWIntrinsic(NamedIntrinsic intrinsic,
19602015 {
19612016 case 4 :
19622017 op4 = getArgForHWIntrinsic (sigReader.GetOp4Type (), sigReader.op4ClsHnd );
1963- op4 = addRangeCheckIfNeeded (intrinsic, op4, mustExpand, immLowerBound, immUpperBound);
2018+ op4 = addRangeCheckIfNeeded (intrinsic, op4, immLowerBound, immUpperBound);
19642019 op3 = getArgForHWIntrinsic (sigReader.GetOp3Type (), sigReader.op3ClsHnd );
19652020 op2 = getArgForHWIntrinsic (sigReader.GetOp2Type (), sigReader.op2ClsHnd );
19662021 op1 = getArgForHWIntrinsic (sigReader.GetOp1Type (), sigReader.op1ClsHnd );
@@ -1974,7 +2029,7 @@ GenTree* Compiler::impHWIntrinsic(NamedIntrinsic intrinsic,
19742029
19752030 case 2 :
19762031 op2 = getArgForHWIntrinsic (sigReader.GetOp2Type (), sigReader.op2ClsHnd );
1977- op2 = addRangeCheckIfNeeded (intrinsic, op2, mustExpand, immLowerBound, immUpperBound);
2032+ op2 = addRangeCheckIfNeeded (intrinsic, op2, immLowerBound, immUpperBound);
19782033 op1 = getArgForHWIntrinsic (sigReader.GetOp1Type (), sigReader.op1ClsHnd );
19792034 break ;
19802035
@@ -2144,7 +2199,7 @@ GenTree* Compiler::impHWIntrinsic(NamedIntrinsic intrinsic,
21442199#ifdef TARGET_ARM64
21452200 if (intrinsic == NI_AdvSimd_LoadAndInsertScalar)
21462201 {
2147- op2 = addRangeCheckIfNeeded (intrinsic, op2, mustExpand, immLowerBound, immUpperBound);
2202+ op2 = addRangeCheckIfNeeded (intrinsic, op2, immLowerBound, immUpperBound);
21482203
21492204 if (op1->OperIs (GT_CAST))
21502205 {
@@ -2158,12 +2213,12 @@ GenTree* Compiler::impHWIntrinsic(NamedIntrinsic intrinsic,
21582213 }
21592214 else if ((intrinsic == NI_AdvSimd_Insert) || (intrinsic == NI_AdvSimd_InsertScalar))
21602215 {
2161- op2 = addRangeCheckIfNeeded (intrinsic, op2, mustExpand, immLowerBound, immUpperBound);
2216+ op2 = addRangeCheckIfNeeded (intrinsic, op2, immLowerBound, immUpperBound);
21622217 }
21632218 else
21642219#endif
21652220 {
2166- op3 = addRangeCheckIfNeeded (intrinsic, op3, mustExpand, immLowerBound, immUpperBound);
2221+ op3 = addRangeCheckIfNeeded (intrinsic, op3, immLowerBound, immUpperBound);
21672222 }
21682223
21692224 retNode = isScalar ? gtNewScalarHWIntrinsicNode (nodeRetType, op1, op2, op3, intrinsic)
0 commit comments