Skip to content

Commit 0be77df

Browse files
committed
ssaupdaterbulk_add_phi_optimization
1 parent dfc0ba6 commit 0be77df

File tree

3 files changed

+106
-2
lines changed

3 files changed

+106
-2
lines changed

llvm/include/llvm/Transforms/Utils/SSAUpdaterBulk.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
#ifndef LLVM_TRANSFORMS_UTILS_SSAUPDATERBULK_H
1414
#define LLVM_TRANSFORMS_UTILS_SSAUPDATERBULK_H
1515

16-
#include "llvm/ADT/DenseMap.h"
1716
#include "llvm/ADT/StringRef.h"
1817
#include "llvm/IR/PredIteratorCache.h"
1918

@@ -77,6 +76,10 @@ class SSAUpdaterBulk {
7776
/// vector.
7877
void RewriteAllUses(DominatorTree *DT,
7978
SmallVectorImpl<PHINode *> *InsertedPHIs = nullptr);
79+
80+
/// Rewrite all uses and simplify the inserted PHI nodes.
81+
/// Use this method to preserve behavior when replacing SSAUpdater.
82+
void RewriteAndOptimizeAllUses(DominatorTree &DT);
8083
};
8184

8285
} // end namespace llvm

llvm/lib/Transforms/Utils/SSAUpdaterBulk.cpp

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,14 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
#include "llvm/Transforms/Utils/SSAUpdaterBulk.h"
14+
#include "llvm/Analysis/InstructionSimplify.h"
1415
#include "llvm/Analysis/IteratedDominanceFrontier.h"
1516
#include "llvm/IR/BasicBlock.h"
1617
#include "llvm/IR/Dominators.h"
1718
#include "llvm/IR/IRBuilder.h"
18-
#include "llvm/IR/Instructions.h"
1919
#include "llvm/IR/Use.h"
2020
#include "llvm/IR/Value.h"
21+
#include "llvm/Transforms/Utils/Local.h"
2122

2223
using namespace llvm;
2324

@@ -222,3 +223,38 @@ void SSAUpdaterBulk::RewriteAllUses(DominatorTree *DT,
222223
}
223224
}
224225
}
226+
227+
// Perform a single pass of simplification over the worklist of PHIs.
228+
static void simplifyPass(MutableArrayRef<PHINode *> Worklist,
229+
const DataLayout &DL) {
230+
for (PHINode *&PHI : Worklist) {
231+
if (Value *Simplified = simplifyInstruction(PHI, DL)) {
232+
PHI->replaceAllUsesWith(Simplified);
233+
PHI->eraseFromParent();
234+
PHI = nullptr; // Mark as removed.
235+
}
236+
}
237+
}
238+
239+
static void deduplicatePass(ArrayRef<PHINode *> Worklist) {
240+
SmallDenseMap<BasicBlock *, unsigned> BBs;
241+
for (PHINode *PHI : Worklist) {
242+
if (PHI)
243+
++BBs[PHI->getParent()];
244+
}
245+
246+
for (auto [BB, NumNewPHIs] : BBs) {
247+
auto FirstExistingPN = std::next(BB->phis().begin(), NumNewPHIs);
248+
EliminateNewDuplicatePHINodes(BB, FirstExistingPN);
249+
}
250+
}
251+
252+
void SSAUpdaterBulk::RewriteAndOptimizeAllUses(DominatorTree &DT) {
253+
SmallVector<PHINode *, 4> PHIs;
254+
RewriteAllUses(&DT, &PHIs);
255+
if (PHIs.empty())
256+
return;
257+
258+
simplifyPass(PHIs, PHIs.front()->getParent()->getDataLayout());
259+
deduplicatePass(PHIs);
260+
}

llvm/unittests/Transforms/Utils/SSAUpdaterBulkTest.cpp

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,3 +308,68 @@ TEST(SSAUpdaterBulk, TwoBBLoop) {
308308
EXPECT_EQ(Phi->getIncomingValueForBlock(Entry), ConstantInt::get(I32Ty, 0));
309309
EXPECT_EQ(Phi->getIncomingValueForBlock(Loop), I);
310310
}
311+
312+
TEST(SSAUpdaterBulk, SimplifyPHIs) {
313+
const char *IR = R"(
314+
define void @main(i32 %val, i1 %cond) {
315+
entry:
316+
br i1 %cond, label %left, label %right
317+
left:
318+
%add = add i32 %val, 1
319+
br label %exit
320+
right:
321+
%sub = sub i32 %val, 1
322+
br label %exit
323+
exit:
324+
%phi = phi i32 [ %sub, %right ], [ %add, %left ]
325+
%cmp = icmp slt i32 0, 42
326+
ret void
327+
}
328+
)";
329+
330+
llvm::LLVMContext Context;
331+
llvm::SMDiagnostic Err;
332+
std::unique_ptr<llvm::Module> M = llvm::parseAssemblyString(IR, Err, Context);
333+
ASSERT_NE(M, nullptr) << "Failed to parse IR: " << Err.getMessage();
334+
335+
Function *F = M->getFunction("main");
336+
auto *Entry = &F->getEntryBlock();
337+
auto *Left = Entry->getTerminator()->getSuccessor(0);
338+
auto *Right = Entry->getTerminator()->getSuccessor(1);
339+
auto *Exit = Left->getSingleSuccessor();
340+
auto *Val = &*F->arg_begin();
341+
auto *Phi = &Exit->front();
342+
auto *Cmp = &*std::next(Exit->begin());
343+
auto *Add = &Left->front();
344+
auto *Sub = &Right->front();
345+
346+
SSAUpdaterBulk Updater;
347+
Type *I32Ty = Type::getInt32Ty(Context);
348+
349+
// Use %val directly instead of creating a phi.
350+
unsigned ValVar = Updater.AddVariable("Val", I32Ty);
351+
Updater.AddAvailableValue(ValVar, Left, Val);
352+
Updater.AddAvailableValue(ValVar, Right, Val);
353+
Updater.AddUse(ValVar, &Cmp->getOperandUse(0));
354+
355+
// Use existing %phi for %add and %sub values.
356+
unsigned AddSubVar = Updater.AddVariable("AddSub", I32Ty);
357+
Updater.AddAvailableValue(AddSubVar, Left, Add);
358+
Updater.AddAvailableValue(AddSubVar, Right, Sub);
359+
Updater.AddUse(AddSubVar, &Cmp->getOperandUse(1));
360+
361+
auto ExitSizeBefore = Exit->size();
362+
DominatorTree DT(*F);
363+
Updater.RewriteAndOptimizeAllUses(DT);
364+
365+
// Output for Exit->dump():
366+
// exit: ; preds = %right, %left
367+
// %phi = phi i32 [ %sub, %right ], [ %add, %left ]
368+
// %cmp = icmp slt i32 %val, %phi
369+
// ret void
370+
371+
ASSERT_EQ(Exit->size(), ExitSizeBefore);
372+
ASSERT_EQ(&Exit->front(), Phi);
373+
EXPECT_EQ(Val, Cmp->getOperand(0));
374+
EXPECT_EQ(Phi, Cmp->getOperand(1));
375+
}

0 commit comments

Comments
 (0)