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