[llvm] 2b6683f - Expand loop peeling phi computation to handle binary ops and casts

Jamie Schmeiser via llvm-commits llvm-commits at lists.llvm.org
Mon Dec 5 09:11:29 PST 2022


Author: Jamie Schmeiser
Date: 2022-12-05T12:10:53-05:00
New Revision: 2b6683fd5f7481d57a29ca6c5cd68822e1cfe5b0

URL: https://github.com/llvm/llvm-project/commit/2b6683fd5f7481d57a29ca6c5cd68822e1cfe5b0
DIFF: https://github.com/llvm/llvm-project/commit/2b6683fd5f7481d57a29ca6c5cd68822e1cfe5b0.diff

LOG: Expand loop peeling phi computation to handle binary ops and casts

Summary:
Expand the capabilities of the code for computing how many peels are
needed to make phis determined.  A cast gets the peel count for the
value being casted while a binary op gets the maximum of the operands.

Respond to review comments: remove redundant asserts.

Author: Jamie Schmeiser <schmeise at ca.ibm.com>
Reviewed By:mkazantsev (Max Kazantsev),syzaara (Zaara Syeda)
Differential Revision: https://reviews.llvm.org/D138719

Added: 
    

Modified: 
    llvm/lib/Transforms/Utils/LoopPeel.cpp
    llvm/test/Transforms/LoopUnroll/peel-loop-phi-analysis.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/Utils/LoopPeel.cpp b/llvm/lib/Transforms/Utils/LoopPeel.cpp
index bfb865a502dc8..0c24c22c2d74e 100644
--- a/llvm/lib/Transforms/Utils/LoopPeel.cpp
+++ b/llvm/lib/Transforms/Utils/LoopPeel.cpp
@@ -231,7 +231,22 @@ PhiAnalyzer::PeelCounter PhiAnalyzer::calculate(const Value &V) {
            "unexpected value saved");
     return (IterationsToInvariance[Phi] = addOne(Iterations));
   }
-  // TODO: handle expressions
+  if (const Instruction *I = dyn_cast<Instruction>(&V)) {
+    if (isa<CmpInst>(I) || I->isBinaryOp()) {
+      // Binary instructions get the max of the operands.
+      PeelCounter LHS = calculate(*I->getOperand(0));
+      if (LHS == Unknown)
+        return Unknown;
+      PeelCounter RHS = calculate(*I->getOperand(1));
+      if (RHS == Unknown)
+        return Unknown;
+      return (IterationsToInvariance[I] = {std::max(*LHS, *RHS)});
+    }
+    if (I->isCast())
+      // Cast instructions get the value of the operand.
+      return (IterationsToInvariance[I] = calculate(*I->getOperand(0)));
+  }
+  // TODO: handle more expressions
 
   // Everything else is Unknown.
   assert(IterationsToInvariance[&V] == Unknown && "unexpected value saved");

