xref: /aosp_15_r20/art/compiler/optimizing/loop_optimization.h (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef ART_COMPILER_OPTIMIZING_LOOP_OPTIMIZATION_H_
18 #define ART_COMPILER_OPTIMIZING_LOOP_OPTIMIZATION_H_
19 
20 #include "base/macros.h"
21 #include "base/scoped_arena_allocator.h"
22 #include "base/scoped_arena_containers.h"
23 #include "induction_var_range.h"
24 #include "loop_analysis.h"
25 #include "nodes.h"
26 #include "optimization.h"
27 #include "superblock_cloner.h"
28 
29 namespace art HIDDEN {
30 
31 class CompilerOptions;
32 class ArchNoOptsLoopHelper;
33 
34 // Determines whether predicated loop vectorization should be tried for ALL loops.
35 #ifdef ART_FORCE_TRY_PREDICATED_SIMD
36   static constexpr bool kForceTryPredicatedSIMD = true;
37 #else
38   static constexpr bool kForceTryPredicatedSIMD = false;
39 #endif
40 
41 /**
42  * Loop optimizations. Builds a loop hierarchy and applies optimizations to
43  * the detected nested loops, such as removal of dead induction and empty loops
44  * and inner loop vectorization.
45  */
46 class HLoopOptimization : public HOptimization {
47  public:
48   HLoopOptimization(HGraph* graph,
49                     const CodeGenerator& codegen,    // Needs info about the target.
50                     HInductionVarAnalysis* induction_analysis,
51                     OptimizingCompilerStats* stats,
52                     const char* name = kLoopOptimizationPassName);
53 
54   bool Run() override;
55 
56   static constexpr const char* kLoopOptimizationPassName = "loop_optimization";
57 
58   // The maximum number of total instructions (trip_count * instruction_count),
59   // where the optimization of removing SuspendChecks from the loop header could
60   // be performed.
61   static constexpr int64_t kMaxTotalInstRemoveSuspendCheck = 128;
62 
63  private:
64   /**
65    * A single loop inside the loop hierarchy representation.
66    */
67   struct LoopNode : public ArenaObject<kArenaAllocLoopOptimization> {
LoopNodeLoopNode68     explicit LoopNode(HLoopInformation* lp_info)
69         : loop_info(lp_info),
70           outer(nullptr),
71           inner(nullptr),
72           previous(nullptr),
73           next(nullptr),
74           try_catch_kind(TryCatchKind::kUnknown) {}
75 
76     enum class TryCatchKind {
77       kUnknown,
78       // Either if we have a try catch in the loop, or if the loop is inside of an outer try catch,
79       // we set `kHasTryCatch`.
80       kHasTryCatch,
81       kNoTryCatch
82     };
83 
84     HLoopInformation* loop_info;
85     LoopNode* outer;
86     LoopNode* inner;
87     LoopNode* previous;
88     LoopNode* next;
89     TryCatchKind try_catch_kind;
90   };
91 
92   /*
93    * Vectorization restrictions (bit mask).
94    */
95   enum VectorRestrictions {
96     kNone            = 0,        // no restrictions
97     kNoMul           = 1 << 0,   // no multiplication
98     kNoDiv           = 1 << 1,   // no division
99     kNoShift         = 1 << 2,   // no shift
100     kNoShr           = 1 << 3,   // no arithmetic shift right
101     kNoHiBits        = 1 << 4,   // "wider" operations cannot bring in higher order bits
102     kNoSignedHAdd    = 1 << 5,   // no signed halving add
103     kNoUnsignedHAdd  = 1 << 6,   // no unsigned halving add
104     kNoUnroundedHAdd = 1 << 7,   // no unrounded halving add
105     kNoAbs           = 1 << 8,   // no absolute value
106     kNoStringCharAt  = 1 << 9,   // no StringCharAt
107     kNoReduction     = 1 << 10,  // no reduction
108     kNoSAD           = 1 << 11,  // no sum of absolute differences (SAD)
109     kNoWideSAD       = 1 << 12,  // no sum of absolute differences (SAD) with operand widening
110     kNoDotProd       = 1 << 13,  // no dot product
111     kNoIfCond        = 1 << 14,  // no if condition conversion
112   };
113 
114   /*
115    * Loop synthesis mode during vectorization
116    * (sequential peeling/cleanup loop or vector loop).
117    */
118   enum class LoopSynthesisMode {
119     kSequential,
120     kVector
121   };
122   friend std::ostream& operator<<(std::ostream& os, const LoopSynthesisMode& fd_logger);
123 
124   /*
125    * Representation of a unit-stride array reference.
126    */
127   struct ArrayReference {
128     ArrayReference(HInstruction* b, HInstruction* o, DataType::Type t, bool l, bool c = false)
baseArrayReference129         : base(b), offset(o), type(t), lhs(l), is_string_char_at(c) { }
130     bool operator<(const ArrayReference& other) const {
131       return
132           (base < other.base) ||
133           (base == other.base &&
134            (offset < other.offset || (offset == other.offset &&
135                                       (type < other.type ||
136                                        (type == other.type &&
137                                         (lhs < other.lhs ||
138                                          (lhs == other.lhs &&
139                                           is_string_char_at < other.is_string_char_at)))))));
140     }
141     HInstruction* base;      // base address
142     HInstruction* offset;    // offset + i
143     DataType::Type type;     // component type
144     bool lhs;                // def/use
145     bool is_string_char_at;  // compressed string read
146   };
147 
148   // This structure describes the control flow (CF) -> data flow (DF) conversion of the loop
149   // with control flow (see below) for the purpose of predicated autovectorization.
150   //
151   // Lets define "loops without control-flow" (or non-CF loops) as loops with two consecutive
152   // blocks and without the branching structure except for the loop exit. And
153   // "loop with control-flow" (or CF-loops) - all other loops.
154   //
155   // In the execution of the original CF-loop on each iteration some basic block Y will be
156   // either executed or not executed, depending on the control flow of the loop. More
157   // specifically, a block will be executed if all the conditional branches of the nodes in
158   // the control dependency graph for that block Y are taken according to the path from the loop
159   // header to that basic block.
160   //
161   // This is the key idea of CF->DF conversion: a boolean value
162   // 'ctrl_pred == cond1 && cond2 && ...' will determine whether the basic block Y will be
163   // executed, where cond_K is whether the branch of the node K in the control dependency
164   // graph upward traversal was taken in the 'right' direction.
165   //
166   // Def.: BB Y is control dependent on BB X iff
167   //   (1) there exists a directed path P from X to Y with any basic block Z in P (excluding X
168   //       and Y) post-dominated by Y and
169   //   (2) X is not post-dominated by Y.
170   //             ...
171   //              X
172   //     false /     \ true
173   //          /       \
174   //                  ...
175   //                   |
176   //                   Y
177   //                  ...
178   //
179   // When doing predicated autovectorization of a CF loop, we use the CF->DF conversion approach:
180   //  1) do the data analysis and vector operation creation as if it was a non-CF loop.
181   //  2) for each HIf block create two vector predicate setting instructions - for True and False
182   //     edges/paths.
183   //  3) assign a governing vector predicate (see comments near HVecPredSetOperation)
184   //     to each vector operation Alpha in the loop (including to those vector predicate setting
185   //     instructions created in #2); do this by:
186   //     - finding the immediate control dependent block of the instruction Alpha's block.
187   //     - choosing the True or False predicate setting instruction (created in #2) depending
188   //       on the path to the instruction.
189   //
190   // For more information check the papers:
191   //
192   //   - Allen, John R and Kennedy, Ken and Porterfield, Carrie and Warren, Joe,
193   //     “Conversion of Control Dependence to Data Dependence,” in Proceedings of the 10th ACM
194   //     SIGACT-SIGPLAN Symposium on Principles of Programming Languages, 1983, pp. 177–189.
195   //   - JEANNE FERRANTE, KARL J. OTTENSTEIN, JOE D. WARREN,
196   //     "The Program Dependence Graph and Its Use in Optimization"
197   //
198   class BlockPredicateInfo : public ArenaObject<kArenaAllocLoopOptimization> {
199    public:
BlockPredicateInfo()200     BlockPredicateInfo() :
201         control_predicate_(nullptr),
202         true_predicate_(nullptr),
203         false_predicate_(nullptr) {}
204 
SetControlFlowInfo(HVecPredSetOperation * true_predicate,HVecPredSetOperation * false_predicate)205     void SetControlFlowInfo(HVecPredSetOperation* true_predicate,
206                             HVecPredSetOperation* false_predicate) {
207       DCHECK(!HasControlFlowOps());
208       true_predicate_ = true_predicate;
209       false_predicate_ = false_predicate;
210     }
211 
HasControlFlowOps()212     bool HasControlFlowOps() const {
213       // Note: a block must have both T/F predicates set or none of them.
214       DCHECK_EQ(true_predicate_ == nullptr, false_predicate_ == nullptr);
215       return true_predicate_ != nullptr;
216     }
217 
GetControlPredicate()218     HVecPredSetOperation* GetControlPredicate() const { return control_predicate_; }
SetControlPredicate(HVecPredSetOperation * control_predicate)219     void SetControlPredicate(HVecPredSetOperation* control_predicate) {
220       control_predicate_ = control_predicate;
221     }
222 
GetTruePredicate()223     HVecPredSetOperation* GetTruePredicate() const { return true_predicate_; }
GetFalsePredicate()224     HVecPredSetOperation* GetFalsePredicate() const { return false_predicate_; }
225 
226    private:
227     // Vector control predicate operation, associated with the block which will determine
228     // the active lanes for all vector operations, originated from this block.
229     HVecPredSetOperation* control_predicate_;
230 
231     // Vector predicate instruction, associated with the true sucessor of the block.
232     HVecPredSetOperation* true_predicate_;
233     // Vector predicate instruction, associated with the false sucessor of the block.
234     HVecPredSetOperation* false_predicate_;
235   };
236 
237   //
238   // Loop setup and traversal.
239   //
240 
241   bool LocalRun();
242   void AddLoop(HLoopInformation* loop_info);
243   void RemoveLoop(LoopNode* node);
244 
245   // Traverses all loops inner to outer to perform simplifications and optimizations.
246   // Returns true if loops nested inside current loop (node) have changed.
247   bool TraverseLoopsInnerToOuter(LoopNode* node);
248 
249   // Calculates `node`'s `try_catch_kind` and sets it to:
250   // 1) kHasTryCatch if it has try catches (or if it's inside of an outer try catch)
251   // 2) kNoTryCatch otherwise.
252   void CalculateAndSetTryCatchKind(LoopNode* node);
253 
254   //
255   // Optimization.
256   //
257 
258   void SimplifyInduction(LoopNode* node);
259   void SimplifyBlocks(LoopNode* node);
260 
261   // Performs optimizations specific to inner loop with finite header logic (empty loop removal,
262   // unrolling, vectorization). Returns true if anything changed.
263   bool TryOptimizeInnerLoopFinite(LoopNode* node);
264 
265   // Performs optimizations specific to inner loop. Returns true if anything changed.
266   bool OptimizeInnerLoop(LoopNode* node);
267 
268   // Tries to apply loop unrolling for branch penalty reduction and better instruction scheduling
269   // opportunities. Returns whether transformation happened. 'generate_code' determines whether the
270   // optimization should be actually applied.
271   bool TryUnrollingForBranchPenaltyReduction(LoopAnalysisInfo* analysis_info,
272                                              bool generate_code = true);
273 
274   // Tries to apply loop peeling for loop invariant exits elimination. Returns whether
275   // transformation happened. 'generate_code' determines whether the optimization should be
276   // actually applied.
277   bool TryPeelingForLoopInvariantExitsElimination(LoopAnalysisInfo* analysis_info,
278                                                   bool generate_code = true);
279 
280   // Tries to perform whole loop unrolling for a small loop with a small trip count to eliminate
281   // the loop check overhead and to have more opportunities for inter-iteration optimizations.
282   // Returns whether transformation happened. 'generate_code' determines whether the optimization
283   // should be actually applied.
284   bool TryFullUnrolling(LoopAnalysisInfo* analysis_info, bool generate_code = true);
285 
286   // Tries to remove SuspendCheck for plain loops with a low trip count. The
287   // SuspendCheck in the codegen makes sure that the thread can be interrupted
288   // during execution for GC. Not being able to do so might decrease the
289   // responsiveness of GC when a very long loop or a long recursion is being
290   // executed. However, for plain loops with a small trip count, the removal of
291   // SuspendCheck should not affect the GC's responsiveness by a large margin.
292   // Consequently, since the thread won't be interrupted for plain loops, it is
293   // assumed that the performance might increase by removing SuspendCheck.
294   bool TryToRemoveSuspendCheckFromLoopHeader(LoopAnalysisInfo* analysis_info,
295                                              bool generate_code = true);
296 
297   // Tries to apply scalar loop optimizations.
298   bool TryLoopScalarOpts(LoopNode* node);
299 
300   //
301   // Vectorization analysis and synthesis.
302   //
303 
304   // Returns whether the data flow requirements are met for vectorization.
305   //
306   //   - checks whether instructions are vectorizable for the target.
307   //   - conducts data dependence analysis for array references.
308   //   - additionally, collects info on peeling and aligment strategy.
309   bool CanVectorizeDataFlow(LoopNode* node, HBasicBlock* header, bool collect_alignment_info);
310 
311   // Does the checks (common for predicated and traditional mode) for the loop.
312   bool ShouldVectorizeCommon(LoopNode* node, HPhi* main_phi, int64_t trip_count);
313 
314   // Try to vectorize the loop, returns whether it was successful.
315   //
316   // There are two versions/algorithms:
317   //  - Predicated: all the vector operations have governing predicates which control
318   //    which individual vector lanes will be active (see HVecPredSetOperation for more details).
319   //    Example: vectorization using AArch64 SVE.
320   //  - Traditional: a regular mode in which all vector operations lanes are unconditionally
321   //    active.
322   //    Example: vectoriation using AArch64 NEON.
323   bool TryVectorizePredicated(LoopNode* node,
324                               HBasicBlock* body,
325                               HBasicBlock* exit,
326                               HPhi* main_phi,
327                               int64_t trip_count);
328 
329   bool TryVectorizedTraditional(LoopNode* node,
330                                 HBasicBlock* body,
331                                 HBasicBlock* exit,
332                                 HPhi* main_phi,
333                                 int64_t trip_count);
334 
335   // Vectorizes the loop for which all checks have been already done.
336   void VectorizePredicated(LoopNode* node,
337                            HBasicBlock* block,
338                            HBasicBlock* exit);
339   void VectorizeTraditional(LoopNode* node,
340                             HBasicBlock* block,
341                             HBasicBlock* exit,
342                             int64_t trip_count);
343 
344   // Performs final steps for whole vectorization process: links reduction, removes the original
345   // scalar loop, updates loop info.
346   void FinalizeVectorization(LoopNode* node);
347 
348   // Helpers that do the vector instruction synthesis for the previously created loop; create
349   // and fill the loop body with instructions.
350   //
351   // A version to generate a vector loop in predicated mode.
352   void GenerateNewLoopPredicated(LoopNode* node,
353                                  HBasicBlock* new_preheader,
354                                  HInstruction* lo,
355                                  HInstruction* hi,
356                                  HInstruction* step);
357 
358   // A version to generate a vector loop in traditional mode or to generate
359   // a scalar loop for both modes.
360   void GenerateNewLoopScalarOrTraditional(LoopNode* node,
361                                           HBasicBlock* new_preheader,
362                                           HInstruction* lo,
363                                           HInstruction* hi,
364                                           HInstruction* step,
365                                           uint32_t unroll);
366 
367   //
368   // Helpers for GenerateNewLoop*.
369   //
370 
371   // Updates vectorization bookkeeping date for the new loop, creates and returns
372   // its main induction Phi.
373   HPhi* InitializeForNewLoop(HBasicBlock* new_preheader, HInstruction* lo);
374 
375   // Finalizes reduction and induction phis' inputs for the newly created loop.
376   void FinalizePhisForNewLoop(HPhi* phi, HInstruction* lo);
377 
378   // Creates empty predicate info object for each basic block and puts it into the map.
379   void PreparePredicateInfoMap(LoopNode* node);
380 
381   // Set up block true/false predicates using info, collected through data flow and control
382   // dependency analysis.
383   void InitPredicateInfoMap(LoopNode* node, HVecPredSetOperation* loop_main_pred);
384 
385   // Performs instruction synthesis for the loop body.
386   void GenerateNewLoopBodyOnce(LoopNode* node,
387                                DataType::Type induc_type,
388                                HInstruction* step);
389 
390   // Returns whether the vector loop needs runtime disambiguation test for array refs.
NeedsArrayRefsDisambiguationTest()391   bool NeedsArrayRefsDisambiguationTest() const { return vector_runtime_test_a_ != nullptr; }
392 
393   bool VectorizeDef(LoopNode* node, HInstruction* instruction, bool generate_code);
394   bool VectorizeUse(LoopNode* node,
395                     HInstruction* instruction,
396                     bool generate_code,
397                     DataType::Type type,
398                     uint64_t restrictions);
399   uint32_t GetVectorSizeInBytes();
400   bool TrySetVectorType(DataType::Type type, /*out*/ uint64_t* restrictions);
401   bool TrySetVectorLengthImpl(uint32_t length);
402 
TrySetVectorLength(DataType::Type type,uint32_t length)403   bool TrySetVectorLength(DataType::Type type, uint32_t length) {
404     bool res = TrySetVectorLengthImpl(length);
405     // Currently the vectorizer supports only the mode when full SIMD registers are used.
406     DCHECK_IMPLIES(res, DataType::Size(type) * length == GetVectorSizeInBytes());
407     return res;
408   }
409 
410   void GenerateVecInv(HInstruction* org, DataType::Type type);
411   void GenerateVecSub(HInstruction* org, HInstruction* offset);
412   void GenerateVecMem(HInstruction* org,
413                       HInstruction* opa,
414                       HInstruction* opb,
415                       HInstruction* offset,
416                       DataType::Type type);
417   void GenerateVecReductionPhi(HPhi* phi);
418   void GenerateVecReductionPhiInputs(HPhi* phi, HInstruction* reduction);
419   HInstruction* ReduceAndExtractIfNeeded(HInstruction* instruction);
420   HInstruction* GenerateVecOp(HInstruction* org,
421                               HInstruction* opa,
422                               HInstruction* opb,
423                               DataType::Type type);
424 
425   // Vectorization idioms.
426   bool VectorizeSaturationIdiom(LoopNode* node,
427                                 HInstruction* instruction,
428                                 bool generate_code,
429                                 DataType::Type type,
430                                 uint64_t restrictions);
431   bool VectorizeHalvingAddIdiom(LoopNode* node,
432                                 HInstruction* instruction,
433                                 bool generate_code,
434                                 DataType::Type type,
435                                 uint64_t restrictions);
436   bool VectorizeSADIdiom(LoopNode* node,
437                          HInstruction* instruction,
438                          bool generate_code,
439                          DataType::Type type,
440                          uint64_t restrictions);
441   bool VectorizeDotProdIdiom(LoopNode* node,
442                              HInstruction* instruction,
443                              bool generate_code,
444                              DataType::Type type,
445                              uint64_t restrictions);
446   bool VectorizeIfCondition(LoopNode* node,
447                             HInstruction* instruction,
448                             bool generate_code,
449                             uint64_t restrictions);
450 
451   // Vectorization heuristics.
452   Alignment ComputeAlignment(HInstruction* offset,
453                              DataType::Type type,
454                              bool is_string_char_at,
455                              uint32_t peeling = 0);
456   void SetAlignmentStrategy(const ScopedArenaVector<uint32_t>& peeling_votes,
457                             const ArrayReference* peeling_candidate);
458   uint32_t MaxNumberPeeled();
459   bool IsVectorizationProfitable(int64_t trip_count);
460 
461   //
462   // Helpers.
463   //
464 
465   bool TrySetPhiInduction(HPhi* phi, bool restrict_uses);
466   bool TrySetPhiReduction(HPhi* phi);
467 
468   // Detects loop header with a single induction (returned in main_phi), possibly
469   // other phis for reductions, but no other side effects. Returns true on success.
470   bool TrySetSimpleLoopHeader(HBasicBlock* block, /*out*/ HPhi** main_phi);
471 
472   bool IsEmptyBody(HBasicBlock* block);
473   bool IsOnlyUsedAfterLoop(HLoopInformation* loop_info,
474                            HInstruction* instruction,
475                            bool collect_loop_uses,
476                            /*out*/ uint32_t* use_count);
477   bool IsUsedOutsideLoop(HLoopInformation* loop_info,
478                          HInstruction* instruction);
479   bool TryReplaceWithLastValue(HLoopInformation* loop_info,
480                                HInstruction* instruction,
481                                HBasicBlock* block);
482   bool TryAssignLastValue(HLoopInformation* loop_info,
483                           HInstruction* instruction,
484                           HBasicBlock* block,
485                           bool collect_loop_uses);
486   void RemoveDeadInstructions(const HInstructionList& list);
487   bool CanRemoveCycle();  // Whether the current 'iset_' is removable.
488 
IsInPredicatedVectorizationMode()489   bool IsInPredicatedVectorizationMode() const { return predicated_vectorization_mode_; }
490   void MaybeInsertInVectorExternalSet(HInstruction* instruction);
491 
492   // Compiler options (to query ISA features).
493   const CompilerOptions* compiler_options_;
494 
495   // Cached target SIMD vector register size in bytes.
496   const size_t simd_register_size_;
497 
498   // Range information based on prior induction variable analysis.
499   InductionVarRange induction_range_;
500 
501   // Phase-local heap memory allocator for the loop optimizer. Storage obtained
502   // through this allocator is immediately released when the loop optimizer is done.
503   ScopedArenaAllocator* loop_allocator_;
504 
505   // Global heap memory allocator. Used to build HIR.
506   ArenaAllocator* global_allocator_;
507 
508   // Entries into the loop hierarchy representation. The hierarchy resides
509   // in phase-local heap memory.
510   LoopNode* top_loop_;
511   LoopNode* last_loop_;
512 
513   // Temporary bookkeeping of a set of instructions.
514   // Contents reside in phase-local heap memory.
515   ScopedArenaSet<HInstruction*>* iset_;
516 
517   // Temporary bookkeeping of reduction instructions. Mapping is two-fold:
518   // (1) reductions in the loop-body are mapped back to their phi definition,
519   // (2) phi definitions are mapped to their initial value (updated during
520   //     code generation to feed the proper values into the new chain).
521   // Contents reside in phase-local heap memory.
522   ScopedArenaSafeMap<HInstruction*, HInstruction*>* reductions_;
523 
524   // Flag that tracks if any simplifications have occurred.
525   bool simplified_;
526 
527   // Whether to use predicated loop vectorization (e.g. for arm64 SVE target).
528   bool predicated_vectorization_mode_;
529 
530   // Number of "lanes" for selected packed type.
531   uint32_t vector_length_;
532 
533   // Set of array references in the vector loop.
534   // Contents reside in phase-local heap memory.
535   ScopedArenaSet<ArrayReference>* vector_refs_;
536 
537   // Static or dynamic loop peeling for alignment.
538   uint32_t vector_static_peeling_factor_;
539   const ArrayReference* vector_dynamic_peeling_candidate_;
540 
541   // Dynamic data dependence test of the form a != b.
542   HInstruction* vector_runtime_test_a_;
543   HInstruction* vector_runtime_test_b_;
544 
545   // Mapping used during vectorization synthesis for both the scalar peeling/cleanup
546   // loop (mode is kSequential) and the actual vector loop (mode is kVector). The data
547   // structure maps original instructions into the new instructions.
548   // Contents reside in phase-local heap memory.
549   ScopedArenaSafeMap<HInstruction*, HInstruction*>* vector_map_;
550 
551   // Permanent mapping used during vectorization synthesis.
552   // Contents reside in phase-local heap memory.
553   ScopedArenaSafeMap<HInstruction*, HInstruction*>* vector_permanent_map_;
554 
555   // Tracks vector operations that are inserted outside of the loop (preheader, exit)
556   // as part of vectorization (e.g. replicate scalar for loop invariants and reduce ops
557   // for loop reductions).
558   //
559   // The instructions in the set are live for the whole vectorization process of the current
560   // loop, not just during generation of a particular loop version (as the sets above).
561   //
562   // Currently the set is being only used in the predicated mode - for assigning governing
563   // predicates.
564   ScopedArenaSet<HInstruction*>* vector_external_set_;
565 
566   // A mapping between a basic block of the original loop and its associated PredicateInfo.
567   //
568   // Only used in predicated loop vectorization mode.
569   ScopedArenaSafeMap<HBasicBlock*, BlockPredicateInfo*>* predicate_info_map_;
570 
571   // Temporary vectorization bookkeeping.
572   LoopSynthesisMode synthesis_mode_;  // synthesis mode
573   HBasicBlock* vector_preheader_;  // preheader of the new loop
574   HBasicBlock* vector_header_;  // header of the new loop
575   HBasicBlock* vector_body_;  // body of the new loop
576   HInstruction* vector_index_;  // normalized index of the new loop
577 
578   // Helper for target-specific behaviour for loop optimizations.
579   ArchNoOptsLoopHelper* arch_loop_helper_;
580 
581   friend class LoopOptimizationTest;
582   friend class PredicatedSimdLoopOptimizationTest;
583 
584   DISALLOW_COPY_AND_ASSIGN(HLoopOptimization);
585 };
586 
587 }  // namespace art
588 
589 #endif  // ART_COMPILER_OPTIMIZING_LOOP_OPTIMIZATION_H_
590