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