[PATCH] D109760: [GVN] Simple GVN hoist
JunMa via Phabricator via llvm-commits
llvm-commits at lists.llvm.org
Wed Sep 15 23:52:19 PDT 2021
junparser added inline comments.
================
Comment at: llvm/lib/Transforms/Scalar/GVN.cpp:2842
+ return I.isVolatile() || I.isAtomic() ||
+ !isGuaranteedToTransferExecutionToSuccessor(&I);
+}
----------------
chill wrote:
> junparser wrote:
> > can you give an example that when I can not transfer execution, how do subsequent instructions in BB to be hoisted? IMHO, collectHoistCandidates should stop here.
> For example:
>
> ```
> define dso_local i32 @f2(i32 %c, i32 %a, i32 %b) {
> entry:
> %tobool = icmp ne i32 %c, 0
> br i1 %tobool, label %if.then, label %if.else
>
> if.then:
> call void @h()
> %0 = sdiv i32 %a, %b
> br label %if.end
>
> if.else:
> call void @h()
> %1 = sdiv i32 %a, %b
> br label %if.end
>
> if.end:
> %2 = phi i32 [%0, %if.then], [%1, %if.else]
> ret i32 %2
> }
>
> declare dso_local void @h() readnone
> ```
>
> `%0` and `%1` will get the same value number, but should not be hoisted, unless ` call void @h()` is also hoisted.
> We would indeed stop the iteration in `collectHoistCandidates`, but hoist the call itself. Then on the next invocation of
> `performHoist` we will have
>
> ```
> define dso_local i32 @f2(i32 %c, i32 %a, i32 %b) {
> entry:
> %tobool = icmp ne i32 %c, 0
> call void @h()
> br i1 %tobool, label %if.then, label %if.else
>
> if.then:
> %0 = sdiv i32 %a, %b
> br label %if.end
>
> if.else:
> %1 = sdiv i32 %a, %b
> br label %if.end
>
> if.end:
> %2 = phi i32 [%0, %if.then], [%1, %if.else]
> ret i32 %2
> }
>
> declare dso_local void @h() readnone
> ```
>
> and **then **we'll move the `sdiv` too.
>
The thing is can we hoist instruction when isGuaranteedToTransferExecutionToSuccessor is true or isVolatile or maythrow. I'm not sure about this. I believe we should not hoist them.
================
Comment at: llvm/lib/Transforms/Scalar/GVN.cpp:3034
+ // Hoisting these creates opportunities for more hoisting.
+ if (P.first->mayReadOrWriteMemory() || isHoistBarrier(*P.first))
+ RunAgain = true;
----------------
chill wrote:
> junparser wrote:
> > ditto
> So, an instruction that reads or writes memory could be a local dependency. If you hoist such an instruction, it may turn the local dependency into a non-local one, thus allowing more hoisting.
>
> I guess there are alternative approaches (see discussion on the ML) when we explicitly have a dependency instruction, e.g. a non-volatile load
> followed by a non-volatile store, aliasing. Store can be hoisted only if the load is hoisted too.
>
> Not clear what to do when we don't have an explicit dependency, e.g.
>
> ```
> define dso_local i32 @f0(i32 %c, i32* %p, i32* %q) {
> entry:
> %tobool = icmp ne i32 %c, 0
> br i1 %tobool, label %if.then, label %if.else
>
> if.then:
> store volatile i32 0, i32* %p
> store volatile i32 0, i32* %q
> br label %if.end
>
> if.else:
> store volatile i32 0, i32* %p
> store volatile i32 0, i32* %q
> br label %if.end
>
> if.end:
> ret i32 0
> }
> ```
>
> (Current patch does not handle this case as well, I guess because of MemDep caching).
same issue with volatiled load/store.
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D109760/new/
https://reviews.llvm.org/D109760
More information about the llvm-commits
mailing list