[PATCH] D29331: [LICM] Hoist loads that are dominated by invariant.start intrinsic, and are invariant in the loop.

Anna Thomas via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Tue Jan 31 13:52:40 PST 2017


anna added a comment.

In https://reviews.llvm.org/D29331#661997, @sanjoy wrote:

> I'm not sure this is correct -- what if you had:
>
>   int* ptr = ...;
>   for (...) { // runs only one iteration
>     *ptr = 20;
>     invariant_start(ptr); // invariant, but only after we've written 20 to *ptr
>     int val = *ptr;
>   }
>
>
> I think this patch will LICM the load to outside the loop incorrectly.  I suspect we can at most hoist up to right after the `invariant_start` call.


Thanks for catching that.  I dont think we have a mechanism currently to hoist upto a specific instruction. LICM uses `canSinkOrHoistInst` to hoist the load to just before the terminator of preheader of the current loop `CurLoop`. Behaviour of sinking to end of loop won't be affected by this patch.

So, I think we can fix this problem by add one more condition for hoisting such loads:  the dominating `invariant.start`'s BB should be outside `CurLoop`. I have a patch for this and it catches the bug above (and from reading LICM code, nested loops with invariant.start would work as well).



================
Comment at: lib/Transforms/Scalar/LICM.cpp:504
+  while (isa<BitCastInst>(LoadOp)) {
+    if (isInvariantStartOperandType())
+      break;
----------------
sanjoy wrote:
> This is very hard to read, not the least because you're implicitly using `LoadOp`. :)
> 
> Can you instead phrase this more straightforwardly, as:
> 
> ```
> auto *Int8PtrTy = ...
> while (isa<bitcast>(...)) {
>   if (LoadOp->getType() == Int8PtrTy)
>     break;
>    ...
> }
> ```
> 
Yes, that implicit `LoadOp` makes it pretty hard. I used a lambda because of the same logic at two places. I think the `if check` as you've written above is fine even with it will be duplicated. 


================
Comment at: lib/Transforms/Scalar/LICM.cpp:529
+        // non-invariant. The only use of an invariant.start instruction is
+        // within its corresponding invariant.end instruction.
+        !II->getNumUses() && DT->dominates(II, LI))
----------------
sanjoy wrote:
> Don't you have to check the size?
yes. The implementation of invariant.start has that possibility of specifying a diffferent size. I'll add that. 


https://reviews.llvm.org/D29331





More information about the llvm-commits mailing list