1 //===- HexagonGenExtract.cpp ----------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
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/IntrinsicsHexagon.h"
21 #include "llvm/IR/PatternMatch.h"
22 #include "llvm/IR/Type.h"
23 #include "llvm/IR/Value.h"
24 #include "llvm/InitializePasses.h"
25 #include "llvm/Pass.h"
26 #include "llvm/Support/CommandLine.h"
33 static cl::opt
<unsigned> ExtractCutoff("extract-cutoff", cl::init(~0U),
34 cl::Hidden
, cl::desc("Cutoff for generating \"extract\""
37 // This prevents generating extract instructions that have the offset of 0.
38 // One of the reasons for "extract" is to put a sequence of bits in a regis-
39 // ter, starting at offset 0 (so that these bits can then be used by an
40 // "insert"). If the bits are already at offset 0, it is better not to gene-
41 // rate "extract", since logical bit operations can be merged into compound
42 // instructions (as opposed to "extract").
43 static cl::opt
<bool> NoSR0("extract-nosr0", cl::init(true), cl::Hidden
,
44 cl::desc("No extract instruction with offset 0"));
46 static cl::opt
<bool> NeedAnd("extract-needand", cl::init(true), cl::Hidden
,
47 cl::desc("Require & in extract patterns"));
51 void initializeHexagonGenExtractPass(PassRegistry
&);
52 FunctionPass
*createHexagonGenExtract();
54 } // end namespace llvm
58 class HexagonGenExtract
: public FunctionPass
{
62 HexagonGenExtract() : FunctionPass(ID
) {
63 initializeHexagonGenExtractPass(*PassRegistry::getPassRegistry());
66 StringRef
getPassName() const override
{
67 return "Hexagon generate \"extract\" instructions";
70 bool runOnFunction(Function
&F
) override
;
72 void getAnalysisUsage(AnalysisUsage
&AU
) const override
{
73 AU
.addRequired
<DominatorTreeWrapperPass
>();
74 AU
.addPreserved
<DominatorTreeWrapperPass
>();
75 FunctionPass::getAnalysisUsage(AU
);
79 bool visitBlock(BasicBlock
*B
);
80 bool convert(Instruction
*In
);
82 unsigned ExtractCount
= 0;
86 } // end anonymous namespace
88 char HexagonGenExtract::ID
= 0;
90 INITIALIZE_PASS_BEGIN(HexagonGenExtract
, "hextract", "Hexagon generate "
91 "\"extract\" instructions", false, false)
92 INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass
)
93 INITIALIZE_PASS_END(HexagonGenExtract
, "hextract", "Hexagon generate "
94 "\"extract\" instructions", false, false)
96 bool HexagonGenExtract::convert(Instruction
*In
) {
97 using namespace PatternMatch
;
100 ConstantInt
*CSL
= nullptr, *CSR
= nullptr, *CM
= nullptr;
101 BasicBlock
*BB
= In
->getParent();
102 LLVMContext
&Ctx
= BB
->getContext();
105 // (and (shl (lshr x, #sr), #sl), #m)
107 bool Match
= match(In
, m_And(m_Shl(m_LShr(m_Value(BF
), m_ConstantInt(CSR
)),
112 // (and (shl (ashr x, #sr), #sl), #m)
114 Match
= match(In
, m_And(m_Shl(m_AShr(m_Value(BF
), m_ConstantInt(CSR
)),
119 // (and (shl x, #sl), #m)
121 CSR
= ConstantInt::get(Type::getInt32Ty(Ctx
), 0);
122 Match
= match(In
, m_And(m_Shl(m_Value(BF
), m_ConstantInt(CSL
)),
128 // (and (lshr x, #sr), #m)
130 CSL
= ConstantInt::get(Type::getInt32Ty(Ctx
), 0);
131 Match
= match(In
, m_And(m_LShr(m_Value(BF
), m_ConstantInt(CSR
)),
135 // (and (ashr x, #sr), #m)
137 CSL
= ConstantInt::get(Type::getInt32Ty(Ctx
), 0);
138 Match
= match(In
, m_And(m_AShr(m_Value(BF
), m_ConstantInt(CSR
)),
143 // (shl (lshr x, #sr), #sl)
145 Match
= match(In
, m_Shl(m_LShr(m_Value(BF
), m_ConstantInt(CSR
)),
146 m_ConstantInt(CSL
)));
150 // (shl (ashr x, #sr), #sl)
152 Match
= match(In
, m_Shl(m_AShr(m_Value(BF
), m_ConstantInt(CSR
)),
153 m_ConstantInt(CSL
)));
158 Type
*Ty
= BF
->getType();
159 if (!Ty
->isIntegerTy())
161 unsigned BW
= Ty
->getPrimitiveSizeInBits();
162 if (BW
!= 32 && BW
!= 64)
165 uint32_t SR
= CSR
->getZExtValue();
166 uint32_t SL
= CSL
->getZExtValue();
169 // If there was no and, and the shift left did not remove all potential
170 // sign bits created by the shift right, then extractu cannot reproduce
172 if (!LogicalSR
&& (SR
> SL
))
174 APInt A
= APInt(BW
, ~0ULL, true).lshr(SR
).shl(SL
);
175 CM
= ConstantInt::get(Ctx
, A
);
178 // CM is the shifted-left mask. Shift it back right to remove the zero
179 // bits on least-significant positions.
180 APInt M
= CM
->getValue().lshr(SL
);
181 uint32_t T
= M
.countr_one();
183 // During the shifts some of the bits will be lost. Calculate how many
184 // of the original value will remain after shift right and then left.
185 uint32_t U
= BW
- std::max(SL
, SR
);
186 // The width of the extracted field is the minimum of the original bits
187 // that remain after the shifts and the number of contiguous 1s in the mask.
188 uint32_t W
= std::min(U
, T
);
189 if (W
== 0 || W
== 1)
192 // Check if the extracted bits are contained within the mask that it is
193 // and-ed with. The extract operation will copy these bits, and so the
194 // mask cannot any holes in it that would clear any of the bits of the
197 // If the shift right was arithmetic, it could have included some 1 bits.
198 // It is still ok to generate extract, but only if the mask eliminates
199 // those bits (i.e. M does not have any bits set beyond U).
200 APInt C
= APInt::getHighBitsSet(BW
, BW
-U
);
201 if (M
.intersects(C
) || !M
.isMask(W
))
204 // Check if M starts with a contiguous sequence of W times 1 bits. Get
205 // the low U bits of M (which eliminates the 0 bits shifted in on the
206 // left), and check if the result is APInt's "mask":
207 if (!M
.getLoBits(U
).isMask(W
))
212 Intrinsic::ID IntId
= (BW
== 32) ? Intrinsic::hexagon_S2_extractu
213 : Intrinsic::hexagon_S2_extractup
;
215 IRB
.CreateIntrinsic(IntId
, {}, {BF
, IRB
.getInt32(W
), IRB
.getInt32(SR
)});
217 NewIn
= IRB
.CreateShl(NewIn
, SL
, CSL
->getName());
218 In
->replaceAllUsesWith(NewIn
);
222 bool HexagonGenExtract::visitBlock(BasicBlock
*B
) {
223 bool Changed
= false;
225 // Depth-first, bottom-up traversal.
226 for (auto *DTN
: children
<DomTreeNode
*>(DT
->getNode(B
)))
227 Changed
|= visitBlock(DTN
->getBlock());
229 // Allow limiting the number of generated extracts for debugging purposes.
230 bool HasCutoff
= ExtractCutoff
.getPosition();
231 unsigned Cutoff
= ExtractCutoff
;
233 BasicBlock::iterator I
= std::prev(B
->end()), NextI
, Begin
= B
->begin();
235 if (HasCutoff
&& (ExtractCount
>= Cutoff
))
237 bool Last
= (I
== Begin
);
239 NextI
= std::prev(I
);
240 Instruction
*In
= &*I
;
241 bool Done
= convert(In
);
242 if (HasCutoff
&& Done
)
252 bool HexagonGenExtract::runOnFunction(Function
&F
) {
256 DT
= &getAnalysis
<DominatorTreeWrapperPass
>().getDomTree();
259 // Traverse the function bottom-up, to see super-expressions before their
261 BasicBlock
*Entry
= GraphTraits
<Function
*>::getEntryNode(&F
);
262 Changed
= visitBlock(Entry
);
267 FunctionPass
*llvm::createHexagonGenExtract() {
268 return new HexagonGenExtract();