[llvm] [SROA] analyze gep(ptr,phi(const...)) (PR #82425)

via llvm-commits llvm-commits at lists.llvm.org
Tue Feb 20 13:50:40 PST 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-transforms

Author: Artem Belevich (Artem-B)

<details>
<summary>Changes</summary>

Recent changes to normalize GEPs to single-index i8 variant (90ba33099cbb1) allow more optimizations,
and some of them result in gep(alloca, phi(C1,C2,...)) which SROA could not handle.

This patch splits such GEPs into phi(gep(alloca, C1), gep(alloca, C2)) so SROA can analyze alloca slices.

---
Full diff: https://github.com/llvm/llvm-project/pull/82425.diff


2 Files Affected:

- (modified) llvm/lib/Transforms/Scalar/SROA.cpp (+57-2) 
- (modified) llvm/test/Transforms/SROA/phi-gep.ll (+48-6) 


``````````diff
diff --git a/llvm/lib/Transforms/Scalar/SROA.cpp b/llvm/lib/Transforms/Scalar/SROA.cpp
index 138dc38b5c14ce..19f092245c6308 100644
--- a/llvm/lib/Transforms/Scalar/SROA.cpp
+++ b/llvm/lib/Transforms/Scalar/SROA.cpp
@@ -4070,12 +4070,67 @@ class AggLoadStoreRewriter : public InstVisitor<AggLoadStoreRewriter, bool> {
     return true;
   }
 
+  bool foldGEPPhiConst(GetElementPtrInst &GEPI) {
+    if (GEPI.getNumIndices() != 1)
+      return false;
+
+    PHINode *PHI = cast<PHINode>(GEPI.getOperand(1));
+    if (!all_of(PHI->incoming_values(), [&](auto &V) {
+          auto *Parent = PHI->getIncomingBlock(V);
+          return isa<ConstantInt>(V) && !succ_empty(Parent) &&
+                 Parent->isLegalToHoistInto();
+        }))
+      return false;
+
+    LLVM_DEBUG(
+        dbgs() << "  Rewriting gep(ptr, phi(const)) -> phi(gep(ptr, const)):"
+               << "\n    original: " << *PHI << "\n              " << GEPI
+               << "\n          to: ");
+
+    SmallVector<Value *, 4> Index(GEPI.indices());
+    bool IsInBounds = GEPI.isInBounds();
+    IRB.SetInsertPoint(GEPI.getParent(), GEPI.getParent()->getFirstNonPHIIt());
+    PHINode *NewPN = IRB.CreatePHI(GEPI.getType(), PHI->getNumIncomingValues(),
+                                   PHI->getName() + ".sroa.phi");
+    for (unsigned I = 0, E = PHI->getNumIncomingValues(); I != E; ++I) {
+      BasicBlock *B = PHI->getIncomingBlock(I);
+      Value *NewVal = nullptr;
+      int Idx = NewPN->getBasicBlockIndex(B);
+      if (Idx >= 0) {
+        NewVal = NewPN->getIncomingValue(Idx);
+      } else {
+        Value *In = PHI->getIncomingValue(I);
+        BasicBlock *Parent = PHI->getIncomingBlock(I);
+        IRB.SetInsertPoint(Parent, Parent->getTerminator()->getIterator());
+        Type *Ty = GEPI.getSourceElementType();
+        NewVal = IRB.CreateGEP(Ty, GEPI.getPointerOperand(), In,
+                               In->getName() + ".sroa.gep", IsInBounds);
+      }
+      NewPN->addIncoming(NewVal, B);
+    }
+
+    Visited.erase(&GEPI);
+    GEPI.replaceAllUsesWith(NewPN);
+    GEPI.eraseFromParent();
+    Visited.insert(NewPN);
+    enqueueUsers(*NewPN);
+
+    LLVM_DEBUG(for (Value *In
+                    : NewPN->incoming_values()) dbgs()
+                   << "\n              " << *In;
+               dbgs() << "\n              " << *NewPN << '\n');
+
+    return true;
+  }
   bool visitGetElementPtrInst(GetElementPtrInst &GEPI) {
     if (foldGEPSelect(GEPI))
       return true;
 
-    if (isa<PHINode>(GEPI.getPointerOperand()) &&
-        foldGEPPhi(GEPI))
+    if (isa<PHINode>(GEPI.getPointerOperand()) && foldGEPPhi(GEPI))
+      return true;
+
+    if (GEPI.hasIndices() && isa<PHINode>(GEPI.getOperand(1)) &&
+        foldGEPPhiConst(GEPI))
       return true;
 
     enqueueUsers(GEPI);
diff --git a/llvm/test/Transforms/SROA/phi-gep.ll b/llvm/test/Transforms/SROA/phi-gep.ll
index c5aa1cdd9cf654..7a69e6d40dd9d2 100644
--- a/llvm/test/Transforms/SROA/phi-gep.ll
+++ b/llvm/test/Transforms/SROA/phi-gep.ll
@@ -3,6 +3,7 @@
 ; RUN: opt -S -passes='sroa<modify-cfg>' < %s | FileCheck %s --check-prefixes=CHECK,CHECK-MODIFY-CFG
 
 %pair = type { i32, i32 }
+%t1   = type { i64, i32, i32, i64, i32, i32 }
 
 define i32 @test_sroa_phi_gep(i1 %cond) {
 ; CHECK-LABEL: @test_sroa_phi_gep(
@@ -245,7 +246,7 @@ define i32 @test_sroa_invoke_phi_gep(i1 %cond) personality ptr @__gxx_personalit
 ; CHECK-NEXT:    br i1 [[COND:%.*]], label [[CALL:%.*]], label [[END:%.*]]
 ; CHECK:       call:
 ; CHECK-NEXT:    [[B:%.*]] = invoke ptr @foo()
-; CHECK-NEXT:    to label [[END]] unwind label [[INVOKE_CATCH:%.*]]
+; CHECK-NEXT:            to label [[END]] unwind label [[INVOKE_CATCH:%.*]]
 ; CHECK:       end:
 ; CHECK-NEXT:    [[PHI:%.*]] = phi ptr [ [[A]], [[ENTRY:%.*]] ], [ [[B]], [[CALL]] ]
 ; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds [[PAIR]], ptr [[PHI]], i32 0, i32 1
@@ -253,7 +254,7 @@ define i32 @test_sroa_invoke_phi_gep(i1 %cond) personality ptr @__gxx_personalit
 ; CHECK-NEXT:    ret i32 [[LOAD]]
 ; CHECK:       invoke_catch:
 ; CHECK-NEXT:    [[RES:%.*]] = landingpad { ptr, i32 }
-; CHECK-NEXT:    catch ptr null
+; CHECK-NEXT:            catch ptr null
 ; CHECK-NEXT:    ret i32 0
 ;
 entry:
@@ -468,10 +469,10 @@ define i32 @test_sroa_phi_gep_multiple_values_from_same_block(i32 %arg) {
 ; CHECK-LABEL: @test_sroa_phi_gep_multiple_values_from_same_block(
 ; CHECK-NEXT:  bb.1:
 ; CHECK-NEXT:    switch i32 [[ARG:%.*]], label [[BB_3:%.*]] [
-; CHECK-NEXT:    i32 1, label [[BB_2:%.*]]
-; CHECK-NEXT:    i32 2, label [[BB_2]]
-; CHECK-NEXT:    i32 3, label [[BB_4:%.*]]
-; CHECK-NEXT:    i32 4, label [[BB_4]]
+; CHECK-NEXT:      i32 1, label [[BB_2:%.*]]
+; CHECK-NEXT:      i32 2, label [[BB_2]]
+; CHECK-NEXT:      i32 3, label [[BB_4:%.*]]
+; CHECK-NEXT:      i32 4, label [[BB_4]]
 ; CHECK-NEXT:    ]
 ; CHECK:       bb.2:
 ; CHECK-NEXT:    br label [[BB_4]]
@@ -504,6 +505,47 @@ bb.4:                                                ; preds = %bb.1, %bb.1, %bb
   ret i32 %load
 }
 
+
+define void @test_gep_phi_const(i32 %arg) {
+; CHECK-LABEL: @test_gep_phi_const(
+; CHECK-NEXT:  bb:
+; CHECK-NEXT:    switch i32 [[ARG:%.*]], label [[BB9:%.*]] [
+; CHECK-NEXT:      i32 0, label [[BB11:%.*]]
+; CHECK-NEXT:      i32 1, label [[BB10:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       bb9:
+; CHECK-NEXT:    [[PHI:%.*]] = phi i64 [ 8, [[BB10]] ], [ 16, [[BB:%.*]] ]
+; CHECK-NEXT:    [[PHI_SROA_PHI_SROA_SPECULATED:%.*]] = phi ptr [ undef, [[BB10]] ], [ undef, [[BB]] ]
+; CHECK-NEXT:    br label [[BB11]]
+; CHECK:       bb10:
+; CHECK-NEXT:    br label [[BB9]]
+; CHECK:       bb11:
+; CHECK-NEXT:    [[PHI12:%.*]] = phi ptr [ [[PHI_SROA_PHI_SROA_SPECULATED]], [[BB9]] ], [ undef, [[BB]] ]
+; CHECK-NEXT:    store i8 0, ptr [[PHI12]], align 1
+; CHECK-NEXT:    ret void
+;
+bb:
+  %alloca = alloca %t1, align 8
+  switch i32 %arg, label %bb9 [
+  i32 0, label %bb11
+  i32 1, label %bb10
+  ]
+
+bb9:                                              ; preds = %bb10, %bb
+  %phi = phi i64 [ 8, %bb10 ], [ 16, %bb ]
+  %getelementptr = getelementptr i8, ptr %alloca, i64 %phi
+  %load = load ptr, ptr %getelementptr, align 8
+  br label %bb11
+
+bb10:                                             ; preds = %bb
+  br label %bb9
+
+bb11:                                             ; preds = %bb9, %bb
+  %phi12 = phi ptr [ %load, %bb9 ], [ undef, %bb ]
+  store i8 0, ptr %phi12, align 1
+  ret void
+}
+
 declare ptr @foo()
 
 declare i32 @__gxx_personality_v0(...)

``````````

</details>


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


More information about the llvm-commits mailing list