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