Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions llvm/include/llvm/Transforms/Utils/SSAUpdaterBulk.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,13 @@ class SSAUpdaterBulk {
/// vector.
void RewriteAllUses(DominatorTree *DT,
SmallVectorImpl<PHINode *> *InsertedPHIs = nullptr);

private:
void createPHIsAndRewrite(DominatorTree *DT,
SmallVectorImpl<PHINode *> &InsertedPHIs);
static bool simplifyPass(SmallVectorImpl<PHINode *> &Worklist);
static bool deduplicatePass(const SmallVectorImpl<PHINode *> &Worklist,
SmallPtrSetImpl<PHINode *> &PHIToRemove);
};

} // end namespace llvm
Expand Down
84 changes: 80 additions & 4 deletions llvm/lib/Transforms/Utils/SSAUpdaterBulk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@
//===----------------------------------------------------------------------===//

#include "llvm/Transforms/Utils/SSAUpdaterBulk.h"
#include "llvm/Analysis/InstructionSimplify.h"
#include "llvm/Analysis/IteratedDominanceFrontier.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Use.h"
#include "llvm/IR/Value.h"
#include "llvm/Transforms/Utils/Local.h"

using namespace llvm;

Expand Down Expand Up @@ -109,8 +111,8 @@ struct BBValueInfo {

/// Perform all the necessary updates, including new PHI-nodes insertion and the
/// requested uses update.
void SSAUpdaterBulk::RewriteAllUses(DominatorTree *DT,
SmallVectorImpl<PHINode *> *InsertedPHIs) {
void SSAUpdaterBulk::createPHIsAndRewrite(
DominatorTree *DT, SmallVectorImpl<PHINode *> &InsertedPHIs) {
DenseMap<BasicBlock *, BBValueInfo> BBInfos;
for (auto &R : Rewrites) {
BBInfos.clear();
Expand Down Expand Up @@ -150,8 +152,7 @@ void SSAUpdaterBulk::RewriteAllUses(DominatorTree *DT,
IRBuilder<> B(FrontierBB, FrontierBB->begin());
PHINode *PN = B.CreatePHI(R.Ty, 0, R.Name);
BBInfos[FrontierBB].LiveInValue = PN;
if (InsertedPHIs)
InsertedPHIs->push_back(PN);
InsertedPHIs.push_back(PN);
}

// IsLiveOut indicates whether we are computing live-out values (true) or
Expand Down Expand Up @@ -223,3 +224,78 @@ void SSAUpdaterBulk::RewriteAllUses(DominatorTree *DT,
}
}
}

bool SSAUpdaterBulk::simplifyPass(SmallVectorImpl<PHINode *> &Worklist) {
if (Worklist.empty())
return false;

const DataLayout &DL = Worklist.front()->getParent()->getDataLayout();
bool Change = false;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
bool Change = false;
bool Changed = false;

nit: More typical naming for this flag.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will address this in the new stacker PR.

for (PHINode *&PHI : Worklist) {
if (Value *Replacement = simplifyInstruction(PHI, DL)) {
PHI->replaceAllUsesWith(Replacement);
PHI->eraseFromParent();
PHI = nullptr; // Mark as removed
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could also iterate over Worklist using erase_if instead to avoid leaving behind nullptrs.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree, but I don't see much sense since this is internal routine and we're know what we're doing after that :)

Change = true;
}
}
return Change;
}

bool SSAUpdaterBulk::deduplicatePass(const SmallVectorImpl<PHINode *> &Worklist,
SmallPtrSetImpl<PHINode *> &PHIToRemove) {

auto FindFirstNonPHIIt = [](BasicBlock *BB) {
PHINode *LastPHI = nullptr;
for (auto &PHI : BB->phis())
LastPHI = &PHI;
assert(LastPHI);
return std::next(LastPHI->getIterator());
};

// BB -> First BB's Non-PHI iterator map
SmallDenseMap<BasicBlock *, BasicBlock::iterator> Blocks;
// Reverse Worklist to preserve the order of new phis.
for (PHINode *PHI : reverse(Worklist)) {
if (!PHI)
continue;
auto *BB = PHI->getParent();
auto [I, Inserted] = Blocks.try_emplace(BB);
if (Inserted)
I->second = FindFirstNonPHIIt(BB);

// Move newly inserted PHIs to the end to ensure that
// EliminateDuplicatePHINodes prioritizes removing the newly created PHIs
// over the existing ones, preserving the original PHI nodes.
PHI->moveBefore(I->second);
}

for (auto [BB, I] : Blocks)
EliminateDuplicatePHINodes(BB, PHIToRemove);

for (PHINode *PHI : PHIToRemove)
PHI->eraseFromParent();

return !PHIToRemove.empty();
}

void SSAUpdaterBulk::RewriteAllUses(DominatorTree *DT,
SmallVectorImpl<PHINode *> *InsertedPHIs) {
SmallVector<PHINode *, 4> PHIs;
createPHIsAndRewrite(DT, PHIs);
simplifyPass(PHIs);

SmallPtrSet<PHINode *, 8> PHIToRemove;
deduplicatePass(PHIs, PHIToRemove);

if (!InsertedPHIs)
return;

for (auto *&PHI : PHIs)
if (PHI && PHIToRemove.count(PHI))
PHI = nullptr; // Mark as removed.

InsertedPHIs->reserve(PHIs.size() - PHIToRemove.size());
std::copy_if(PHIs.begin(), PHIs.end(), std::back_inserter(*InsertedPHIs),
[](PHINode *PHI) { return PHI != nullptr; });
}
4 changes: 2 additions & 2 deletions llvm/test/CodeGen/WebAssembly/lower-wasm-sjlj.ll
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ entry:
; CHECK-NEXT: br label %setjmp.dispatch

; CHECK: setjmp.dispatch:
; CHECK-NEXT: %label.phi = phi i32 [ %label, %if.end ], [ -1, %entry ]
; CHECK-NEXT: %[[VAL2:.*]] = phi i32 [ %val, %if.end ], [ undef, %entry ]
; CHECK-NEXT: %[[BUF:.*]] = phi ptr [ %[[BUF2:.*]], %if.end ], [ undef, %entry ]
; CHECK-NEXT: %label.phi = phi i32 [ %label, %if.end ], [ -1, %entry ]
; CHECK-NEXT: switch i32 %label.phi, label %entry.split [
; CHECK-NEXT: i32 1, label %entry.split.split
; CHECK-NEXT: ]
Expand All @@ -42,8 +42,8 @@ entry:
; CHECK-NEXT: br label %entry.split.split

; CHECK: entry.split.split:
; CHECK-NEXT: %[[BUF2]] = phi ptr [ %[[BUF]], %setjmp.dispatch ], [ %buf, %entry.split ]
; CHECK-NEXT: %setjmp.ret = phi i32 [ 0, %entry.split ], [ %[[VAL2]], %setjmp.dispatch ]
; CHECK-NEXT: %[[BUF2]] = phi ptr [ %[[BUF]], %setjmp.dispatch ], [ %buf, %entry.split ]
; CHECK-NEXT: invoke void @__wasm_longjmp(ptr %[[BUF2]], i32 1)
; CHECK-NEXT: to label %.noexc unwind label %catch.dispatch.longjmp

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,14 @@ define i32 @test1(i32 %num) {
; CHECK-NEXT: [[CMP_EXIT:%.*]] = icmp slt i32 [[INC]], [[NUM:%.*]]
; CHECK-NEXT: br i1 [[CMP_EXIT]], label [[FOR_BODY]], label [[FOR_END:%.*]]
; CHECK: for.inc.jt2:
; CHECK-NEXT: [[COUNT4:%.*]] = phi i32 [ [[COUNT1]], [[SEL_SI_UNFOLD_FALSE_JT2]] ], [ [[COUNT2]], [[CASE1]] ]
; CHECK-NEXT: [[STATE_NEXT_JT2]] = phi i32 [ 2, [[CASE1]] ], [ [[DOTSI_UNFOLD_PHI_JT2]], [[SEL_SI_UNFOLD_FALSE_JT2]] ]
; CHECK-NEXT: [[COUNT4:%.*]] = phi i32 [ [[COUNT1]], [[SEL_SI_UNFOLD_FALSE_JT2]] ], [ [[COUNT2]], [[CASE1]] ]
; CHECK-NEXT: [[INC_JT2]] = add nsw i32 [[COUNT4]], 1
; CHECK-NEXT: [[CMP_EXIT_JT2:%.*]] = icmp slt i32 [[INC_JT2]], [[NUM]]
; CHECK-NEXT: br i1 [[CMP_EXIT_JT2]], label [[FOR_BODY_JT2]], label [[FOR_END]]
; CHECK: for.inc.jt1:
; CHECK-NEXT: [[COUNT3:%.*]] = phi i32 [ [[COUNT]], [[FOR_BODY]] ], [ [[COUNT1]], [[CASE2]] ]
; CHECK-NEXT: [[STATE_NEXT_JT1]] = phi i32 [ 1, [[CASE2]] ], [ 1, [[FOR_BODY]] ]
; CHECK-NEXT: [[COUNT3:%.*]] = phi i32 [ [[COUNT]], [[FOR_BODY]] ], [ [[COUNT1]], [[CASE2]] ]
; CHECK-NEXT: [[INC_JT1]] = add nsw i32 [[COUNT3]], 1
; CHECK-NEXT: [[CMP_EXIT_JT1:%.*]] = icmp slt i32 [[INC_JT1]], [[NUM]]
; CHECK-NEXT: br i1 [[CMP_EXIT_JT1]], label [[FOR_BODY_JT1]], label [[FOR_END]]
Expand Down
14 changes: 7 additions & 7 deletions llvm/test/Transforms/DFAJumpThreading/dfa-unfold-select.ll
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,14 @@ define i32 @test1(i32 %num) {
; CHECK-NEXT: [[CMP_EXIT:%.*]] = icmp slt i32 [[INC]], [[NUM:%.*]]
; CHECK-NEXT: br i1 [[CMP_EXIT]], label [[FOR_BODY]], label [[FOR_END:%.*]]
; CHECK: for.inc.jt2:
; CHECK-NEXT: [[COUNT4:%.*]] = phi i32 [ [[COUNT1]], [[SEL_SI_UNFOLD_FALSE_JT2]] ], [ [[COUNT2]], [[CASE1]] ]
; CHECK-NEXT: [[STATE_NEXT_JT2]] = phi i32 [ 2, [[CASE1]] ], [ [[DOTSI_UNFOLD_PHI_JT2]], [[SEL_SI_UNFOLD_FALSE_JT2]] ]
; CHECK-NEXT: [[COUNT4:%.*]] = phi i32 [ [[COUNT1]], [[SEL_SI_UNFOLD_FALSE_JT2]] ], [ [[COUNT2]], [[CASE1]] ]
; CHECK-NEXT: [[INC_JT2]] = add nsw i32 [[COUNT4]], 1
; CHECK-NEXT: [[CMP_EXIT_JT2:%.*]] = icmp slt i32 [[INC_JT2]], [[NUM]]
; CHECK-NEXT: br i1 [[CMP_EXIT_JT2]], label [[FOR_BODY_JT2]], label [[FOR_END]]
; CHECK: for.inc.jt1:
; CHECK-NEXT: [[COUNT3:%.*]] = phi i32 [ [[COUNT]], [[FOR_BODY]] ], [ [[COUNT1]], [[CASE2]] ]
; CHECK-NEXT: [[STATE_NEXT_JT1]] = phi i32 [ 1, [[CASE2]] ], [ 1, [[FOR_BODY]] ]
; CHECK-NEXT: [[COUNT3:%.*]] = phi i32 [ [[COUNT]], [[FOR_BODY]] ], [ [[COUNT1]], [[CASE2]] ]
; CHECK-NEXT: [[INC_JT1]] = add nsw i32 [[COUNT3]], 1
; CHECK-NEXT: [[CMP_EXIT_JT1:%.*]] = icmp slt i32 [[INC_JT1]], [[NUM]]
; CHECK-NEXT: br i1 [[CMP_EXIT_JT1]], label [[FOR_BODY_JT1]], label [[FOR_END]]
Expand Down Expand Up @@ -156,8 +156,8 @@ define i32 @test2(i32 %num) {
; CHECK-NEXT: [[DOTSI_UNFOLD_PHI4_JT2:%.*]] = phi i32 [ 2, [[STATE1_1_SI_UNFOLD_TRUE:%.*]] ]
; CHECK-NEXT: br label [[FOR_INC_JT2]]
; CHECK: for.inc:
; CHECK-NEXT: [[COUNT5:%.*]] = phi i32 [ [[COUNT_JT3]], [[FOR_BODY_JT3:%.*]] ], [ undef, [[STATE1_1_SI_UNFOLD_TRUE]] ], [ [[COUNT6]], [[STATE1_1_SI_UNFOLD_FALSE]] ], [ undef, [[STATE1_2_SI_UNFOLD_FALSE:%.*]] ], [ [[COUNT]], [[STATE2_2_SI_UNFOLD_FALSE]] ]
; CHECK-NEXT: [[STATE_NEXT]] = phi i32 [ [[STATE2_1_SI_UNFOLD_PHI]], [[STATE2_2_SI_UNFOLD_FALSE]] ], [ poison, [[STATE1_2_SI_UNFOLD_FALSE]] ], [ poison, [[STATE1_1_SI_UNFOLD_TRUE]] ], [ [[DOTSI_UNFOLD_PHI4]], [[STATE1_1_SI_UNFOLD_FALSE]] ], [ 1, [[FOR_BODY_JT3]] ]
; CHECK-NEXT: [[STATE_NEXT]] = phi i32 [ [[STATE2_1_SI_UNFOLD_PHI]], [[STATE2_2_SI_UNFOLD_FALSE]] ], [ poison, [[STATE1_2_SI_UNFOLD_FALSE:%.*]] ], [ poison, [[STATE1_1_SI_UNFOLD_TRUE]] ], [ [[DOTSI_UNFOLD_PHI4]], [[STATE1_1_SI_UNFOLD_FALSE]] ], [ 1, [[FOR_BODY_JT3:%.*]] ]
; CHECK-NEXT: [[COUNT5:%.*]] = phi i32 [ [[COUNT_JT3]], [[FOR_BODY_JT3]] ], [ undef, [[STATE1_1_SI_UNFOLD_TRUE]] ], [ [[COUNT6]], [[STATE1_1_SI_UNFOLD_FALSE]] ], [ undef, [[STATE1_2_SI_UNFOLD_FALSE]] ], [ [[COUNT]], [[STATE2_2_SI_UNFOLD_FALSE]] ]
; CHECK-NEXT: [[INC]] = add nsw i32 [[COUNT5]], 1
; CHECK-NEXT: [[CMP_EXIT:%.*]] = icmp slt i32 [[INC]], [[NUM:%.*]]
; CHECK-NEXT: br i1 [[CMP_EXIT]], label [[FOR_BODY]], label [[FOR_END:%.*]]
Expand All @@ -167,14 +167,14 @@ define i32 @test2(i32 %num) {
; CHECK-NEXT: [[CMP_EXIT_JT2:%.*]] = icmp slt i32 [[INC_JT2]], [[NUM]]
; CHECK-NEXT: br i1 [[CMP_EXIT_JT2]], label [[FOR_BODY_JT2:%.*]], label [[FOR_END]]
; CHECK: for.inc.jt1:
; CHECK-NEXT: [[COUNT7:%.*]] = phi i32 [ [[COUNT6]], [[STATE1_1_SI_UNFOLD_TRUE_JT1]] ], [ [[COUNT]], [[STATE2_2_SI_UNFOLD_FALSE_JT1]] ], [ [[COUNT]], [[FOR_BODY]] ]
; CHECK-NEXT: [[STATE_NEXT_JT1]] = phi i32 [ 1, [[FOR_BODY]] ], [ [[STATE2_1_SI_UNFOLD_PHI_JT1]], [[STATE2_2_SI_UNFOLD_FALSE_JT1]] ], [ [[DOTSI_UNFOLD_PHI3_JT1]], [[STATE1_1_SI_UNFOLD_TRUE_JT1]] ]
; CHECK-NEXT: [[COUNT7:%.*]] = phi i32 [ [[COUNT6]], [[STATE1_1_SI_UNFOLD_TRUE_JT1]] ], [ [[COUNT]], [[STATE2_2_SI_UNFOLD_FALSE_JT1]] ], [ [[COUNT]], [[FOR_BODY]] ]
; CHECK-NEXT: [[INC_JT1]] = add nsw i32 [[COUNT7]], 1
; CHECK-NEXT: [[CMP_EXIT_JT1:%.*]] = icmp slt i32 [[INC_JT1]], [[NUM]]
; CHECK-NEXT: br i1 [[CMP_EXIT_JT1]], label [[FOR_BODY_JT1]], label [[FOR_END]]
; CHECK: for.inc.jt3:
; CHECK-NEXT: [[COUNT8:%.*]] = phi i32 [ [[COUNT6]], [[STATE1_2_SI_UNFOLD_FALSE_JT3]] ], [ [[COUNT]], [[CASE2]] ]
; CHECK-NEXT: [[STATE_NEXT_JT3]] = phi i32 [ 3, [[CASE2]] ], [ [[DOTSI_UNFOLD_PHI2_JT3]], [[STATE1_2_SI_UNFOLD_FALSE_JT3]] ]
; CHECK-NEXT: [[COUNT8:%.*]] = phi i32 [ [[COUNT6]], [[STATE1_2_SI_UNFOLD_FALSE_JT3]] ], [ [[COUNT]], [[CASE2]] ]
; CHECK-NEXT: [[INC_JT3]] = add nsw i32 [[COUNT8]], 1
; CHECK-NEXT: [[CMP_EXIT_JT3:%.*]] = icmp slt i32 [[INC_JT3]], [[NUM]]
; CHECK-NEXT: br i1 [[CMP_EXIT_JT3]], label [[FOR_BODY_JT3]], label [[FOR_END]]
Expand Down Expand Up @@ -305,8 +305,8 @@ define i32 @test3(i32 %num) {
; CHECK-NEXT: [[CMP_EXIT_JT2:%.*]] = icmp slt i32 [[INC_JT2]], [[NUM]]
; CHECK-NEXT: br i1 [[CMP_EXIT_JT2]], label [[FOR_BODY_JT2]], label [[FOR_END]]
; CHECK: for.inc.jt1:
; CHECK-NEXT: [[COUNT4:%.*]] = phi i32 [ [[COUNT_JT4]], [[FOR_BODY_JT4]] ], [ [[COUNT_JT3]], [[FOR_BODY_JT3]] ], [ [[COUNT5]], [[SEL_1_SI_UNFOLD_TRUE_JT1]] ], [ [[COUNT]], [[FOR_BODY]] ]
; CHECK-NEXT: [[STATE_NEXT_JT1]] = phi i32 [ 1, [[FOR_BODY]] ], [ 1, [[FOR_BODY_JT3]] ], [ 1, [[FOR_BODY_JT4]] ], [ [[DOTSI_UNFOLD_PHI2_JT1]], [[SEL_1_SI_UNFOLD_TRUE_JT1]] ]
; CHECK-NEXT: [[COUNT4:%.*]] = phi i32 [ [[COUNT_JT4]], [[FOR_BODY_JT4]] ], [ [[COUNT_JT3]], [[FOR_BODY_JT3]] ], [ [[COUNT5]], [[SEL_1_SI_UNFOLD_TRUE_JT1]] ], [ [[COUNT]], [[FOR_BODY]] ]
; CHECK-NEXT: [[INC_JT1]] = add nsw i32 [[COUNT4]], 1
; CHECK-NEXT: [[CMP_EXIT_JT1:%.*]] = icmp slt i32 [[INC_JT1]], [[NUM]]
; CHECK-NEXT: br i1 [[CMP_EXIT_JT1]], label [[FOR_BODY_JT1]], label [[FOR_END]]
Expand Down
66 changes: 66 additions & 0 deletions llvm/unittests/Transforms/Utils/SSAUpdaterBulkTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -308,3 +308,69 @@ TEST(SSAUpdaterBulk, TwoBBLoop) {
EXPECT_EQ(Phi->getIncomingValueForBlock(Entry), ConstantInt::get(I32Ty, 0));
EXPECT_EQ(Phi->getIncomingValueForBlock(Loop), I);
}

TEST(SSAUpdaterBulk, SimplifyPHIs) {
const char *IR = R"(
define void @main(i32 %val, i1 %cond) {
entry:
br i1 %cond, label %left, label %right
left:
%add = add i32 %val, 1
br label %exit
right:
%sub = sub i32 %val, 1
br label %exit
exit:
%phi = phi i32 [ %sub, %right ], [ %add, %left ]
%cmp = icmp slt i32 0, 42
ret void
}
)";

llvm::LLVMContext Context;
llvm::SMDiagnostic Err;
std::unique_ptr<llvm::Module> M = llvm::parseAssemblyString(IR, Err, Context);
ASSERT_NE(M, nullptr) << "Failed to parse IR: " << Err.getMessage();

Function *F = M->getFunction("main");
auto *Entry = &F->getEntryBlock();
auto *Left = Entry->getTerminator()->getSuccessor(0);
auto *Right = Entry->getTerminator()->getSuccessor(1);
auto *Exit = Left->getSingleSuccessor();
auto *Val = &*F->arg_begin();
auto *Phi = &Exit->front();
auto *Cmp = &*std::next(Exit->begin());
auto *Add = &Left->front();
auto *Sub = &Right->front();

SSAUpdaterBulk Updater;
Type *I32Ty = Type::getInt32Ty(Context);

// Use %val directly instead of creating a phi.
unsigned ValVar = Updater.AddVariable("Val", I32Ty);
Updater.AddAvailableValue(ValVar, Left, Val);
Updater.AddAvailableValue(ValVar, Right, Val);
Updater.AddUse(ValVar, &Cmp->getOperandUse(0));

// Use existing %phi for %add and %sub values.
unsigned AddSubVar = Updater.AddVariable("AddSub", I32Ty);
Updater.AddAvailableValue(AddSubVar, Left, Add);
Updater.AddAvailableValue(AddSubVar, Right, Sub);
Updater.AddUse(AddSubVar, &Cmp->getOperandUse(1));

SmallVector<PHINode *, 2> Inserted;
DominatorTree DT(*F);
Updater.RewriteAllUses(&DT, &Inserted);

#if 0 // Enable for debugging.
Exit->dump();
// Output:
// exit: ; preds = %right, %left
// %phi = phi i32 [ %sub, %right ], [ %add, %left ]
// %cmp = icmp slt i32 %val, %phi
// ret void
#endif
EXPECT_EQ(Inserted.size(), 0u);
EXPECT_EQ(Val, Cmp->getOperand(0));
EXPECT_EQ(Phi, Cmp->getOperand(1));
}