xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/PowerPC/PPCBoolRetToInt.cpp (revision 0b57cec536236d46e3dba9bd041533462f33dbb7)
1*0b57cec5SDimitry Andric //===- PPCBoolRetToInt.cpp ------------------------------------------------===//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric //
9*0b57cec5SDimitry Andric // This file implements converting i1 values to i32/i64 if they could be more
10*0b57cec5SDimitry Andric // profitably allocated as GPRs rather than CRs. This pass will become totally
11*0b57cec5SDimitry Andric // unnecessary if Register Bank Allocation and Global Instruction Selection ever
12*0b57cec5SDimitry Andric // go upstream.
13*0b57cec5SDimitry Andric //
14*0b57cec5SDimitry Andric // Presently, the pass converts i1 Constants, and Arguments to i32/i64 if the
15*0b57cec5SDimitry Andric // transitive closure of their uses includes only PHINodes, CallInsts, and
16*0b57cec5SDimitry Andric // ReturnInsts. The rational is that arguments are generally passed and returned
17*0b57cec5SDimitry Andric // in GPRs rather than CRs, so casting them to i32/i64 at the LLVM IR level will
18*0b57cec5SDimitry Andric // actually save casts at the Machine Instruction level.
19*0b57cec5SDimitry Andric //
20*0b57cec5SDimitry Andric // It might be useful to expand this pass to add bit-wise operations to the list
21*0b57cec5SDimitry Andric // of safe transitive closure types. Also, we miss some opportunities when LLVM
22*0b57cec5SDimitry Andric // represents logical AND and OR operations with control flow rather than data
23*0b57cec5SDimitry Andric // flow. For example by lowering the expression: return (A && B && C)
24*0b57cec5SDimitry Andric //
25*0b57cec5SDimitry Andric // as: return A ? true : B && C.
26*0b57cec5SDimitry Andric //
27*0b57cec5SDimitry Andric // There's code in SimplifyCFG that code be used to turn control flow in data
28*0b57cec5SDimitry Andric // flow using SelectInsts. Selects are slow on some architectures (P7/P8), so
29*0b57cec5SDimitry Andric // this probably isn't good in general, but for the special case of i1, the
30*0b57cec5SDimitry Andric // Selects could be further lowered to bit operations that are fast everywhere.
31*0b57cec5SDimitry Andric //
32*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
33*0b57cec5SDimitry Andric 
34*0b57cec5SDimitry Andric #include "PPC.h"
35*0b57cec5SDimitry Andric #include "PPCTargetMachine.h"
36*0b57cec5SDimitry Andric #include "llvm/ADT/DenseMap.h"
37*0b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h"
38*0b57cec5SDimitry Andric #include "llvm/ADT/SmallPtrSet.h"
39*0b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h"
40*0b57cec5SDimitry Andric #include "llvm/ADT/Statistic.h"
41*0b57cec5SDimitry Andric #include "llvm/IR/Argument.h"
42*0b57cec5SDimitry Andric #include "llvm/IR/Constants.h"
43*0b57cec5SDimitry Andric #include "llvm/IR/Dominators.h"
44*0b57cec5SDimitry Andric #include "llvm/IR/Function.h"
45*0b57cec5SDimitry Andric #include "llvm/IR/Instruction.h"
46*0b57cec5SDimitry Andric #include "llvm/IR/Instructions.h"
47*0b57cec5SDimitry Andric #include "llvm/IR/IntrinsicInst.h"
48*0b57cec5SDimitry Andric #include "llvm/IR/OperandTraits.h"
49*0b57cec5SDimitry Andric #include "llvm/IR/Type.h"
50*0b57cec5SDimitry Andric #include "llvm/IR/Use.h"
51*0b57cec5SDimitry Andric #include "llvm/IR/User.h"
52*0b57cec5SDimitry Andric #include "llvm/IR/Value.h"
53*0b57cec5SDimitry Andric #include "llvm/Pass.h"
54*0b57cec5SDimitry Andric #include "llvm/CodeGen/TargetPassConfig.h"
55*0b57cec5SDimitry Andric #include "llvm/Support/Casting.h"
56*0b57cec5SDimitry Andric #include <cassert>
57*0b57cec5SDimitry Andric 
58*0b57cec5SDimitry Andric using namespace llvm;
59*0b57cec5SDimitry Andric 
60*0b57cec5SDimitry Andric namespace {
61*0b57cec5SDimitry Andric 
62*0b57cec5SDimitry Andric #define DEBUG_TYPE "bool-ret-to-int"
63*0b57cec5SDimitry Andric 
64*0b57cec5SDimitry Andric STATISTIC(NumBoolRetPromotion,
65*0b57cec5SDimitry Andric           "Number of times a bool feeding a RetInst was promoted to an int");
66*0b57cec5SDimitry Andric STATISTIC(NumBoolCallPromotion,
67*0b57cec5SDimitry Andric           "Number of times a bool feeding a CallInst was promoted to an int");
68*0b57cec5SDimitry Andric STATISTIC(NumBoolToIntPromotion,
69*0b57cec5SDimitry Andric           "Total number of times a bool was promoted to an int");
70*0b57cec5SDimitry Andric 
71*0b57cec5SDimitry Andric class PPCBoolRetToInt : public FunctionPass {
72*0b57cec5SDimitry Andric   static SmallPtrSet<Value *, 8> findAllDefs(Value *V) {
73*0b57cec5SDimitry Andric     SmallPtrSet<Value *, 8> Defs;
74*0b57cec5SDimitry Andric     SmallVector<Value *, 8> WorkList;
75*0b57cec5SDimitry Andric     WorkList.push_back(V);
76*0b57cec5SDimitry Andric     Defs.insert(V);
77*0b57cec5SDimitry Andric     while (!WorkList.empty()) {
78*0b57cec5SDimitry Andric       Value *Curr = WorkList.back();
79*0b57cec5SDimitry Andric       WorkList.pop_back();
80*0b57cec5SDimitry Andric       auto *CurrUser = dyn_cast<User>(Curr);
81*0b57cec5SDimitry Andric       // Operands of CallInst are skipped because they may not be Bool type,
82*0b57cec5SDimitry Andric       // and their positions are defined by ABI.
83*0b57cec5SDimitry Andric       if (CurrUser && !isa<CallInst>(Curr))
84*0b57cec5SDimitry Andric         for (auto &Op : CurrUser->operands())
85*0b57cec5SDimitry Andric           if (Defs.insert(Op).second)
86*0b57cec5SDimitry Andric             WorkList.push_back(Op);
87*0b57cec5SDimitry Andric     }
88*0b57cec5SDimitry Andric     return Defs;
89*0b57cec5SDimitry Andric   }
90*0b57cec5SDimitry Andric 
91*0b57cec5SDimitry Andric   // Translate a i1 value to an equivalent i32/i64 value:
92*0b57cec5SDimitry Andric   Value *translate(Value *V) {
93*0b57cec5SDimitry Andric     Type *IntTy = ST->isPPC64() ? Type::getInt64Ty(V->getContext())
94*0b57cec5SDimitry Andric                                 : Type::getInt32Ty(V->getContext());
95*0b57cec5SDimitry Andric 
96*0b57cec5SDimitry Andric     if (auto *C = dyn_cast<Constant>(V))
97*0b57cec5SDimitry Andric       return ConstantExpr::getZExt(C, IntTy);
98*0b57cec5SDimitry Andric     if (auto *P = dyn_cast<PHINode>(V)) {
99*0b57cec5SDimitry Andric       // Temporarily set the operands to 0. We'll fix this later in
100*0b57cec5SDimitry Andric       // runOnUse.
101*0b57cec5SDimitry Andric       Value *Zero = Constant::getNullValue(IntTy);
102*0b57cec5SDimitry Andric       PHINode *Q =
103*0b57cec5SDimitry Andric         PHINode::Create(IntTy, P->getNumIncomingValues(), P->getName(), P);
104*0b57cec5SDimitry Andric       for (unsigned i = 0; i < P->getNumOperands(); ++i)
105*0b57cec5SDimitry Andric         Q->addIncoming(Zero, P->getIncomingBlock(i));
106*0b57cec5SDimitry Andric       return Q;
107*0b57cec5SDimitry Andric     }
108*0b57cec5SDimitry Andric 
109*0b57cec5SDimitry Andric     auto *A = dyn_cast<Argument>(V);
110*0b57cec5SDimitry Andric     auto *I = dyn_cast<Instruction>(V);
111*0b57cec5SDimitry Andric     assert((A || I) && "Unknown value type");
112*0b57cec5SDimitry Andric 
113*0b57cec5SDimitry Andric     auto InstPt =
114*0b57cec5SDimitry Andric       A ? &*A->getParent()->getEntryBlock().begin() : I->getNextNode();
115*0b57cec5SDimitry Andric     return new ZExtInst(V, IntTy, "", InstPt);
116*0b57cec5SDimitry Andric   }
117*0b57cec5SDimitry Andric 
118*0b57cec5SDimitry Andric   typedef SmallPtrSet<const PHINode *, 8> PHINodeSet;
119*0b57cec5SDimitry Andric 
120*0b57cec5SDimitry Andric   // A PHINode is Promotable if:
121*0b57cec5SDimitry Andric   // 1. Its type is i1 AND
122*0b57cec5SDimitry Andric   // 2. All of its uses are ReturnInt, CallInst, PHINode, or DbgInfoIntrinsic
123*0b57cec5SDimitry Andric   // AND
124*0b57cec5SDimitry Andric   // 3. All of its operands are Constant or Argument or
125*0b57cec5SDimitry Andric   //    CallInst or PHINode AND
126*0b57cec5SDimitry Andric   // 4. All of its PHINode uses are Promotable AND
127*0b57cec5SDimitry Andric   // 5. All of its PHINode operands are Promotable
128*0b57cec5SDimitry Andric   static PHINodeSet getPromotablePHINodes(const Function &F) {
129*0b57cec5SDimitry Andric     PHINodeSet Promotable;
130*0b57cec5SDimitry Andric     // Condition 1
131*0b57cec5SDimitry Andric     for (auto &BB : F)
132*0b57cec5SDimitry Andric       for (auto &I : BB)
133*0b57cec5SDimitry Andric         if (const auto *P = dyn_cast<PHINode>(&I))
134*0b57cec5SDimitry Andric           if (P->getType()->isIntegerTy(1))
135*0b57cec5SDimitry Andric             Promotable.insert(P);
136*0b57cec5SDimitry Andric 
137*0b57cec5SDimitry Andric     SmallVector<const PHINode *, 8> ToRemove;
138*0b57cec5SDimitry Andric     for (const PHINode *P : Promotable) {
139*0b57cec5SDimitry Andric       // Condition 2 and 3
140*0b57cec5SDimitry Andric       auto IsValidUser = [] (const Value *V) -> bool {
141*0b57cec5SDimitry Andric         return isa<ReturnInst>(V) || isa<CallInst>(V) || isa<PHINode>(V) ||
142*0b57cec5SDimitry Andric         isa<DbgInfoIntrinsic>(V);
143*0b57cec5SDimitry Andric       };
144*0b57cec5SDimitry Andric       auto IsValidOperand = [] (const Value *V) -> bool {
145*0b57cec5SDimitry Andric         return isa<Constant>(V) || isa<Argument>(V) || isa<CallInst>(V) ||
146*0b57cec5SDimitry Andric         isa<PHINode>(V);
147*0b57cec5SDimitry Andric       };
148*0b57cec5SDimitry Andric       const auto &Users = P->users();
149*0b57cec5SDimitry Andric       const auto &Operands = P->operands();
150*0b57cec5SDimitry Andric       if (!llvm::all_of(Users, IsValidUser) ||
151*0b57cec5SDimitry Andric           !llvm::all_of(Operands, IsValidOperand))
152*0b57cec5SDimitry Andric         ToRemove.push_back(P);
153*0b57cec5SDimitry Andric     }
154*0b57cec5SDimitry Andric 
155*0b57cec5SDimitry Andric     // Iterate to convergence
156*0b57cec5SDimitry Andric     auto IsPromotable = [&Promotable] (const Value *V) -> bool {
157*0b57cec5SDimitry Andric       const auto *Phi = dyn_cast<PHINode>(V);
158*0b57cec5SDimitry Andric       return !Phi || Promotable.count(Phi);
159*0b57cec5SDimitry Andric     };
160*0b57cec5SDimitry Andric     while (!ToRemove.empty()) {
161*0b57cec5SDimitry Andric       for (auto &User : ToRemove)
162*0b57cec5SDimitry Andric         Promotable.erase(User);
163*0b57cec5SDimitry Andric       ToRemove.clear();
164*0b57cec5SDimitry Andric 
165*0b57cec5SDimitry Andric       for (const PHINode *P : Promotable) {
166*0b57cec5SDimitry Andric         // Condition 4 and 5
167*0b57cec5SDimitry Andric         const auto &Users = P->users();
168*0b57cec5SDimitry Andric         const auto &Operands = P->operands();
169*0b57cec5SDimitry Andric         if (!llvm::all_of(Users, IsPromotable) ||
170*0b57cec5SDimitry Andric             !llvm::all_of(Operands, IsPromotable))
171*0b57cec5SDimitry Andric           ToRemove.push_back(P);
172*0b57cec5SDimitry Andric       }
173*0b57cec5SDimitry Andric     }
174*0b57cec5SDimitry Andric 
175*0b57cec5SDimitry Andric     return Promotable;
176*0b57cec5SDimitry Andric   }
177*0b57cec5SDimitry Andric 
178*0b57cec5SDimitry Andric   typedef DenseMap<Value *, Value *> B2IMap;
179*0b57cec5SDimitry Andric 
180*0b57cec5SDimitry Andric  public:
181*0b57cec5SDimitry Andric   static char ID;
182*0b57cec5SDimitry Andric 
183*0b57cec5SDimitry Andric   PPCBoolRetToInt() : FunctionPass(ID) {
184*0b57cec5SDimitry Andric     initializePPCBoolRetToIntPass(*PassRegistry::getPassRegistry());
185*0b57cec5SDimitry Andric   }
186*0b57cec5SDimitry Andric 
187*0b57cec5SDimitry Andric   bool runOnFunction(Function &F) override {
188*0b57cec5SDimitry Andric     if (skipFunction(F))
189*0b57cec5SDimitry Andric       return false;
190*0b57cec5SDimitry Andric 
191*0b57cec5SDimitry Andric     auto *TPC = getAnalysisIfAvailable<TargetPassConfig>();
192*0b57cec5SDimitry Andric     if (!TPC)
193*0b57cec5SDimitry Andric       return false;
194*0b57cec5SDimitry Andric 
195*0b57cec5SDimitry Andric     auto &TM = TPC->getTM<PPCTargetMachine>();
196*0b57cec5SDimitry Andric     ST = TM.getSubtargetImpl(F);
197*0b57cec5SDimitry Andric 
198*0b57cec5SDimitry Andric     PHINodeSet PromotablePHINodes = getPromotablePHINodes(F);
199*0b57cec5SDimitry Andric     B2IMap Bool2IntMap;
200*0b57cec5SDimitry Andric     bool Changed = false;
201*0b57cec5SDimitry Andric     for (auto &BB : F) {
202*0b57cec5SDimitry Andric       for (auto &I : BB) {
203*0b57cec5SDimitry Andric         if (auto *R = dyn_cast<ReturnInst>(&I))
204*0b57cec5SDimitry Andric           if (F.getReturnType()->isIntegerTy(1))
205*0b57cec5SDimitry Andric             Changed |=
206*0b57cec5SDimitry Andric               runOnUse(R->getOperandUse(0), PromotablePHINodes, Bool2IntMap);
207*0b57cec5SDimitry Andric 
208*0b57cec5SDimitry Andric         if (auto *CI = dyn_cast<CallInst>(&I))
209*0b57cec5SDimitry Andric           for (auto &U : CI->operands())
210*0b57cec5SDimitry Andric             if (U->getType()->isIntegerTy(1))
211*0b57cec5SDimitry Andric               Changed |= runOnUse(U, PromotablePHINodes, Bool2IntMap);
212*0b57cec5SDimitry Andric       }
213*0b57cec5SDimitry Andric     }
214*0b57cec5SDimitry Andric 
215*0b57cec5SDimitry Andric     return Changed;
216*0b57cec5SDimitry Andric   }
217*0b57cec5SDimitry Andric 
218*0b57cec5SDimitry Andric   bool runOnUse(Use &U, const PHINodeSet &PromotablePHINodes,
219*0b57cec5SDimitry Andric                        B2IMap &BoolToIntMap) {
220*0b57cec5SDimitry Andric     auto Defs = findAllDefs(U);
221*0b57cec5SDimitry Andric 
222*0b57cec5SDimitry Andric     // If the values are all Constants or Arguments, don't bother
223*0b57cec5SDimitry Andric     if (llvm::none_of(Defs, isa<Instruction, Value *>))
224*0b57cec5SDimitry Andric       return false;
225*0b57cec5SDimitry Andric 
226*0b57cec5SDimitry Andric     // Presently, we only know how to handle PHINode, Constant, Arguments and
227*0b57cec5SDimitry Andric     // CallInst. Potentially, bitwise operations (AND, OR, XOR, NOT) and sign
228*0b57cec5SDimitry Andric     // extension could also be handled in the future.
229*0b57cec5SDimitry Andric     for (Value *V : Defs)
230*0b57cec5SDimitry Andric       if (!isa<PHINode>(V) && !isa<Constant>(V) &&
231*0b57cec5SDimitry Andric           !isa<Argument>(V) && !isa<CallInst>(V))
232*0b57cec5SDimitry Andric         return false;
233*0b57cec5SDimitry Andric 
234*0b57cec5SDimitry Andric     for (Value *V : Defs)
235*0b57cec5SDimitry Andric       if (const auto *P = dyn_cast<PHINode>(V))
236*0b57cec5SDimitry Andric         if (!PromotablePHINodes.count(P))
237*0b57cec5SDimitry Andric           return false;
238*0b57cec5SDimitry Andric 
239*0b57cec5SDimitry Andric     if (isa<ReturnInst>(U.getUser()))
240*0b57cec5SDimitry Andric       ++NumBoolRetPromotion;
241*0b57cec5SDimitry Andric     if (isa<CallInst>(U.getUser()))
242*0b57cec5SDimitry Andric       ++NumBoolCallPromotion;
243*0b57cec5SDimitry Andric     ++NumBoolToIntPromotion;
244*0b57cec5SDimitry Andric 
245*0b57cec5SDimitry Andric     for (Value *V : Defs)
246*0b57cec5SDimitry Andric       if (!BoolToIntMap.count(V))
247*0b57cec5SDimitry Andric         BoolToIntMap[V] = translate(V);
248*0b57cec5SDimitry Andric 
249*0b57cec5SDimitry Andric     // Replace the operands of the translated instructions. They were set to
250*0b57cec5SDimitry Andric     // zero in the translate function.
251*0b57cec5SDimitry Andric     for (auto &Pair : BoolToIntMap) {
252*0b57cec5SDimitry Andric       auto *First = dyn_cast<User>(Pair.first);
253*0b57cec5SDimitry Andric       auto *Second = dyn_cast<User>(Pair.second);
254*0b57cec5SDimitry Andric       assert((!First || Second) && "translated from user to non-user!?");
255*0b57cec5SDimitry Andric       // Operands of CallInst are skipped because they may not be Bool type,
256*0b57cec5SDimitry Andric       // and their positions are defined by ABI.
257*0b57cec5SDimitry Andric       if (First && !isa<CallInst>(First))
258*0b57cec5SDimitry Andric         for (unsigned i = 0; i < First->getNumOperands(); ++i)
259*0b57cec5SDimitry Andric           Second->setOperand(i, BoolToIntMap[First->getOperand(i)]);
260*0b57cec5SDimitry Andric     }
261*0b57cec5SDimitry Andric 
262*0b57cec5SDimitry Andric     Value *IntRetVal = BoolToIntMap[U];
263*0b57cec5SDimitry Andric     Type *Int1Ty = Type::getInt1Ty(U->getContext());
264*0b57cec5SDimitry Andric     auto *I = cast<Instruction>(U.getUser());
265*0b57cec5SDimitry Andric     Value *BackToBool = new TruncInst(IntRetVal, Int1Ty, "backToBool", I);
266*0b57cec5SDimitry Andric     U.set(BackToBool);
267*0b57cec5SDimitry Andric 
268*0b57cec5SDimitry Andric     return true;
269*0b57cec5SDimitry Andric   }
270*0b57cec5SDimitry Andric 
271*0b57cec5SDimitry Andric   void getAnalysisUsage(AnalysisUsage &AU) const override {
272*0b57cec5SDimitry Andric     AU.addPreserved<DominatorTreeWrapperPass>();
273*0b57cec5SDimitry Andric     FunctionPass::getAnalysisUsage(AU);
274*0b57cec5SDimitry Andric   }
275*0b57cec5SDimitry Andric 
276*0b57cec5SDimitry Andric private:
277*0b57cec5SDimitry Andric   const PPCSubtarget *ST;
278*0b57cec5SDimitry Andric };
279*0b57cec5SDimitry Andric 
280*0b57cec5SDimitry Andric } // end anonymous namespace
281*0b57cec5SDimitry Andric 
282*0b57cec5SDimitry Andric char PPCBoolRetToInt::ID = 0;
283*0b57cec5SDimitry Andric INITIALIZE_PASS(PPCBoolRetToInt, "bool-ret-to-int",
284*0b57cec5SDimitry Andric                 "Convert i1 constants to i32/i64 if they are returned",
285*0b57cec5SDimitry Andric                 false, false)
286*0b57cec5SDimitry Andric 
287*0b57cec5SDimitry Andric FunctionPass *llvm::createPPCBoolRetToIntPass() { return new PPCBoolRetToInt(); }
288