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
32using namespace llvm;
33
34static cl::opt<unsigned> ExtractCutoff("extract-cutoff", cl::init(Val: ~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").
44static cl::opt<bool> NoSR0("extract-nosr0", cl::init(Val: true), cl::Hidden,
45 cl::desc("No extract instruction with offset 0"));
46
47namespace {
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
77char HexagonGenExtract::ID = 0;
78
79INITIALIZE_PASS_BEGIN(HexagonGenExtract, "hextract", "Hexagon generate "
80 "\"extract\" instructions", false, false)
81INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
82INITIALIZE_PASS_END(HexagonGenExtract, "hextract", "Hexagon generate "
83 "\"extract\" instructions", false, false)
84
85bool 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(V: In, P: m_And(L: m_Shl(L: m_LShr(L: m_Value(V&: BF), R: m_ConstantInt(CI&: CSR)),
97 R: m_ConstantInt(CI&: CSL)),
98 R: m_ConstantInt(CI&: CM)));
99
100 if (!Match) {
101 // (and (shl (ashr x, #sr), #sl), #m)
102 LogicalSR = false;
103 Match = match(V: In, P: m_And(L: m_Shl(L: m_AShr(L: m_Value(V&: BF), R: m_ConstantInt(CI&: CSR)),
104 R: m_ConstantInt(CI&: CSL)),
105 R: m_ConstantInt(CI&: CM)));
106 }
107 if (!Match) {
108 // (and (shl x, #sl), #m)
109 LogicalSR = true;
110 CSR = ConstantInt::get(Ty: Type::getInt32Ty(C&: Ctx), V: 0);
111 Match = match(V: In, P: m_And(L: m_Shl(L: m_Value(V&: BF), R: m_ConstantInt(CI&: CSL)),
112 R: m_ConstantInt(CI&: 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(Ty: Type::getInt32Ty(C&: Ctx), V: 0);
120 Match = match(V: In, P: m_And(L: m_LShr(L: m_Value(V&: BF), R: m_ConstantInt(CI&: CSR)),
121 R: m_ConstantInt(CI&: CM)));
122 }
123 if (!Match) {
124 // (and (ashr x, #sr), #m)
125 LogicalSR = false;
126 CSL = ConstantInt::get(Ty: Type::getInt32Ty(C&: Ctx), V: 0);
127 Match = match(V: In, P: m_And(L: m_AShr(L: m_Value(V&: BF), R: m_ConstantInt(CI&: CSR)),
128 R: m_ConstantInt(CI&: CM)));
129 }
130 if (!Match) {
131 CM = nullptr;
132 // (shl (lshr x, #sr), #sl)
133 LogicalSR = true;
134 Match = match(V: In, P: m_Shl(L: m_LShr(L: m_Value(V&: BF), R: m_ConstantInt(CI&: CSR)),
135 R: m_ConstantInt(CI&: CSL)));
136 }
137 if (!Match) {
138 CM = nullptr;
139 // (shl (ashr x, #sr), #sl)
140 LogicalSR = false;
141 Match = match(V: In, P: m_Shl(L: m_AShr(L: m_Value(V&: BF), R: m_ConstantInt(CI&: CSR)),
142 R: m_ConstantInt(CI&: 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(shiftAmt: SR).shl(shiftAmt: SL);
164 CM = ConstantInt::get(Context&: Ctx, V: 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(shiftAmt: 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(a: SL, b: 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(a: U, b: 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(numBits: BW, hiBitsSet: BW-U);
190 if (M.intersects(RHS: C) || !M.isMask(numBits: 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(numBits: U).isMask(numBits: 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(ID: IntId, Args: {BF, IRB.getInt32(C: W), IRB.getInt32(C: SR)});
205 if (SL != 0)
206 NewIn = IRB.CreateShl(LHS: NewIn, RHS: SL, Name: CSL->getName());
207 In->replaceAllUsesWith(V: NewIn);
208 return true;
209}
210
211bool HexagonGenExtract::visitBlock(BasicBlock *B) {
212 bool Changed = false;
213
214 // Depth-first, bottom-up traversal.
215 for (auto *DTN : children<DomTreeNode*>(G: DT->getNode(BB: B)))
216 Changed |= visitBlock(B: 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(x: 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(x: 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
241bool 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: &F);
251 Changed = visitBlock(B: Entry);
252
253 return Changed;
254}
255
256FunctionPass *llvm::createHexagonGenExtract() {
257 return new HexagonGenExtract();
258}
259