diff --git a/llvm/include/llvm/Transforms/IPO/FunctionSpecialization.h b/llvm/include/llvm/Transforms/IPO/FunctionSpecialization.h --- a/llvm/include/llvm/Transforms/IPO/FunctionSpecialization.h +++ b/llvm/include/llvm/Transforms/IPO/FunctionSpecialization.h @@ -126,6 +126,15 @@ SCCPSolver &Solver; ConstMap KnownConstants; + // Basic blocks known to be unreachable after constant propagation. + DenseSet DeadBlocks; + // PHI nodes we have visited before. + DenseSet VisitedPHIs; + // PHI nodes we have visited once without successfully constant folding them. + // Once the InstCostVisitor has processed all the specialization arguments, + // it should be possible to determine whether those PHIs can be folded + // (some of their incoming values may have become constant or dead). + SmallVector PendingPHIs; ConstMap::iterator LastVisited; @@ -134,7 +143,10 @@ TargetTransformInfo &TTI, SCCPSolver &Solver) : DL(DL), BFI(BFI), TTI(TTI), Solver(Solver) {} - Cost getUserBonus(Instruction *User, Value *Use, Constant *C); + Cost getUserBonus(Instruction *User, Value *Use = nullptr, + Constant *C = nullptr); + + Cost getBonusFromPendingPHIs(); private: friend class InstVisitor; @@ -143,6 +155,7 @@ Cost estimateBranchInst(BranchInst &I); Constant *visitInstruction(Instruction &I) { return nullptr; } + Constant *visitPHINode(PHINode &I); Constant *visitFreezeInst(FreezeInst &I); Constant *visitCallBase(CallBase &I); Constant *visitLoadInst(LoadInst &I); diff --git a/llvm/lib/Transforms/IPO/FunctionSpecialization.cpp b/llvm/lib/Transforms/IPO/FunctionSpecialization.cpp --- a/llvm/lib/Transforms/IPO/FunctionSpecialization.cpp +++ b/llvm/lib/Transforms/IPO/FunctionSpecialization.cpp @@ -104,6 +104,7 @@ // the combination of size and latency savings in comparison to the non // specialized version of the function. static Cost estimateBasicBlocks(SmallVectorImpl &WorkList, + DenseSet &DeadBlocks, ConstMap &KnownConstants, SCCPSolver &Solver, BlockFrequencyInfo &BFI, TargetTransformInfo &TTI) { @@ -118,6 +119,9 @@ if (!Weight) continue; + if (!DeadBlocks.insert(BB).second) + continue; + for (Instruction &I : *BB) { // Disregard SSA copies. if (auto *II = dyn_cast(&I)) @@ -152,9 +156,19 @@ return nullptr; } +Cost InstCostVisitor::getBonusFromPendingPHIs() { + Cost Bonus = 0; + while (!PendingPHIs.empty()) { + Instruction *Phi = PendingPHIs.pop_back_val(); + Bonus += getUserBonus(Phi); + } + return Bonus; +} + Cost InstCostVisitor::getUserBonus(Instruction *User, Value *Use, Constant *C) { // Cache the iterator before visiting. - LastVisited = KnownConstants.insert({Use, C}).first; + if (Use) + LastVisited = KnownConstants.insert({Use, C}).first; if (auto *I = dyn_cast(User)) return estimateSwitchInst(*I); @@ -181,7 +195,7 @@ for (auto *U : User->users()) if (auto *UI = dyn_cast(U)) - if (Solver.isBlockExecutable(UI->getParent())) + if (UI != User && Solver.isBlockExecutable(UI->getParent())) Bonus += getUserBonus(UI, User, C); return Bonus; @@ -208,7 +222,8 @@ WorkList.push_back(BB); } - return estimateBasicBlocks(WorkList, KnownConstants, Solver, BFI, TTI); + return estimateBasicBlocks(WorkList, DeadBlocks, KnownConstants, Solver, BFI, + TTI); } Cost InstCostVisitor::estimateBranchInst(BranchInst &I) { @@ -223,7 +238,34 @@ Succ->getUniquePredecessor() == I.getParent()) WorkList.push_back(Succ); - return estimateBasicBlocks(WorkList, KnownConstants, Solver, BFI, TTI); + return estimateBasicBlocks(WorkList, DeadBlocks, KnownConstants, Solver, BFI, + TTI); +} + +Constant *InstCostVisitor::visitPHINode(PHINode &I) { + if (I.getNumIncomingValues() > 4) + return nullptr; + + bool Inserted = VisitedPHIs.insert(&I).second; + Constant *Const = nullptr; + + for (unsigned Idx = 0, E = I.getNumIncomingValues(); Idx != E; ++Idx) { + Value *V = I.getIncomingValue(Idx); + if (auto *Inst = dyn_cast(V)) + if (Inst == &I || DeadBlocks.contains(I.getIncomingBlock(Idx))) + continue; + Costant *C = findConstantFor(V, KnownConstants); + if (!C) { + if (Inserted) + PendingPHIs.push_back(&I); + return nullptr; + } + if (!Const) + Const = C; + else if (C != Const) + return nullptr; + } + return Const; } Constant *InstCostVisitor::visitFreezeInst(FreezeInst &I) { @@ -713,13 +755,17 @@ AllSpecs[Index].CallSites.push_back(&CS); } else { // Calculate the specialisation gain. - Cost Score = 0 - SpecCost; + Cost Score = 0; InstCostVisitor Visitor = getInstCostVisitorFor(F); for (ArgInfo &A : S.Args) Score += getSpecializationBonus(A.Formal, A.Actual, Visitor); + Score += Visitor.getBonusFromPendingPHIs(); + + LLVM_DEBUG(dbgs() << "FnSpecialization: Specialization score = " + << Score << "\n"); // Discard unprofitable specialisations. - if (!ForceSpecialization && Score <= 0) + if (!ForceSpecialization && Score <= SpecCost) continue; // Create a new specialisation entry. diff --git a/llvm/unittests/Transforms/IPO/FunctionSpecializationTest.cpp b/llvm/unittests/Transforms/IPO/FunctionSpecializationTest.cpp --- a/llvm/unittests/Transforms/IPO/FunctionSpecializationTest.cpp +++ b/llvm/unittests/Transforms/IPO/FunctionSpecializationTest.cpp @@ -287,3 +287,56 @@ Bonus = Specializer.getSpecializationBonus(F->getArg(3), Undef, Visitor); EXPECT_TRUE(Bonus == 0); } + +TEST_F(FunctionSpecializationTest, PhiNode) { + const char *ModuleString = R"( + define void @foo(i32 %a, i32 %b, i32 %i) { + entry: + br label %loop + loop: + switch i32 %i, label %default + [ i32 1, label %case1 + i32 2, label %case2 ] + case1: + %0 = add i32 %a, 1 + br label %bb + case2: + %1 = sub i32 %b, 1 + br label %bb + bb: + %2 = phi i32 [ %0, %case1 ], [ %1, %case2 ], [ %2, %bb ] + %3 = icmp eq i32 %2, 2 + br i1 %3, label %bb, label %loop + default: + ret void + } + )"; + + Module &M = parseModule(ModuleString); + Function *F = M.getFunction("foo"); + FunctionSpecializer Specializer = getSpecializerFor(F); + InstCostVisitor Visitor = Specializer.getInstCostVisitorFor(F); + + Constant *One = ConstantInt::get(IntegerType::getInt32Ty(M.getContext()), 1); + + auto FuncIter = F->begin(); + for (int I = 0; I < 4; ++I) + ++FuncIter; + + BasicBlock &BB = *FuncIter; + + Instruction &Phi = BB.front(); + Instruction &Icmp = *++BB.begin(); + + Cost Bonus = Specializer.getSpecializationBonus(F->getArg(0), One, Visitor) + + Specializer.getSpecializationBonus(F->getArg(1), One, Visitor) + + Specializer.getSpecializationBonus(F->getArg(2), One, Visitor); + EXPECT_TRUE(Bonus > 0); + + // phi + icmp + Cost Ref = getInstCost(Phi) + getInstCost(Icmp); + Bonus = Visitor.getBonusFromPendingPHIs(); + EXPECT_EQ(Bonus, Ref); + EXPECT_TRUE(Bonus > 0); +} +