Index: llvm/lib/Transforms/Scalar/SROA.cpp =================================================================== --- llvm/lib/Transforms/Scalar/SROA.cpp +++ llvm/lib/Transforms/Scalar/SROA.cpp @@ -3464,6 +3464,46 @@ } bool visitGetElementPtrInst(GetElementPtrInst &GEPI) { + // Fold gep (phi ptr1, ptr2) => phi gep(ptr1), gep(ptr2) + if (PHINode *PHI = dyn_cast(GEPI.getPointerOperand())) { + LLVM_DEBUG(dbgs() << " Rewriting gep(phi) -> phi(gep):" + << "\n original: " << *PHI + << "\n " << GEPI + << "\n to: "); + + SmallVector Index(GEPI.idx_begin(), GEPI.idx_end()); + bool IsInBounds = GEPI.isInBounds(); + IRBuilderTy PHIBuilder(GEPI.getParent()->getFirstNonPHI()); + PHINode *NewPN = PHIBuilder.CreatePHI(GEPI.getType(), + PHI->getNumIncomingValues(), + PHI->getName() + ".sroa.phi"); + for (unsigned I = 0, E = PHI->getNumIncomingValues(); I != E; ++I) { + Value *In = PHI->getIncomingValue(I); + BasicBlock *InBB = cast(PHI->getIncomingBlock(I)); + Instruction *Ins = dyn_cast(In); + if (!Ins) + Ins = InBB->getFirstNonPHI(); + IRBuilderTy Builder(Ins); + Value *NewVal = + IsInBounds + ? Builder.CreateInBoundsGEP(In, Index, + In->getName() + ".sroa.gep") + : Builder.CreateGEP(In, Index, In->getName() + ".sroa.gep"); + NewPN->addIncoming(NewVal, InBB); + if (isa(NewVal)) + visit(cast(NewVal)); + } + + GEPI.replaceAllUsesWith(NewPN); + GEPI.eraseFromParent(); + + LLVM_DEBUG(for (Value *In : NewPN->incoming_values()) + dbgs() << "\n " << *In; + dbgs() << "\n " << *NewPN << '\n'); + + return true; + } + enqueueUsers(GEPI); return false; } Index: llvm/test/Transforms/SROA/phi-and-select.ll =================================================================== --- llvm/test/Transforms/SROA/phi-and-select.ll +++ llvm/test/Transforms/SROA/phi-and-select.ll @@ -636,8 +636,7 @@ if.end: ; preds = %for.cond, %entry %f2 = phi %struct.S* [ %f, %entry ], [ %f, %for.cond ] -; CHECK: phi i32 -; CHECK: %[[cast:.*]] = bitcast i32* %[[alloca]] to %struct.S* +; CHECK: phi i32 [ undef, %entry ], [ undef, %for.cond ] phi i32 [ undef, %entry ], [ undef, %for.cond ] br i1 undef, label %if.then5, label %if.then2 @@ -646,7 +645,7 @@ if.then5: ; preds = %if.then2, %if.end %f1 = phi %struct.S* [ undef, %if.then2 ], [ %f2, %if.end ] -; CHECK: phi {{.*}} %[[cast]] +; CHECK: %f1.sroa.phi = phi i32* [ undef, %if.then2 ], [ %[[alloca]], %if.end ] store %struct.S undef, %struct.S* %f1, align 4 ret void } Index: llvm/test/Transforms/SROA/phi-gep.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/SROA/phi-gep.ll @@ -0,0 +1,81 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -S -sroa < %s | FileCheck %s + +%pair = type { i32, i32 } + +define i32 @test_sroa_phi_gep(i1 %cond) { +; CHECK-LABEL: @test_sroa_phi_gep( +; CHECK-NEXT: entry: +; CHECK-NEXT: br i1 [[COND:%.*]], label [[IF_THEN:%.*]], label [[END:%.*]] +; CHECK: if.then: +; CHECK-NEXT: br label [[END]] +; CHECK: end: +; CHECK-NEXT: [[PHI_SROA_PHI_SROA_SPECULATED:%.*]] = phi i32 [ undef, [[ENTRY:%.*]] ], [ undef, [[IF_THEN]] ] +; CHECK-NEXT: ret i32 [[PHI_SROA_PHI_SROA_SPECULATED]] +; +entry: + %a = alloca %pair, align 4 + %b = alloca %pair, align 4 + br i1 %cond, label %if.then, label %end + +if.then: + br label %end + +end: + %phi = phi %pair* [ %a, %entry], [ %b, %if.then ] + %gep = getelementptr inbounds %pair, %pair* %phi, i32 0, i32 1 + %load = load i32, i32* %gep, align 4 + ret i32 %load +} + +define i32 @test_sroa_phi_gep_undef(i1 %cond) { +; CHECK-LABEL: @test_sroa_phi_gep_undef( +; CHECK-NEXT: entry: +; CHECK-NEXT: br i1 [[COND:%.*]], label [[IF_THEN:%.*]], label [[END:%.*]] +; CHECK: if.then: +; CHECK-NEXT: [[PHI_SROA_PHI_SROA_SPECULATE_LOAD_IF_THEN:%.*]] = load i32, i32* undef, align 4 +; CHECK-NEXT: br label [[END]] +; CHECK: end: +; CHECK-NEXT: [[PHI_SROA_PHI_SROA_SPECULATED:%.*]] = phi i32 [ undef, [[ENTRY:%.*]] ], [ [[PHI_SROA_PHI_SROA_SPECULATE_LOAD_IF_THEN]], [[IF_THEN]] ] +; CHECK-NEXT: ret i32 [[PHI_SROA_PHI_SROA_SPECULATED]] +; +entry: + %a = alloca %pair, align 4 + br i1 %cond, label %if.then, label %end + +if.then: + br label %end + +end: + %phi = phi %pair* [ %a, %entry], [ undef, %if.then ] + %gep = getelementptr inbounds %pair, %pair* %phi, i32 0, i32 1 + %load = load i32, i32* %gep, align 4 + ret i32 %load +} + +@g = global %pair zeroinitializer, align 4 + +define i32 @test_sroa_phi_gep_global(i1 %cond) { +; CHECK-LABEL: @test_sroa_phi_gep_global( +; CHECK-NEXT: entry: +; CHECK-NEXT: br i1 [[COND:%.*]], label [[IF_THEN:%.*]], label [[END:%.*]] +; CHECK: if.then: +; CHECK-NEXT: [[PHI_SROA_PHI_SROA_SPECULATE_LOAD_IF_THEN:%.*]] = load i32, i32* getelementptr inbounds (%pair, %pair* @g, i32 0, i32 1), align 4 +; CHECK-NEXT: br label [[END]] +; CHECK: end: +; CHECK-NEXT: [[PHI_SROA_PHI_SROA_SPECULATED:%.*]] = phi i32 [ undef, [[ENTRY:%.*]] ], [ [[PHI_SROA_PHI_SROA_SPECULATE_LOAD_IF_THEN]], [[IF_THEN]] ] +; CHECK-NEXT: ret i32 [[PHI_SROA_PHI_SROA_SPECULATED]] +; +entry: + %a = alloca %pair, align 4 + br i1 %cond, label %if.then, label %end + +if.then: + br label %end + +end: + %phi = phi %pair* [ %a, %entry], [ @g, %if.then ] + %gep = getelementptr inbounds %pair, %pair* %phi, i32 0, i32 1 + %load = load i32, i32* %gep, align 4 + ret i32 %load +}