Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Arm64] Implement ASIMD Extract Insert ExtractVector64 ExtractVector128 #35030

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
14bdaf1
Put ExtractAndNarrowLow after ExtractAndNarrowHigh in AdvSimd.cs AdvS…
echesakov Apr 5, 2020
dfcf01f
Add Extract in AdvSimd.cs AdvSimd.PlatformNotSupported.cs
echesakov Apr 5, 2020
74b4868
Add Insert in AdvSimd.cs AdvSimd.PlatformNotSupported.cs
echesakov Mar 24, 2020
803e2f5
Add ExtractVector64 in AdvSimd.cs AdvSimd.PlatformNotSupported.cs
echesakov Apr 5, 2020
b1852ad
Add ExtractVector128 in AdvSimd.cs AdvSimd.PlatformNotSupported.cs
echesakov Mar 26, 2020
8cec295
Update System.Runtime.Intrinsics.Experimental.cs
echesakov Apr 5, 2020
648ee20
Update Helpers.cs Helpers.tt
echesakov Apr 5, 2020
6b4fbed
Add ExtractTest.template
echesakov Apr 5, 2020
9a82b44
Add ExtractVectorTest.template
echesakov Apr 5, 2020
1fcbade
Add InsertTest.template
echesakov Apr 5, 2020
bf58686
Add Extract in GenerateTests.csx
echesakov Apr 5, 2020
34eccf3
Add ExtractVector64 and ExtractVector128 in GenerateTests.csx
echesakov Apr 5, 2020
7effe2a
Add Insert in GenerateTests.csx
echesakov Apr 5, 2020
c5673aa
Put ExtractAndNarrowLow after ExtractAndNarrowHigh in GenerateTests.csx
echesakov Apr 9, 2020
6aaaa41
Update AdvSimd/ AdvSimd.Arm64/
echesakov Apr 5, 2020
6953bb2
Add emitter unit tests for INS_ext in codegenarm64.cpp
echesakov Mar 27, 2020
f75ab71
Implement INS_ext in emitarm64.cpp emitfmtsarm64.h instrsarm64.h
echesakov Mar 27, 2020
233c348
Update hwintrinsiclistarm64.h
echesakov Apr 10, 2020
8246181
Formatting in instrsarm64.h
echesakov Mar 27, 2020
9f3c72e
Remove HWIntrinsicInfo::ival on Arm64 in hwintrinsic.cpp hwintrinsic.…
echesakov Apr 6, 2020
36d4e96
Remove lookupImmUpperBound on Arm64 in hwintrinsic.h hwintrinsicarm64…
echesakov Apr 10, 2020
7d87daa
Remove HW_Flag_NoContainment and add HW_Flag_SupportsContainment in h…
echesakov Apr 9, 2020
23c1b94
Remove HWIntrinsic in hwintrinsiccodegenarm64.cpp
echesakov Apr 10, 2020
0d82dcd
Add HWIntrinsic in hwintrinsic.h
echesakov Apr 10, 2020
563c3e0
Remove #include-s in hwintrinsiccodegenarm64.cpp
echesakov Apr 10, 2020
6843309
Add analysis for allocation of branchTargetReg in lsraarm64.cpp
echesakov Apr 10, 2020
62ec8a5
Add ContainmentAnalysis for ASIMD Extract in lowerarmarch.cpp
echesakov Apr 10, 2020
e75ed7f
Add ContainmentAnalysis for ASIMD ExtractVector64 and ExtractVector12…
echesakov Apr 10, 2020
1cc6804
Add ContainmentAnalysis for ASIMD Insert in lowerarmarch.cpp
echesakov Apr 10, 2020
991ae92
Add HWIntrinsicImmOpHelper in codegen.h hwintrinsiccodegenarm64.cpp
echesakov Apr 10, 2020
78ceca9
Add ASIMD Extract in hwintrinsiccodegenarm64.cpp
echesakov Apr 10, 2020
59b73ae
Add ASIMD ExtractVector64 and ExtractVector128 in hwintrinsiccodegena…
echesakov Apr 10, 2020
e254782
Add ASIMD Insert in hwintrinsiccodegenarm64.cpp
echesakov Apr 10, 2020
4b71324
Remove isInImmRange in hwintrinsic.cpp hwintrinsic.h
echesakov Apr 10, 2020
9fa5b54
Remove redundant #ifdef-#endif FEATURE_HW_INTRINSICS in hwintrinsic.cpp
echesakov Apr 10, 2020
c29c46d
Remove TYP_lastIntrins in vartype.h
echesakov Apr 13, 2020
a82f248
Remove unused call to HWIntrinsicInfo::lookupCategory in Compiler::g…
echesakov Apr 13, 2020
d732e2d
Implement HWIntrinsicInfo::lookupImmUpperBound on Arm64 in hwintrinsi…
echesakov Apr 14, 2020
ed72d41
Pass immUpperBound explicitely in addRangeCheckIfNeeded in compiler.h…
echesakov Apr 14, 2020
9471dc3
Refactor logic to check an immediate operand and support Arm64 intrin…
echesakov Apr 14, 2020
29d87b7
Add missing . between className and methodName in Compiler::lookupNam…
echesakov Apr 15, 2020
c2416a0
Re-refactor impHWIntrinsic in hwintrinsic.cpp
echesakov Apr 16, 2020
a12ed8d
Has HWIntrinsicInfo::isInImmRange accept unnecessary arguments on x86…
echesakov Apr 16, 2020
2436d51
Remove Extract methods that operate on 64x1_t types in AdvSimd.cs Adv…
echesakov Apr 21, 2020
2b710cc
Remove Insert methods that operate on 64x1_t types in AdvSimd.cs AdvS…
echesakov Apr 21, 2020
19394b0
Update System.Runtime.Intrinsics.Experimental.cs
echesakov Apr 21, 2020
532a9f4
Update comment for Compiler::getArgForHWIntrinsic in hwintrinsic.cpp
echesakov Apr 21, 2020
347b2c8
Add comment and rename elemType->baseType in HWIntrinsicInfo::lookupI…
echesakov Apr 21, 2020
02892e4
Rename EmitAtFirst->EmitBegin and EmitAfterCase->EmitCaseEnd in CodeG…
echesakov Apr 21, 2020
7fc1c43
Rename BranchAtNonZero->TestImmOpZeroOrOne in CodeGen::HWIntrinsicImm…
echesakov Apr 21, 2020
6ba615f
Document HWIntrinsicImmOpHelper class and how it should be used in co…
echesakov Apr 21, 2020
65ca881
Make more flags in HWIntrinsicFlag platform-specific and re-order the…
echesakov Apr 21, 2020
b0bcb43
Merge branch 'master' into Arm64-ASIMD-Extract-Insert-ExtractVector64…
echesakov Apr 21, 2020
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: 52 additions & 0 deletions src/coreclr/src/jit/codegen.h
Original file line number Diff line number Diff line change
Expand Up @@ -1047,6 +1047,58 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
regNumber offsReg,
HWIntrinsicSwitchCaseBody emitSwCase);
#endif // defined(TARGET_XARCH)

