[llvm] Reapply "[LICM] Fold associative binary ops to promote code hoisting (#81608)" (PR #100377)

Nikita Popov via llvm-commits llvm-commits at lists.llvm.org
Thu Jul 25 05:59:04 PDT 2024


================
@@ -2779,6 +2781,72 @@ static bool hoistMulAddAssociation(Instruction &I, Loop &L,
   return true;
 }
 
+/// Reassociate associative binary expressions of the form
+///
+/// 1. "(LV op C1) op C2" ==> "LV op (C1 op C2)"
+///
+/// where op is an associative binary op, LV is a loop variant, and C1 and C2
+/// are loop invariants that we want to hoist.
+///
+/// TODO: This can be extended to more cases such as
+/// 2. "C1 op (C2 op LV)" ==> "(C1 op C2) op LV"
+/// 3. "(C1 op LV) op C2" ==> "LV op (C1 op C2)" if op is commutative
+/// 4. "C1 op (LV op C2)" ==> "(C1 op C2) op LV" if op is commutative
+static bool hoistBOAssociation(Instruction &I, Loop &L,
+                               ICFLoopSafetyInfo &SafetyInfo,
+                               MemorySSAUpdater &MSSAU, AssumptionCache *AC,
+                               DominatorTree *DT) {
+  BinaryOperator *BO = dyn_cast<BinaryOperator>(&I);
+  if (!BO || !BO->isAssociative())
+    return false;
+
+  // Only fold ADDs for now.
+  Instruction::BinaryOps Opcode = BO->getOpcode();
+  if (Opcode != Instruction::Add)
+    return false;
+
+  BinaryOperator *BO0 = dyn_cast<BinaryOperator>(BO->getOperand(0));
+
+  // Transform: "(LV op C1) op C2" ==> "LV op (C1 op C2)"
+  if (BO0 && BO0->getOpcode() == Opcode && BO0->isAssociative()) {
+    Value *LV = BO0->getOperand(0);
+    Value *C1 = BO0->getOperand(1);
+    Value *C2 = BO->getOperand(1);
+
+    if (L.isLoopInvariant(LV) || !L.isLoopInvariant(C1) ||
+        !L.isLoopInvariant(C2))
+      return false;
+
+    auto *Preheader = L.getLoopPreheader();
+    assert(Preheader && "Loop is not in simplify form?");
+
+    auto *Inv = BinaryOperator::Create(Opcode, C1, C2, "invariant.op",
+                                       Preheader->getTerminator());
+    auto *NewBO = BinaryOperator::Create(Opcode, LV, Inv,
+                                         BO->getName() + ".reass", BO);
+
+    // Copy NUW for ADDs if both instructions have it.
+    // https://alive2.llvm.org/ce/z/K9W3rk
+    if (Opcode == Instruction::Add && BO->hasNoUnsignedWrap() &&
+        BO0->hasNoUnsignedWrap()) {
+      Inv->setHasNoUnsignedWrap(true);
+      NewBO->setHasNoUnsignedWrap(true);
+    }
+
+    BO->replaceAllUsesWith(NewBO);
+    eraseInstruction(*BO, SafetyInfo, MSSAU);
+
+    // Note: (LV op C1) might not be erased if it has more uses than the one we
+    //       just replaced.
----------------
nikic wrote:

```suggestion
    // (LV op C1) might not be erased if it has more uses than the one we
    // just replaced.
```

https://github.com/llvm/llvm-project/pull/100377


More information about the llvm-commits mailing list