1fd4e5da5Sopenharmony_ci// Copyright (c) 2018 Google LLC. 2fd4e5da5Sopenharmony_ci// 3fd4e5da5Sopenharmony_ci// Licensed under the Apache License, Version 2.0 (the "License"); 4fd4e5da5Sopenharmony_ci// you may not use this file except in compliance with the License. 5fd4e5da5Sopenharmony_ci// You may obtain a copy of the License at 6fd4e5da5Sopenharmony_ci// 7fd4e5da5Sopenharmony_ci// http://www.apache.org/licenses/LICENSE-2.0 8fd4e5da5Sopenharmony_ci// 9fd4e5da5Sopenharmony_ci// Unless required by applicable law or agreed to in writing, software 10fd4e5da5Sopenharmony_ci// distributed under the License is distributed on an "AS IS" BASIS, 11fd4e5da5Sopenharmony_ci// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12fd4e5da5Sopenharmony_ci// See the License for the specific language governing permissions and 13fd4e5da5Sopenharmony_ci// limitations under the License. 14fd4e5da5Sopenharmony_ci 15fd4e5da5Sopenharmony_ci#ifndef SOURCE_OPT_LOOP_PEELING_H_ 16fd4e5da5Sopenharmony_ci#define SOURCE_OPT_LOOP_PEELING_H_ 17fd4e5da5Sopenharmony_ci 18fd4e5da5Sopenharmony_ci#include <algorithm> 19fd4e5da5Sopenharmony_ci#include <limits> 20fd4e5da5Sopenharmony_ci#include <memory> 21fd4e5da5Sopenharmony_ci#include <tuple> 22fd4e5da5Sopenharmony_ci#include <unordered_map> 23fd4e5da5Sopenharmony_ci#include <unordered_set> 24fd4e5da5Sopenharmony_ci#include <utility> 25fd4e5da5Sopenharmony_ci#include <vector> 26fd4e5da5Sopenharmony_ci 27fd4e5da5Sopenharmony_ci#include "source/opt/ir_context.h" 28fd4e5da5Sopenharmony_ci#include "source/opt/loop_descriptor.h" 29fd4e5da5Sopenharmony_ci#include "source/opt/loop_utils.h" 30fd4e5da5Sopenharmony_ci#include "source/opt/pass.h" 31fd4e5da5Sopenharmony_ci#include "source/opt/scalar_analysis.h" 32fd4e5da5Sopenharmony_ci 33fd4e5da5Sopenharmony_cinamespace spvtools { 34fd4e5da5Sopenharmony_cinamespace opt { 35fd4e5da5Sopenharmony_ci 36fd4e5da5Sopenharmony_ci// Utility class to perform the peeling of a given loop. 37fd4e5da5Sopenharmony_ci// The loop peeling transformation make a certain amount of a loop iterations to 38fd4e5da5Sopenharmony_ci// be executed either before (peel before) or after (peel after) the transformed 39fd4e5da5Sopenharmony_ci// loop. 40fd4e5da5Sopenharmony_ci// 41fd4e5da5Sopenharmony_ci// For peeling cases the transformation does the following steps: 42fd4e5da5Sopenharmony_ci// - It clones the loop and inserts the cloned loop before the original loop; 43fd4e5da5Sopenharmony_ci// - It connects all iterating values of the cloned loop with the 44fd4e5da5Sopenharmony_ci// corresponding original loop values so that the second loop starts with 45fd4e5da5Sopenharmony_ci// the appropriate values. 46fd4e5da5Sopenharmony_ci// - It inserts a new induction variable "i" is inserted into the cloned that 47fd4e5da5Sopenharmony_ci// starts with the value 0 and increment by step of one. 48fd4e5da5Sopenharmony_ci// 49fd4e5da5Sopenharmony_ci// The last step is specific to each case: 50fd4e5da5Sopenharmony_ci// - Peel before: the transformation is to peel the "N" first iterations. 51fd4e5da5Sopenharmony_ci// The exit condition of the cloned loop is changed so that the loop 52fd4e5da5Sopenharmony_ci// exits when "i < N" becomes false. The original loop is then protected to 53fd4e5da5Sopenharmony_ci// only execute if there is any iteration left to do. 54fd4e5da5Sopenharmony_ci// - Peel after: the transformation is to peel the "N" last iterations, 55fd4e5da5Sopenharmony_ci// then the exit condition of the cloned loop is changed so that the loop 56fd4e5da5Sopenharmony_ci// exits when "i + N < max_iteration" becomes false, where "max_iteration" 57fd4e5da5Sopenharmony_ci// is the upper bound of the loop. The cloned loop is then protected to 58fd4e5da5Sopenharmony_ci// only execute if there is any iteration left to do no covered by the 59fd4e5da5Sopenharmony_ci// second. 60fd4e5da5Sopenharmony_ci// 61fd4e5da5Sopenharmony_ci// To be peelable: 62fd4e5da5Sopenharmony_ci// - The loop must be in LCSSA form; 63fd4e5da5Sopenharmony_ci// - The loop must not contain any breaks; 64fd4e5da5Sopenharmony_ci// - The loop must not have any ambiguous iterators updates (see 65fd4e5da5Sopenharmony_ci// "CanPeelLoop"). 66fd4e5da5Sopenharmony_ci// The method "CanPeelLoop" checks that those constrained are met. 67fd4e5da5Sopenharmony_ciclass LoopPeeling { 68fd4e5da5Sopenharmony_ci public: 69fd4e5da5Sopenharmony_ci // LoopPeeling constructor. 70fd4e5da5Sopenharmony_ci // |loop| is the loop to peel. 71fd4e5da5Sopenharmony_ci // |loop_iteration_count| is the instruction holding the |loop| iteration 72fd4e5da5Sopenharmony_ci // count, must be invariant for |loop| and must be of an int 32 type (signed 73fd4e5da5Sopenharmony_ci // or unsigned). 74fd4e5da5Sopenharmony_ci // |canonical_induction_variable| is an induction variable that can be used to 75fd4e5da5Sopenharmony_ci // count the number of iterations, must be of the same type as 76fd4e5da5Sopenharmony_ci // |loop_iteration_count| and start at 0 and increase by step of one at each 77fd4e5da5Sopenharmony_ci // iteration. The value nullptr is interpreted as no suitable variable exists 78fd4e5da5Sopenharmony_ci // and one will be created. 79fd4e5da5Sopenharmony_ci LoopPeeling(Loop* loop, Instruction* loop_iteration_count, 80fd4e5da5Sopenharmony_ci Instruction* canonical_induction_variable = nullptr) 81fd4e5da5Sopenharmony_ci : context_(loop->GetContext()), 82fd4e5da5Sopenharmony_ci loop_utils_(loop->GetContext(), loop), 83fd4e5da5Sopenharmony_ci loop_(loop), 84fd4e5da5Sopenharmony_ci loop_iteration_count_(!loop->IsInsideLoop(loop_iteration_count) 85fd4e5da5Sopenharmony_ci ? loop_iteration_count 86fd4e5da5Sopenharmony_ci : nullptr), 87fd4e5da5Sopenharmony_ci int_type_(nullptr), 88fd4e5da5Sopenharmony_ci original_loop_canonical_induction_variable_( 89fd4e5da5Sopenharmony_ci canonical_induction_variable), 90fd4e5da5Sopenharmony_ci canonical_induction_variable_(nullptr) { 91fd4e5da5Sopenharmony_ci if (loop_iteration_count_) { 92fd4e5da5Sopenharmony_ci int_type_ = context_->get_type_mgr() 93fd4e5da5Sopenharmony_ci ->GetType(loop_iteration_count_->type_id()) 94fd4e5da5Sopenharmony_ci ->AsInteger(); 95fd4e5da5Sopenharmony_ci if (canonical_induction_variable_) { 96fd4e5da5Sopenharmony_ci assert(canonical_induction_variable_->type_id() == 97fd4e5da5Sopenharmony_ci loop_iteration_count_->type_id() && 98fd4e5da5Sopenharmony_ci "loop_iteration_count and canonical_induction_variable do not " 99fd4e5da5Sopenharmony_ci "have the same type"); 100fd4e5da5Sopenharmony_ci } 101fd4e5da5Sopenharmony_ci } 102fd4e5da5Sopenharmony_ci GetIteratingExitValues(); 103fd4e5da5Sopenharmony_ci } 104fd4e5da5Sopenharmony_ci 105fd4e5da5Sopenharmony_ci // Returns true if the loop can be peeled. 106fd4e5da5Sopenharmony_ci // To be peelable, all operation involved in the update of the loop iterators 107fd4e5da5Sopenharmony_ci // must not dominates the exit condition. This restriction is a work around to 108fd4e5da5Sopenharmony_ci // not miss compile code like: 109fd4e5da5Sopenharmony_ci // 110fd4e5da5Sopenharmony_ci // for (int i = 0; i + 1 < N; i++) {} 111fd4e5da5Sopenharmony_ci // for (int i = 0; ++i < N; i++) {} 112fd4e5da5Sopenharmony_ci // 113fd4e5da5Sopenharmony_ci // The increment will happen before the test on the exit condition leading to 114fd4e5da5Sopenharmony_ci // very look-a-like code. 115fd4e5da5Sopenharmony_ci // 116fd4e5da5Sopenharmony_ci // This restriction will not apply if a loop rotate is applied before (i.e. 117fd4e5da5Sopenharmony_ci // becomes a do-while loop). 118fd4e5da5Sopenharmony_ci bool CanPeelLoop() const { 119fd4e5da5Sopenharmony_ci CFG& cfg = *context_->cfg(); 120fd4e5da5Sopenharmony_ci 121fd4e5da5Sopenharmony_ci if (!loop_iteration_count_) { 122fd4e5da5Sopenharmony_ci return false; 123fd4e5da5Sopenharmony_ci } 124fd4e5da5Sopenharmony_ci if (!int_type_) { 125fd4e5da5Sopenharmony_ci return false; 126fd4e5da5Sopenharmony_ci } 127fd4e5da5Sopenharmony_ci if (int_type_->width() != 32) { 128fd4e5da5Sopenharmony_ci return false; 129fd4e5da5Sopenharmony_ci } 130fd4e5da5Sopenharmony_ci if (!loop_->IsLCSSA()) { 131fd4e5da5Sopenharmony_ci return false; 132fd4e5da5Sopenharmony_ci } 133fd4e5da5Sopenharmony_ci if (!loop_->GetMergeBlock()) { 134fd4e5da5Sopenharmony_ci return false; 135fd4e5da5Sopenharmony_ci } 136fd4e5da5Sopenharmony_ci if (cfg.preds(loop_->GetMergeBlock()->id()).size() != 1) { 137fd4e5da5Sopenharmony_ci return false; 138fd4e5da5Sopenharmony_ci } 139fd4e5da5Sopenharmony_ci if (!IsConditionCheckSideEffectFree()) { 140fd4e5da5Sopenharmony_ci return false; 141fd4e5da5Sopenharmony_ci } 142fd4e5da5Sopenharmony_ci 143fd4e5da5Sopenharmony_ci return !std::any_of(exit_value_.cbegin(), exit_value_.cend(), 144fd4e5da5Sopenharmony_ci [](std::pair<uint32_t, Instruction*> it) { 145fd4e5da5Sopenharmony_ci return it.second == nullptr; 146fd4e5da5Sopenharmony_ci }); 147fd4e5da5Sopenharmony_ci } 148fd4e5da5Sopenharmony_ci 149fd4e5da5Sopenharmony_ci // Moves the execution of the |factor| first iterations of the loop into a 150fd4e5da5Sopenharmony_ci // dedicated loop. 151fd4e5da5Sopenharmony_ci void PeelBefore(uint32_t factor); 152fd4e5da5Sopenharmony_ci 153fd4e5da5Sopenharmony_ci // Moves the execution of the |factor| last iterations of the loop into a 154fd4e5da5Sopenharmony_ci // dedicated loop. 155fd4e5da5Sopenharmony_ci void PeelAfter(uint32_t factor); 156fd4e5da5Sopenharmony_ci 157fd4e5da5Sopenharmony_ci // Returns the cloned loop. 158fd4e5da5Sopenharmony_ci Loop* GetClonedLoop() { return cloned_loop_; } 159fd4e5da5Sopenharmony_ci // Returns the original loop. 160fd4e5da5Sopenharmony_ci Loop* GetOriginalLoop() { return loop_; } 161fd4e5da5Sopenharmony_ci 162fd4e5da5Sopenharmony_ci private: 163fd4e5da5Sopenharmony_ci IRContext* context_; 164fd4e5da5Sopenharmony_ci LoopUtils loop_utils_; 165fd4e5da5Sopenharmony_ci // The original loop. 166fd4e5da5Sopenharmony_ci Loop* loop_; 167fd4e5da5Sopenharmony_ci // The initial |loop_| upper bound. 168fd4e5da5Sopenharmony_ci Instruction* loop_iteration_count_; 169fd4e5da5Sopenharmony_ci // The int type to use for the canonical_induction_variable_. 170fd4e5da5Sopenharmony_ci analysis::Integer* int_type_; 171fd4e5da5Sopenharmony_ci // The cloned loop. 172fd4e5da5Sopenharmony_ci Loop* cloned_loop_; 173fd4e5da5Sopenharmony_ci // This is set to true when the exit and back-edge branch instruction is the 174fd4e5da5Sopenharmony_ci // same. 175fd4e5da5Sopenharmony_ci bool do_while_form_; 176fd4e5da5Sopenharmony_ci // The canonical induction variable from the original loop if it exists. 177fd4e5da5Sopenharmony_ci Instruction* original_loop_canonical_induction_variable_; 178fd4e5da5Sopenharmony_ci // The canonical induction variable of the cloned loop. The induction variable 179fd4e5da5Sopenharmony_ci // is initialized to 0 and incremented by step of 1. 180fd4e5da5Sopenharmony_ci Instruction* canonical_induction_variable_; 181fd4e5da5Sopenharmony_ci // Map between loop iterators and exit values. Loop iterators 182fd4e5da5Sopenharmony_ci std::unordered_map<uint32_t, Instruction*> exit_value_; 183fd4e5da5Sopenharmony_ci 184fd4e5da5Sopenharmony_ci // Duplicate |loop_| and place the new loop before the cloned loop. Iterating 185fd4e5da5Sopenharmony_ci // values from the cloned loop are then connected to the original loop as 186fd4e5da5Sopenharmony_ci // initializer. 187fd4e5da5Sopenharmony_ci void DuplicateAndConnectLoop(LoopUtils::LoopCloningResult* clone_results); 188fd4e5da5Sopenharmony_ci 189fd4e5da5Sopenharmony_ci // Insert the canonical induction variable into the first loop as a simplified 190fd4e5da5Sopenharmony_ci // counter. 191fd4e5da5Sopenharmony_ci void InsertCanonicalInductionVariable( 192fd4e5da5Sopenharmony_ci LoopUtils::LoopCloningResult* clone_results); 193fd4e5da5Sopenharmony_ci 194fd4e5da5Sopenharmony_ci // Fixes the exit condition of the before loop. The function calls 195fd4e5da5Sopenharmony_ci // |condition_builder| to get the condition to use in the conditional branch 196fd4e5da5Sopenharmony_ci // of the loop exit. The loop will be exited if the condition evaluate to 197fd4e5da5Sopenharmony_ci // true. |condition_builder| takes an Instruction* that represent the 198fd4e5da5Sopenharmony_ci // insertion point. 199fd4e5da5Sopenharmony_ci void FixExitCondition( 200fd4e5da5Sopenharmony_ci const std::function<uint32_t(Instruction*)>& condition_builder); 201fd4e5da5Sopenharmony_ci 202fd4e5da5Sopenharmony_ci // Gathers all operations involved in the update of |iterator| into 203fd4e5da5Sopenharmony_ci // |operations|. 204fd4e5da5Sopenharmony_ci void GetIteratorUpdateOperations( 205fd4e5da5Sopenharmony_ci const Loop* loop, Instruction* iterator, 206fd4e5da5Sopenharmony_ci std::unordered_set<Instruction*>* operations); 207fd4e5da5Sopenharmony_ci 208fd4e5da5Sopenharmony_ci // Gathers exiting iterator values. The function builds a map between each 209fd4e5da5Sopenharmony_ci // iterating value in the loop (a phi instruction in the loop header) and its 210fd4e5da5Sopenharmony_ci // SSA value when it exit the loop. If no exit value can be accurately found, 211fd4e5da5Sopenharmony_ci // it is map to nullptr (see comment on CanPeelLoop). 212fd4e5da5Sopenharmony_ci void GetIteratingExitValues(); 213fd4e5da5Sopenharmony_ci 214fd4e5da5Sopenharmony_ci // Returns true if a for-loop has no instruction with effects before the 215fd4e5da5Sopenharmony_ci // condition check. 216fd4e5da5Sopenharmony_ci bool IsConditionCheckSideEffectFree() const; 217fd4e5da5Sopenharmony_ci 218fd4e5da5Sopenharmony_ci // Creates a new basic block and insert it between |bb| and the predecessor of 219fd4e5da5Sopenharmony_ci // |bb|. 220fd4e5da5Sopenharmony_ci BasicBlock* CreateBlockBefore(BasicBlock* bb); 221fd4e5da5Sopenharmony_ci 222fd4e5da5Sopenharmony_ci // Inserts code to only execute |loop| only if the given |condition| is true. 223fd4e5da5Sopenharmony_ci // |if_merge| is a suitable basic block to be used by the if condition as 224fd4e5da5Sopenharmony_ci // merge block. 225fd4e5da5Sopenharmony_ci // The function returns the if block protecting the loop. 226fd4e5da5Sopenharmony_ci BasicBlock* ProtectLoop(Loop* loop, Instruction* condition, 227fd4e5da5Sopenharmony_ci BasicBlock* if_merge); 228fd4e5da5Sopenharmony_ci}; 229fd4e5da5Sopenharmony_ci 230fd4e5da5Sopenharmony_ci// Implements a loop peeling optimization. 231fd4e5da5Sopenharmony_ci// For each loop, the pass will try to peel it if there is conditions that 232fd4e5da5Sopenharmony_ci// are true for the "N" first or last iterations of the loop. 233fd4e5da5Sopenharmony_ci// To avoid code size explosion, too large loops will not be peeled. 234fd4e5da5Sopenharmony_ciclass LoopPeelingPass : public Pass { 235fd4e5da5Sopenharmony_ci public: 236fd4e5da5Sopenharmony_ci // Describes the peeling direction. 237fd4e5da5Sopenharmony_ci enum class PeelDirection { 238fd4e5da5Sopenharmony_ci kNone, // Cannot peel 239fd4e5da5Sopenharmony_ci kBefore, // Can peel before 240fd4e5da5Sopenharmony_ci kAfter // Can peel last 241fd4e5da5Sopenharmony_ci }; 242fd4e5da5Sopenharmony_ci 243fd4e5da5Sopenharmony_ci // Holds some statistics about peeled function. 244fd4e5da5Sopenharmony_ci struct LoopPeelingStats { 245fd4e5da5Sopenharmony_ci std::vector<std::tuple<const Loop*, PeelDirection, uint32_t>> peeled_loops_; 246fd4e5da5Sopenharmony_ci }; 247fd4e5da5Sopenharmony_ci 248fd4e5da5Sopenharmony_ci LoopPeelingPass(LoopPeelingStats* stats = nullptr) : stats_(stats) {} 249fd4e5da5Sopenharmony_ci 250fd4e5da5Sopenharmony_ci // Sets the loop peeling growth threshold. If the code size increase is above 251fd4e5da5Sopenharmony_ci // |code_grow_threshold|, the loop will not be peeled. The code size is 252fd4e5da5Sopenharmony_ci // measured in terms of SPIR-V instructions. 253fd4e5da5Sopenharmony_ci static void SetLoopPeelingThreshold(size_t code_grow_threshold) { 254fd4e5da5Sopenharmony_ci code_grow_threshold_ = code_grow_threshold; 255fd4e5da5Sopenharmony_ci } 256fd4e5da5Sopenharmony_ci 257fd4e5da5Sopenharmony_ci // Returns the loop peeling code growth threshold. 258fd4e5da5Sopenharmony_ci static size_t GetLoopPeelingThreshold() { return code_grow_threshold_; } 259fd4e5da5Sopenharmony_ci 260fd4e5da5Sopenharmony_ci const char* name() const override { return "loop-peeling"; } 261fd4e5da5Sopenharmony_ci 262fd4e5da5Sopenharmony_ci // Processes the given |module|. Returns Status::Failure if errors occur when 263fd4e5da5Sopenharmony_ci // processing. Returns the corresponding Status::Success if processing is 264fd4e5da5Sopenharmony_ci // successful to indicate whether changes have been made to the module. 265fd4e5da5Sopenharmony_ci Pass::Status Process() override; 266fd4e5da5Sopenharmony_ci 267fd4e5da5Sopenharmony_ci private: 268fd4e5da5Sopenharmony_ci // Describes the peeling direction. 269fd4e5da5Sopenharmony_ci enum class CmpOperator { 270fd4e5da5Sopenharmony_ci kLT, // less than 271fd4e5da5Sopenharmony_ci kGT, // greater than 272fd4e5da5Sopenharmony_ci kLE, // less than or equal 273fd4e5da5Sopenharmony_ci kGE, // greater than or equal 274fd4e5da5Sopenharmony_ci }; 275fd4e5da5Sopenharmony_ci 276fd4e5da5Sopenharmony_ci class LoopPeelingInfo { 277fd4e5da5Sopenharmony_ci public: 278fd4e5da5Sopenharmony_ci using Direction = std::pair<PeelDirection, uint32_t>; 279fd4e5da5Sopenharmony_ci 280fd4e5da5Sopenharmony_ci LoopPeelingInfo(Loop* loop, size_t loop_max_iterations, 281fd4e5da5Sopenharmony_ci ScalarEvolutionAnalysis* scev_analysis) 282fd4e5da5Sopenharmony_ci : context_(loop->GetContext()), 283fd4e5da5Sopenharmony_ci loop_(loop), 284fd4e5da5Sopenharmony_ci scev_analysis_(scev_analysis), 285fd4e5da5Sopenharmony_ci loop_max_iterations_(loop_max_iterations) {} 286fd4e5da5Sopenharmony_ci 287fd4e5da5Sopenharmony_ci // Returns by how much and to which direction a loop should be peeled to 288fd4e5da5Sopenharmony_ci // make the conditional branch of the basic block |bb| an unconditional 289fd4e5da5Sopenharmony_ci // branch. If |bb|'s terminator is not a conditional branch or the condition 290fd4e5da5Sopenharmony_ci // is not workable then it returns PeelDirection::kNone and a 0 factor. 291fd4e5da5Sopenharmony_ci Direction GetPeelingInfo(BasicBlock* bb) const; 292fd4e5da5Sopenharmony_ci 293fd4e5da5Sopenharmony_ci private: 294fd4e5da5Sopenharmony_ci // Returns the id of the loop invariant operand of the conditional 295fd4e5da5Sopenharmony_ci // expression |condition|. It returns if no operand is invariant. 296fd4e5da5Sopenharmony_ci uint32_t GetFirstLoopInvariantOperand(Instruction* condition) const; 297fd4e5da5Sopenharmony_ci // Returns the id of the non loop invariant operand of the conditional 298fd4e5da5Sopenharmony_ci // expression |condition|. It returns if all operands are invariant. 299fd4e5da5Sopenharmony_ci uint32_t GetFirstNonLoopInvariantOperand(Instruction* condition) const; 300fd4e5da5Sopenharmony_ci 301fd4e5da5Sopenharmony_ci // Returns the value of |rec| at the first loop iteration. 302fd4e5da5Sopenharmony_ci SExpression GetValueAtFirstIteration(SERecurrentNode* rec) const; 303fd4e5da5Sopenharmony_ci // Returns the value of |rec| at the given |iteration|. 304fd4e5da5Sopenharmony_ci SExpression GetValueAtIteration(SERecurrentNode* rec, 305fd4e5da5Sopenharmony_ci int64_t iteration) const; 306fd4e5da5Sopenharmony_ci // Returns the value of |rec| at the last loop iteration. 307fd4e5da5Sopenharmony_ci SExpression GetValueAtLastIteration(SERecurrentNode* rec) const; 308fd4e5da5Sopenharmony_ci 309fd4e5da5Sopenharmony_ci bool EvalOperator(CmpOperator cmp_op, SExpression lhs, SExpression rhs, 310fd4e5da5Sopenharmony_ci bool* result) const; 311fd4e5da5Sopenharmony_ci 312fd4e5da5Sopenharmony_ci Direction HandleEquality(SExpression lhs, SExpression rhs) const; 313fd4e5da5Sopenharmony_ci Direction HandleInequality(CmpOperator cmp_op, SExpression lhs, 314fd4e5da5Sopenharmony_ci SERecurrentNode* rhs) const; 315fd4e5da5Sopenharmony_ci 316fd4e5da5Sopenharmony_ci static Direction GetNoneDirection() { 317fd4e5da5Sopenharmony_ci return Direction{LoopPeelingPass::PeelDirection::kNone, 0}; 318fd4e5da5Sopenharmony_ci } 319fd4e5da5Sopenharmony_ci IRContext* context_; 320fd4e5da5Sopenharmony_ci Loop* loop_; 321fd4e5da5Sopenharmony_ci ScalarEvolutionAnalysis* scev_analysis_; 322fd4e5da5Sopenharmony_ci size_t loop_max_iterations_; 323fd4e5da5Sopenharmony_ci }; 324fd4e5da5Sopenharmony_ci // Peel profitable loops in |f|. 325fd4e5da5Sopenharmony_ci bool ProcessFunction(Function* f); 326fd4e5da5Sopenharmony_ci // Peel |loop| if profitable. 327fd4e5da5Sopenharmony_ci std::pair<bool, Loop*> ProcessLoop(Loop* loop, CodeMetrics* loop_size); 328fd4e5da5Sopenharmony_ci 329fd4e5da5Sopenharmony_ci static size_t code_grow_threshold_; 330fd4e5da5Sopenharmony_ci LoopPeelingStats* stats_; 331fd4e5da5Sopenharmony_ci}; 332fd4e5da5Sopenharmony_ci 333fd4e5da5Sopenharmony_ci} // namespace opt 334fd4e5da5Sopenharmony_ci} // namespace spvtools 335fd4e5da5Sopenharmony_ci 336fd4e5da5Sopenharmony_ci#endif // SOURCE_OPT_LOOP_PEELING_H_ 337