#ifdef TARGET_ARM64
class HWIntrinsicImmOpHelper final
{
public:
HWIntrinsicImmOpHelper(CodeGen* codeGen, GenTree* immOp, GenTreeHWIntrinsic* intrin);

void EmitBegin();
void EmitCaseEnd();

// Returns true after the last call to EmitCaseEnd() (i.e. this signals that code generation is done).
bool Done() const
{
return immValue == immUpperBound;
}

// Returns a value of the immediate operand that should be used for a case.
int ImmValue() const
{
return immValue;
}

private:
// Returns true if immOp is non contained immediate (i.e. the value of the immediate operand is enregistered in
// nonConstImmReg).
bool NonConstImmOp() const
{
return nonConstImmReg != REG_NA;
}

// Returns true if a non constant immediate operand can be either 0 or 1.
bool TestImmOpZeroOrOne() const
{
assert(NonConstImmOp());
return immUpperBound == 2;
}

emitter* GetEmitter() const
{
return codeGen->GetEmitter();
}

CodeGen* const codeGen;
BasicBlock* endLabel;
BasicBlock* nonZeroLabel;
int immValue;
int immUpperBound;
regNumber nonConstImmReg;
regNumber branchTargetReg;
};
#endif // TARGET_ARM64

#endif // FEATURE_HW_INTRINSICS

