-
Notifications
You must be signed in to change notification settings - Fork 10.5k
COWArrayOpts: make the optimization work again for two-dimensional arrays. #19714
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
Conversation
@swift-ci test |
@swift-ci benchmark |
Build failed |
Build comment file:Performance: -O
Code size: -O
Performance: -Osize
Code size: -Osize
Performance: -Onone
Code size: Swift libraries
How to read the dataThe tables contain differences in performance which are larger than 8% and differences in code size which are larger than 1%.If you see any unexpected regressions, you should consider fixing the regressions before you merge the PR. Noise: Sometimes the performance results (not code size!) contain false alarms. Unexpected regressions which are marked with '(?)' are probably noise. If you see regressions which you cannot explain you can try to run the benchmarks again. If regressions still show up, please consult with the performance team (@eeckstein). Hardware Overview
|
@swift-ci smoke test |
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.
These changes look good to me except for the points below. I'd also feel more comfortable if @aschwaighofer takes a look at it too.
makeMutableCalls.push_back(MakeMutableCall); | ||
} | ||
|
||
for (ArraySemanticsCall MakeMutableCall : makeMutableCalls) { |
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.
[style] it makes a little more sense to "pop" the values out of makeMutableCalls
so it doesn't contain dangling references. Or at least comment that the loop consumes the array.
The other option that I like, especially when it's not so easy to collect all the input, is to have any transformation that deletes instructions return a valid iterator to the next instruction, possibly pointing to new replacement instructions, or to the end of the block.
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.
I needed to do it this way (for good reasons) in an earlier version. But not anymore in this version. I'll change it back to the original code.
} | ||
if (auto *IA = dyn_cast<IndexAddrInst>(V)) { | ||
SILBasicBlock *IndexBlock = IA->getIndex()->getParentBlock(); | ||
if (IndexBlock && !DomTree->dominates(IndexBlock, Preheader)) |
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.
[code clarity] It's not clear why there needs to be a dominance check here. (I assume it has something to do with bounds checking but I'm not sure why).
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.
It's because all projections have to be loop invariant. index_addr is different from other projection instructions because it has a second operand which has to be checked separately.
I'll add a comment
Preheader->getTerminator(), DomTree); | ||
/// Return the underlying Array address after stripping off all address | ||
/// projections. Returns an invalid SILValue if the array base does not dominate | ||
/// the loop. |
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.
[question] getArrayAddressBase
is only called for the self
of a make_mutable call. How could an Array self
be produced by any of the projection instructions handled below? Is this helper entirely meant to handle 2d arrays? Is there a test case that exercises getArrayAddressBase
?
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.
It's especially important for 2d arrays. But it can an appear whenever the array is contained in another struct/class.
There are test cases in cowarray_opt.sil for this.
LLVM_DEBUG(llvm::dbgs() << " Skipping Array: does not dominate loop!\n"); | ||
return false; | ||
} | ||
|
||
SmallVector<unsigned, 4> AccessPath; | ||
SILValue ArrayContainer = getAccessPath(CurrentArrayAddr, AccessPath); | ||
bool arrayContainerIsUnique = checkUniqueArrayContainer(ArrayContainer); |
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.
[follow-up] checkUniqueArrayContainer
should work in a lot more places now that we have exclusive access markers. Should we file a bug for that or just add a TODO here?
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.
I'll add a todo
bool arrayContainerIsUnique = checkUniqueArrayContainer(ArrayContainer); | ||
|
||
StructUseCollector StructUses; | ||
StructUses.collectUses(ArrayContainer, AccessPath); |
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.
[design] I don't understand the motivation for moving collectUses
early. Now, for large, complicated loops, a lot of work is done up front, and when the array is not unique, we throw the work away. I supposed you could just guard the call to collectUses
with a check fro arrayContainerIsUnique
.
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 motivation was that it is now also needed in case of hasLoopOnlyDestructorSafeArrayOperations() == true.
But you are right, I can move it past the arrayContainerIsUnique check.
This option is very old. The same effect can now be achieved with pass-manager options, like -sil-print-before
…rays. With removing of pinning and with addressors, the pattern matching did not work anymore. The good thing is that the SIL is now much simpler and we can handle the 2D case without pattern matching at all. This removes a lot of code from COWArrayOpts. rdar://problem/43863081
@swift-ci smoke test |
1 similar comment
@swift-ci smoke test |
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 code changes look good to me.
But there seem to be no 2d array sil tests anymore. They all look like they test one dimensional cases to me?
LGTM. I agree with Arnold that's it's nice to have SIL tests whenever there's a fair amount of extra complexity in the pass to handle that SIL. |
The 2d tests start at 'sil @hoist_array2d' |
They should (more or less) test all the extra logic which I added (which was not much) |
@swift-ci smoke test OS X platform |
1 similar comment
@swift-ci smoke test OS X platform |
COWArrayOpts: make the optimization work again for two-dimensional arrays.
With removing of pinning and with addressors, the pattern matching did not work anymore.
The good thing is that the SIL is now much simpler and we can handle the 2D case without pattern matching at all.
This removes a lot of code from COWArrayOpts.
rdar://problem/43863081