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); 810b57cec5SDimitry Andric // Operands of CallInst are skipped because they may not be Bool type, 820b57cec5SDimitry Andric // and their positions are defined by ABI. 830b57cec5SDimitry Andric if (CurrUser && !isa<CallInst>(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) { 930b57cec5SDimitry Andric Type *IntTy = ST->isPPC64() ? Type::getInt64Ty(V->getContext()) 940b57cec5SDimitry Andric : Type::getInt32Ty(V->getContext()); 950b57cec5SDimitry Andric 960b57cec5SDimitry Andric if (auto *C = dyn_cast<Constant>(V)) 970b57cec5SDimitry Andric return ConstantExpr::getZExt(C, IntTy); 980b57cec5SDimitry Andric if (auto *P = dyn_cast<PHINode>(V)) { 990b57cec5SDimitry Andric // Temporarily set the operands to 0. We'll fix this later in 1000b57cec5SDimitry Andric // runOnUse. 1010b57cec5SDimitry Andric Value *Zero = Constant::getNullValue(IntTy); 1020b57cec5SDimitry Andric PHINode *Q = 1030b57cec5SDimitry Andric PHINode::Create(IntTy, P->getNumIncomingValues(), P->getName(), P); 1040b57cec5SDimitry Andric for (unsigned i = 0; i < P->getNumOperands(); ++i) 1050b57cec5SDimitry Andric Q->addIncoming(Zero, P->getIncomingBlock(i)); 1060b57cec5SDimitry Andric return Q; 1070b57cec5SDimitry Andric } 1080b57cec5SDimitry Andric 1090b57cec5SDimitry Andric auto *A = dyn_cast<Argument>(V); 1100b57cec5SDimitry Andric auto *I = dyn_cast<Instruction>(V); 1110b57cec5SDimitry Andric assert((A || I) && "Unknown value type"); 1120b57cec5SDimitry Andric 1130b57cec5SDimitry Andric auto InstPt = 1140b57cec5SDimitry Andric A ? &*A->getParent()->getEntryBlock().begin() : I->getNextNode(); 1150b57cec5SDimitry Andric return new ZExtInst(V, IntTy, "", InstPt); 1160b57cec5SDimitry Andric } 1170b57cec5SDimitry Andric 1180b57cec5SDimitry Andric typedef SmallPtrSet<const PHINode *, 8> PHINodeSet; 1190b57cec5SDimitry Andric 1200b57cec5SDimitry Andric // A PHINode is Promotable if: 1210b57cec5SDimitry Andric // 1. Its type is i1 AND 1220b57cec5SDimitry Andric // 2. All of its uses are ReturnInt, CallInst, PHINode, or DbgInfoIntrinsic 1230b57cec5SDimitry Andric // AND 1240b57cec5SDimitry Andric // 3. All of its operands are Constant or Argument or 1250b57cec5SDimitry Andric // CallInst or PHINode AND 1260b57cec5SDimitry Andric // 4. All of its PHINode uses are Promotable AND 1270b57cec5SDimitry Andric // 5. All of its PHINode operands are Promotable 1280b57cec5SDimitry Andric static PHINodeSet getPromotablePHINodes(const Function &F) { 1290b57cec5SDimitry Andric PHINodeSet Promotable; 1300b57cec5SDimitry Andric // Condition 1 1310b57cec5SDimitry Andric for (auto &BB : F) 1320b57cec5SDimitry Andric for (auto &I : BB) 1330b57cec5SDimitry Andric if (const auto *P = dyn_cast<PHINode>(&I)) 1340b57cec5SDimitry Andric if (P->getType()->isIntegerTy(1)) 1350b57cec5SDimitry Andric Promotable.insert(P); 1360b57cec5SDimitry Andric 1370b57cec5SDimitry Andric SmallVector<const PHINode *, 8> ToRemove; 1380b57cec5SDimitry Andric for (const PHINode *P : Promotable) { 1390b57cec5SDimitry Andric // Condition 2 and 3 1400b57cec5SDimitry Andric auto IsValidUser = [] (const Value *V) -> bool { 1410b57cec5SDimitry Andric return isa<ReturnInst>(V) || isa<CallInst>(V) || isa<PHINode>(V) || 1420b57cec5SDimitry Andric isa<DbgInfoIntrinsic>(V); 1430b57cec5SDimitry Andric }; 1440b57cec5SDimitry Andric auto IsValidOperand = [] (const Value *V) -> bool { 1450b57cec5SDimitry Andric return isa<Constant>(V) || isa<Argument>(V) || isa<CallInst>(V) || 1460b57cec5SDimitry Andric isa<PHINode>(V); 1470b57cec5SDimitry Andric }; 1480b57cec5SDimitry Andric const auto &Users = P->users(); 1490b57cec5SDimitry Andric const auto &Operands = P->operands(); 1500b57cec5SDimitry Andric if (!llvm::all_of(Users, IsValidUser) || 1510b57cec5SDimitry Andric !llvm::all_of(Operands, IsValidOperand)) 1520b57cec5SDimitry Andric ToRemove.push_back(P); 1530b57cec5SDimitry Andric } 1540b57cec5SDimitry Andric 1550b57cec5SDimitry Andric // Iterate to convergence 1560b57cec5SDimitry Andric auto IsPromotable = [&Promotable] (const Value *V) -> bool { 1570b57cec5SDimitry Andric const auto *Phi = dyn_cast<PHINode>(V); 1580b57cec5SDimitry Andric return !Phi || Promotable.count(Phi); 1590b57cec5SDimitry Andric }; 1600b57cec5SDimitry Andric while (!ToRemove.empty()) { 1610b57cec5SDimitry Andric for (auto &User : ToRemove) 1620b57cec5SDimitry Andric Promotable.erase(User); 1630b57cec5SDimitry Andric ToRemove.clear(); 1640b57cec5SDimitry Andric 1650b57cec5SDimitry Andric for (const PHINode *P : Promotable) { 1660b57cec5SDimitry Andric // Condition 4 and 5 1670b57cec5SDimitry Andric const auto &Users = P->users(); 1680b57cec5SDimitry Andric const auto &Operands = P->operands(); 1690b57cec5SDimitry Andric if (!llvm::all_of(Users, IsPromotable) || 1700b57cec5SDimitry Andric !llvm::all_of(Operands, IsPromotable)) 1710b57cec5SDimitry Andric ToRemove.push_back(P); 1720b57cec5SDimitry Andric } 1730b57cec5SDimitry Andric } 1740b57cec5SDimitry Andric 1750b57cec5SDimitry Andric return Promotable; 1760b57cec5SDimitry Andric } 1770b57cec5SDimitry Andric 1780b57cec5SDimitry Andric typedef DenseMap<Value *, Value *> B2IMap; 1790b57cec5SDimitry Andric 1800b57cec5SDimitry Andric public: 1810b57cec5SDimitry Andric static char ID; 1820b57cec5SDimitry Andric 1830b57cec5SDimitry Andric PPCBoolRetToInt() : FunctionPass(ID) { 1840b57cec5SDimitry Andric initializePPCBoolRetToIntPass(*PassRegistry::getPassRegistry()); 1850b57cec5SDimitry Andric } 1860b57cec5SDimitry Andric 1870b57cec5SDimitry Andric bool runOnFunction(Function &F) override { 1880b57cec5SDimitry Andric if (skipFunction(F)) 1890b57cec5SDimitry Andric return false; 1900b57cec5SDimitry Andric 1910b57cec5SDimitry Andric auto *TPC = getAnalysisIfAvailable<TargetPassConfig>(); 1920b57cec5SDimitry Andric if (!TPC) 1930b57cec5SDimitry Andric return false; 1940b57cec5SDimitry Andric 1950b57cec5SDimitry Andric auto &TM = TPC->getTM<PPCTargetMachine>(); 1960b57cec5SDimitry Andric ST = TM.getSubtargetImpl(F); 1970b57cec5SDimitry Andric 1980b57cec5SDimitry Andric PHINodeSet PromotablePHINodes = getPromotablePHINodes(F); 1990b57cec5SDimitry Andric B2IMap Bool2IntMap; 2000b57cec5SDimitry Andric bool Changed = false; 2010b57cec5SDimitry Andric for (auto &BB : F) { 2020b57cec5SDimitry Andric for (auto &I : BB) { 2030b57cec5SDimitry Andric if (auto *R = dyn_cast<ReturnInst>(&I)) 2040b57cec5SDimitry Andric if (F.getReturnType()->isIntegerTy(1)) 2050b57cec5SDimitry Andric Changed |= 2060b57cec5SDimitry Andric runOnUse(R->getOperandUse(0), PromotablePHINodes, Bool2IntMap); 2070b57cec5SDimitry Andric 2080b57cec5SDimitry Andric if (auto *CI = dyn_cast<CallInst>(&I)) 2090b57cec5SDimitry Andric for (auto &U : CI->operands()) 2100b57cec5SDimitry Andric if (U->getType()->isIntegerTy(1)) 2110b57cec5SDimitry Andric Changed |= runOnUse(U, PromotablePHINodes, Bool2IntMap); 2120b57cec5SDimitry Andric } 2130b57cec5SDimitry Andric } 2140b57cec5SDimitry Andric 2150b57cec5SDimitry Andric return Changed; 2160b57cec5SDimitry Andric } 2170b57cec5SDimitry Andric 2180b57cec5SDimitry Andric bool runOnUse(Use &U, const PHINodeSet &PromotablePHINodes, 2190b57cec5SDimitry Andric B2IMap &BoolToIntMap) { 2200b57cec5SDimitry Andric auto Defs = findAllDefs(U); 2210b57cec5SDimitry Andric 2220b57cec5SDimitry Andric // If the values are all Constants or Arguments, don't bother 223*5ffd83dbSDimitry Andric if (llvm::none_of(Defs, [](Value *V) { return isa<Instruction>(V); })) 2240b57cec5SDimitry Andric return false; 2250b57cec5SDimitry Andric 2260b57cec5SDimitry Andric // Presently, we only know how to handle PHINode, Constant, Arguments and 2270b57cec5SDimitry Andric // CallInst. Potentially, bitwise operations (AND, OR, XOR, NOT) and sign 2280b57cec5SDimitry Andric // extension could also be handled in the future. 2290b57cec5SDimitry Andric for (Value *V : Defs) 2300b57cec5SDimitry Andric if (!isa<PHINode>(V) && !isa<Constant>(V) && 2310b57cec5SDimitry Andric !isa<Argument>(V) && !isa<CallInst>(V)) 2320b57cec5SDimitry Andric return false; 2330b57cec5SDimitry Andric 2340b57cec5SDimitry Andric for (Value *V : Defs) 2350b57cec5SDimitry Andric if (const auto *P = dyn_cast<PHINode>(V)) 2360b57cec5SDimitry Andric if (!PromotablePHINodes.count(P)) 2370b57cec5SDimitry Andric return false; 2380b57cec5SDimitry Andric 2390b57cec5SDimitry Andric if (isa<ReturnInst>(U.getUser())) 2400b57cec5SDimitry Andric ++NumBoolRetPromotion; 2410b57cec5SDimitry Andric if (isa<CallInst>(U.getUser())) 2420b57cec5SDimitry Andric ++NumBoolCallPromotion; 2430b57cec5SDimitry Andric ++NumBoolToIntPromotion; 2440b57cec5SDimitry Andric 2450b57cec5SDimitry Andric for (Value *V : Defs) 2460b57cec5SDimitry Andric if (!BoolToIntMap.count(V)) 2470b57cec5SDimitry Andric BoolToIntMap[V] = translate(V); 2480b57cec5SDimitry Andric 2490b57cec5SDimitry Andric // Replace the operands of the translated instructions. They were set to 2500b57cec5SDimitry Andric // zero in the translate function. 2510b57cec5SDimitry Andric for (auto &Pair : BoolToIntMap) { 2520b57cec5SDimitry Andric auto *First = dyn_cast<User>(Pair.first); 2530b57cec5SDimitry Andric auto *Second = dyn_cast<User>(Pair.second); 2540b57cec5SDimitry Andric assert((!First || Second) && "translated from user to non-user!?"); 2550b57cec5SDimitry Andric // Operands of CallInst are skipped because they may not be Bool type, 2560b57cec5SDimitry Andric // and their positions are defined by ABI. 2570b57cec5SDimitry Andric if (First && !isa<CallInst>(First)) 2580b57cec5SDimitry Andric for (unsigned i = 0; i < First->getNumOperands(); ++i) 2590b57cec5SDimitry Andric Second->setOperand(i, BoolToIntMap[First->getOperand(i)]); 2600b57cec5SDimitry Andric } 2610b57cec5SDimitry Andric 2620b57cec5SDimitry Andric Value *IntRetVal = BoolToIntMap[U]; 2630b57cec5SDimitry Andric Type *Int1Ty = Type::getInt1Ty(U->getContext()); 2640b57cec5SDimitry Andric auto *I = cast<Instruction>(U.getUser()); 2650b57cec5SDimitry Andric Value *BackToBool = new TruncInst(IntRetVal, Int1Ty, "backToBool", I); 2660b57cec5SDimitry Andric U.set(BackToBool); 2670b57cec5SDimitry Andric 2680b57cec5SDimitry Andric return true; 2690b57cec5SDimitry Andric } 2700b57cec5SDimitry Andric 2710b57cec5SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 2720b57cec5SDimitry Andric AU.addPreserved<DominatorTreeWrapperPass>(); 2730b57cec5SDimitry Andric FunctionPass::getAnalysisUsage(AU); 2740b57cec5SDimitry Andric } 2750b57cec5SDimitry Andric 2760b57cec5SDimitry Andric private: 2770b57cec5SDimitry Andric const PPCSubtarget *ST; 2780b57cec5SDimitry Andric }; 2790b57cec5SDimitry Andric 2800b57cec5SDimitry Andric } // end anonymous namespace 2810b57cec5SDimitry Andric 2820b57cec5SDimitry Andric char PPCBoolRetToInt::ID = 0; 2830b57cec5SDimitry Andric INITIALIZE_PASS(PPCBoolRetToInt, "bool-ret-to-int", 2840b57cec5SDimitry Andric "Convert i1 constants to i32/i64 if they are returned", 2850b57cec5SDimitry Andric false, false) 2860b57cec5SDimitry Andric 2870b57cec5SDimitry Andric FunctionPass *llvm::createPPCBoolRetToIntPass() { return new PPCBoolRetToInt(); } 288