diff  --git a/llvm/test/Transforms/LoopUnroll/peel-loop-phi-analysis.ll b/llvm/test/Transforms/LoopUnroll/peel-loop-phi-analysis.ll
index 2b2936d41d8d1..e24eeef52de4e 100644
--- a/llvm/test/Transforms/LoopUnroll/peel-loop-phi-analysis.ll
+++ b/llvm/test/Transforms/LoopUnroll/peel-loop-phi-analysis.ll
@@ -24,7 +24,6 @@ define void @_Z8castTestv() {
 ; Third iteration: g(0), x=5 (requires cast), f(5.0), a=5.0
 ; Fourth iteration (and subsequent): g(5), x=5, f(5.0), a=5.0
 ; Therefore, peeling 3 times removes the phi nodes, so check for 3 peels.
-; CURRENT LIMITATION: only peels twice because cannot handle cast
 ;
 ; void castTest() {
 ;   int x = 0;
@@ -61,8 +60,17 @@ define void @_Z8castTestv() {
 ; CHECK-NEXT:    [[EXITCOND_PEEL5:%.*]] = icmp ne i32 [[INC_PEEL4]], 100000
 ; CHECK-NEXT:    br i1 [[EXITCOND_PEEL5]], label [[FOR_BODY_PEEL_NEXT1:%.*]], label [[FOR_COND_CLEANUP]]
 ; CHECK:       for.body.peel.next1:
-; CHECK-NEXT:    br label [[FOR_BODY_PEEL_NEXT6:%.*]]
+; CHECK-NEXT:    br label [[FOR_BODY_PEEL7:%.*]]
+; CHECK:       for.body.peel7:
+; CHECK-NEXT:    tail call void @_Z1gi(i32 noundef signext [[CONV_PEEL3]])
+; CHECK-NEXT:    [[CONV_PEEL8:%.*]] = fptosi float 5.000000e+00 to i32
+; CHECK-NEXT:    tail call void @_Z1ff(float noundef 5.000000e+00)
+; CHECK-NEXT:    [[INC_PEEL9:%.*]] = add nuw nsw i32 [[INC_PEEL4]], 1
+; CHECK-NEXT:    [[EXITCOND_PEEL10:%.*]] = icmp ne i32 [[INC_PEEL9]], 100000
+; CHECK-NEXT:    br i1 [[EXITCOND_PEEL10]], label [[FOR_BODY_PEEL_NEXT6:%.*]], label [[FOR_COND_CLEANUP]]
 ; CHECK:       for.body.peel.next6:
+; CHECK-NEXT:    br label [[FOR_BODY_PEEL_NEXT11:%.*]]
+; CHECK:       for.body.peel.next11:
 ; CHECK-NEXT:    br label [[ENTRY_PEEL_NEWPH:%.*]]
 ; CHECK:       entry.peel.newph:
 ; CHECK-NEXT:    br label [[FOR_BODY:%.*]]
@@ -71,8 +79,8 @@ define void @_Z8castTestv() {
 ; CHECK:       for.cond.cleanup:
 ; CHECK-NEXT:    ret void
 ; CHECK:       for.body:
-; CHECK-NEXT:    [[I:%.*]] = phi i32 [ [[INC_PEEL4]], [[ENTRY_PEEL_NEWPH]] ], [ [[INC:%.*]], [[FOR_BODY]] ]
-; CHECK-NEXT:    [[X:%.*]] = phi i32 [ [[CONV_PEEL3]], [[ENTRY_PEEL_NEWPH]] ], [ 5, [[FOR_BODY]] ]
+; CHECK-NEXT:    [[I:%.*]] = phi i32 [ [[INC_PEEL9]], [[ENTRY_PEEL_NEWPH]] ], [ [[INC:%.*]], [[FOR_BODY]] ]
+; CHECK-NEXT:    [[X:%.*]] = phi i32 [ [[CONV_PEEL8]], [[ENTRY_PEEL_NEWPH]] ], [ 5, [[FOR_BODY]] ]
 ; CHECK-NEXT:    tail call void @_Z1gi(i32 noundef signext [[X]])
 ; CHECK-NEXT:    tail call void @_Z1ff(float noundef 5.000000e+00)
 ; CHECK-NEXT:    [[INC]] = add nuw nsw i32 [[I]], 1
@@ -110,7 +118,6 @@ define void @_Z6binaryv() {
 ; Third iteration: g(1), x=6, g(5), y=6, a=5
 ; Fourth iteration (and subsequent): g(6), x=6, g(5), y=6, a=5
 ; Therefore, peeling 3 times removes the phi nodes.
-; CURRENT_LIMITATION: only peels once because cannot handle binary operator
 ;
 ; void g(int);
 ; void binary() {
@@ -139,8 +146,24 @@ define void @_Z6binaryv() {
 ; CHECK-NEXT:    [[EXITCOND_PEEL:%.*]] = icmp eq i32 [[INC_PEEL]], 100000
 ; CHECK-NEXT:    br i1 [[EXITCOND_PEEL]], label [[FOR_COND_CLEANUP:%.*]], label [[FOR_BODY_PEEL_NEXT:%.*]]
 ; CHECK:       for.body.peel.next:
-; CHECK-NEXT:    br label [[FOR_BODY_PEEL_NEXT1:%.*]]
+; CHECK-NEXT:    br label [[FOR_BODY_PEEL2:%.*]]
+; CHECK:       for.body.peel2:
+; CHECK-NEXT:    tail call void @_Z1gi(i32 signext 0)
+; CHECK-NEXT:    tail call void @_Z1gi(i32 signext 5)
+; CHECK-NEXT:    [[INC_PEEL4:%.*]] = add nuw nsw i32 [[INC_PEEL]], 1
+; CHECK-NEXT:    [[EXITCOND_PEEL5:%.*]] = icmp eq i32 [[INC_PEEL4]], 100000
+; CHECK-NEXT:    br i1 [[EXITCOND_PEEL5]], label [[FOR_COND_CLEANUP]], label [[FOR_BODY_PEEL_NEXT1:%.*]]
 ; CHECK:       for.body.peel.next1:
+; CHECK-NEXT:    br label [[FOR_BODY_PEEL7:%.*]]
+; CHECK:       for.body.peel7:
+; CHECK-NEXT:    tail call void @_Z1gi(i32 signext [[ADD_PEEL]])
+; CHECK-NEXT:    tail call void @_Z1gi(i32 signext 5)
+; CHECK-NEXT:    [[INC_PEEL9:%.*]] = add nuw nsw i32 [[INC_PEEL4]], 1
+; CHECK-NEXT:    [[EXITCOND_PEEL10:%.*]] = icmp eq i32 [[INC_PEEL9]], 100000
+; CHECK-NEXT:    br i1 [[EXITCOND_PEEL10]], label [[FOR_COND_CLEANUP]], label [[FOR_BODY_PEEL_NEXT6:%.*]]
+; CHECK:       for.body.peel.next6:
+; CHECK-NEXT:    br label [[FOR_BODY_PEEL_NEXT11:%.*]]
+; CHECK:       for.body.peel.next11:
 ; CHECK-NEXT:    br label [[ENTRY_PEEL_NEWPH:%.*]]
 ; CHECK:       entry.peel.newph:
 ; CHECK-NEXT:    br label [[FOR_BODY:%.*]]
@@ -149,10 +172,8 @@ define void @_Z6binaryv() {
 ; CHECK:       for.cond.cleanup:
 ; CHECK-NEXT:    ret void
 ; CHECK:       for.body:
-; CHECK-NEXT:    [[I:%.*]] = phi i32 [ [[INC_PEEL]], [[ENTRY_PEEL_NEWPH]] ], [ [[INC:%.*]], [[FOR_BODY]] ]
-; CHECK-NEXT:    [[Y:%.*]] = phi i32 [ [[ADD_PEEL]], [[ENTRY_PEEL_NEWPH]] ], [ 6, [[FOR_BODY]] ]
-; CHECK-NEXT:    [[X:%.*]] = phi i32 [ 0, [[ENTRY_PEEL_NEWPH]] ], [ [[Y]], [[FOR_BODY]] ]
-; CHECK-NEXT:    tail call void @_Z1gi(i32 signext [[X]])
+; CHECK-NEXT:    [[I:%.*]] = phi i32 [ [[INC_PEEL9]], [[ENTRY_PEEL_NEWPH]] ], [ [[INC:%.*]], [[FOR_BODY]] ]
+; CHECK-NEXT:    tail call void @_Z1gi(i32 signext 6)
 ; CHECK-NEXT:    tail call void @_Z1gi(i32 signext 5)
 ; CHECK-NEXT:    [[INC]] = add nuw nsw i32 [[I]], 1
 ; CHECK-NEXT:    [[EXITCOND:%.*]] = icmp eq i32 [[INC]], 100000


        


More information about the llvm-commits mailing list