[llvm] LICM: hoist BO assoc when BinOp is in RHS (PR #107072)
Ramkumar Ramachandra via llvm-commits
llvm-commits at lists.llvm.org
Wed Sep 4 05:22:02 PDT 2024
https://github.com/artagnon updated https://github.com/llvm/llvm-project/pull/107072
>From d7f2c17251755fbb306505077f18925fa20cb6c5 Mon Sep 17 00:00:00 2001
From: Ramkumar Ramachandra <ramkumar.ramachandra at codasip.com>
Date: Tue, 3 Sep 2024 10:36:01 +0100
Subject: [PATCH] LICM: hoist BO assoc when BinOp is in RHS
Extend hoistBOAssociation smoothly to handle the case when the inner
BinaryOperator is in the RHS of the outer BinaryOperator. This completes
the generalization of hoistBOAssociation, and the only limitation after
this patch is the fact that only Add and Mul are hoisted.
---
llvm/lib/Transforms/Scalar/LICM.cpp | 37 +++++---
llvm/test/Transforms/LICM/hoist-binop.ll | 107 ++++++++++++++++++++++-
2 files changed, 129 insertions(+), 15 deletions(-)
diff --git a/llvm/lib/Transforms/Scalar/LICM.cpp b/llvm/lib/Transforms/Scalar/LICM.cpp
index 5cf7c252bb5f3d..f10dbcf5f89cd0 100644
--- a/llvm/lib/Transforms/Scalar/LICM.cpp
+++ b/llvm/lib/Transforms/Scalar/LICM.cpp
@@ -2805,13 +2805,11 @@ static bool hoistMulAddAssociation(Instruction &I, Loop &L,
///
/// 1. "(LV op C1) op C2" ==> "LV op (C1 op C2)" if op is an associative BinOp
/// 2. "(C1 op LV) op C2" ==> "LV op (C1 op C2)" if op is a commutative BinOp
+/// 3. "C2 op (C1 op LV)" ==> "(C2 op C1) op LV" if op an associative BinOp
+/// 4. "C2 op (LV op C1)" ==> "(C2 op C1) op LV" if op is a commutative BinOp
///
/// where 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
-/// 1. "C1 op (C2 op LV)" ==> "(C1 op C2) op LV" if op an associative BinOp
-/// 2. "C1 op (LV op C2)" ==> "(C1 op C2) op LV" if op is a commutative BinOp
static bool hoistBOAssociation(Instruction &I, Loop &L,
ICFLoopSafetyInfo &SafetyInfo,
MemorySSAUpdater &MSSAU, AssumptionCache *AC,
@@ -2825,30 +2823,45 @@ static bool hoistBOAssociation(Instruction &I, Loop &L,
if (Opcode != Instruction::Add && Opcode != Instruction::Mul)
return false;
- auto *BO0 = dyn_cast<BinaryOperator>(BO->getOperand(0));
+ bool BinOpInRHS = isa<BinaryOperator>(BO->getOperand(1));
+ auto *BO0 = dyn_cast<BinaryOperator>(BO->getOperand(BinOpInRHS));
if (!BO0 || BO0->getOpcode() != Opcode || !BO0->isAssociative() ||
BO0->hasNUsesOrMore(3))
return false;
Value *LV = BO0->getOperand(0);
Value *C1 = BO0->getOperand(1);
- Value *C2 = BO->getOperand(1);
+ Value *C2 = BO->getOperand(!BinOpInRHS);
- if (L.isLoopInvariant(LV) && !L.isLoopInvariant(C1)) {
- assert(BO0->isCommutative() && "Associativity implies commutativity");
+ if (!L.isLoopInvariant(C2))
+ return false;
+ if (!L.isLoopInvariant(LV) && L.isLoopInvariant(C1)) {
+ if (BinOpInRHS)
+ assert(BO0->isCommutative() && "Associativity implies commutativity");
+ } else if (L.isLoopInvariant(LV) && !L.isLoopInvariant(C1)) {
+ if (!BinOpInRHS)
+ assert(BO0->isCommutative() && "Associativity implies commutativity");
std::swap(LV, C1);
- }
- if (L.isLoopInvariant(LV) || !L.isLoopInvariant(C1) || !L.isLoopInvariant(C2))
+ } else {
return false;
+ }
auto *Preheader = L.getLoopPreheader();
assert(Preheader && "Loop is not in simplify form?");
+ // To create C2 op C1, instead of C1 op C2.
+ if (BinOpInRHS)
+ std::swap(C1, C2);
+
IRBuilder<> Builder(Preheader->getTerminator());
auto *Inv = Builder.CreateBinOp(Opcode, C1, C2, "invariant.op");
- auto *NewBO = BinaryOperator::Create(
- Opcode, LV, Inv, BO->getName() + ".reass", BO->getIterator());
+ auto *NewBO =
+ BinOpInRHS
+ ? BinaryOperator::Create(Opcode, Inv, LV, BO->getName() + ".reass",
+ BO->getIterator())
+ : BinaryOperator::Create(Opcode, LV, Inv, BO->getName() + ".reass",
+ BO->getIterator());
// Copy NUW for ADDs if both instructions have it.
if (Opcode == Instruction::Add && BO->hasNoUnsignedWrap() &&
diff --git a/llvm/test/Transforms/LICM/hoist-binop.ll b/llvm/test/Transforms/LICM/hoist-binop.ll
index b0ee45a5fb350e..f50f308faea676 100644
--- a/llvm/test/Transforms/LICM/hoist-binop.ll
+++ b/llvm/test/Transforms/LICM/hoist-binop.ll
@@ -67,8 +67,8 @@ loop:
br label %loop
}
-
-; Hoist ADD and copy NUW if both ops have it. Commutative version.
+; Hoist ADD and copy NUW if both ops have it.
+; Version where operands are commuted.
define void @add_nuw_comm(i64 %c1, i64 %c2) {
; CHECK-LABEL: @add_nuw_comm(
; CHECK-NEXT: entry:
@@ -92,6 +92,56 @@ loop:
br label %loop
}
+; Hoist ADD and copy NUW if both ops have it.
+; Another version where operands are commuted.
+define void @add_nuw_comm2(i64 %c1, i64 %c2) {
+; CHECK-LABEL: @add_nuw_comm2(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[INVARIANT_OP:%.*]] = add nuw i64 [[C2:%.*]], [[C1:%.*]]
+; CHECK-NEXT: br label [[LOOP:%.*]]
+; CHECK: loop:
+; CHECK-NEXT: [[INDEX:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[INDEX_NEXT_REASS:%.*]], [[LOOP]] ]
+; CHECK-NEXT: [[STEP_ADD:%.*]] = add nuw i64 [[INDEX]], [[C1]]
+; CHECK-NEXT: call void @use(i64 [[STEP_ADD]])
+; CHECK-NEXT: [[INDEX_NEXT_REASS]] = add nuw i64 [[INVARIANT_OP]], [[INDEX]]
+; CHECK-NEXT: br label [[LOOP]]
+;
+entry:
+ br label %loop
+
+loop:
+ %index = phi i64 [ 0, %entry ], [ %index.next, %loop ]
+ %step.add = add nuw i64 %index, %c1
+ call void @use(i64 %step.add)
+ %index.next = add nuw i64 %c2, %step.add
+ br label %loop
+}
+
+; Hoist ADD and copy NUW if both ops have it.
+; Another version where operands are commuted.
+define void @add_nuw_comm3(i64 %c1, i64 %c2) {
+; CHECK-LABEL: @add_nuw_comm3(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[INVARIANT_OP:%.*]] = add nuw i64 [[C2:%.*]], [[C1:%.*]]
+; CHECK-NEXT: br label [[LOOP:%.*]]
+; CHECK: loop:
+; CHECK-NEXT: [[INDEX:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[INDEX_NEXT_REASS:%.*]], [[LOOP]] ]
+; CHECK-NEXT: [[STEP_ADD:%.*]] = add nuw i64 [[C1]], [[INDEX]]
+; CHECK-NEXT: call void @use(i64 [[STEP_ADD]])
+; CHECK-NEXT: [[INDEX_NEXT_REASS]] = add nuw i64 [[INVARIANT_OP]], [[INDEX]]
+; CHECK-NEXT: br label [[LOOP]]
+;
+entry:
+ br label %loop
+
+loop:
+ %index = phi i64 [ 0, %entry ], [ %index.next, %loop ]
+ %step.add = add nuw i64 %c1, %index
+ call void @use(i64 %step.add)
+ %index.next = add nuw i64 %c2, %step.add
+ br label %loop
+}
+
; Hoist MUL and drop NUW even if both ops have it.
define void @mul_nuw(i64 %c1, i64 %c2) {
; CHECK-LABEL: @mul_nuw(
@@ -116,7 +166,8 @@ loop:
br label %loop
}
-; Hoist MUL and drop NUW even if both ops have it. Commutative version.
+; Hoist MUL and drop NUW even if both ops have it.
+; Version where operands are commuted.
define void @mul_nuw_comm(i64 %c1, i64 %c2) {
; CHECK-LABEL: @mul_nuw_comm(
; CHECK-NEXT: entry:
@@ -140,6 +191,56 @@ loop:
br label %loop
}
+; Hoist MUL and drop NUW even if both ops have it.
+; Another version where operands are commuted.
+define void @mul_nuw_comm2(i64 %c1, i64 %c2) {
+; CHECK-LABEL: @mul_nuw_comm2(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[INVARIANT_OP:%.*]] = mul i64 [[C2:%.*]], [[C1:%.*]]
+; CHECK-NEXT: br label [[LOOP:%.*]]
+; CHECK: loop:
+; CHECK-NEXT: [[INDEX:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[INDEX_NEXT_REASS:%.*]], [[LOOP]] ]
+; CHECK-NEXT: [[STEP_ADD:%.*]] = mul nuw i64 [[INDEX]], [[C1]]
+; CHECK-NEXT: call void @use(i64 [[STEP_ADD]])
+; CHECK-NEXT: [[INDEX_NEXT_REASS]] = mul i64 [[INVARIANT_OP]], [[INDEX]]
+; CHECK-NEXT: br label [[LOOP]]
+;
+entry:
+ br label %loop
+
+loop:
+ %index = phi i64 [ 0, %entry ], [ %index.next, %loop ]
+ %step.add = mul nuw i64 %index, %c1
+ call void @use(i64 %step.add)
+ %index.next = mul nuw i64 %c2, %step.add
+ br label %loop
+}
+
+; Hoist MUL and drop NUW even if both ops have it.
+; Another version where operands are commuted.
+define void @mul_nuw_comm3(i64 %c1, i64 %c2) {
+; CHECK-LABEL: @mul_nuw_comm3(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[INVARIANT_OP:%.*]] = mul i64 [[C2:%.*]], [[C1:%.*]]
+; CHECK-NEXT: br label [[LOOP:%.*]]
+; CHECK: loop:
+; CHECK-NEXT: [[INDEX:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[INDEX_NEXT_REASS:%.*]], [[LOOP]] ]
+; CHECK-NEXT: [[STEP_ADD:%.*]] = mul nuw i64 [[C1]], [[INDEX]]
+; CHECK-NEXT: call void @use(i64 [[STEP_ADD]])
+; CHECK-NEXT: [[INDEX_NEXT_REASS]] = mul i64 [[INVARIANT_OP]], [[INDEX]]
+; CHECK-NEXT: br label [[LOOP]]
+;
+entry:
+ br label %loop
+
+loop:
+ %index = phi i64 [ 0, %entry ], [ %index.next, %loop ]
+ %step.add = mul nuw i64 %c1, %index
+ call void @use(i64 %step.add)
+ %index.next = mul nuw i64 %c2, %step.add
+ br label %loop
+}
+
; Hoist ADD but don't copy NUW if only one op has it.
define void @add_no_nuw(i64 %c1, i64 %c2) {
; CHECK-LABEL: @add_no_nuw(
More information about the llvm-commits
mailing list