[llvm] Reapply "[LICM] Fold associative binary ops to promote code hoisting (#81608)" (PR #100377)
Sudharsan Veeravalli via llvm-commits
llvm-commits at lists.llvm.org
Tue Aug 6 03:04:24 PDT 2024
================
@@ -2779,6 +2781,68 @@ 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) {
+ auto *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;
+
+ auto *BO0 = dyn_cast<BinaryOperator>(BO->getOperand(0));
+ if (!BO0 || BO0->getOpcode() != Opcode || !BO0->isAssociative())
+ return false;
+
+ // Transform: "(LV op C1) op C2" ==> "LV op (C1 op C2)"
+ 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.
+ if (Opcode == Instruction::Add && BO->hasNoUnsignedWrap() &&
+ BO0->hasNoUnsignedWrap()) {
+ Inv->setHasNoUnsignedWrap(true);
+ NewBO->setHasNoUnsignedWrap(true);
+ }
+
+ BO->replaceAllUsesWith(NewBO);
----------------
svs-quic wrote:
Hi, do we need to preserve the debug information of the original binary operator by copying it over to the new one?
Something like:
`NewBO->setDebugLoc(BO->getDebugLoc());`
https://github.com/llvm/llvm-project/pull/100377
More information about the llvm-commits
mailing list