1 //===----- SVEIntrinsicOpts - SVE ACLE Intrinsics Opts --------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // Performs general IR level optimizations on SVE intrinsics.
11 //
12 // This pass performs the following optimizations:
13 //
14 // - removes unnecessary reinterpret intrinsics
15 //   (llvm.aarch64.sve.convert.[to|from].svbool), e.g:
16 //     %1 = @llvm.aarch64.sve.convert.to.svbool.nxv4i1(<vscale x 4 x i1> %a)
17 //     %2 = @llvm.aarch64.sve.convert.from.svbool.nxv4i1(<vscale x 16 x i1> %1)
18 //
19 // - removes unnecessary ptrue intrinsics (llvm.aarch64.sve.ptrue), e.g:
20 //     %1 = @llvm.aarch64.sve.ptrue.nxv4i1(i32 31)
21 //     %2 = @llvm.aarch64.sve.ptrue.nxv8i1(i32 31)
22 //     ; (%1 can be replaced with a reinterpret of %2)
23 //
24 // - optimizes ptest intrinsics and phi instructions where the operands are
25 //   being needlessly converted to and from svbool_t.
26 //
27 //===----------------------------------------------------------------------===//
28 
29 #include "Utils/AArch64BaseInfo.h"
30 #include "llvm/ADT/PostOrderIterator.h"
31 #include "llvm/ADT/SetVector.h"
32 #include "llvm/IR/Constants.h"
33 #include "llvm/IR/Dominators.h"
34 #include "llvm/IR/IRBuilder.h"
35 #include "llvm/IR/Instructions.h"
36 #include "llvm/IR/IntrinsicInst.h"
37 #include "llvm/IR/IntrinsicsAArch64.h"
38 #include "llvm/IR/LLVMContext.h"
39 #include "llvm/IR/PatternMatch.h"
40 #include "llvm/InitializePasses.h"
41 #include "llvm/Support/Debug.h"
42 
43 using namespace llvm;
44 using namespace llvm::PatternMatch;
45 
46 #define DEBUG_TYPE "aarch64-sve-intrinsic-opts"
47 
48 namespace llvm {
49 void initializeSVEIntrinsicOptsPass(PassRegistry &);
50 }
51 
52 namespace {
53 struct SVEIntrinsicOpts : public ModulePass {
54   static char ID; // Pass identification, replacement for typeid
55   SVEIntrinsicOpts() : ModulePass(ID) {
56     initializeSVEIntrinsicOptsPass(*PassRegistry::getPassRegistry());
57   }
58 
59   bool runOnModule(Module &M) override;
60   void getAnalysisUsage(AnalysisUsage &AU) const override;
61 
62 private:
63   static IntrinsicInst *isReinterpretToSVBool(Value *V);
64 
65   bool coalescePTrueIntrinsicCalls(BasicBlock &BB,
66                                    SmallSetVector<IntrinsicInst *, 4> &PTrues);
67   bool optimizePTrueIntrinsicCalls(SmallSetVector<Function *, 4> &Functions);
68 
69   /// Operates at the instruction-scope. I.e., optimizations are applied local
70   /// to individual instructions.
71   static bool optimizeIntrinsic(Instruction *I);
72   bool optimizeIntrinsicCalls(SmallSetVector<Function *, 4> &Functions);
73 
74   /// Operates at the function-scope. I.e., optimizations are applied local to
75   /// the functions themselves.
76   bool optimizeFunctions(SmallSetVector<Function *, 4> &Functions);
77 
78   static bool optimizeConvertFromSVBool(IntrinsicInst *I);
79   static bool optimizePTest(IntrinsicInst *I);
80   static bool optimizeVectorMul(IntrinsicInst *I);
81   static bool optimizeTBL(IntrinsicInst *I);
82 
83   static bool processPhiNode(IntrinsicInst *I);
84 };
85 } // end anonymous namespace
86 
87 void SVEIntrinsicOpts::getAnalysisUsage(AnalysisUsage &AU) const {
88   AU.addRequired<DominatorTreeWrapperPass>();
89   AU.setPreservesCFG();
90 }
91 
92 char SVEIntrinsicOpts::ID = 0;
93 static const char *name = "SVE intrinsics optimizations";
94 INITIALIZE_PASS_BEGIN(SVEIntrinsicOpts, DEBUG_TYPE, name, false, false)
95 INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass);
96 INITIALIZE_PASS_END(SVEIntrinsicOpts, DEBUG_TYPE, name, false, false)
97 
98 namespace llvm {
99 ModulePass *createSVEIntrinsicOptsPass() { return new SVEIntrinsicOpts(); }
100 } // namespace llvm
101 
102 /// Returns V if it's a cast from <n x 16 x i1> (aka svbool_t), nullptr
103 /// otherwise.
104 IntrinsicInst *SVEIntrinsicOpts::isReinterpretToSVBool(Value *V) {
105   IntrinsicInst *I = dyn_cast<IntrinsicInst>(V);
106   if (!I)
107     return nullptr;
108 
109   if (I->getIntrinsicID() != Intrinsic::aarch64_sve_convert_to_svbool)
110     return nullptr;
111 
112   return I;
113 }
114 
115 /// Checks if a ptrue intrinsic call is promoted. The act of promoting a
116 /// ptrue will introduce zeroing. For example:
117 ///
118 ///     %1 = <vscale x 4 x i1> call @llvm.aarch64.sve.ptrue.nxv4i1(i32 31)
119 ///     %2 = <vscale x 16 x i1> call @llvm.aarch64.sve.convert.to.svbool.nxv4i1(<vscale x 4 x i1> %1)
120 ///     %3 = <vscale x 8 x i1> call @llvm.aarch64.sve.convert.from.svbool.nxv8i1(<vscale x 16 x i1> %2)
121 ///
122 /// %1 is promoted, because it is converted:
123 ///
124 ///     <vscale x 4 x i1> => <vscale x 16 x i1> => <vscale x 8 x i1>
125 ///
126 /// via a sequence of the SVE reinterpret intrinsics convert.{to,from}.svbool.
127 bool isPTruePromoted(IntrinsicInst *PTrue) {
128   // Find all users of this intrinsic that are calls to convert-to-svbool
129   // reinterpret intrinsics.
130   SmallVector<IntrinsicInst *, 4> ConvertToUses;
131   for (User *User : PTrue->users()) {
132     if (match(User, m_Intrinsic<Intrinsic::aarch64_sve_convert_to_svbool>())) {
133       ConvertToUses.push_back(cast<IntrinsicInst>(User));
134     }
135   }
136 
137   // If no such calls were found, this is ptrue is not promoted.
138   if (ConvertToUses.empty())
139     return false;
140 
141   // Otherwise, try to find users of the convert-to-svbool intrinsics that are
142   // calls to the convert-from-svbool intrinsic, and would result in some lanes
143   // being zeroed.
144   const auto *PTrueVTy = cast<ScalableVectorType>(PTrue->getType());
145   for (IntrinsicInst *ConvertToUse : ConvertToUses) {
146     for (User *User : ConvertToUse->users()) {
147       auto *IntrUser = dyn_cast<IntrinsicInst>(User);
148       if (IntrUser && IntrUser->getIntrinsicID() ==
149                           Intrinsic::aarch64_sve_convert_from_svbool) {
150         const auto *IntrUserVTy = cast<ScalableVectorType>(IntrUser->getType());
151 
152         // Would some lanes become zeroed by the conversion?
153         if (IntrUserVTy->getElementCount().getKnownMinValue() >
154             PTrueVTy->getElementCount().getKnownMinValue())
155           // This is a promoted ptrue.
156           return true;
157       }
158     }
159   }
160 
161   // If no matching calls were found, this is not a promoted ptrue.
162   return false;
163 }
164 
165 /// Attempts to coalesce ptrues in a basic block.
166 bool SVEIntrinsicOpts::coalescePTrueIntrinsicCalls(
167     BasicBlock &BB, SmallSetVector<IntrinsicInst *, 4> &PTrues) {
168   if (PTrues.size() <= 1)
169     return false;
170 
171   // Find the ptrue with the most lanes.
172   auto *MostEncompassingPTrue = *std::max_element(
173       PTrues.begin(), PTrues.end(), [](auto *PTrue1, auto *PTrue2) {
174         auto *PTrue1VTy = cast<ScalableVectorType>(PTrue1->getType());
175         auto *PTrue2VTy = cast<ScalableVectorType>(PTrue2->getType());
176         return PTrue1VTy->getElementCount().getKnownMinValue() <
177                PTrue2VTy->getElementCount().getKnownMinValue();
178       });
179 
180   // Remove the most encompassing ptrue, as well as any promoted ptrues, leaving
181   // behind only the ptrues to be coalesced.
182   PTrues.remove(MostEncompassingPTrue);
183   PTrues.remove_if([](auto *PTrue) { return isPTruePromoted(PTrue); });
184 
185   // Hoist MostEncompassingPTrue to the start of the basic block. It is always
186   // safe to do this, since ptrue intrinsic calls are guaranteed to have no
187   // predecessors.
188   MostEncompassingPTrue->moveBefore(BB, BB.getFirstInsertionPt());
189 
190   LLVMContext &Ctx = BB.getContext();
191   IRBuilder<> Builder(Ctx);
192   Builder.SetInsertPoint(&BB, ++MostEncompassingPTrue->getIterator());
193 
194   auto *MostEncompassingPTrueVTy =
195       cast<VectorType>(MostEncompassingPTrue->getType());
196   auto *ConvertToSVBool = Builder.CreateIntrinsic(
197       Intrinsic::aarch64_sve_convert_to_svbool, {MostEncompassingPTrueVTy},
198       {MostEncompassingPTrue});
199 
200   for (auto *PTrue : PTrues) {
201     auto *PTrueVTy = cast<VectorType>(PTrue->getType());
202 
203     Builder.SetInsertPoint(&BB, ++ConvertToSVBool->getIterator());
204     auto *ConvertFromSVBool =
205         Builder.CreateIntrinsic(Intrinsic::aarch64_sve_convert_from_svbool,
206                                 {PTrueVTy}, {ConvertToSVBool});
207     PTrue->replaceAllUsesWith(ConvertFromSVBool);
208     PTrue->eraseFromParent();
209   }
210 
211   return true;
212 }
213 
214 /// The goal of this function is to remove redundant calls to the SVE ptrue
215 /// intrinsic in each basic block within the given functions.
216 ///
217 /// SVE ptrues have two representations in LLVM IR:
218 /// - a logical representation -- an arbitrary-width scalable vector of i1s,
219 ///   i.e. <vscale x N x i1>.
220 /// - a physical representation (svbool, <vscale x 16 x i1>) -- a 16-element
221 ///   scalable vector of i1s, i.e. <vscale x 16 x i1>.
222 ///
223 /// The SVE ptrue intrinsic is used to create a logical representation of an SVE
224 /// predicate. Suppose that we have two SVE ptrue intrinsic calls: P1 and P2. If
225 /// P1 creates a logical SVE predicate that is at least as wide as the logical
226 /// SVE predicate created by P2, then all of the bits that are true in the
227 /// physical representation of P2 are necessarily also true in the physical
228 /// representation of P1. P1 'encompasses' P2, therefore, the intrinsic call to
229 /// P2 is redundant and can be replaced by an SVE reinterpret of P1 via
230 /// convert.{to,from}.svbool.
231 ///
232 /// Currently, this pass only coalesces calls to SVE ptrue intrinsics
233 /// if they match the following conditions:
234 ///
235 /// - the call to the intrinsic uses either the SV_ALL or SV_POW2 patterns.
236 ///   SV_ALL indicates that all bits of the predicate vector are to be set to
237 ///   true. SV_POW2 indicates that all bits of the predicate vector up to the
238 ///   largest power-of-two are to be set to true.
239 /// - the result of the call to the intrinsic is not promoted to a wider
240 ///   predicate. In this case, keeping the extra ptrue leads to better codegen
241 ///   -- coalescing here would create an irreducible chain of SVE reinterprets
242 ///   via convert.{to,from}.svbool.
243 ///
244 /// EXAMPLE:
245 ///
246 ///     %1 = <vscale x 8 x i1> ptrue(i32 SV_ALL)
247 ///     ; Logical:  <1, 1, 1, 1, 1, 1, 1, 1>
248 ///     ; Physical: <1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0>
249 ///     ...
250 ///
251 ///     %2 = <vscale x 4 x i1> ptrue(i32 SV_ALL)
252 ///     ; Logical:  <1, 1, 1, 1>
253 ///     ; Physical: <1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0>
254 ///     ...
255 ///
256 /// Here, %2 can be replaced by an SVE reinterpret of %1, giving, for instance:
257 ///
258 ///     %1 = <vscale x 8 x i1> ptrue(i32 i31)
259 ///     %2 = <vscale x 16 x i1> convert.to.svbool(<vscale x 8 x i1> %1)
260 ///     %3 = <vscale x 4 x i1> convert.from.svbool(<vscale x 16 x i1> %2)
261 ///
262 bool SVEIntrinsicOpts::optimizePTrueIntrinsicCalls(
263     SmallSetVector<Function *, 4> &Functions) {
264   bool Changed = false;
265 
266   for (auto *F : Functions) {
267     for (auto &BB : *F) {
268       SmallSetVector<IntrinsicInst *, 4> SVAllPTrues;
269       SmallSetVector<IntrinsicInst *, 4> SVPow2PTrues;
270 
271       // For each basic block, collect the used ptrues and try to coalesce them.
272       for (Instruction &I : BB) {
273         if (I.use_empty())
274           continue;
275 
276         auto *IntrI = dyn_cast<IntrinsicInst>(&I);
277         if (!IntrI || IntrI->getIntrinsicID() != Intrinsic::aarch64_sve_ptrue)
278           continue;
279 
280         const auto PTruePattern =
281             cast<ConstantInt>(IntrI->getOperand(0))->getZExtValue();
282 
283         if (PTruePattern == AArch64SVEPredPattern::all)
284           SVAllPTrues.insert(IntrI);
285         if (PTruePattern == AArch64SVEPredPattern::pow2)
286           SVPow2PTrues.insert(IntrI);
287       }
288 
289       Changed |= coalescePTrueIntrinsicCalls(BB, SVAllPTrues);
290       Changed |= coalescePTrueIntrinsicCalls(BB, SVPow2PTrues);
291     }
292   }
293 
294   return Changed;
295 }
296 
297 /// The function will remove redundant reinterprets casting in the presence
298 /// of the control flow
299 bool SVEIntrinsicOpts::processPhiNode(IntrinsicInst *X) {
300 
301   SmallVector<Instruction *, 32> Worklist;
302   auto RequiredType = X->getType();
303 
304   auto *PN = dyn_cast<PHINode>(X->getArgOperand(0));
305   assert(PN && "Expected Phi Node!");
306 
307   // Don't create a new Phi unless we can remove the old one.
308   if (!PN->hasOneUse())
309     return false;
310 
311   for (Value *IncValPhi : PN->incoming_values()) {
312     auto *Reinterpret = isReinterpretToSVBool(IncValPhi);
313     if (!Reinterpret ||
314         RequiredType != Reinterpret->getArgOperand(0)->getType())
315       return false;
316   }
317 
318   // Create the new Phi
319   LLVMContext &Ctx = PN->getContext();
320   IRBuilder<> Builder(Ctx);
321   Builder.SetInsertPoint(PN);
322   PHINode *NPN = Builder.CreatePHI(RequiredType, PN->getNumIncomingValues());
323   Worklist.push_back(PN);
324 
325   for (unsigned I = 0; I < PN->getNumIncomingValues(); I++) {
326     auto *Reinterpret = cast<Instruction>(PN->getIncomingValue(I));
327     NPN->addIncoming(Reinterpret->getOperand(0), PN->getIncomingBlock(I));
328     Worklist.push_back(Reinterpret);
329   }
330 
331   // Cleanup Phi Node and reinterprets
332   X->replaceAllUsesWith(NPN);
333   X->eraseFromParent();
334 
335   for (auto &I : Worklist)
336     if (I->use_empty())
337       I->eraseFromParent();
338 
339   return true;
340 }
341 
342 bool SVEIntrinsicOpts::optimizePTest(IntrinsicInst *I) {
343   IntrinsicInst *Op1 = dyn_cast<IntrinsicInst>(I->getArgOperand(0));
344   IntrinsicInst *Op2 = dyn_cast<IntrinsicInst>(I->getArgOperand(1));
345 
346   if (Op1 && Op2 &&
347       Op1->getIntrinsicID() == Intrinsic::aarch64_sve_convert_to_svbool &&
348       Op2->getIntrinsicID() == Intrinsic::aarch64_sve_convert_to_svbool &&
349       Op1->getArgOperand(0)->getType() == Op2->getArgOperand(0)->getType()) {
350 
351     Value *Ops[] = {Op1->getArgOperand(0), Op2->getArgOperand(0)};
352     Type *Tys[] = {Op1->getArgOperand(0)->getType()};
353     Module *M = I->getParent()->getParent()->getParent();
354 
355     auto Fn = Intrinsic::getDeclaration(M, I->getIntrinsicID(), Tys);
356     auto CI = CallInst::Create(Fn, Ops, I->getName(), I);
357 
358     I->replaceAllUsesWith(CI);
359     I->eraseFromParent();
360     if (Op1->use_empty())
361       Op1->eraseFromParent();
362     if (Op1 != Op2 && Op2->use_empty())
363       Op2->eraseFromParent();
364 
365     return true;
366   }
367 
368   return false;
369 }
370 
371 bool SVEIntrinsicOpts::optimizeVectorMul(IntrinsicInst *I) {
372   assert((I->getIntrinsicID() == Intrinsic::aarch64_sve_mul ||
373           I->getIntrinsicID() == Intrinsic::aarch64_sve_fmul) &&
374          "Unexpected opcode");
375 
376   auto *OpPredicate = I->getOperand(0);
377   auto *OpMultiplicand = I->getOperand(1);
378   auto *OpMultiplier = I->getOperand(2);
379 
380   // Return true if a given instruction is an aarch64_sve_dup_x intrinsic call
381   // with a unit splat value, false otherwise.
382   auto IsUnitDupX = [](auto *I) {
383     auto *IntrI = dyn_cast<IntrinsicInst>(I);
384     if (!IntrI || IntrI->getIntrinsicID() != Intrinsic::aarch64_sve_dup_x)
385       return false;
386 
387     auto *SplatValue = IntrI->getOperand(0);
388     return match(SplatValue, m_FPOne()) || match(SplatValue, m_One());
389   };
390 
391   // Return true if a given instruction is an aarch64_sve_dup intrinsic call
392   // with a unit splat value, false otherwise.
393   auto IsUnitDup = [](auto *I) {
394     auto *IntrI = dyn_cast<IntrinsicInst>(I);
395     if (!IntrI || IntrI->getIntrinsicID() != Intrinsic::aarch64_sve_dup)
396       return false;
397 
398     auto *SplatValue = IntrI->getOperand(2);
399     return match(SplatValue, m_FPOne()) || match(SplatValue, m_One());
400   };
401 
402   bool Changed = true;
403 
404   // The OpMultiplier variable should always point to the dup (if any), so
405   // swap if necessary.
406   if (IsUnitDup(OpMultiplicand) || IsUnitDupX(OpMultiplicand))
407     std::swap(OpMultiplier, OpMultiplicand);
408 
409   if (IsUnitDupX(OpMultiplier)) {
410     // [f]mul pg (dupx 1) %n => %n
411     I->replaceAllUsesWith(OpMultiplicand);
412     I->eraseFromParent();
413     Changed = true;
414   } else if (IsUnitDup(OpMultiplier)) {
415     // [f]mul pg (dup pg 1) %n => %n
416     auto *DupInst = cast<IntrinsicInst>(OpMultiplier);
417     auto *DupPg = DupInst->getOperand(1);
418     // TODO: this is naive. The optimization is still valid if DupPg
419     // 'encompasses' OpPredicate, not only if they're the same predicate.
420     if (OpPredicate == DupPg) {
421       I->replaceAllUsesWith(OpMultiplicand);
422       I->eraseFromParent();
423       Changed = true;
424     }
425   }
426 
427   // If an instruction was optimized out then it is possible that some dangling
428   // instructions are left.
429   if (Changed) {
430     auto *OpPredicateInst = dyn_cast<Instruction>(OpPredicate);
431     auto *OpMultiplierInst = dyn_cast<Instruction>(OpMultiplier);
432     if (OpMultiplierInst && OpMultiplierInst->use_empty())
433       OpMultiplierInst->eraseFromParent();
434     if (OpPredicateInst && OpPredicateInst->use_empty())
435       OpPredicateInst->eraseFromParent();
436   }
437 
438   return Changed;
439 }
440 
441 bool SVEIntrinsicOpts::optimizeTBL(IntrinsicInst *I) {
442   assert(I->getIntrinsicID() == Intrinsic::aarch64_sve_tbl &&
443          "Unexpected opcode");
444 
445   auto *OpVal = I->getOperand(0);
446   auto *OpIndices = I->getOperand(1);
447   VectorType *VTy = cast<VectorType>(I->getType());
448 
449   // Check whether OpIndices is an aarch64_sve_dup_x intrinsic call with
450   // constant splat value < minimal element count of result.
451   auto *DupXIntrI = dyn_cast<IntrinsicInst>(OpIndices);
452   if (!DupXIntrI || DupXIntrI->getIntrinsicID() != Intrinsic::aarch64_sve_dup_x)
453     return false;
454 
455   auto *SplatValue = dyn_cast<ConstantInt>(DupXIntrI->getOperand(0));
456   if (!SplatValue ||
457       SplatValue->getValue().uge(VTy->getElementCount().getKnownMinValue()))
458     return false;
459 
460   // Convert sve_tbl(OpVal sve_dup_x(SplatValue)) to
461   // splat_vector(extractelement(OpVal, SplatValue)) for further optimization.
462   LLVMContext &Ctx = I->getContext();
463   IRBuilder<> Builder(Ctx);
464   Builder.SetInsertPoint(I);
465   auto *Extract = Builder.CreateExtractElement(OpVal, SplatValue);
466   auto *VectorSplat =
467       Builder.CreateVectorSplat(VTy->getElementCount(), Extract);
468 
469   I->replaceAllUsesWith(VectorSplat);
470   I->eraseFromParent();
471   if (DupXIntrI->use_empty())
472     DupXIntrI->eraseFromParent();
473   return true;
474 }
475 
476 bool SVEIntrinsicOpts::optimizeConvertFromSVBool(IntrinsicInst *I) {
477   assert(I->getIntrinsicID() == Intrinsic::aarch64_sve_convert_from_svbool &&
478          "Unexpected opcode");
479 
480   // If the reinterpret instruction operand is a PHI Node
481   if (isa<PHINode>(I->getArgOperand(0)))
482     return processPhiNode(I);
483 
484   SmallVector<Instruction *, 32> CandidatesForRemoval;
485   Value *Cursor = I->getOperand(0), *EarliestReplacement = nullptr;
486 
487   const auto *IVTy = cast<VectorType>(I->getType());
488 
489   // Walk the chain of conversions.
490   while (Cursor) {
491     // If the type of the cursor has fewer lanes than the final result, zeroing
492     // must take place, which breaks the equivalence chain.
493     const auto *CursorVTy = cast<VectorType>(Cursor->getType());
494     if (CursorVTy->getElementCount().getKnownMinValue() <
495         IVTy->getElementCount().getKnownMinValue())
496       break;
497 
498     // If the cursor has the same type as I, it is a viable replacement.
499     if (Cursor->getType() == IVTy)
500       EarliestReplacement = Cursor;
501 
502     auto *IntrinsicCursor = dyn_cast<IntrinsicInst>(Cursor);
503 
504     // If this is not an SVE conversion intrinsic, this is the end of the chain.
505     if (!IntrinsicCursor || !(IntrinsicCursor->getIntrinsicID() ==
506                                   Intrinsic::aarch64_sve_convert_to_svbool ||
507                               IntrinsicCursor->getIntrinsicID() ==
508                                   Intrinsic::aarch64_sve_convert_from_svbool))
509       break;
510 
511     CandidatesForRemoval.insert(CandidatesForRemoval.begin(), IntrinsicCursor);
512     Cursor = IntrinsicCursor->getOperand(0);
513   }
514 
515   // If no viable replacement in the conversion chain was found, there is
516   // nothing to do.
517   if (!EarliestReplacement)
518     return false;
519 
520   I->replaceAllUsesWith(EarliestReplacement);
521   I->eraseFromParent();
522 
523   while (!CandidatesForRemoval.empty()) {
524     Instruction *Candidate = CandidatesForRemoval.pop_back_val();
525     if (Candidate->use_empty())
526       Candidate->eraseFromParent();
527   }
528   return true;
529 }
530 
531 bool SVEIntrinsicOpts::optimizeIntrinsic(Instruction *I) {
532   IntrinsicInst *IntrI = dyn_cast<IntrinsicInst>(I);
533   if (!IntrI)
534     return false;
535 
536   switch (IntrI->getIntrinsicID()) {
537   case Intrinsic::aarch64_sve_convert_from_svbool:
538     return optimizeConvertFromSVBool(IntrI);
539   case Intrinsic::aarch64_sve_fmul:
540   case Intrinsic::aarch64_sve_mul:
541     return optimizeVectorMul(IntrI);
542   case Intrinsic::aarch64_sve_ptest_any:
543   case Intrinsic::aarch64_sve_ptest_first:
544   case Intrinsic::aarch64_sve_ptest_last:
545     return optimizePTest(IntrI);
546   case Intrinsic::aarch64_sve_tbl:
547     return optimizeTBL(IntrI);
548   default:
549     return false;
550   }
551 
552   return true;
553 }
554 
555 bool SVEIntrinsicOpts::optimizeIntrinsicCalls(
556     SmallSetVector<Function *, 4> &Functions) {
557   bool Changed = false;
558   for (auto *F : Functions) {
559     DominatorTree *DT = &getAnalysis<DominatorTreeWrapperPass>(*F).getDomTree();
560 
561     // Traverse the DT with an rpo walk so we see defs before uses, allowing
562     // simplification to be done incrementally.
563     BasicBlock *Root = DT->getRoot();
564     ReversePostOrderTraversal<BasicBlock *> RPOT(Root);
565     for (auto *BB : RPOT)
566       for (Instruction &I : make_early_inc_range(*BB))
567         Changed |= optimizeIntrinsic(&I);
568   }
569   return Changed;
570 }
571 
572 bool SVEIntrinsicOpts::optimizeFunctions(
573     SmallSetVector<Function *, 4> &Functions) {
574   bool Changed = false;
575 
576   Changed |= optimizePTrueIntrinsicCalls(Functions);
577   Changed |= optimizeIntrinsicCalls(Functions);
578 
579   return Changed;
580 }
581 
582 bool SVEIntrinsicOpts::runOnModule(Module &M) {
583   bool Changed = false;
584   SmallSetVector<Function *, 4> Functions;
585 
586   // Check for SVE intrinsic declarations first so that we only iterate over
587   // relevant functions. Where an appropriate declaration is found, store the
588   // function(s) where it is used so we can target these only.
589   for (auto &F : M.getFunctionList()) {
590     if (!F.isDeclaration())
591       continue;
592 
593     switch (F.getIntrinsicID()) {
594     case Intrinsic::aarch64_sve_convert_from_svbool:
595     case Intrinsic::aarch64_sve_ptest_any:
596     case Intrinsic::aarch64_sve_ptest_first:
597     case Intrinsic::aarch64_sve_ptest_last:
598     case Intrinsic::aarch64_sve_ptrue:
599     case Intrinsic::aarch64_sve_mul:
600     case Intrinsic::aarch64_sve_fmul:
601     case Intrinsic::aarch64_sve_tbl:
602       for (User *U : F.users())
603         Functions.insert(cast<Instruction>(U)->getFunction());
604       break;
605     default:
606       break;
607     }
608   }
609 
610   if (!Functions.empty())
611     Changed |= optimizeFunctions(Functions);
612 
613   return Changed;
614 }
615