#if !defined(TARGET_64BIT)
Expand Down
6 changes: 6 additions & 0 deletions src/coreclr/src/jit/codegenarm64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7217,6 +7217,12 @@ void CodeGen::genArm64EmitterUnitTests()
theEmitter->emitIns_R_R_I(INS_smov, EA_2BYTE, REG_R6, REG_V18, 4);
theEmitter->emitIns_R_R_I(INS_smov, EA_1BYTE, REG_R7, REG_V19, 8);

// ext extract vector from pair of vectors
theEmitter->emitIns_R_R_R_I(INS_ext, EA_8BYTE, REG_V0, REG_V1, REG_V2, 3, INS_OPTS_8B);
theEmitter->emitIns_R_R_R_I(INS_ext, EA_8BYTE, REG_V4, REG_V5, REG_V6, 7, INS_OPTS_8B);
theEmitter->emitIns_R_R_R_I(INS_ext, EA_16BYTE, REG_V8, REG_V9, REG_V10, 11, INS_OPTS_16B);
theEmitter->emitIns_R_R_R_I(INS_ext, EA_16BYTE, REG_V12, REG_V13, REG_V14, 15, INS_OPTS_16B);

#endif // ALL_ARM64_EMITTER_UNIT_TESTS

#ifdef ALL_ARM64_EMITTER_UNIT_TESTS
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/src/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -3690,7 +3690,7 @@ class Compiler

GenTree* getArgForHWIntrinsic(var_types argType, CORINFO_CLASS_HANDLE argClass);
GenTree* impNonConstFallback(NamedIntrinsic intrinsic, var_types simdType, var_types baseType);
GenTree* addRangeCheckIfNeeded(NamedIntrinsic intrinsic, GenTree* lastOp, bool mustExpand);
GenTree* addRangeCheckIfNeeded(NamedIntrinsic intrinsic, GenTree* lastOp, bool mustExpand, int immUpperBound);

