-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Update the JIT to support rewriting more complex intrinsics as user calls #102702
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
Changes from all commits
ba591a3
45d9e23
39e424c
c41dfd2
a0cea27
a0a0749
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 |
|---|---|---|
|
|
@@ -559,6 +559,7 @@ enum GenTreeFlags : unsigned int | |
|
|
||
| #ifdef FEATURE_HW_INTRINSICS | ||
| GTF_HW_EM_OP = 0x10000000, // GT_HWINTRINSIC -- node is used as an operand to an embedded mask | ||
| GTF_HW_USER_CALL = 0x20000000, // GT_HWINTRINSIC -- node is implemented via a user call | ||
| #endif // FEATURE_HW_INTRINSICS | ||
| }; | ||
|
|
||
|
|
@@ -6089,6 +6090,15 @@ struct GenTreeMultiOp : public GenTree | |
| } | ||
| #endif | ||
|
|
||
| bool IsUserCall() const | ||
| { | ||
| #if defined(FEATURE_HW_INTRINSICS) | ||
| return OperIs(GT_HWINTRINSIC) && (gtFlags & GTF_HW_USER_CALL) != 0; | ||
| #else | ||
| return false; | ||
| #endif | ||
| } | ||
|
|
||
| GenTree*& Op(size_t index) | ||
| { | ||
| size_t actualIndex = index - 1; | ||
|
|
@@ -6217,7 +6227,29 @@ class IntrinsicNodeBuilder final | |
| struct GenTreeJitIntrinsic : public GenTreeMultiOp | ||
| { | ||
| protected: | ||
| GenTree* gtInlineOperands[2]; | ||
| union | ||
| { | ||
| // We don't have enough space to carry both the inline operands | ||
| // and the necessary information required to support rewriting | ||
| // the intrinsic back into a user call. As such, we union the | ||
| // data instead and use the GTF_HW_USER_CALL flag to indicate | ||
| // which fields are valid to access. -- Tracking the fields | ||
| // independently causes TREE_NODE_SZ_LARGE to increase and for | ||
| // GenTreeJitIntrinsic to become the largest node, which is | ||
| // undesirable, so this approach helps keep things pay-for-play. | ||
|
|
||
| GenTree* gtInlineOperands[2]; | ||
|
Member
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. I don't think I follow what gtInlineOperands is (and the logic inside SetMethodHandle does, can you explain?
Member
Author
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.
In order to facilitate rewriting the hwintrinsic back to a call, however, we need to be able to track the It's worth noting the actual
Member
Author
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. -- Notably the reason we don't have enough free space is primarily because of padding bytes caused by inheritance. There's a few places where nodes are wasting 4-7 bytes of space to maintain 8-byte alignment and that repeats several times. We could avoid tricks like the one being employed here if we had a better mechanism for avoiding such wasted padding for derived node kinds. But that's a much more complex and independent work item.
Member
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. Ah I didn't notice it was a pre-existing field - I though you added it in this PR 🙂 |
||
|
|
||
| struct | ||
| { | ||
| CORINFO_METHOD_HANDLE gtMethodHandle; | ||
|
|
||
| #if defined(FEATURE_READYTORUN) | ||
| // Call target lookup info for method call from a Ready To Run module | ||
| CORINFO_CONST_LOOKUP* gtEntryPoint; | ||
| #endif // FEATURE_READYTORUN | ||
| }; | ||
| }; | ||
| regNumberSmall gtOtherReg; // The second register for multi-reg intrinsics. | ||
| MultiRegSpillFlags gtSpillFlags; // Spill flags for multi-reg intrinsics. | ||
| unsigned char gtAuxiliaryJitType; // For intrinsics than need another type (e.g. Avx2.Gather* or SIMD (by element)) | ||
|
|
@@ -6226,6 +6258,24 @@ struct GenTreeJitIntrinsic : public GenTreeMultiOp | |
| NamedIntrinsic gtHWIntrinsicId; | ||
|
|
||
| public: | ||
| CORINFO_METHOD_HANDLE GetMethodHandle() const | ||
| { | ||
| assert(IsUserCall()); | ||
| return gtMethodHandle; | ||
| } | ||
|
|
||
| void SetMethodHandle(Compiler* comp, CORINFO_METHOD_HANDLE methodHandle); | ||
|
|
||
| #if defined(FEATURE_READYTORUN) | ||
| CORINFO_CONST_LOOKUP GetEntryPoint() const | ||
| { | ||
| assert(IsUserCall()); | ||
| return *gtEntryPoint; | ||
| } | ||
|
|
||
| void SetEntryPoint(Compiler* comp, CORINFO_CONST_LOOKUP entryPoint); | ||
| #endif // FEATURE_READYTORUN | ||
|
|
||
| //----------------------------------------------------------- | ||
| // GetRegNumByIdx: Get regNumber of i'th position. | ||
| // | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.