10b57cec5SDimitry Andric //===- PPCBoolRetToInt.cpp ------------------------------------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This file implements converting i1 values to i32/i64 if they could be more 100b57cec5SDimitry Andric // profitably allocated as GPRs rather than CRs. This pass will become totally 110b57cec5SDimitry Andric // unnecessary if Register Bank Allocation and Global Instruction Selection ever 120b57cec5SDimitry Andric // go upstream. 130b57cec5SDimitry Andric // 140b57cec5SDimitry Andric // Presently, the pass converts i1 Constants, and Arguments to i32/i64 if the 150b57cec5SDimitry Andric // transitive closure of their uses includes only PHINodes, CallInsts, and 160b57cec5SDimitry Andric // ReturnInsts. The rational is that arguments are generally passed and returned 170b57cec5SDimitry Andric // in GPRs rather than CRs, so casting them to i32/i64 at the LLVM IR level will 180b57cec5SDimitry Andric // actually save casts at the Machine Instruction level. 190b57cec5SDimitry Andric // 200b57cec5SDimitry Andric // It might be useful to expand this pass to add bit-wise operations to the list 210b57cec5SDimitry Andric // of safe transitive closure types. Also, we miss some opportunities when LLVM 220b57cec5SDimitry Andric // represents logical AND and OR operations with control flow rather than data 230b57cec5SDimitry Andric // flow. For example by lowering the expression: return (A && B && C) 240b57cec5SDimitry Andric // 250b57cec5SDimitry Andric // as: return A ? true : B && C. 260b57cec5SDimitry Andric // 270b57cec5SDimitry Andric // There's code in SimplifyCFG that code be used to turn control flow in data 280b57cec5SDimitry Andric // flow using SelectInsts. Selects are slow on some architectures (P7/P8), so 290b57cec5SDimitry Andric // this probably isn't good in general, but for the special case of i1, the 300b57cec5SDimitry Andric // Selects could be further lowered to bit operations that are fast everywhere. 310b57cec5SDimitry Andric // 320b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 330b57cec5SDimitry Andric 340b57cec5SDimitry Andric #include "PPC.h" 350b57cec5SDimitry Andric #include "PPCTargetMachine.h" 360b57cec5SDimitry Andric #include "llvm/ADT/DenseMap.h" 370b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h" 380b57cec5SDimitry Andric #include "llvm/ADT/SmallPtrSet.h" 390b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h" 400b57cec5SDimitry Andric #include "llvm/ADT/Statistic.h" 410b57cec5SDimitry Andric #include "llvm/IR/Argument.h" 420b57cec5SDimitry Andric #include "llvm/IR/Constants.h" 430b57cec5SDimitry Andric #include "llvm/IR/Dominators.h" 440b57cec5SDimitry Andric #include "llvm/IR/Function.h" 450b57cec5SDimitry Andric #include "llvm/IR/Instruction.h" 460b57cec5SDimitry Andric #include "llvm/IR/Instructions.h" 470b57cec5SDimitry Andric #include "llvm/IR/IntrinsicInst.h" 480b57cec5SDimitry Andric #include "llvm/IR/OperandTraits.h" 490b57cec5SDimitry Andric #include "llvm/IR/Type.h" 500b57cec5SDimitry Andric #include "llvm/IR/Use.h" 510b57cec5SDimitry Andric #include "llvm/IR/User.h" 520b57cec5SDimitry Andric #include "llvm/IR/Value.h" 530b57cec5SDimitry Andric #include "llvm/Pass.h" 540b57cec5SDimitry Andric #include "llvm/CodeGen/TargetPassConfig.h" 550b57cec5SDimitry Andric #include "llvm/Support/Casting.h" 560b57cec5SDimitry Andric #include <cassert> 570b57cec5SDimitry Andric 580b57cec5SDimitry Andric using namespace llvm; 590b57cec5SDimitry Andric 600b57cec5SDimitry Andric namespace { 610b57cec5SDimitry Andric 620b57cec5SDimitry Andric #define DEBUG_TYPE "bool-ret-to-int" 630b57cec5SDimitry Andric 640b57cec5SDimitry Andric STATISTIC(NumBoolRetPromotion, 650b57cec5SDimitry Andric "Number of times a bool feeding a RetInst was promoted to an int"); 660b57cec5SDimitry Andric STATISTIC(NumBoolCallPromotion, 670b57cec5SDimitry Andric "Number of times a bool feeding a CallInst was promoted to an int"); 680b57cec5SDimitry Andric STATISTIC(NumBoolToIntPromotion, 690b57cec5SDimitry Andric "Total number of times a bool was promoted to an int"); 700b57cec5SDimitry Andric 710b57cec5SDimitry Andric class PPCBoolRetToInt : public FunctionPass { 720b57cec5SDimitry Andric static SmallPtrSet<Value *, 8> findAllDefs(Value *V) { 730b57cec5SDimitry Andric SmallPtrSet<Value *, 8> Defs; 740b57cec5SDimitry Andric SmallVector<Value *, 8> WorkList; 750b57cec5SDimitry Andric WorkList.push_back(V); 760b57cec5SDimitry Andric Defs.insert(V); 770b57cec5SDimitry Andric while (!WorkList.empty()) { 780b57cec5SDimitry Andric Value *Curr = WorkList.back(); 790b57cec5SDimitry Andric WorkList.pop_back(); 800b57cec5SDimitry Andric auto *CurrUser = dyn_cast<User>(Curr); 81*16d6b3b3SDimitry Andric // Operands of CallInst/Constant are skipped because they may not be Bool 82*16d6b3b3SDimitry Andric // type. For CallInst, their positions are defined by ABI. 83*16d6b3b3SDimitry Andric if (CurrUser && !isa<CallInst>(Curr) && !isa<Constant>(Curr)) 840b57cec5SDimitry Andric for (auto &Op : CurrUser->operands()) 850b57cec5SDimitry Andric if (Defs.insert(Op).second) 860b57cec5SDimitry Andric WorkList.push_back(Op); 870b57cec5SDimitry Andric } 880b57cec5SDimitry Andric return Defs; 890b57cec5SDimitry Andric } 900b57cec5SDimitry Andric 910b57cec5SDimitry Andric // Translate a i1 value to an equivalent i32/i64 value: 920b57cec5SDimitry Andric Value *translate(Value *V) { 93*16d6b3b3SDimitry Andric assert(V->getType() == Type::getInt1Ty(V->getContext()) && 94*16d6b3b3SDimitry Andric "Expect an i1 value"); 95*16d6b3b3SDimitry Andric 960b57cec5SDimitry Andric Type *IntTy = ST->isPPC64() ? Type::getInt64Ty(V->getContext()) 970b57cec5SDimitry Andric : Type::getInt32Ty(V->getContext()); 980b57cec5SDimitry Andric 990b57cec5SDimitry Andric if (auto *C = dyn_cast<Constant>(V)) 1000b57cec5SDimitry Andric return ConstantExpr::getZExt(C, IntTy); 1010b57cec5SDimitry Andric if (auto *P = dyn_cast<PHINode>(V)) { 1020b57cec5SDimitry Andric // Temporarily set the operands to 0. We'll fix this later in 1030b57cec5SDimitry Andric // runOnUse. 1040b57cec5SDimitry Andric Value *Zero = Constant::getNullValue(IntTy); 1050b57cec5SDimitry Andric PHINode *Q = 1060b57cec5SDimitry Andric PHINode::Create(IntTy, P->getNumIncomingValues(), P->getName(), P); 1070b57cec5SDimitry Andric for (unsigned i = 0; i < P->getNumOperands(); ++i) 1080b57cec5SDimitry Andric Q->addIncoming(Zero, P->getIncomingBlock(i)); 1090b57cec5SDimitry Andric return Q; 1100b57cec5SDimitry Andric } 1110b57cec5SDimitry Andric 1120b57cec5SDimitry Andric auto *A = dyn_cast<Argument>(V); 1130b57cec5SDimitry Andric auto *I = dyn_cast<Instruction>(V); 1140b57cec5SDimitry Andric assert((A || I) && "Unknown value type"); 1150b57cec5SDimitry Andric 1160b57cec5SDimitry Andric auto InstPt = 1170b57cec5SDimitry Andric A ? &*A->getParent()->getEntryBlock().begin() : I->getNextNode(); 1180b57cec5SDimitry Andric return new ZExtInst(V, IntTy, "", InstPt); 1190b57cec5SDimitry Andric } 1200b57cec5SDimitry Andric 1210b57cec5SDimitry Andric typedef SmallPtrSet<const PHINode *, 8> PHINodeSet; 1220b57cec5SDimitry Andric 1230b57cec5SDimitry Andric // A PHINode is Promotable if: 1240b57cec5SDimitry Andric // 1. Its type is i1 AND 1250b57cec5SDimitry Andric // 2. All of its uses are ReturnInt, CallInst, PHINode, or DbgInfoIntrinsic 1260b57cec5SDimitry Andric // AND 1270b57cec5SDimitry Andric // 3. All of its operands are Constant or Argument or 1280b57cec5SDimitry Andric // CallInst or PHINode AND 1290b57cec5SDimitry Andric // 4. All of its PHINode uses are Promotable AND 1300b57cec5SDimitry Andric // 5. All of its PHINode operands are Promotable 1310b57cec5SDimitry Andric static PHINodeSet getPromotablePHINodes(const Function &F) { 1320b57cec5SDimitry Andric PHINodeSet Promotable; 1330b57cec5SDimitry Andric // Condition 1 1340b57cec5SDimitry Andric for (auto &BB : F) 1350b57cec5SDimitry Andric for (auto &I : BB) 1360b57cec5SDimitry Andric if (const auto *P = dyn_cast<PHINode>(&I)) 1370b57cec5SDimitry Andric if (P->getType()->isIntegerTy(1)) 1380b57cec5SDimitry Andric Promotable.insert(P); 1390b57cec5SDimitry Andric 1400b57cec5SDimitry Andric SmallVector<const PHINode *, 8> ToRemove; 1410b57cec5SDimitry Andric for (const PHINode *P : Promotable) { 1420b57cec5SDimitry Andric // Condition 2 and 3 1430b57cec5SDimitry Andric auto IsValidUser = [] (const Value *V) -> bool { 1440b57cec5SDimitry Andric return isa<ReturnInst>(V) || isa<CallInst>(V) || isa<PHINode>(V) || 1450b57cec5SDimitry Andric isa<DbgInfoIntrinsic>(V); 1460b57cec5SDimitry Andric }; 1470b57cec5SDimitry Andric auto IsValidOperand = [] (const Value *V) -> bool { 1480b57cec5SDimitry Andric return isa<Constant>(V) || isa<Argument>(V) || isa<CallInst>(V) || 1490b57cec5SDimitry Andric isa<PHINode>(V); 1500b57cec5SDimitry Andric }; 1510b57cec5SDimitry Andric const auto &Users = P->users(); 1520b57cec5SDimitry Andric const auto &Operands = P->operands(); 1530b57cec5SDimitry Andric if (!llvm::all_of(Users, IsValidUser) || 1540b57cec5SDimitry Andric !llvm::all_of(Operands, IsValidOperand)) 1550b57cec5SDimitry Andric ToRemove.push_back(P); 1560b57cec5SDimitry Andric } 1570b57cec5SDimitry Andric 1580b57cec5SDimitry Andric // Iterate to convergence 1590b57cec5SDimitry Andric auto IsPromotable = [&Promotable] (const Value *V) -> bool { 1600b57cec5SDimitry Andric const auto *Phi = dyn_cast<PHINode>(V); 1610b57cec5SDimitry Andric return !Phi || Promotable.count(Phi); 1620b57cec5SDimitry Andric }; 1630b57cec5SDimitry Andric while (!ToRemove.empty()) { 1640b57cec5SDimitry Andric for (auto &User : ToRemove) 1650b57cec5SDimitry Andric Promotable.erase(User); 1660b57cec5SDimitry Andric ToRemove.clear(); 1670b57cec5SDimitry Andric 1680b57cec5SDimitry Andric for (const PHINode *P : Promotable) { 1690b57cec5SDimitry Andric // Condition 4 and 5 1700b57cec5SDimitry Andric const auto &Users = P->users(); 1710b57cec5SDimitry Andric const auto &Operands = P->operands(); 1720b57cec5SDimitry Andric if (!llvm::all_of(Users, IsPromotable) || 1730b57cec5SDimitry Andric !llvm::all_of(Operands, IsPromotable)) 1740b57cec5SDimitry Andric ToRemove.push_back(P); 1750b57cec5SDimitry Andric } 1760b57cec5SDimitry Andric } 1770b57cec5SDimitry Andric 1780b57cec5SDimitry Andric return Promotable; 1790b57cec5SDimitry Andric } 1800b57cec5SDimitry Andric 1810b57cec5SDimitry Andric typedef DenseMap<Value *, Value *> B2IMap; 1820b57cec5SDimitry Andric 1830b57cec5SDimitry Andric public: 1840b57cec5SDimitry Andric static char ID; 1850b57cec5SDimitry Andric 1860b57cec5SDimitry Andric PPCBoolRetToInt() : FunctionPass(ID) { 1870b57cec5SDimitry Andric initializePPCBoolRetToIntPass(*PassRegistry::getPassRegistry()); 1880b57cec5SDimitry Andric } 1890b57cec5SDimitry Andric 1900b57cec5SDimitry Andric bool runOnFunction(Function &F) override { 1910b57cec5SDimitry Andric if (skipFunction(F)) 1920b57cec5SDimitry Andric return false; 1930b57cec5SDimitry Andric 1940b57cec5SDimitry Andric auto *TPC = getAnalysisIfAvailable<TargetPassConfig>(); 1950b57cec5SDimitry Andric if (!TPC) 1960b57cec5SDimitry Andric return false; 1970b57cec5SDimitry Andric 1980b57cec5SDimitry Andric auto &TM = TPC->getTM<PPCTargetMachine>(); 1990b57cec5SDimitry Andric ST = TM.getSubtargetImpl(F); 2000b57cec5SDimitry Andric 2010b57cec5SDimitry Andric PHINodeSet PromotablePHINodes = getPromotablePHINodes(F); 2020b57cec5SDimitry Andric B2IMap Bool2IntMap; 2030b57cec5SDimitry Andric bool Changed = false; 2040b57cec5SDimitry Andric for (auto &BB : F) { 2050b57cec5SDimitry Andric for (auto &I : BB) { 2060b57cec5SDimitry Andric if (auto *R = dyn_cast<ReturnInst>(&I)) 2070b57cec5SDimitry Andric if (F.getReturnType()->isIntegerTy(1)) 2080b57cec5SDimitry Andric Changed |= 2090b57cec5SDimitry Andric runOnUse(R->getOperandUse(0), PromotablePHINodes, Bool2IntMap); 2100b57cec5SDimitry Andric 2110b57cec5SDimitry Andric if (auto *CI = dyn_cast<CallInst>(&I)) 2120b57cec5SDimitry Andric for (auto &U : CI->operands()) 2130b57cec5SDimitry Andric if (U->getType()->isIntegerTy(1)) 2140b57cec5SDimitry Andric Changed |= runOnUse(U, PromotablePHINodes, Bool2IntMap); 2150b57cec5SDimitry Andric } 2160b57cec5SDimitry Andric } 2170b57cec5SDimitry Andric 2180b57cec5SDimitry Andric return Changed; 2190b57cec5SDimitry Andric } 2200b57cec5SDimitry Andric 2210b57cec5SDimitry Andric bool runOnUse(Use &U, const PHINodeSet &PromotablePHINodes, 2220b57cec5SDimitry Andric B2IMap &BoolToIntMap) { 2230b57cec5SDimitry Andric auto Defs = findAllDefs(U); 2240b57cec5SDimitry Andric 2250b57cec5SDimitry Andric // If the values are all Constants or Arguments, don't bother 2265ffd83dbSDimitry Andric if (llvm::none_of(Defs, [](Value *V) { return isa<Instruction>(V); })) 2270b57cec5SDimitry Andric return false; 2280b57cec5SDimitry Andric 2290b57cec5SDimitry Andric // Presently, we only know how to handle PHINode, Constant, Arguments and 2300b57cec5SDimitry Andric // CallInst. Potentially, bitwise operations (AND, OR, XOR, NOT) and sign 2310b57cec5SDimitry Andric // extension could also be handled in the future. 2320b57cec5SDimitry Andric for (Value *V : Defs) 2330b57cec5SDimitry Andric if (!isa<PHINode>(V) && !isa<Constant>(V) && 2340b57cec5SDimitry Andric !isa<Argument>(V) && !isa<CallInst>(V)) 2350b57cec5SDimitry Andric return false; 2360b57cec5SDimitry Andric 2370b57cec5SDimitry Andric for (Value *V : Defs) 2380b57cec5SDimitry Andric if (const auto *P = dyn_cast<PHINode>(V)) 2390b57cec5SDimitry Andric if (!PromotablePHINodes.count(P)) 2400b57cec5SDimitry Andric return false; 2410b57cec5SDimitry Andric 2420b57cec5SDimitry Andric if (isa<ReturnInst>(U.getUser())) 2430b57cec5SDimitry Andric ++NumBoolRetPromotion; 2440b57cec5SDimitry Andric if (isa<CallInst>(U.getUser())) 2450b57cec5SDimitry Andric ++NumBoolCallPromotion; 2460b57cec5SDimitry Andric ++NumBoolToIntPromotion; 2470b57cec5SDimitry Andric 2480b57cec5SDimitry Andric for (Value *V : Defs) 2490b57cec5SDimitry Andric if (!BoolToIntMap.count(V)) 2500b57cec5SDimitry Andric BoolToIntMap[V] = translate(V); 2510b57cec5SDimitry Andric 2520b57cec5SDimitry Andric // Replace the operands of the translated instructions. They were set to 2530b57cec5SDimitry Andric // zero in the translate function. 2540b57cec5SDimitry Andric for (auto &Pair : BoolToIntMap) { 2550b57cec5SDimitry Andric auto *First = dyn_cast<User>(Pair.first); 2560b57cec5SDimitry Andric auto *Second = dyn_cast<User>(Pair.second); 2570b57cec5SDimitry Andric assert((!First || Second) && "translated from user to non-user!?"); 258*16d6b3b3SDimitry Andric // Operands of CallInst/Constant are skipped because they may not be Bool 259*16d6b3b3SDimitry Andric // type. For CallInst, their positions are defined by ABI. 260*16d6b3b3SDimitry Andric if (First && !isa<CallInst>(First) && !isa<Constant>(First)) 2610b57cec5SDimitry Andric for (unsigned i = 0; i < First->getNumOperands(); ++i) 2620b57cec5SDimitry Andric Second->setOperand(i, BoolToIntMap[First->getOperand(i)]); 2630b57cec5SDimitry Andric } 2640b57cec5SDimitry Andric 2650b57cec5SDimitry Andric Value *IntRetVal = BoolToIntMap[U]; 2660b57cec5SDimitry Andric Type *Int1Ty = Type::getInt1Ty(U->getContext()); 2670b57cec5SDimitry Andric auto *I = cast<Instruction>(U.getUser()); 2680b57cec5SDimitry Andric Value *BackToBool = new TruncInst(IntRetVal, Int1Ty, "backToBool", I); 2690b57cec5SDimitry Andric U.set(BackToBool); 2700b57cec5SDimitry Andric 2710b57cec5SDimitry Andric return true; 2720b57cec5SDimitry Andric } 2730b57cec5SDimitry Andric 2740b57cec5SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 2750b57cec5SDimitry Andric AU.addPreserved<DominatorTreeWrapperPass>(); 2760b57cec5SDimitry Andric FunctionPass::getAnalysisUsage(AU); 2770b57cec5SDimitry Andric } 2780b57cec5SDimitry Andric 2790b57cec5SDimitry Andric private: 2800b57cec5SDimitry Andric const PPCSubtarget *ST; 2810b57cec5SDimitry Andric }; 2820b57cec5SDimitry Andric 2830b57cec5SDimitry Andric } // end anonymous namespace 2840b57cec5SDimitry Andric 2850b57cec5SDimitry Andric char PPCBoolRetToInt::ID = 0; 2860b57cec5SDimitry Andric INITIALIZE_PASS(PPCBoolRetToInt, "bool-ret-to-int", 2870b57cec5SDimitry Andric "Convert i1 constants to i32/i64 if they are returned", 2880b57cec5SDimitry Andric false, false) 2890b57cec5SDimitry Andric 2900b57cec5SDimitry Andric FunctionPass *llvm::createPPCBoolRetToIntPass() { return new PPCBoolRetToInt(); } 291