LLVM 20.0.0git
HexagonGenExtract.cpp
Go to the documentation of this file.
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"
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"
19#include "llvm/IR/Intrinsics.h"
20#include "llvm/IR/IntrinsicsHexagon.h"
22#include "llvm/IR/Type.h"
23#include "llvm/IR/Value.h"
25#include "llvm/Pass.h"
27#include <algorithm>
28#include <cstdint>
29#include <iterator>
30
31using namespace llvm;
32
33static cl::opt<unsigned> ExtractCutoff("extract-cutoff", cl::init(~0U),
34 cl::Hidden, cl::desc("Cutoff for generating \"extract\""
35 " instructions"));
36
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").
43static cl::opt<bool> NoSR0("extract-nosr0", cl::init(true), cl::Hidden,
44 cl::desc("No extract instruction with offset 0"));
45
46static cl::opt<bool> NeedAnd("extract-needand", cl::init(true), cl::Hidden,
47 cl::desc("Require & in extract patterns"));
48
49namespace llvm {
50
53
54} // end namespace llvm
55
56namespace {
57
58 class HexagonGenExtract : public FunctionPass {
59 public:
60 static char ID;
61
62 HexagonGenExtract() : FunctionPass(ID) {
64 }
65
66 StringRef getPassName() const override {
67 return "Hexagon generate \"extract\" instructions";
68 }
69
70 bool runOnFunction(Function &F) override;
71
72 void getAnalysisUsage(AnalysisUsage &AU) const override {
76 }
77
78 private:
79 bool visitBlock(BasicBlock *B);
80 bool convert(Instruction *In);
81
82 unsigned ExtractCount = 0;
83 DominatorTree *DT;
84 };
85
86} // end anonymous namespace
87
88char HexagonGenExtract::ID = 0;
89
90INITIALIZE_PASS_BEGIN(HexagonGenExtract, "hextract", "Hexagon generate "
91 "\"extract\" instructions", false, false)
93INITIALIZE_PASS_END(HexagonGenExtract, "hextract", "Hexagon generate "
95
96bool HexagonGenExtract::convert(Instruction *In) {
97 using namespace PatternMatch;
98
99 Value *BF = nullptr;
100 ConstantInt *CSL = nullptr, *CSR = nullptr, *CM = nullptr;
101 BasicBlock *BB = In->getParent();
102 LLVMContext &Ctx = BB->getContext();
103 bool LogicalSR;
104
105 // (and (shl (lshr x, #sr), #sl), #m)
106 LogicalSR = true;
107 bool Match = match(In, m_And(m_Shl(m_LShr(m_Value(BF), m_ConstantInt(CSR)),
108 m_ConstantInt(CSL)),
109 m_ConstantInt(CM)));
110
111 if (!Match) {
112 // (and (shl (ashr x, #sr), #sl), #m)
113 LogicalSR = false;
115 m_ConstantInt(CSL)),
116 m_ConstantInt(CM)));
117 }
118 if (!Match) {
119 // (and (shl x, #sl), #m)
120 LogicalSR = true;
121 CSR = ConstantInt::get(Type::getInt32Ty(Ctx), 0);
122 Match = match(In, m_And(m_Shl(m_Value(BF), m_ConstantInt(CSL)),
123 m_ConstantInt(CM)));
124 if (Match && NoSR0)
125 return false;
126 }
127 if (!Match) {
128 // (and (lshr x, #sr), #m)
129 LogicalSR = true;
130 CSL = ConstantInt::get(Type::getInt32Ty(Ctx), 0);
131 Match = match(In, m_And(m_LShr(m_Value(BF), m_ConstantInt(CSR)),
132 m_ConstantInt(CM)));
133 }
134 if (!Match) {
135 // (and (ashr x, #sr), #m)
136 LogicalSR = false;
137 CSL = ConstantInt::get(Type::getInt32Ty(Ctx), 0);
138 Match = match(In, m_And(m_AShr(m_Value(BF), m_ConstantInt(CSR)),
139 m_ConstantInt(CM)));
140 }
141 if (!Match) {
142 CM = nullptr;
143 // (shl (lshr x, #sr), #sl)
144 LogicalSR = true;
145 Match = match(In, m_Shl(m_LShr(m_Value(BF), m_ConstantInt(CSR)),
146 m_ConstantInt(CSL)));
147 }
148 if (!Match) {
149 CM = nullptr;
150 // (shl (ashr x, #sr), #sl)
151 LogicalSR = false;
152 Match = match(In, m_Shl(m_AShr(m_Value(BF), m_ConstantInt(CSR)),
153 m_ConstantInt(CSL)));
154 }
155 if (!Match)
156 return false;
157
158 Type *Ty = BF->getType();
159 if (!Ty->isIntegerTy())
160 return false;
161 unsigned BW = Ty->getPrimitiveSizeInBits();
162 if (BW != 32 && BW != 64)
163 return false;
164
165 uint32_t SR = CSR->getZExtValue();
166 uint32_t SL = CSL->getZExtValue();
167
168 if (!CM) {
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
171 // this value.
172 if (!LogicalSR && (SR > SL))
173 return false;
174 APInt A = APInt(BW, ~0ULL).lshr(SR).shl(SL);
175 CM = ConstantInt::get(Ctx, A);
176 }
177
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();
182
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)
190 return false;
191
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
195 // extracted field.
196 if (!LogicalSR) {
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))
202 return false;
203 } else {
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))
208 return false;
209 }
210
211 IRBuilder<> IRB(In);
212 Intrinsic::ID IntId = (BW == 32) ? Intrinsic::hexagon_S2_extractu
213 : Intrinsic::hexagon_S2_extractup;
214 Module *Mod = BB->getParent()->getParent();
215 Function *ExtF = Intrinsic::getDeclaration(Mod, IntId);
216 Value *NewIn = IRB.CreateCall(ExtF, {BF, IRB.getInt32(W), IRB.getInt32(SR)});
217 if (SL != 0)
218 NewIn = IRB.CreateShl(NewIn, SL, CSL->getName());
219 In->replaceAllUsesWith(NewIn);
220 return true;
221}
222
223bool HexagonGenExtract::visitBlock(BasicBlock *B) {
224 bool Changed = false;
225
226 // Depth-first, bottom-up traversal.
227 for (auto *DTN : children<DomTreeNode*>(DT->getNode(B)))
228 Changed |= visitBlock(DTN->getBlock());
229
230 // Allow limiting the number of generated extracts for debugging purposes.
231 bool HasCutoff = ExtractCutoff.getPosition();
232 unsigned Cutoff = ExtractCutoff;
233
234 BasicBlock::iterator I = std::prev(B->end()), NextI, Begin = B->begin();
235 while (true) {
236 if (HasCutoff && (ExtractCount >= Cutoff))
237 return Changed;
238 bool Last = (I == Begin);
239 if (!Last)
240 NextI = std::prev(I);
241 Instruction *In = &*I;
242 bool Done = convert(In);
243 if (HasCutoff && Done)
244 ExtractCount++;
245 Changed |= Done;
246 if (Last)
247 break;
248 I = NextI;
249 }
250 return Changed;
251}
252
253bool HexagonGenExtract::runOnFunction(Function &F) {
254 if (skipFunction(F))
255 return false;
256
257 DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
258 bool Changed;
259
260 // Traverse the function bottom-up, to see super-expressions before their
261 // sub-expressions.
263 Changed = visitBlock(Entry);
264
265 return Changed;
266}
267
269 return new HexagonGenExtract();
270}
This file implements a class to represent arbitrary precision integral constant values and operations...
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
This file contains the declarations for the subclasses of Constant, which represent the different fla...
expand large fp convert
This file defines the little GraphTraits<X> template class that should be specialized by classes that...
static cl::opt< unsigned > ExtractCutoff("extract-cutoff", cl::init(~0U), cl::Hidden, cl::desc("Cutoff for generating \"extract\"" " instructions"))
static cl::opt< bool > NeedAnd("extract-needand", cl::init(true), cl::Hidden, cl::desc("Require & in extract patterns"))
static cl::opt< bool > NoSR0("extract-nosr0", cl::init(true), cl::Hidden, cl::desc("No extract instruction with offset 0"))
Hexagon generate extract instructions
This file provides various utilities for inspecting and working with the control flow graph in LLVM I...
loop extract
#define F(x, y, z)
Definition: MD5.cpp:55
#define I(x, y, z)
Definition: MD5.cpp:58
if(auto Err=PB.parsePassPipeline(MPM, Passes)) return wrap(std MPM run * Mod
#define INITIALIZE_PASS_DEPENDENCY(depName)
Definition: PassSupport.h:55
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
Definition: PassSupport.h:57
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
Definition: PassSupport.h:52
Class for arbitrary precision integers.
Definition: APInt.h:78
APInt shl(unsigned shiftAmt) const
Left-shift function.
Definition: APInt.h:851
static APInt getHighBitsSet(unsigned numBits, unsigned hiBitsSet)
Constructs an APInt value that has the top hiBitsSet bits set.
Definition: APInt.h:274
APInt lshr(unsigned shiftAmt) const
Logical right-shift function.
Definition: APInt.h:829
Represent the analysis usage information of a pass.
AnalysisUsage & addRequired()
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
LLVM Basic Block Representation.
Definition: BasicBlock.h:61
const Function * getParent() const
Return the enclosing method, or null if none.
Definition: BasicBlock.h:219
InstListType::iterator iterator
Instruction iterators...
Definition: BasicBlock.h:177
LLVMContext & getContext() const
Get the context in which this basic block lives.
Definition: BasicBlock.cpp:168
This is the shared class of boolean and integer constants.
Definition: Constants.h:81
uint64_t getZExtValue() const
Return the constant as a 64-bit unsigned integer value after it has been zero extended as appropriate...
Definition: Constants.h:155
Legacy analysis pass which computes a DominatorTree.
Definition: Dominators.h:317
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree.
Definition: Dominators.h:162
FunctionPass class - This class is used to implement most global optimizations.
Definition: Pass.h:310
virtual bool runOnFunction(Function &F)=0
runOnFunction - Virtual method overriden by subclasses to do the per-function processing of the pass.
Module * getParent()
Get the module that this global value is contained inside of...
Definition: GlobalValue.h:656
ConstantInt * getInt32(uint32_t C)
Get a constant 32-bit value.
Definition: IRBuilder.h:483
Value * CreateShl(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)
Definition: IRBuilder.h:1433
CallInst * CreateCall(FunctionType *FTy, Value *Callee, ArrayRef< Value * > Args=std::nullopt, const Twine &Name="", MDNode *FPMathTag=nullptr)
Definition: IRBuilder.h:2432
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Definition: IRBuilder.h:2686
This is an important class for using LLVM in a threaded context.
Definition: LLVMContext.h:67
A Module instance is used to store all the information related to an LLVM module.
Definition: Module.h:65
PassRegistry - This class manages the registration and intitialization of the pass subsystem as appli...
Definition: PassRegistry.h:37
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
virtual void getAnalysisUsage(AnalysisUsage &) const
getAnalysisUsage - This function should be overriden by passes that need analysis information to do t...
Definition: Pass.cpp:98
virtual StringRef getPassName() const
getPassName - Return a nice clean name for a pass.
Definition: Pass.cpp:81
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
static IntegerType * getInt32Ty(LLVMContext &C)
bool isIntegerTy() const
True if this is an instance of IntegerType.
Definition: Type.h:224
TypeSize getPrimitiveSizeInBits() const LLVM_READONLY
Return the basic size of this type if it is a primitive type.
LLVM Value Representation.
Definition: Value.h:74
Type * getType() const
All values are typed, get the type of this value.
Definition: Value.h:255
StringRef getName() const
Return a constant reference to the value's name.
Definition: Value.cpp:309
@ Entry
Definition: COFF.h:826
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition: CallingConv.h:24
@ C
The default llvm calling convention, compatible with C.
Definition: CallingConv.h:34
Function * getDeclaration(Module *M, ID id, ArrayRef< Type * > Tys=std::nullopt)
Create or insert an LLVM Function declaration for an intrinsic, and return it.
Definition: Function.cpp:1539
BinaryOp_match< LHS, RHS, Instruction::And > m_And(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, Instruction::AShr > m_AShr(const LHS &L, const RHS &R)
bool match(Val *V, const Pattern &P)
Definition: PatternMatch.h:49
class_match< ConstantInt > m_ConstantInt()
Match an arbitrary ConstantInt and ignore it.
Definition: PatternMatch.h:168
class_match< Value > m_Value()
Match an arbitrary value and ignore it.
Definition: PatternMatch.h:92
BinaryOp_match< LHS, RHS, Instruction::LShr > m_LShr(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, Instruction::Shl > m_Shl(const LHS &L, const RHS &R)
initializer< Ty > init(const Ty &Val)
Definition: CommandLine.h:443
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
@ Done
Definition: Threading.h:61
FunctionPass * createHexagonGenExtract()
void initializeHexagonGenExtractPass(PassRegistry &)