1 //===--- HexagonGenExtract.cpp --------------------------------------------===// 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 #include "llvm/ADT/APInt.h" 11 #include "llvm/ADT/StringRef.h" 12 #include "llvm/IR/BasicBlock.h" 13 #include "llvm/IR/CFG.h" 14 #include "llvm/IR/Constants.h" 15 #include "llvm/IR/Dominators.h" 16 #include "llvm/IR/Function.h" 17 #include "llvm/IR/Instruction.h" 18 #include "llvm/IR/Instructions.h" 19 #include "llvm/IR/Intrinsics.h" 20 #include "llvm/IR/IRBuilder.h" 21 #include "llvm/IR/PatternMatch.h" 22 #include "llvm/IR/Type.h" 23 #include "llvm/IR/Value.h" 24 #include "llvm/Pass.h" 25 #include "llvm/Support/CommandLine.h" 26 #include <algorithm> 27 #include <cstdint> 28 #include <iterator> 29 30 using namespace llvm; 31 32 static cl::opt<unsigned> ExtractCutoff("extract-cutoff", cl::init(~0U), 33 cl::Hidden, cl::desc("Cutoff for generating \"extract\"" 34 " instructions")); 35 36 // This prevents generating extract instructions that have the offset of 0. 37 // One of the reasons for "extract" is to put a sequence of bits in a regis- 38 // ter, starting at offset 0 (so that these bits can then be used by an 39 // "insert"). If the bits are already at offset 0, it is better not to gene- 40 // rate "extract", since logical bit operations can be merged into compound 41 // instructions (as opposed to "extract"). 42 static cl::opt<bool> NoSR0("extract-nosr0", cl::init(true), cl::Hidden, 43 cl::desc("No extract instruction with offset 0")); 44 45 static cl::opt<bool> NeedAnd("extract-needand", cl::init(true), cl::Hidden, 46 cl::desc("Require & in extract patterns")); 47 48 namespace llvm { 49 50 void initializeHexagonGenExtractPass(PassRegistry&); 51 FunctionPass *createHexagonGenExtract(); 52 53 } // end namespace llvm 54 55 namespace { 56 57 class HexagonGenExtract : public FunctionPass { 58 public: 59 static char ID; 60 61 HexagonGenExtract() : FunctionPass(ID), ExtractCount(0) { 62 initializeHexagonGenExtractPass(*PassRegistry::getPassRegistry()); 63 } 64 65 StringRef getPassName() const override { 66 return "Hexagon generate \"extract\" instructions"; 67 } 68 69 bool runOnFunction(Function &F) override; 70 71 void getAnalysisUsage(AnalysisUsage &AU) const override { 72 AU.addRequired<DominatorTreeWrapperPass>(); 73 AU.addPreserved<DominatorTreeWrapperPass>(); 74 FunctionPass::getAnalysisUsage(AU); 75 } 76 77 private: 78 bool visitBlock(BasicBlock *B); 79 bool convert(Instruction *In); 80 81 unsigned ExtractCount; 82 DominatorTree *DT; 83 }; 84 85 char HexagonGenExtract::ID = 0; 86 87 } // end anonymous namespace 88 89 INITIALIZE_PASS_BEGIN(HexagonGenExtract, "hextract", "Hexagon generate " 90 "\"extract\" instructions", false, false) 91 INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass) 92 INITIALIZE_PASS_END(HexagonGenExtract, "hextract", "Hexagon generate " 93 "\"extract\" instructions", false, false) 94 95 bool HexagonGenExtract::convert(Instruction *In) { 96 using namespace PatternMatch; 97 98 Value *BF = nullptr; 99 ConstantInt *CSL = nullptr, *CSR = nullptr, *CM = nullptr; 100 BasicBlock *BB = In->getParent(); 101 LLVMContext &Ctx = BB->getContext(); 102 bool LogicalSR; 103 104 // (and (shl (lshr x, #sr), #sl), #m) 105 LogicalSR = true; 106 bool Match = match(In, m_And(m_Shl(m_LShr(m_Value(BF), m_ConstantInt(CSR)), 107 m_ConstantInt(CSL)), 108 m_ConstantInt(CM))); 109 110 if (!Match) { 111 // (and (shl (ashr x, #sr), #sl), #m) 112 LogicalSR = false; 113 Match = match(In, m_And(m_Shl(m_AShr(m_Value(BF), m_ConstantInt(CSR)), 114 m_ConstantInt(CSL)), 115 m_ConstantInt(CM))); 116 } 117 if (!Match) { 118 // (and (shl x, #sl), #m) 119 LogicalSR = true; 120 CSR = ConstantInt::get(Type::getInt32Ty(Ctx), 0); 121 Match = match(In, m_And(m_Shl(m_Value(BF), m_ConstantInt(CSL)), 122 m_ConstantInt(CM))); 123 if (Match && NoSR0) 124 return false; 125 } 126 if (!Match) { 127 // (and (lshr x, #sr), #m) 128 LogicalSR = true; 129 CSL = ConstantInt::get(Type::getInt32Ty(Ctx), 0); 130 Match = match(In, m_And(m_LShr(m_Value(BF), m_ConstantInt(CSR)), 131 m_ConstantInt(CM))); 132 } 133 if (!Match) { 134 // (and (ashr x, #sr), #m) 135 LogicalSR = false; 136 CSL = ConstantInt::get(Type::getInt32Ty(Ctx), 0); 137 Match = match(In, m_And(m_AShr(m_Value(BF), m_ConstantInt(CSR)), 138 m_ConstantInt(CM))); 139 } 140 if (!Match) { 141 CM = nullptr; 142 // (shl (lshr x, #sr), #sl) 143 LogicalSR = true; 144 Match = match(In, m_Shl(m_LShr(m_Value(BF), m_ConstantInt(CSR)), 145 m_ConstantInt(CSL))); 146 } 147 if (!Match) { 148 CM = nullptr; 149 // (shl (ashr x, #sr), #sl) 150 LogicalSR = false; 151 Match = match(In, m_Shl(m_AShr(m_Value(BF), m_ConstantInt(CSR)), 152 m_ConstantInt(CSL))); 153 } 154 if (!Match) 155 return false; 156 157 Type *Ty = BF->getType(); 158 if (!Ty->isIntegerTy()) 159 return false; 160 unsigned BW = Ty->getPrimitiveSizeInBits(); 161 if (BW != 32 && BW != 64) 162 return false; 163 164 uint32_t SR = CSR->getZExtValue(); 165 uint32_t SL = CSL->getZExtValue(); 166 167 if (!CM) { 168 // If there was no and, and the shift left did not remove all potential 169 // sign bits created by the shift right, then extractu cannot reproduce 170 // this value. 171 if (!LogicalSR && (SR > SL)) 172 return false; 173 APInt A = APInt(BW, ~0ULL).lshr(SR).shl(SL); 174 CM = ConstantInt::get(Ctx, A); 175 } 176 177 // CM is the shifted-left mask. Shift it back right to remove the zero 178 // bits on least-significant positions. 179 APInt M = CM->getValue().lshr(SL); 180 uint32_t T = M.countTrailingOnes(); 181 182 // During the shifts some of the bits will be lost. Calculate how many 183 // of the original value will remain after shift right and then left. 184 uint32_t U = BW - std::max(SL, SR); 185 // The width of the extracted field is the minimum of the original bits 186 // that remain after the shifts and the number of contiguous 1s in the mask. 187 uint32_t W = std::min(U, T); 188 if (W == 0) 189 return false; 190 191 // Check if the extracted bits are contained within the mask that it is 192 // and-ed with. The extract operation will copy these bits, and so the 193 // mask cannot any holes in it that would clear any of the bits of the 194 // extracted field. 195 if (!LogicalSR) { 196 // If the shift right was arithmetic, it could have included some 1 bits. 197 // It is still ok to generate extract, but only if the mask eliminates 198 // those bits (i.e. M does not have any bits set beyond U). 199 APInt C = APInt::getHighBitsSet(BW, BW-U); 200 if (M.intersects(C) || !APIntOps::isMask(W, M)) 201 return false; 202 } else { 203 // Check if M starts with a contiguous sequence of W times 1 bits. Get 204 // the low U bits of M (which eliminates the 0 bits shifted in on the 205 // left), and check if the result is APInt's "mask": 206 if (!APIntOps::isMask(W, M.getLoBits(U))) 207 return false; 208 } 209 210 IRBuilder<> IRB(In); 211 Intrinsic::ID IntId = (BW == 32) ? Intrinsic::hexagon_S2_extractu 212 : Intrinsic::hexagon_S2_extractup; 213 Module *Mod = BB->getParent()->getParent(); 214 Value *ExtF = Intrinsic::getDeclaration(Mod, IntId); 215 Value *NewIn = IRB.CreateCall(ExtF, {BF, IRB.getInt32(W), IRB.getInt32(SR)}); 216 if (SL != 0) 217 NewIn = IRB.CreateShl(NewIn, SL, CSL->getName()); 218 In->replaceAllUsesWith(NewIn); 219 return true; 220 } 221 222 bool HexagonGenExtract::visitBlock(BasicBlock *B) { 223 // Depth-first, bottom-up traversal. 224 DomTreeNode *DTN = DT->getNode(B); 225 typedef GraphTraits<DomTreeNode*> GTN; 226 typedef GTN::ChildIteratorType Iter; 227 for (Iter I = GTN::child_begin(DTN), E = GTN::child_end(DTN); I != E; ++I) 228 visitBlock((*I)->getBlock()); 229 230 // Allow limiting the number of generated extracts for debugging purposes. 231 bool HasCutoff = ExtractCutoff.getPosition(); 232 unsigned Cutoff = ExtractCutoff; 233 234 bool Changed = false; 235 BasicBlock::iterator I = std::prev(B->end()), NextI, Begin = B->begin(); 236 while (true) { 237 if (HasCutoff && (ExtractCount >= Cutoff)) 238 return Changed; 239 bool Last = (I == Begin); 240 if (!Last) 241 NextI = std::prev(I); 242 Instruction *In = &*I; 243 bool Done = convert(In); 244 if (HasCutoff && Done) 245 ExtractCount++; 246 Changed |= Done; 247 if (Last) 248 break; 249 I = NextI; 250 } 251 return Changed; 252 } 253 254 bool HexagonGenExtract::runOnFunction(Function &F) { 255 if (skipFunction(F)) 256 return false; 257 258 DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree(); 259 bool Changed; 260 261 // Traverse the function bottom-up, to see super-expressions before their 262 // sub-expressions. 263 BasicBlock *Entry = GraphTraits<Function*>::getEntryNode(&F); 264 Changed = visitBlock(Entry); 265 266 return Changed; 267 } 268 269 FunctionPass *llvm::createHexagonGenExtract() { 270 return new HexagonGenExtract(); 271 } 272