While looking at tests with opaque pointers it was noticed that Loop Strength Reduction behaved differently in cases when a pointer is NULL.
This patch adds a special case to deal with NULL.
Details
Diff Detail
- Repository
- rG LLVM Github Monorepo
Event Timeline
llvm/lib/Transforms/Scalar/LICM.cpp | ||
---|---|---|
2101 ↗ | (On Diff #458454) | So, the null special case doesn't make a lot of sense to me, in that promoting a null pointer is pretty pointless -- those accesses are UB anyway, right? However, I do think that that this bailout can be removed entirely: https://reviews.llvm.org/D133485 |
llvm/lib/Transforms/Scalar/LICM.cpp | ||
---|---|---|
2101 ↗ | (On Diff #458454) |
I took a look at that patch and I agree that is a better solution than what I have here. I will change this patch to remove the changes in LICM. |
Sorry that this took a few days.
Removed the code from LICM.
Added a test for the loop strength reduction. The test shows simpler code when
the guard for the NULL is added. However, there may be other tests where the
reverse is true.
llvm/test/Transforms/LoopStrengthReduce/Power/opaque-null-ptr.ll | ||
---|---|---|
2 | As this is just testing the IR transform, it would be better to use opt -S -mtriple=powerpc64le-unknown-linux-gnu -mcpu=pwr8 -loop-reduce < %s or so (in which case you can also use update_test_checks.py). |
llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp | ||
---|---|---|
3478 | NULL has a live range. If you assume all the users of the NULL are GEPs, then I guess in practice the null is going to get eliminated... but GEPs from null should be extremely rare: it implies you're loading from an absolute address. And it's undefined behavior to load from a null pointer unless the function is marked null_pointer_is_valid (or you're in a non-zero address space). | |
llvm/test/Transforms/LoopStrengthReduce/Power/opaque-null-ptr.ll | ||
27 | Does this really reflect actual user code? The first iteration of the loop loads from the constant addresses "4" and "8". |
Thank you both for looking at this patch.
Looking at the comments I feel like I made an incorrect assumption about NULL pointers in this case and I'm just going to abandon this patch.
However, I have also replied to the comments below.
llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp | ||
---|---|---|
3478 | Fair enough. I agree with you. However, I would like to give more background on the motivation of the patch because that is what I was trying to address in the first place. I have been looking at switching some tests from typed pointers to opaque pointers. The issue I have found is that certain passes (including this one) behave differently and sometimes produce different code when we switch from typed to opaque pointers. The reason for this is that we are asking for the "users" of ptr null (here: for (const Use &U : V->uses()) {). %i1 = getelementptr inbounds i8, i8* null, i64 %adr1 %f2 = getelementptr inbounds float, float* null, i64 %adr2 vs. %i1 = getelementptr inbounds i8, ptr null, i64 %adr1 %f2 = getelementptr inbounds float, ptr null, i64 %adr2 In the first example there is one use of i8* null and one use of float* null. However, in the second example we have two uses of ptr null. This then takes a different path through the compiler and we may end up with different code. Anyway, I agree with you that GEPs from NULL (basically a form of inttoptr) are not common. However, should we be concerned about this behaviour? Would we need to document it? Or it is just rare enough that we don't really care? | |
llvm/test/Transforms/LoopStrengthReduce/Power/opaque-null-ptr.ll | ||
2 | I did try this initially but for some reason I was getting different results for this test. Anyway, I plan on abandoning this patch so I'm not going to look further into exactly why I am getting different results. | |
27 | This is actually a reduced test from user code. |
llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp | ||
---|---|---|
3478 | If you're iterating over the use-list of "null", you're probably doing something which doesn't make sense, anyway... it should be rare enough that it doesn't really matter. |
NULL has a live range.
If you assume all the users of the NULL are GEPs, then I guess in practice the null is going to get eliminated... but GEPs from null should be extremely rare: it implies you're loading from an absolute address. And it's undefined behavior to load from a null pointer unless the function is marked null_pointer_is_valid (or you're in a non-zero address space).