-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
Changes from all commits
14bdaf1
dfcf01f
74b4868
803e2f5
b1852ad
8cec295
648ee20
6b4fbed
9a82b44
1fcbade
bf58686
34eccf3
7effe2a
c5673aa
6aaaa41
6953bb2
f75ab71
233c348
8246181
9f3c72e
36d4e96
7d87daa
23c1b94
0d82dcd
563c3e0
6843309
62ec8a5
e75ed7f
1cc6804
991ae92
78ceca9
59b73ae
e254782
4b71324
9fa5b54
c29c46d
a82f248
d732e2d
ed72d41
9471dc3
29d87b7
c2416a0
a12ed8d
2436d51
2b710cc
19394b0
532a9f4
347b2c8
02892e4
7fc1c43
6ba615f
65ca881
b0bcb43
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 | ||
|
@@ -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; | ||
|
@@ -223,7 +221,6 @@ CORINFO_CLASS_HANDLE Compiler::gtGetStructHandleForHWSIMD(var_types simdType, va | |
return NO_CLASS_HANDLE; | ||
} | ||
|
||
#ifdef FEATURE_HW_INTRINSICS | ||
//------------------------------------------------------------------------ | ||
// vnEncodesResultTypeForHWIntrinsic(NamedIntrinsic hwIntrinsicID): | ||
// | ||
|
@@ -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 | ||
|
@@ -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) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||
|
@@ -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) | ||
{ | ||
|
@@ -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) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, I realized this yesterday - for a case |
||
{ | ||
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 | ||
|
@@ -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)))) | ||
|
@@ -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); | ||
|
@@ -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); | ||
|
||
|
@@ -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); | ||
|
||
|
There was a problem hiding this comment.
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.