-
Notifications
You must be signed in to change notification settings - Fork 5.3k
JIT: "Scaled" addressing mode on ARM #60808
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
9843f90
2ea2be6
692dec1
8c9f466
65bd5ad
9f17ed0
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 |
|---|---|---|
|
|
@@ -2968,21 +2968,29 @@ bool Compiler::gtCanSwapOrder(GenTree* firstNode, GenTree* secondNode) | |
| bool Compiler::gtMarkAddrMode(GenTree* addr, int* pCostEx, int* pCostSz, var_types type) | ||
| { | ||
| // These are "out" parameters on the call to genCreateAddrMode(): | ||
| bool rev; // This will be true if the operands will need to be reversed. At this point we | ||
| // don't care about this because we're not yet instantiating this addressing mode. | ||
| #if SCALED_ADDR_MODES | ||
| unsigned mul; // This is the index (scale) value for the addressing mode | ||
| #endif | ||
| bool rev; // This will be true if the operands will need to be reversed. At this point we | ||
| // don't care about this because we're not yet instantiating this addressing mode. | ||
| unsigned mul; // This is the index (scale) value for the addressing mode | ||
| ssize_t cns; // This is the constant offset | ||
| GenTree* base; // This is the base of the address. | ||
| GenTree* idx; // This is the index. | ||
|
|
||
| if (codeGen->genCreateAddrMode(addr, false /*fold*/, &rev, &base, &idx, | ||
| #if SCALED_ADDR_MODES | ||
| &mul, | ||
| #endif // SCALED_ADDR_MODES | ||
| &cns)) | ||
| if (codeGen->genCreateAddrMode(addr, false /*fold*/, &rev, &base, &idx, &mul, &cns)) | ||
| { | ||
|
|
||
| #ifdef TARGET_ARMARCH | ||
| // Multiplier should be a "natural-scale" power of two number which is equal to target's width. | ||
| // | ||
| // *(ulong*)(data + index * 8); - can be optimized | ||
| // *(ulong*)(data + index * 7); - can not be optimized | ||
| // *(int*)(data + index * 2); - can not be optimized | ||
| // | ||
| if ((mul > 0) && (genTypeSize(type) != mul)) | ||
EgorBo marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| { | ||
| return false; | ||
| } | ||
| #endif | ||
|
|
||
| // We can form a complex addressing mode, so mark each of the interior | ||
| // nodes with GTF_ADDRMODE_NO_CSE and calculate a more accurate cost. | ||
|
|
||
|
|
@@ -3157,11 +3165,7 @@ bool Compiler::gtMarkAddrMode(GenTree* addr, int* pCostEx, int* pCostSz, var_typ | |
| // Note that cns can be zero. | ||
| CLANG_FORMAT_COMMENT_ANCHOR; | ||
|
|
||
| #if SCALED_ADDR_MODES | ||
| assert((base != nullptr) || (idx != nullptr && mul >= 2)); | ||
| #else | ||
| assert(base != NULL); | ||
| #endif | ||
|
|
||
| INDEBUG(GenTree* op1Save = addr); | ||
|
|
||
|
|
@@ -3176,12 +3180,14 @@ bool Compiler::gtMarkAddrMode(GenTree* addr, int* pCostEx, int* pCostSz, var_typ | |
| assert(op1 != op1Save); | ||
| assert(op2 != nullptr); | ||
|
|
||
| #if defined(TARGET_XARCH) | ||
|
Contributor
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. Can you add a comment here explaining why arm64 doesn't/shouldn't do this walk?
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. Added |
||
| // Walk the operands again (the third operand is unused in this case). | ||
| // This time we will only consider adds with constant op2's, since | ||
| // we have already found either a non-ADD op1 or a non-constant op2. | ||
| // NOTE: we don't support ADD(op1, cns) addressing for ARM/ARM64 yet so | ||
| // this walk makes no sense there. | ||
| gtWalkOp(&op1, &op2, nullptr, true); | ||
|
|
||
| #if defined(TARGET_XARCH) | ||
| // For XARCH we will fold GT_ADDs in the op2 position into the addressing mode, so we call | ||
| // gtWalkOp on both operands of the original GT_ADD. | ||
| // This is not done for ARMARCH. Though the stated reason is that we don't try to create a | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4897,11 +4897,12 @@ bool Lowering::AreSourcesPossiblyModifiedLocals(GenTree* addr, GenTree* base, Ge | |
| // Arguments: | ||
| // use - the use of the address we want to transform | ||
| // isContainable - true if this addressing mode can be contained | ||
| // targetType - on arm we can use "scale" only for appropriate target type | ||
| // | ||
| // Returns: | ||
| // true if the address node was changed to a LEA, false otherwise. | ||
| // | ||
| bool Lowering::TryCreateAddrMode(GenTree* addr, bool isContainable) | ||
| bool Lowering::TryCreateAddrMode(GenTree* addr, bool isContainable, var_types targetType) | ||
| { | ||
| if (!addr->OperIs(GT_ADD) || addr->gtOverflow()) | ||
| { | ||
|
|
@@ -4915,16 +4916,27 @@ bool Lowering::TryCreateAddrMode(GenTree* addr, bool isContainable) | |
| bool rev = false; | ||
|
|
||
| // Find out if an addressing mode can be constructed | ||
| bool doAddrMode = comp->codeGen->genCreateAddrMode(addr, // address | ||
| true, // fold | ||
| &rev, // reverse ops | ||
| &base, // base addr | ||
| &index, // index val | ||
| #if SCALED_ADDR_MODES | ||
| bool doAddrMode = comp->codeGen->genCreateAddrMode(addr, // address | ||
| true, // fold | ||
| &rev, // reverse ops | ||
| &base, // base addr | ||
| &index, // index val | ||
| &scale, // scaling | ||
| #endif // SCALED_ADDR_MODES | ||
| &offset); // displacement | ||
|
|
||
| #ifdef TARGET_ARMARCH | ||
| // Multiplier should be a "natural-scale" power of two number which is equal to target's width. | ||
| // | ||
| // *(ulong*)(data + index * 8); - can be optimized | ||
| // *(ulong*)(data + index * 7); - can not be optimized | ||
| // *(int*)(data + index * 2); - can not be optimized | ||
| // | ||
| if ((scale > 0) && (genTypeSize(targetType) != scale)) | ||
| { | ||
| return false; | ||
|
Contributor
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. Are there cases now where we look for and find a scale, but it is not the appropriate number, and so we bail out on creating an addressing mode that we would previously find?
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. Example: https://godbolt.org/z/xG4TsYYTG - in case of
Contributor
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. Ok, but in that case we would also bail out in the baseline as well as with this change, right?
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. From my understanding genCreateAddrMode is called from two places (gtSetEvalOrder and in Lower) and these checks are needed in both otherwise it leads to asserts. |
||
| } | ||
| #endif | ||
|
|
||
| if (scale == 0) | ||
| { | ||
| scale = 1; | ||
|
|
@@ -6678,7 +6690,7 @@ void Lowering::ContainCheckBitCast(GenTree* node) | |
| void Lowering::LowerStoreIndirCommon(GenTreeStoreInd* ind) | ||
| { | ||
| assert(ind->TypeGet() != TYP_STRUCT); | ||
| TryCreateAddrMode(ind->Addr(), true); | ||
| TryCreateAddrMode(ind->Addr(), true, ind->TypeGet()); | ||
| if (!comp->codeGen->gcInfo.gcIsWriteBarrierStoreIndNode(ind)) | ||
| { | ||
| LowerStoreIndir(ind); | ||
|
|
@@ -6701,7 +6713,7 @@ void Lowering::LowerIndir(GenTreeIndir* ind) | |
| // TODO-Cleanup: We're passing isContainable = true but ContainCheckIndir rejects | ||
| // address containment in some cases so we end up creating trivial (reg + offfset) | ||
| // or (reg + reg) LEAs that are not necessary. | ||
| TryCreateAddrMode(ind->Addr(), true); | ||
| TryCreateAddrMode(ind->Addr(), true, ind->TypeGet()); | ||
| ContainCheckIndir(ind); | ||
|
|
||
| if (ind->OperIs(GT_NULLCHECK) || ind->IsUnusedValue()) | ||
|
|
@@ -6714,7 +6726,7 @@ void Lowering::LowerIndir(GenTreeIndir* ind) | |
| // If the `ADDR` node under `STORE_OBJ(dstAddr, IND(struct(ADDR))` | ||
| // is a complex one it could benefit from an `LEA` that is not contained. | ||
| const bool isContainable = false; | ||
| TryCreateAddrMode(ind->Addr(), isContainable); | ||
| TryCreateAddrMode(ind->Addr(), isContainable, ind->TypeGet()); | ||
| } | ||
| } | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.