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

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


https://github.com/Artem-B created https://github.com/llvm/llvm-project/pull/82425

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.

>From 16c50370cded490a02f662a8caae5d8d6facf79f Mon Sep 17 00:00:00 2001
From: Artem Belevich <tra at google.com>
Date: Fri, 16 Feb 2024 17:06:17 -0800
Subject: [PATCH 1/2] [SROA] analyze gep(ptr,phi(const...))

Recent changes to normalize GEPs to single-index i8 variant 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 accesses.
---
 llvm/lib/Transforms/Scalar/SROA.cpp | 59 ++++++++++++++++++++++++++++-
 1 file changed, 57 insertions(+), 2 deletions(-)

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);

>From 655290cc843b8b1d8485c70de05eefaadbc59a81 Mon Sep 17 00:00:00 2001
From: Artem Belevich <tra at google.com>
Date: Tue, 20 Feb 2024 13:45:37 -0800
Subject: [PATCH 2/2] Added a test for SROA over gep(ptr, phi(const))

---
 llvm/test/Transforms/SROA/phi-gep.ll | 54 ++++++++++++++++++++++++----
 1 file changed, 48 insertions(+), 6 deletions(-)

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(...)



More information about the llvm-commits mailing list