1d88c1a5aSDimitry Andric //===- PPCBoolRetToInt.cpp ------------------------------------------------===//
27d523365SDimitry Andric //
37d523365SDimitry Andric //                     The LLVM Compiler Infrastructure
47d523365SDimitry Andric //
57d523365SDimitry Andric // This file is distributed under the University of Illinois Open Source
67d523365SDimitry Andric // License. See LICENSE.TXT for details.
77d523365SDimitry Andric //
87d523365SDimitry Andric //===----------------------------------------------------------------------===//
97d523365SDimitry Andric //
10*db17bf38SDimitry Andric // This file implements converting i1 values to i32/i64 if they could be more
117d523365SDimitry Andric // profitably allocated as GPRs rather than CRs. This pass will become totally
127d523365SDimitry Andric // unnecessary if Register Bank Allocation and Global Instruction Selection ever
137d523365SDimitry Andric // go upstream.
147d523365SDimitry Andric //
15*db17bf38SDimitry Andric // Presently, the pass converts i1 Constants, and Arguments to i32/i64 if the
167d523365SDimitry Andric // transitive closure of their uses includes only PHINodes, CallInsts, and
177d523365SDimitry Andric // ReturnInsts. The rational is that arguments are generally passed and returned
18*db17bf38SDimitry Andric // in GPRs rather than CRs, so casting them to i32/i64 at the LLVM IR level will
197d523365SDimitry Andric // actually save casts at the Machine Instruction level.
207d523365SDimitry Andric //
217d523365SDimitry Andric // It might be useful to expand this pass to add bit-wise operations to the list
227d523365SDimitry Andric // of safe transitive closure types. Also, we miss some opportunities when LLVM
237d523365SDimitry Andric // represents logical AND and OR operations with control flow rather than data
247d523365SDimitry Andric // flow. For example by lowering the expression: return (A && B && C)
257d523365SDimitry Andric //
267d523365SDimitry Andric // as: return A ? true : B && C.
277d523365SDimitry Andric //
287d523365SDimitry Andric // There's code in SimplifyCFG that code be used to turn control flow in data
297d523365SDimitry Andric // flow using SelectInsts. Selects are slow on some architectures (P7/P8), so
307d523365SDimitry Andric // this probably isn't good in general, but for the special case of i1, the
317d523365SDimitry Andric // Selects could be further lowered to bit operations that are fast everywhere.
327d523365SDimitry Andric //
337d523365SDimitry Andric //===----------------------------------------------------------------------===//
347d523365SDimitry Andric 
357d523365SDimitry Andric #include "PPC.h"
36*db17bf38SDimitry Andric #include "PPCTargetMachine.h"
37d88c1a5aSDimitry Andric #include "llvm/ADT/DenseMap.h"
38*db17bf38SDimitry Andric #include "llvm/ADT/STLExtras.h"
397d523365SDimitry Andric #include "llvm/ADT/SmallPtrSet.h"
40d88c1a5aSDimitry Andric #include "llvm/ADT/SmallVector.h"
417d523365SDimitry Andric #include "llvm/ADT/Statistic.h"
42d88c1a5aSDimitry Andric #include "llvm/IR/Argument.h"
437d523365SDimitry Andric #include "llvm/IR/Constants.h"
447d523365SDimitry Andric #include "llvm/IR/Dominators.h"
45d88c1a5aSDimitry Andric #include "llvm/IR/Function.h"
46d88c1a5aSDimitry Andric #include "llvm/IR/Instruction.h"
477d523365SDimitry Andric #include "llvm/IR/Instructions.h"
487d523365SDimitry Andric #include "llvm/IR/IntrinsicInst.h"
49d88c1a5aSDimitry Andric #include "llvm/IR/OperandTraits.h"
50d88c1a5aSDimitry Andric #include "llvm/IR/Type.h"
51d88c1a5aSDimitry Andric #include "llvm/IR/Use.h"
52d88c1a5aSDimitry Andric #include "llvm/IR/User.h"
53d88c1a5aSDimitry Andric #include "llvm/IR/Value.h"
547d523365SDimitry Andric #include "llvm/Pass.h"
55*db17bf38SDimitry Andric #include "llvm/CodeGen/TargetPassConfig.h"
56*db17bf38SDimitry Andric #include "llvm/Support/Casting.h"
57d88c1a5aSDimitry Andric #include <cassert>
587d523365SDimitry Andric 
597d523365SDimitry Andric using namespace llvm;
607d523365SDimitry Andric 
617d523365SDimitry Andric namespace {
627d523365SDimitry Andric 
637d523365SDimitry Andric #define DEBUG_TYPE "bool-ret-to-int"
647d523365SDimitry Andric 
657d523365SDimitry Andric STATISTIC(NumBoolRetPromotion,
667d523365SDimitry Andric           "Number of times a bool feeding a RetInst was promoted to an int");
677d523365SDimitry Andric STATISTIC(NumBoolCallPromotion,
687d523365SDimitry Andric           "Number of times a bool feeding a CallInst was promoted to an int");
697d523365SDimitry Andric STATISTIC(NumBoolToIntPromotion,
707d523365SDimitry Andric           "Total number of times a bool was promoted to an int");
717d523365SDimitry Andric 
727d523365SDimitry Andric class PPCBoolRetToInt : public FunctionPass {
findAllDefs(Value * V)737d523365SDimitry Andric   static SmallPtrSet<Value *, 8> findAllDefs(Value *V) {
747d523365SDimitry Andric     SmallPtrSet<Value *, 8> Defs;
757d523365SDimitry Andric     SmallVector<Value *, 8> WorkList;
767d523365SDimitry Andric     WorkList.push_back(V);
777d523365SDimitry Andric     Defs.insert(V);
787d523365SDimitry Andric     while (!WorkList.empty()) {
797d523365SDimitry Andric       Value *Curr = WorkList.back();
807d523365SDimitry Andric       WorkList.pop_back();
81d88c1a5aSDimitry Andric       auto *CurrUser = dyn_cast<User>(Curr);
82d88c1a5aSDimitry Andric       // Operands of CallInst are skipped because they may not be Bool type,
83d88c1a5aSDimitry Andric       // and their positions are defined by ABI.
84d88c1a5aSDimitry Andric       if (CurrUser && !isa<CallInst>(Curr))
857d523365SDimitry Andric         for (auto &Op : CurrUser->operands())
867d523365SDimitry Andric           if (Defs.insert(Op).second)
877d523365SDimitry Andric             WorkList.push_back(Op);
887d523365SDimitry Andric     }
897d523365SDimitry Andric     return Defs;
907d523365SDimitry Andric   }
917d523365SDimitry Andric 
92*db17bf38SDimitry Andric   // Translate a i1 value to an equivalent i32/i64 value:
translate(Value * V)93*db17bf38SDimitry Andric   Value *translate(Value *V) {
94*db17bf38SDimitry Andric     Type *IntTy = ST->isPPC64() ? Type::getInt64Ty(V->getContext())
95*db17bf38SDimitry Andric                                 : Type::getInt32Ty(V->getContext());
96*db17bf38SDimitry Andric 
97d88c1a5aSDimitry Andric     if (auto *C = dyn_cast<Constant>(V))
98*db17bf38SDimitry Andric       return ConstantExpr::getZExt(C, IntTy);
99d88c1a5aSDimitry Andric     if (auto *P = dyn_cast<PHINode>(V)) {
1007d523365SDimitry Andric       // Temporarily set the operands to 0. We'll fix this later in
1017d523365SDimitry Andric       // runOnUse.
102*db17bf38SDimitry Andric       Value *Zero = Constant::getNullValue(IntTy);
1037d523365SDimitry Andric       PHINode *Q =
104*db17bf38SDimitry Andric         PHINode::Create(IntTy, P->getNumIncomingValues(), P->getName(), P);
1057d523365SDimitry Andric       for (unsigned i = 0; i < P->getNumOperands(); ++i)
1067d523365SDimitry Andric         Q->addIncoming(Zero, P->getIncomingBlock(i));
1077d523365SDimitry Andric       return Q;
1087d523365SDimitry Andric     }
1097d523365SDimitry Andric 
110d88c1a5aSDimitry Andric     auto *A = dyn_cast<Argument>(V);
111d88c1a5aSDimitry Andric     auto *I = dyn_cast<Instruction>(V);
1127d523365SDimitry Andric     assert((A || I) && "Unknown value type");
1137d523365SDimitry Andric 
1147d523365SDimitry Andric     auto InstPt =
1157d523365SDimitry Andric       A ? &*A->getParent()->getEntryBlock().begin() : I->getNextNode();
116*db17bf38SDimitry Andric     return new ZExtInst(V, IntTy, "", InstPt);
1177d523365SDimitry Andric   }
1187d523365SDimitry Andric 
1197d523365SDimitry Andric   typedef SmallPtrSet<const PHINode *, 8> PHINodeSet;
1207d523365SDimitry Andric 
1217d523365SDimitry Andric   // A PHINode is Promotable if:
1227d523365SDimitry Andric   // 1. Its type is i1 AND
1237d523365SDimitry Andric   // 2. All of its uses are ReturnInt, CallInst, PHINode, or DbgInfoIntrinsic
1247d523365SDimitry Andric   // AND
1257d523365SDimitry Andric   // 3. All of its operands are Constant or Argument or
1267d523365SDimitry Andric   //    CallInst or PHINode AND
1277d523365SDimitry Andric   // 4. All of its PHINode uses are Promotable AND
1287d523365SDimitry Andric   // 5. All of its PHINode operands are Promotable
getPromotablePHINodes(const Function & F)1297d523365SDimitry Andric   static PHINodeSet getPromotablePHINodes(const Function &F) {
1307d523365SDimitry Andric     PHINodeSet Promotable;
1317d523365SDimitry Andric     // Condition 1
1327d523365SDimitry Andric     for (auto &BB : F)
1337d523365SDimitry Andric       for (auto &I : BB)
134d88c1a5aSDimitry Andric         if (const auto *P = dyn_cast<PHINode>(&I))
1357d523365SDimitry Andric           if (P->getType()->isIntegerTy(1))
1367d523365SDimitry Andric             Promotable.insert(P);
1377d523365SDimitry Andric 
1387d523365SDimitry Andric     SmallVector<const PHINode *, 8> ToRemove;
1393ca95b02SDimitry Andric     for (const PHINode *P : Promotable) {
1407d523365SDimitry Andric       // Condition 2 and 3
1417d523365SDimitry Andric       auto IsValidUser = [] (const Value *V) -> bool {
1427d523365SDimitry Andric         return isa<ReturnInst>(V) || isa<CallInst>(V) || isa<PHINode>(V) ||
1437d523365SDimitry Andric         isa<DbgInfoIntrinsic>(V);
1447d523365SDimitry Andric       };
1457d523365SDimitry Andric       auto IsValidOperand = [] (const Value *V) -> bool {
1467d523365SDimitry Andric         return isa<Constant>(V) || isa<Argument>(V) || isa<CallInst>(V) ||
1477d523365SDimitry Andric         isa<PHINode>(V);
1487d523365SDimitry Andric       };
1497d523365SDimitry Andric       const auto &Users = P->users();
1507d523365SDimitry Andric       const auto &Operands = P->operands();
151d88c1a5aSDimitry Andric       if (!llvm::all_of(Users, IsValidUser) ||
152d88c1a5aSDimitry Andric           !llvm::all_of(Operands, IsValidOperand))
1537d523365SDimitry Andric         ToRemove.push_back(P);
1547d523365SDimitry Andric     }
1557d523365SDimitry Andric 
1567d523365SDimitry Andric     // Iterate to convergence
1577d523365SDimitry Andric     auto IsPromotable = [&Promotable] (const Value *V) -> bool {
158d88c1a5aSDimitry Andric       const auto *Phi = dyn_cast<PHINode>(V);
1597d523365SDimitry Andric       return !Phi || Promotable.count(Phi);
1607d523365SDimitry Andric     };
1617d523365SDimitry Andric     while (!ToRemove.empty()) {
1627d523365SDimitry Andric       for (auto &User : ToRemove)
1637d523365SDimitry Andric         Promotable.erase(User);
1647d523365SDimitry Andric       ToRemove.clear();
1657d523365SDimitry Andric 
1663ca95b02SDimitry Andric       for (const PHINode *P : Promotable) {
1677d523365SDimitry Andric         // Condition 4 and 5
1687d523365SDimitry Andric         const auto &Users = P->users();
1697d523365SDimitry Andric         const auto &Operands = P->operands();
170d88c1a5aSDimitry Andric         if (!llvm::all_of(Users, IsPromotable) ||
171d88c1a5aSDimitry Andric             !llvm::all_of(Operands, IsPromotable))
1727d523365SDimitry Andric           ToRemove.push_back(P);
1737d523365SDimitry Andric       }
1747d523365SDimitry Andric     }
1757d523365SDimitry Andric 
1767d523365SDimitry Andric     return Promotable;
1777d523365SDimitry Andric   }
1787d523365SDimitry Andric 
1797d523365SDimitry Andric   typedef DenseMap<Value *, Value *> B2IMap;
1807d523365SDimitry Andric 
1817d523365SDimitry Andric  public:
1827d523365SDimitry Andric   static char ID;
183d88c1a5aSDimitry Andric 
PPCBoolRetToInt()1847d523365SDimitry Andric   PPCBoolRetToInt() : FunctionPass(ID) {
1857d523365SDimitry Andric     initializePPCBoolRetToIntPass(*PassRegistry::getPassRegistry());
1867d523365SDimitry Andric   }
1877d523365SDimitry Andric 
runOnFunction(Function & F)188d88c1a5aSDimitry Andric   bool runOnFunction(Function &F) override {
1893ca95b02SDimitry Andric     if (skipFunction(F))
1903ca95b02SDimitry Andric       return false;
1913ca95b02SDimitry Andric 
192*db17bf38SDimitry Andric     auto *TPC = getAnalysisIfAvailable<TargetPassConfig>();
193*db17bf38SDimitry Andric     if (!TPC)
194*db17bf38SDimitry Andric       return false;
195*db17bf38SDimitry Andric 
196*db17bf38SDimitry Andric     auto &TM = TPC->getTM<PPCTargetMachine>();
197*db17bf38SDimitry Andric     ST = TM.getSubtargetImpl(F);
198*db17bf38SDimitry Andric 
1997d523365SDimitry Andric     PHINodeSet PromotablePHINodes = getPromotablePHINodes(F);
2007d523365SDimitry Andric     B2IMap Bool2IntMap;
2017d523365SDimitry Andric     bool Changed = false;
2027d523365SDimitry Andric     for (auto &BB : F) {
2037d523365SDimitry Andric       for (auto &I : BB) {
204d88c1a5aSDimitry Andric         if (auto *R = dyn_cast<ReturnInst>(&I))
2057d523365SDimitry Andric           if (F.getReturnType()->isIntegerTy(1))
2067d523365SDimitry Andric             Changed |=
2077d523365SDimitry Andric               runOnUse(R->getOperandUse(0), PromotablePHINodes, Bool2IntMap);
2087d523365SDimitry Andric 
209d88c1a5aSDimitry Andric         if (auto *CI = dyn_cast<CallInst>(&I))
2107d523365SDimitry Andric           for (auto &U : CI->operands())
2117d523365SDimitry Andric             if (U->getType()->isIntegerTy(1))
2127d523365SDimitry Andric               Changed |= runOnUse(U, PromotablePHINodes, Bool2IntMap);
2137d523365SDimitry Andric       }
2147d523365SDimitry Andric     }
2157d523365SDimitry Andric 
2167d523365SDimitry Andric     return Changed;
2177d523365SDimitry Andric   }
2187d523365SDimitry Andric 
runOnUse(Use & U,const PHINodeSet & PromotablePHINodes,B2IMap & BoolToIntMap)219*db17bf38SDimitry Andric   bool runOnUse(Use &U, const PHINodeSet &PromotablePHINodes,
2207d523365SDimitry Andric                        B2IMap &BoolToIntMap) {
2217d523365SDimitry Andric     auto Defs = findAllDefs(U);
2227d523365SDimitry Andric 
2237d523365SDimitry Andric     // If the values are all Constants or Arguments, don't bother
224d88c1a5aSDimitry Andric     if (llvm::none_of(Defs, isa<Instruction, Value *>))
2257d523365SDimitry Andric       return false;
2267d523365SDimitry Andric 
227d88c1a5aSDimitry Andric     // Presently, we only know how to handle PHINode, Constant, Arguments and
228d88c1a5aSDimitry Andric     // CallInst. Potentially, bitwise operations (AND, OR, XOR, NOT) and sign
229d88c1a5aSDimitry Andric     // extension could also be handled in the future.
2303ca95b02SDimitry Andric     for (Value *V : Defs)
231d88c1a5aSDimitry Andric       if (!isa<PHINode>(V) && !isa<Constant>(V) &&
232d88c1a5aSDimitry Andric           !isa<Argument>(V) && !isa<CallInst>(V))
2337d523365SDimitry Andric         return false;
2347d523365SDimitry Andric 
2353ca95b02SDimitry Andric     for (Value *V : Defs)
236d88c1a5aSDimitry Andric       if (const auto *P = dyn_cast<PHINode>(V))
2377d523365SDimitry Andric         if (!PromotablePHINodes.count(P))
2387d523365SDimitry Andric           return false;
2397d523365SDimitry Andric 
2407d523365SDimitry Andric     if (isa<ReturnInst>(U.getUser()))
2417d523365SDimitry Andric       ++NumBoolRetPromotion;
2427d523365SDimitry Andric     if (isa<CallInst>(U.getUser()))
2437d523365SDimitry Andric       ++NumBoolCallPromotion;
2447d523365SDimitry Andric     ++NumBoolToIntPromotion;
2457d523365SDimitry Andric 
2463ca95b02SDimitry Andric     for (Value *V : Defs)
2477d523365SDimitry Andric       if (!BoolToIntMap.count(V))
2487d523365SDimitry Andric         BoolToIntMap[V] = translate(V);
2497d523365SDimitry Andric 
250d88c1a5aSDimitry Andric     // Replace the operands of the translated instructions. They were set to
2517d523365SDimitry Andric     // zero in the translate function.
2527d523365SDimitry Andric     for (auto &Pair : BoolToIntMap) {
253d88c1a5aSDimitry Andric       auto *First = dyn_cast<User>(Pair.first);
254d88c1a5aSDimitry Andric       auto *Second = dyn_cast<User>(Pair.second);
2557d523365SDimitry Andric       assert((!First || Second) && "translated from user to non-user!?");
256d88c1a5aSDimitry Andric       // Operands of CallInst are skipped because they may not be Bool type,
257d88c1a5aSDimitry Andric       // and their positions are defined by ABI.
258d88c1a5aSDimitry Andric       if (First && !isa<CallInst>(First))
2597d523365SDimitry Andric         for (unsigned i = 0; i < First->getNumOperands(); ++i)
2607d523365SDimitry Andric           Second->setOperand(i, BoolToIntMap[First->getOperand(i)]);
2617d523365SDimitry Andric     }
2627d523365SDimitry Andric 
2637d523365SDimitry Andric     Value *IntRetVal = BoolToIntMap[U];
2647d523365SDimitry Andric     Type *Int1Ty = Type::getInt1Ty(U->getContext());
265d88c1a5aSDimitry Andric     auto *I = cast<Instruction>(U.getUser());
2667d523365SDimitry Andric     Value *BackToBool = new TruncInst(IntRetVal, Int1Ty, "backToBool", I);
2677d523365SDimitry Andric     U.set(BackToBool);
2687d523365SDimitry Andric 
2697d523365SDimitry Andric     return true;
2707d523365SDimitry Andric   }
2717d523365SDimitry Andric 
getAnalysisUsage(AnalysisUsage & AU) const272d88c1a5aSDimitry Andric   void getAnalysisUsage(AnalysisUsage &AU) const override {
2737d523365SDimitry Andric     AU.addPreserved<DominatorTreeWrapperPass>();
2747d523365SDimitry Andric     FunctionPass::getAnalysisUsage(AU);
2757d523365SDimitry Andric   }
276*db17bf38SDimitry Andric 
277*db17bf38SDimitry Andric private:
278*db17bf38SDimitry Andric   const PPCSubtarget *ST;
2797d523365SDimitry Andric };
280d88c1a5aSDimitry Andric 
281d88c1a5aSDimitry Andric } // end anonymous namespace
2827d523365SDimitry Andric 
2837d523365SDimitry Andric char PPCBoolRetToInt::ID = 0;
2847d523365SDimitry Andric INITIALIZE_PASS(PPCBoolRetToInt, "bool-ret-to-int",
285*db17bf38SDimitry Andric                 "Convert i1 constants to i32/i64 if they are returned",
2867d523365SDimitry Andric                 false, false)
2877d523365SDimitry Andric 
createPPCBoolRetToIntPass()2887d523365SDimitry Andric FunctionPass *llvm::createPPCBoolRetToIntPass() { return new PPCBoolRetToInt(); }
289