[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 10:15:51 PDT 2024
https://github.com/artagnon updated https://github.com/llvm/llvm-project/pull/107072
>From 2bc99bfae2f1ff58a189241e226566c2ad75e34c 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 1/3] 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..ecb65be1600907 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(
>From 8e8f1d776b53e240a6968b17138b4f7df41705a5 Mon Sep 17 00:00:00 2001
From: Ramkumar Ramachandra <ramkumar.ramachandra at codasip.com>
Date: Wed, 4 Sep 2024 16:47:22 +0100
Subject: [PATCH 2/3] LICM: generalize further strengthening check
---
llvm/lib/Transforms/Scalar/LICM.cpp | 39 ++++++++----------------
llvm/test/Transforms/LICM/hoist-binop.ll | 16 +++++-----
2 files changed, 21 insertions(+), 34 deletions(-)
diff --git a/llvm/lib/Transforms/Scalar/LICM.cpp b/llvm/lib/Transforms/Scalar/LICM.cpp
index ecb65be1600907..6498f37d9c798c 100644
--- a/llvm/lib/Transforms/Scalar/LICM.cpp
+++ b/llvm/lib/Transforms/Scalar/LICM.cpp
@@ -2803,13 +2803,14 @@ static bool hoistMulAddAssociation(Instruction &I, Loop &L,
/// Reassociate associative binary expressions of the form
///
-/// 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
+/// 1. "(LV op C1) op C2" ==> "LV op (C1 op C2)"
+/// 2. "(C1 op LV) op C2" ==> "LV op (C1 op C2)"
+/// 3. "C2 op (C1 op LV)" ==> "LV op (C1 op C2)"
+/// 4. "C2 op (LV op C1)" ==> "LV op (C1 op C2)"
///
-/// where LV is a loop variant, and C1 and C2 are loop invariants that we want
-/// to hoist.
+/// where op is an associative BinOp, LV is a loop variant, and C1 and C2 are
+/// loop invariants that we want to hoist, noting that associativity implies
+/// commutativity.
static bool hoistBOAssociation(Instruction &I, Loop &L,
ICFLoopSafetyInfo &SafetyInfo,
MemorySSAUpdater &MSSAU, AssumptionCache *AC,
@@ -2833,35 +2834,21 @@ static bool hoistBOAssociation(Instruction &I, Loop &L,
Value *C1 = BO0->getOperand(1);
Value *C2 = BO->getOperand(!BinOpInRHS);
- 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");
+ assert(BO->isCommutative() && BO0->isCommutative() &&
+ "Associativity implies commutativity");
+ if (L.isLoopInvariant(LV) && !L.isLoopInvariant(C1))
std::swap(LV, C1);
- } else {
+ if (L.isLoopInvariant(LV) || !L.isLoopInvariant(C1) || !L.isLoopInvariant(C2))
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 =
- BinOpInRHS
- ? BinaryOperator::Create(Opcode, Inv, LV, BO->getName() + ".reass",
- BO->getIterator())
- : BinaryOperator::Create(Opcode, LV, Inv, BO->getName() + ".reass",
- BO->getIterator());
+ auto *NewBO = 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 f50f308faea676..a092f13703db5e 100644
--- a/llvm/test/Transforms/LICM/hoist-binop.ll
+++ b/llvm/test/Transforms/LICM/hoist-binop.ll
@@ -97,13 +97,13 @@ loop:
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: [[INVARIANT_OP:%.*]] = add nuw i64 [[C1:%.*]], [[C2:%.*]]
; 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: [[INDEX_NEXT_REASS]] = add nuw i64 [[INDEX]], [[INVARIANT_OP]]
; CHECK-NEXT: br label [[LOOP]]
;
entry:
@@ -122,13 +122,13 @@ loop:
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: [[INVARIANT_OP:%.*]] = add nuw i64 [[C1:%.*]], [[C2:%.*]]
; 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: [[INDEX_NEXT_REASS]] = add nuw i64 [[INDEX]], [[INVARIANT_OP]]
; CHECK-NEXT: br label [[LOOP]]
;
entry:
@@ -196,13 +196,13 @@ loop:
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: [[INVARIANT_OP:%.*]] = mul i64 [[C1:%.*]], [[C2:%.*]]
; 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: [[INDEX_NEXT_REASS]] = mul i64 [[INDEX]], [[INVARIANT_OP]]
; CHECK-NEXT: br label [[LOOP]]
;
entry:
@@ -221,13 +221,13 @@ loop:
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: [[INVARIANT_OP:%.*]] = mul i64 [[C1:%.*]], [[C2:%.*]]
; 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: [[INDEX_NEXT_REASS]] = mul i64 [[INDEX]], [[INVARIANT_OP]]
; CHECK-NEXT: br label [[LOOP]]
;
entry:
>From e575d84e4a1cc3b6dd582e0731e39f41c9d15f41 Mon Sep 17 00:00:00 2001
From: Ramkumar Ramachandra <ramkumar.ramachandra at codasip.com>
Date: Wed, 4 Sep 2024 17:57:20 +0100
Subject: [PATCH 3/3] LICM: handle BinOp in RHS correctly
---
llvm/lib/Transforms/Scalar/LICM.cpp | 6 +--
llvm/test/Transforms/LICM/hoist-binop.ll | 54 ++++++++++++++++++++++++
2 files changed, 57 insertions(+), 3 deletions(-)
diff --git a/llvm/lib/Transforms/Scalar/LICM.cpp b/llvm/lib/Transforms/Scalar/LICM.cpp
index 6498f37d9c798c..23e9c70b62642a 100644
--- a/llvm/lib/Transforms/Scalar/LICM.cpp
+++ b/llvm/lib/Transforms/Scalar/LICM.cpp
@@ -2824,15 +2824,15 @@ static bool hoistBOAssociation(Instruction &I, Loop &L,
if (Opcode != Instruction::Add && Opcode != Instruction::Mul)
return false;
- bool BinOpInRHS = isa<BinaryOperator>(BO->getOperand(1));
- auto *BO0 = dyn_cast<BinaryOperator>(BO->getOperand(BinOpInRHS));
+ bool LVInRHS = L.isLoopInvariant(BO->getOperand(0));
+ auto *BO0 = dyn_cast<BinaryOperator>(BO->getOperand(LVInRHS));
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(!BinOpInRHS);
+ Value *C2 = BO->getOperand(!LVInRHS);
assert(BO->isCommutative() && BO0->isCommutative() &&
"Associativity implies commutativity");
diff --git a/llvm/test/Transforms/LICM/hoist-binop.ll b/llvm/test/Transforms/LICM/hoist-binop.ll
index a092f13703db5e..a840e247578840 100644
--- a/llvm/test/Transforms/LICM/hoist-binop.ll
+++ b/llvm/test/Transforms/LICM/hoist-binop.ll
@@ -142,6 +142,33 @@ loop:
br label %loop
}
+; Hoist ADD and copy NUW if both ops have it.
+; A version where the LHS and RHS of the outer BinOp are BinOps.
+define void @add_nuw_twobinops(i64 %c1, i64 %c2) {
+; CHECK-LABEL: @add_nuw_twobinops(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[C2_PLUS_2:%.*]] = add nuw i64 [[C2:%.*]], 2
+; CHECK-NEXT: [[INVARIANT_OP:%.*]] = add nuw i64 [[C1:%.*]], [[C2_PLUS_2]]
+; 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 [[INDEX]], [[INVARIANT_OP]]
+; 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)
+ %c2.plus.2 = add nuw i64 %c2, 2
+ %index.next = add nuw i64 %step.add, %c2.plus.2
+ 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(
@@ -241,6 +268,33 @@ loop:
br label %loop
}
+; Hoist MUL and drop NUW even if both ops have it.
+; A version where the LHS and RHS of the outer BinOp are BinOps.
+define void @mul_nuw_twobinops(i64 %c1, i64 %c2) {
+; CHECK-LABEL: @mul_nuw_twobinops(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[C2_PLUS_2:%.*]] = add nuw i64 [[C2:%.*]], 2
+; CHECK-NEXT: [[INVARIANT_OP:%.*]] = mul i64 [[C1:%.*]], [[C2_PLUS_2]]
+; 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 [[INDEX]], [[INVARIANT_OP]]
+; 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)
+ %c2.plus.2 = add nuw i64 %c2, 2
+ %index.next = mul nuw i64 %step.add, %c2.plus.2
+ 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