#ifdef TARGET_XARCH
GenTree* impBaseIntrinsic(NamedIntrinsic intrinsic,
Expand Down
45 changes: 45 additions & 0 deletions src/coreclr/src/jit/emitarm64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -859,6 +859,15 @@ void emitter::emitInsSanityCheck(instrDesc* id)
assert(isVectorRegister(id->idReg3()));
break;

case IF_DV_3G: // DV_3G .Q.........mmmmm .iiii.nnnnnddddd Vd Vn Vm imm (vector)
assert(isValidVectorDatasize(id->idOpSize()));
assert(isValidArrangement(id->idOpSize(), id->idInsOpt()));
assert(isValidVectorIndex(id->idOpSize(), EA_1BYTE, emitGetInsSC(id)));
assert(isVectorRegister(id->idReg1()));
assert(isVectorRegister(id->idReg2()));
assert(isVectorRegister(id->idReg3()));
break;

case IF_DV_4A: // DR_4A .........X.mmmmm .aaaaannnnnddddd Rd Rn Rm Ra (scalar)
assert(isValidGeneralDatasize(id->idOpSize()));
assert(isVectorRegister(id->idReg1()));
Expand Down Expand Up @@ -947,6 +956,7 @@ bool emitter::emitInsMayWriteToGCReg(instrDesc* id)
case IF_DV_3D: // DV_3D .........X.mmmmm ......nnnnnddddd Vd Vn Vm (scalar)
case IF_DV_3DI: // DV_3DI .........XLmmmmm ....H.nnnnnddddd Vd Vn Vm[] (scalar by elem)
case IF_DV_3E: // DV_3E ...........mmmmm ......nnnnnddddd Vd Vn Vm (scalar)
case IF_DV_3G: // DV_3G .Q.........mmmmm .iiii.nnnnnddddd Vd Vn Vm imm (vector)
case IF_DV_4A: // DV_4A .........X.mmmmm .aaaaannnnnddddd Vd Va Vn Vm (scalar)
// Tracked GC pointers cannot be placed into the SIMD registers.
return false;
Expand Down Expand Up @@ -2129,6 +2139,7 @@ emitter::code_t emitter::emitInsCode(instruction ins, insFormat fmt)
case IF_DV_3DI:
case IF_DV_3E:
case IF_DV_3F:
case IF_DV_3G:
case IF_DV_4A:
case IF_SN_0A:
case IF_SI_0A:
Expand Down Expand Up @@ -6058,6 +6069,17 @@ void emitter::emitIns_R_R_R_I(instruction ins,
fmt = IF_LS_3G;
break;

case INS_ext:
assert(isVectorRegister(reg1));
assert(isVectorRegister(reg2));
assert(isVectorRegister(reg3));
assert(isValidVectorDatasize(size));
assert(isValidArrangement(size, opt));
assert((opt == INS_OPTS_8B) || (opt == INS_OPTS_16B));
assert(isValidVectorIndex(size, EA_1BYTE, imm));
fmt = IF_DV_3G;
break;

default:
unreached();
break;
Expand Down Expand Up @@ -10654,6 +10676,17 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp)
dst += emitOutput_Instr(dst, code);
break;

case IF_DV_3G: // DV_3G .Q.........mmmmm .iiii.nnnnnddddd Vd Vn Vm imm (vector)
imm = emitGetInsSC(id);
code = emitInsCode(ins, fmt);
code |= insEncodeVectorsize(id->idOpSize()); // Q
code |= insEncodeReg_Vm(id->idReg3()); // mmmmm
code |= ((code_t)imm << 11); // iiii
code |= insEncodeReg_Vn(id->idReg2()); // nnnnn
code |= insEncodeReg_Vd(id->idReg1()); // ddddd
dst += emitOutput_Instr(dst, code);
break;

case IF_DV_4A: // DV_4A .........X.mmmmm .aaaaannnnnddddd Vd Va Vn Vm (scalar)
code = emitInsCode(ins, fmt);
elemsize = id->idOpSize();
Expand Down Expand Up @@ -12270,6 +12303,13 @@ void emitter::emitDispIns(
emitDispVectorRegIndex(id->idReg3(), elemsize, emitGetInsSC(id), false);
break;

case IF_DV_3G: // DV_3G .Q.........mmmmm .iiii.nnnnnddddd Vd Vn Vm imm (vector)
emitDispVectorReg(id->idReg1(), id->idInsOpt(), true);
emitDispVectorReg(id->idReg2(), id->idInsOpt(), true);
emitDispVectorReg(id->idReg3(), id->idInsOpt(), true);
emitDispImm(emitGetInsSC(id), false);
break;

case IF_DV_4A: // DV_4A .........X.mmmmm .aaaaannnnnddddd Vd Va Vn Vm (scalar)
emitDispReg(id->idReg1(), size, true);
emitDispReg(id->idReg2(), size, true);
Expand Down Expand Up @@ -13950,6 +13990,11 @@ emitter::insExecutionCharacteristics emitter::getInsExecutionCharacteristics(ins
result.insLatency = PERFSCORE_LATENCY_2C;
break;

case IF_DV_3G: // ext
result.insThroughput = PERFSCORE_THROUGHPUT_2X;
result.insLatency = PERFSCORE_LATENCY_2C;
break;

case IF_DV_2L: // abs, neg, cmeq, cmge, cmgt, cmle, cmlt (scalar)
case IF_DV_2M: // (vector)
// abs, neg, mvn, not, cmeq, cmge, cmgt, cmle, cmlt,
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/src/jit/emitfmtsarm64.h
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@ IF_DEF(DV_3D, IS_NONE, NONE) // DV_3D .........X.mmmmm ......nnnnnddddd
IF_DEF(DV_3DI, IS_NONE, NONE) // DV_3DI .........XLmmmmm ....H.nnnnnddddd Vd Vn Vm[] (scalar by elem)
IF_DEF(DV_3E, IS_NONE, NONE) // DV_3E ...........mmmmm ......nnnnnddddd Vd Vn Vm (scalar)
IF_DEF(DV_3F, IS_NONE, NONE) // DV_3F ...........mmmmm ......nnnnnddddd Qd Sn Vm (Qd used as both source and destination)
IF_DEF(DV_3G, IS_NONE, NONE) // DV_3G .Q.........mmmmm .iiii.nnnnnddddd Vd Vn Vm imm (vector)

IF_DEF(DV_4A, IS_NONE, NONE) // DV_4A .........X.mmmmm .aaaaannnnnddddd Vd Vn Vm Va (scalar)

Expand Down
91 changes: 62 additions & 29 deletions src/coreclr/src/jit/hwintrinsic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ static const HWIntrinsicInfo hwIntrinsicInfoArray[] = {
{NI_##id, name, InstructionSet_##isa, static_cast<int>(ival), static_cast<unsigned>(size), numarg, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, category, static_cast<HWIntrinsicFlag>(flag)},
#include "hwintrinsiclistxarch.h"
#elif defined (TARGET_ARM64)
#define HARDWARE_INTRINSIC(isa, name, ival, size, numarg, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, category, flag) \
{NI_##isa##_##name, #name, InstructionSet_##isa, static_cast<int>(ival), static_cast<unsigned>(size), numarg, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, category, static_cast<HWIntrinsicFlag>(flag)},
#define HARDWARE_INTRINSIC(isa, name, size, numarg, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, category, flag) \
{NI_##isa##_##name, #name, InstructionSet_##isa, static_cast<unsigned>(size), numarg, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, category, static_cast<HWIntrinsicFlag>(flag)},
#include "hwintrinsiclistarm64.h"
#else
#error Unsupported platform
Expand Down Expand Up @@ -59,8 +59,6 @@ var_types Compiler::getBaseTypeFromArgIfNeeded(NamedIntrinsic intrinsic,
CORINFO_SIG_INFO* sig,
var_types baseType)
{
HWIntrinsicCategory category = HWIntrinsicInfo::lookupCategory(intrinsic);

if (HWIntrinsicInfo::BaseTypeFromSecondArg(intrinsic) || HWIntrinsicInfo::BaseTypeFromFirstArg(intrinsic))
{
CORINFO_ARG_LIST_HANDLE arg = sig->args;
Expand Down Expand Up @@ -223,7 +221,6 @@ CORINFO_CLASS_HANDLE Compiler::gtGetStructHandleForHWSIMD(var_types simdType, va
return NO_CLASS_HANDLE;
}

#ifdef FEATURE_HW_INTRINSICS
//------------------------------------------------------------------------
// vnEncodesResultTypeForHWIntrinsic(NamedIntrinsic hwIntrinsicID):
//
Expand Down Expand Up @@ -284,7 +281,6 @@ CORINFO_CLASS_HANDLE Compiler::gtGetStructHandleForHWSIMD(var_types simdType, va
// If we see two (or more) different instructions we need the extra VNF_SimdType arg
return (diffInsCount >= 2);
}
#endif // FEATURE_HW_INTRINSICS

//------------------------------------------------------------------------
// lookupId: Gets the NamedIntrinsic for a given method name and InstructionSet
Expand Down Expand Up @@ -533,15 +529,16 @@ GenTree* Compiler::getArgForHWIntrinsic(var_types argType, CORINFO_CLASS_HANDLE
// addRangeCheckIfNeeded: add a GT_HW_INTRINSIC_CHK node for non-full-range imm-intrinsic
//
// Arguments:
// intrinsic -- intrinsic ID
// immOP -- the last operand of the intrinsic that points to the imm-arg
// mustExpand -- true if the compiler is compiling the fallback(GT_CALL) of this intrinsics
// intrinsic -- intrinsic ID
// immOp -- the immediate operand of the intrinsic
// mustExpand -- true if the compiler is compiling the fallback(GT_CALL) of this intrinsics
// immUpperBound -- upper bound for a value of the immediate operand (for a non-full-range imm-intrinsic)
//
// Return Value:
// add a GT_HW_INTRINSIC_CHK node for non-full-range imm-intrinsic, which would throw ArgumentOutOfRangeException
// when the imm-argument is not in the valid range
//
GenTree* Compiler::addRangeCheckIfNeeded(NamedIntrinsic intrinsic, GenTree* immOp, bool mustExpand)
GenTree* Compiler::addRangeCheckIfNeeded(NamedIntrinsic intrinsic, GenTree* immOp, bool mustExpand, int immUpperBound)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new argument should be documented in the header comment.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The header comment needs to be updated for this additional argument.

{
assert(immOp != nullptr);
// Full-range imm-intrinsics do not need the range-check
Expand All @@ -555,7 +552,7 @@ GenTree* Compiler::addRangeCheckIfNeeded(NamedIntrinsic intrinsic, GenTree* immO
)
{
assert(!immOp->IsCnsIntOrI());
GenTree* upperBoundNode = gtNewIconNode(HWIntrinsicInfo::lookupImmUpperBound(intrinsic), TYP_INT);
GenTree* upperBoundNode = gtNewIconNode(immUpperBound, TYP_INT);
GenTree* index = nullptr;
if ((immOp->gtFlags & GTF_SIDE_EFFECT) != 0)
{
Expand Down Expand Up @@ -643,30 +640,48 @@ GenTree* Compiler::impHWIntrinsic(NamedIntrinsic intrinsic,
assert(sizeBytes != 0);
}

// NOTE: The following code assumes that for all intrinsics
// taking an immediate operand, that operand will be last.
if (sig->numArgs > 0 && HWIntrinsicInfo::isImmOp(intrinsic, impStackTop().val))
baseType = getBaseTypeFromArgIfNeeded(intrinsic, clsHnd, sig, baseType);
unsigned simdSize = HWIntrinsicInfo::lookupSimdSize(this, intrinsic, sig);

GenTree* immOp = nullptr;

#ifdef TARGET_ARM64
if (intrinsic == NI_AdvSimd_Insert)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should likely be tweaked a bit more, ARM64 will have cases with 2 immediate operands at varying positions.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I realized this yesterday - for a case ins Vd.T[imm1], Vs.T[imm2] - perhaps this could wait until I start working on that intrinsic so I could get Insert and Extract in - Kunal is blocked on these.

{
assert(sig->numArgs == 3);
immOp = impStackTop(1).val;
assert(HWIntrinsicInfo::isImmOp(intrinsic, immOp));
}
else
#endif
if ((sig->numArgs > 0) && HWIntrinsicInfo::isImmOp(intrinsic, impStackTop().val))
{
// NOTE: The following code assumes that for all intrinsics
// taking an immediate operand, that operand will be last.
immOp = impStackTop().val;
}

if (immOp != nullptr)
{
GenTree* lastOp = impStackTop().val;
// The imm-HWintrinsics that do not accept all imm8 values may throw
// ArgumentOutOfRangeException when the imm argument is not in the valid range
if (!HWIntrinsicInfo::HasFullRangeImm(intrinsic))
if (!HWIntrinsicInfo::HasFullRangeImm(intrinsic) && immOp->IsCnsIntOrI())
{
if (!mustExpand && lastOp->IsCnsIntOrI() &&
!HWIntrinsicInfo::isInImmRange(intrinsic, (int)lastOp->AsIntCon()->IconValue()))
const int ival = (int)immOp->AsIntCon()->IconValue();

if (!HWIntrinsicInfo::isInImmRange(intrinsic, ival, simdSize, baseType))
{
assert(!mustExpand);
// The imm-HWintrinsics that do not accept all imm8 values may throw
// ArgumentOutOfRangeException when the imm argument is not in the valid range
return nullptr;
}
}

if (!lastOp->IsCnsIntOrI())
else if (!immOp->IsCnsIntOrI())
{
if (HWIntrinsicInfo::NoJmpTableImm(intrinsic))
{
return impNonConstFallback(intrinsic, retType, baseType);
}

if (!mustExpand)
else if (!mustExpand)
{
// When the imm-argument is not a constant and we are not being forced to expand, we need to
// return nullptr so a GT_CALL to the intrinsic method is emitted instead. The
Expand All @@ -687,13 +702,22 @@ GenTree* Compiler::impHWIntrinsic(NamedIntrinsic intrinsic,
// table-driven importer of simple intrinsics
if (impIsTableDrivenHWIntrinsic(intrinsic, category))
{
baseType = getBaseTypeFromArgIfNeeded(intrinsic, clsHnd, sig, baseType);
unsigned simdSize = HWIntrinsicInfo::lookupSimdSize(this, intrinsic, sig);
bool isScalar = category == HW_Category_Scalar;
CORINFO_ARG_LIST_HANDLE argList = sig->args;
var_types argType = TYP_UNKNOWN;
CORINFO_CLASS_HANDLE argClass;

int immUpperBound = 0;

if (immOp != nullptr)
{
#if defined(TARGET_XARCH)
immUpperBound = HWIntrinsicInfo::lookupImmUpperBound(intrinsic);
#elif defined(TARGET_ARM64)
immUpperBound = HWIntrinsicInfo::lookupImmUpperBound(intrinsic, simdSize, baseType);
#endif
}

assert(numArgs >= 0);
if (!isScalar && ((HWIntrinsicInfo::lookupIns(intrinsic, baseType) == INS_invalid) ||
((simdSize != 8) && (simdSize != 16) && (simdSize != 32))))
Expand Down Expand Up @@ -742,7 +766,7 @@ GenTree* Compiler::impHWIntrinsic(NamedIntrinsic intrinsic,
argType = JITtype2varType(strip(info.compCompHnd->getArgType(sig, arg2, &argClass)));
op2 = getArgForHWIntrinsic(argType, argClass);

op2 = addRangeCheckIfNeeded(intrinsic, op2, mustExpand);
op2 = addRangeCheckIfNeeded(intrinsic, op2, mustExpand, immUpperBound);

argType = JITtype2varType(strip(info.compCompHnd->getArgType(sig, argList, &argClass)));
op1 = getArgForHWIntrinsic(argType, argClass);
Expand Down Expand Up @@ -775,8 +799,6 @@ GenTree* Compiler::impHWIntrinsic(NamedIntrinsic intrinsic,
argType = JITtype2varType(strip(info.compCompHnd->getArgType(sig, arg3, &argClass)));
GenTree* op3 = getArgForHWIntrinsic(argType, argClass);

op3 = addRangeCheckIfNeeded(intrinsic, op3, mustExpand);

argType = JITtype2varType(strip(info.compCompHnd->getArgType(sig, arg2, &argClass)));
op2 = getArgForHWIntrinsic(argType, argClass);

Expand All @@ -785,6 +807,17 @@ GenTree* Compiler::impHWIntrinsic(NamedIntrinsic intrinsic,
argType = JITtype2varType(strip(info.compCompHnd->getArgType(sig, argList, &argClass)));
op1 = getArgForHWIntrinsic(argType, argClass);

#ifdef TARGET_ARM64
if (intrinsic == NI_AdvSimd_Insert)
{
op2 = addRangeCheckIfNeeded(intrinsic, op2, mustExpand, immUpperBound);
}
else
#endif
{
op3 = addRangeCheckIfNeeded(intrinsic, op3, mustExpand, immUpperBound);
}

retNode = isScalar ? gtNewScalarHWIntrinsicNode(retType, op1, op2, op3, intrinsic)
: gtNewSimdHWIntrinsicNode(retType, op1, op2, op3, intrinsic, baseType, simdSize);

Expand Down
Loading