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