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