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