Coverage Report

Created: 2024-09-11 07:09

/src/spirv-tools/source/opt/loop_descriptor.cpp
Line
Count
Source (jump to first uncovered line)
1
// Copyright (c) 2017 Google Inc.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
#include "source/opt/loop_descriptor.h"
16
17
#include <algorithm>
18
#include <limits>
19
#include <stack>
20
#include <utility>
21
#include <vector>
22
23
#include "source/opt/cfg.h"
24
#include "source/opt/constants.h"
25
#include "source/opt/dominator_tree.h"
26
#include "source/opt/ir_context.h"
27
#include "source/opt/iterator.h"
28
#include "source/opt/tree_iterator.h"
29
#include "source/util/make_unique.h"
30
31
namespace spvtools {
32
namespace opt {
33
34
// Takes in a phi instruction |induction| and the loop |header| and returns the
35
// step operation of the loop.
36
Instruction* Loop::GetInductionStepOperation(
37
22.9k
    const Instruction* induction) const {
38
  // Induction must be a phi instruction.
39
22.9k
  assert(induction->opcode() == spv::Op::OpPhi);
40
41
22.9k
  Instruction* step = nullptr;
42
43
22.9k
  analysis::DefUseManager* def_use_manager = context_->get_def_use_mgr();
44
45
  // Traverse the incoming operands of the phi instruction.
46
45.9k
  for (uint32_t operand_id = 1; operand_id < induction->NumInOperands();
47
45.9k
       operand_id += 2) {
48
    // Incoming edge.
49
45.9k
    BasicBlock* incoming_block =
50
45.9k
        context_->cfg()->block(induction->GetSingleWordInOperand(operand_id));
51
52
    // Check if the block is dominated by header, and thus coming from within
53
    // the loop.
54
45.9k
    if (IsInsideLoop(incoming_block)) {
55
22.9k
      step = def_use_manager->GetDef(
56
22.9k
          induction->GetSingleWordInOperand(operand_id - 1));
57
22.9k
      break;
58
22.9k
    }
59
45.9k
  }
60
61
22.9k
  if (!step || !IsSupportedStepOp(step->opcode())) {
62
85
    return nullptr;
63
85
  }
64
65
  // The induction variable which binds the loop must only be modified once.
66
22.8k
  uint32_t lhs = step->GetSingleWordInOperand(0);
67
22.8k
  uint32_t rhs = step->GetSingleWordInOperand(1);
68
69
  // One of the left hand side or right hand side of the step instruction must
70
  // be the induction phi and the other must be an OpConstant.
71
22.8k
  if (lhs != induction->result_id() && rhs != induction->result_id()) {
72
89
    return nullptr;
73
89
  }
74
75
22.8k
  if (def_use_manager->GetDef(lhs)->opcode() != spv::Op::OpConstant &&
76
22.8k
      def_use_manager->GetDef(rhs)->opcode() != spv::Op::OpConstant) {
77
9
    return nullptr;
78
9
  }
79
80
22.7k
  return step;
81
22.8k
}
82
83
// Returns true if the |step| operation is an induction variable step operation
84
// which is currently handled.
85
22.9k
bool Loop::IsSupportedStepOp(spv::Op step) const {
86
22.9k
  switch (step) {
87
7.93k
    case spv::Op::OpISub:
88
22.8k
    case spv::Op::OpIAdd:
89
22.8k
      return true;
90
85
    default:
91
85
      return false;
92
22.9k
  }
93
22.9k
}
94
95
32.2k
bool Loop::IsSupportedCondition(spv::Op condition) const {
96
32.2k
  switch (condition) {
97
    // <
98
2.02k
    case spv::Op::OpULessThan:
99
19.2k
    case spv::Op::OpSLessThan:
100
    // >
101
21.4k
    case spv::Op::OpUGreaterThan:
102
26.6k
    case spv::Op::OpSGreaterThan:
103
104
    // >=
105
29.8k
    case spv::Op::OpSGreaterThanEqual:
106
30.4k
    case spv::Op::OpUGreaterThanEqual:
107
    // <=
108
31.7k
    case spv::Op::OpSLessThanEqual:
109
32.0k
    case spv::Op::OpULessThanEqual:
110
111
32.0k
      return true;
112
196
    default:
113
196
      return false;
114
32.2k
  }
115
32.2k
}
116
117
int64_t Loop::GetResidualConditionValue(spv::Op condition,
118
                                        int64_t initial_value,
119
                                        int64_t step_value,
120
                                        size_t number_of_iterations,
121
0
                                        size_t factor) {
122
0
  int64_t remainder =
123
0
      initial_value + (number_of_iterations % factor) * step_value;
124
125
  // We subtract or add one as the above formula calculates the remainder if the
126
  // loop where just less than or greater than. Adding or subtracting one should
127
  // give a functionally equivalent value.
128
0
  switch (condition) {
129
0
    case spv::Op::OpSGreaterThanEqual:
130
0
    case spv::Op::OpUGreaterThanEqual: {
131
0
      remainder -= 1;
132
0
      break;
133
0
    }
134
0
    case spv::Op::OpSLessThanEqual:
135
0
    case spv::Op::OpULessThanEqual: {
136
0
      remainder += 1;
137
0
      break;
138
0
    }
139
140
0
    default:
141
0
      break;
142
0
  }
143
0
  return remainder;
144
0
}
145
146
0
Instruction* Loop::GetConditionInst() const {
147
0
  BasicBlock* condition_block = FindConditionBlock();
148
0
  if (!condition_block) {
149
0
    return nullptr;
150
0
  }
151
0
  Instruction* branch_conditional = &*condition_block->tail();
152
0
  if (!branch_conditional ||
153
0
      branch_conditional->opcode() != spv::Op::OpBranchConditional) {
154
0
    return nullptr;
155
0
  }
156
0
  Instruction* condition_inst = context_->get_def_use_mgr()->GetDef(
157
0
      branch_conditional->GetSingleWordInOperand(0));
158
0
  if (IsSupportedCondition(condition_inst->opcode())) {
159
0
    return condition_inst;
160
0
  }
161
162
0
  return nullptr;
163
0
}
164
165
// Extract the initial value from the |induction| OpPhi instruction and store it
166
// in |value|. If the function couldn't find the initial value of |induction|
167
// return false.
168
bool Loop::GetInductionInitValue(const Instruction* induction,
169
22.7k
                                 int64_t* value) const {
170
22.7k
  Instruction* constant_instruction = nullptr;
171
22.7k
  analysis::DefUseManager* def_use_manager = context_->get_def_use_mgr();
172
173
68.3k
  for (uint32_t operand_id = 0; operand_id < induction->NumInOperands();
174
45.5k
       operand_id += 2) {
175
45.5k
    BasicBlock* bb = context_->cfg()->block(
176
45.5k
        induction->GetSingleWordInOperand(operand_id + 1));
177
178
45.5k
    if (!IsInsideLoop(bb)) {
179
22.7k
      constant_instruction = def_use_manager->GetDef(
180
22.7k
          induction->GetSingleWordInOperand(operand_id));
181
22.7k
    }
182
45.5k
  }
183
184
22.7k
  if (!constant_instruction) return false;
185
186
22.7k
  const analysis::Constant* constant =
187
22.7k
      context_->get_constant_mgr()->FindDeclaredConstant(
188
22.7k
          constant_instruction->result_id());
189
22.7k
  if (!constant) return false;
190
191
22.7k
  if (value) {
192
22.7k
    const analysis::Integer* type = constant->type()->AsInteger();
193
22.7k
    if (!type) {
194
0
      return false;
195
0
    }
196
197
22.7k
    *value = type->IsSigned() ? constant->GetSignExtendedValue()
198
22.7k
                              : constant->GetZeroExtendedValue();
199
22.7k
  }
200
201
22.7k
  return true;
202
22.7k
}
203
204
Loop::Loop(IRContext* context, DominatorAnalysis* dom_analysis,
205
           BasicBlock* header, BasicBlock* continue_target,
206
           BasicBlock* merge_target)
207
    : context_(context),
208
      loop_header_(header),
209
      loop_continue_(continue_target),
210
      loop_merge_(merge_target),
211
      loop_preheader_(nullptr),
212
      parent_(nullptr),
213
18.9k
      loop_is_marked_for_removal_(false) {
214
18.9k
  assert(context);
215
18.9k
  assert(dom_analysis);
216
18.9k
  loop_preheader_ = FindLoopPreheader(dom_analysis);
217
18.9k
  loop_latch_ = FindLatchBlock();
218
18.9k
}
219
220
18.9k
BasicBlock* Loop::FindLoopPreheader(DominatorAnalysis* dom_analysis) {
221
18.9k
  CFG* cfg = context_->cfg();
222
18.9k
  DominatorTree& dom_tree = dom_analysis->GetDomTree();
223
18.9k
  DominatorTreeNode* header_node = dom_tree.GetTreeNode(loop_header_);
224
225
  // The loop predecessor.
226
18.9k
  BasicBlock* loop_pred = nullptr;
227
228
18.9k
  auto header_pred = cfg->preds(loop_header_->id());
229
38.0k
  for (uint32_t p_id : header_pred) {
230
38.0k
    DominatorTreeNode* node = dom_tree.GetTreeNode(p_id);
231
38.0k
    if (node && !dom_tree.Dominates(header_node, node)) {
232
      // The predecessor is not part of the loop, so potential loop preheader.
233
19.0k
      if (loop_pred && node->bb_ != loop_pred) {
234
        // If we saw 2 distinct predecessors that are outside the loop, we don't
235
        // have a loop preheader.
236
14
        return nullptr;
237
14
      }
238
18.9k
      loop_pred = node->bb_;
239
18.9k
    }
240
38.0k
  }
241
  // Safe guard against invalid code, SPIR-V spec forbids loop with the entry
242
  // node as header.
243
18.9k
  assert(loop_pred && "The header node is the entry block ?");
244
245
  // So we have a unique basic block that can enter this loop.
246
  // If this loop is the unique successor of this block, then it is a loop
247
  // preheader.
248
18.9k
  bool is_preheader = true;
249
18.9k
  uint32_t loop_header_id = loop_header_->id();
250
18.9k
  const auto* const_loop_pred = loop_pred;
251
18.9k
  const_loop_pred->ForEachSuccessorLabel(
252
18.9k
      [&is_preheader, loop_header_id](const uint32_t id) {
253
18.9k
        if (id != loop_header_id) is_preheader = false;
254
18.9k
      });
255
18.9k
  if (is_preheader) return loop_pred;
256
1
  return nullptr;
257
18.9k
}
258
259
0
bool Loop::IsInsideLoop(Instruction* inst) const {
260
0
  const BasicBlock* parent_block = context_->get_instr_block(inst);
261
0
  if (!parent_block) return false;
262
0
  return IsInsideLoop(parent_block);
263
0
}
264
265
0
bool Loop::IsBasicBlockInLoopSlow(const BasicBlock* bb) {
266
0
  assert(bb->GetParent() && "The basic block does not belong to a function");
267
0
  DominatorAnalysis* dom_analysis =
268
0
      context_->GetDominatorAnalysis(bb->GetParent());
269
0
  if (dom_analysis->IsReachable(bb) &&
270
0
      !dom_analysis->Dominates(GetHeaderBlock(), bb))
271
0
    return false;
272
273
0
  return true;
274
0
}
275
276
0
BasicBlock* Loop::GetOrCreatePreHeaderBlock() {
277
0
  if (loop_preheader_) return loop_preheader_;
278
279
0
  CFG* cfg = context_->cfg();
280
0
  loop_header_ = cfg->SplitLoopHeader(loop_header_);
281
0
  return loop_preheader_;
282
0
}
283
284
0
void Loop::SetContinueBlock(BasicBlock* continue_block) {
285
0
  assert(IsInsideLoop(continue_block));
286
0
  loop_continue_ = continue_block;
287
0
}
288
289
0
void Loop::SetLatchBlock(BasicBlock* latch) {
290
0
#ifndef NDEBUG
291
0
  assert(latch->GetParent() && "The basic block does not belong to a function");
292
293
0
  const auto* const_latch = latch;
294
0
  const_latch->ForEachSuccessorLabel([this](uint32_t id) {
295
0
    assert((!IsInsideLoop(id) || id == GetHeaderBlock()->id()) &&
296
0
           "A predecessor of the continue block does not belong to the loop");
297
0
  });
298
0
#endif  // NDEBUG
299
0
  assert(IsInsideLoop(latch) && "The continue block is not in the loop");
300
301
0
  SetLatchBlockImpl(latch);
302
0
}
303
304
0
void Loop::SetMergeBlock(BasicBlock* merge) {
305
0
#ifndef NDEBUG
306
0
  assert(merge->GetParent() && "The basic block does not belong to a function");
307
0
#endif  // NDEBUG
308
0
  assert(!IsInsideLoop(merge) && "The merge block is in the loop");
309
310
0
  SetMergeBlockImpl(merge);
311
0
  if (GetHeaderBlock()->GetLoopMergeInst()) {
312
0
    UpdateLoopMergeInst();
313
0
  }
314
0
}
315
316
0
void Loop::SetPreHeaderBlock(BasicBlock* preheader) {
317
0
  if (preheader) {
318
0
    assert(!IsInsideLoop(preheader) && "The preheader block is in the loop");
319
0
    assert(preheader->tail()->opcode() == spv::Op::OpBranch &&
320
0
           "The preheader block does not unconditionally branch to the header "
321
0
           "block");
322
0
    assert(preheader->tail()->GetSingleWordOperand(0) ==
323
0
               GetHeaderBlock()->id() &&
324
0
           "The preheader block does not unconditionally branch to the header "
325
0
           "block");
326
0
  }
327
0
  loop_preheader_ = preheader;
328
0
}
329
330
18.9k
BasicBlock* Loop::FindLatchBlock() {
331
18.9k
  CFG* cfg = context_->cfg();
332
333
18.9k
  DominatorAnalysis* dominator_analysis =
334
18.9k
      context_->GetDominatorAnalysis(loop_header_->GetParent());
335
336
  // Look at the predecessors of the loop header to find a predecessor block
337
  // which is dominated by the loop continue target. There should only be one
338
  // block which meets this criteria and this is the latch block, as per the
339
  // SPIR-V spec.
340
38.0k
  for (uint32_t block_id : cfg->preds(loop_header_->id())) {
341
38.0k
    if (dominator_analysis->Dominates(loop_continue_->id(), block_id)) {
342
18.9k
      return cfg->block(block_id);
343
18.9k
    }
344
38.0k
  }
345
346
0
  assert(
347
0
      false &&
348
0
      "Every loop should have a latch block dominated by the continue target");
349
0
  return nullptr;
350
0
}
351
352
0
void Loop::GetExitBlocks(std::unordered_set<uint32_t>* exit_blocks) const {
353
0
  CFG* cfg = context_->cfg();
354
0
  exit_blocks->clear();
355
356
0
  for (uint32_t bb_id : GetBlocks()) {
357
0
    const BasicBlock* bb = cfg->block(bb_id);
358
0
    bb->ForEachSuccessorLabel([exit_blocks, this](uint32_t succ) {
359
0
      if (!IsInsideLoop(succ)) {
360
0
        exit_blocks->insert(succ);
361
0
      }
362
0
    });
363
0
  }
364
0
}
365
366
void Loop::GetMergingBlocks(
367
0
    std::unordered_set<uint32_t>* merging_blocks) const {
368
0
  assert(GetMergeBlock() && "This loop is not structured");
369
0
  CFG* cfg = context_->cfg();
370
0
  merging_blocks->clear();
371
372
0
  std::stack<const BasicBlock*> to_visit;
373
0
  to_visit.push(GetMergeBlock());
374
0
  while (!to_visit.empty()) {
375
0
    const BasicBlock* bb = to_visit.top();
376
0
    to_visit.pop();
377
0
    merging_blocks->insert(bb->id());
378
0
    for (uint32_t pred_id : cfg->preds(bb->id())) {
379
0
      if (!IsInsideLoop(pred_id) && !merging_blocks->count(pred_id)) {
380
0
        to_visit.push(cfg->block(pred_id));
381
0
      }
382
0
    }
383
0
  }
384
0
}
385
386
namespace {
387
388
0
inline bool IsBasicBlockSafeToClone(IRContext* context, BasicBlock* bb) {
389
0
  for (Instruction& inst : *bb) {
390
0
    if (!inst.IsBranch() && !context->IsCombinatorInstruction(&inst))
391
0
      return false;
392
0
  }
393
394
0
  return true;
395
0
}
396
397
}  // namespace
398
399
0
bool Loop::IsSafeToClone() const {
400
0
  CFG& cfg = *context_->cfg();
401
402
0
  for (uint32_t bb_id : GetBlocks()) {
403
0
    BasicBlock* bb = cfg.block(bb_id);
404
0
    assert(bb);
405
0
    if (!IsBasicBlockSafeToClone(context_, bb)) return false;
406
0
  }
407
408
  // Look at the merge construct.
409
0
  if (GetHeaderBlock()->GetLoopMergeInst()) {
410
0
    std::unordered_set<uint32_t> blocks;
411
0
    GetMergingBlocks(&blocks);
412
0
    blocks.erase(GetMergeBlock()->id());
413
0
    for (uint32_t bb_id : blocks) {
414
0
      BasicBlock* bb = cfg.block(bb_id);
415
0
      assert(bb);
416
0
      if (!IsBasicBlockSafeToClone(context_, bb)) return false;
417
0
    }
418
0
  }
419
420
0
  return true;
421
0
}
422
423
0
bool Loop::IsLCSSA() const {
424
0
  CFG* cfg = context_->cfg();
425
0
  analysis::DefUseManager* def_use_mgr = context_->get_def_use_mgr();
426
427
0
  std::unordered_set<uint32_t> exit_blocks;
428
0
  GetExitBlocks(&exit_blocks);
429
430
  // Declare ir_context so we can capture context_ in the below lambda
431
0
  IRContext* ir_context = context_;
432
433
0
  for (uint32_t bb_id : GetBlocks()) {
434
0
    for (Instruction& insn : *cfg->block(bb_id)) {
435
      // All uses must be either:
436
      //  - In the loop;
437
      //  - In an exit block and in a phi instruction.
438
0
      if (!def_use_mgr->WhileEachUser(
439
0
              &insn,
440
0
              [&exit_blocks, ir_context, this](Instruction* use) -> bool {
441
0
                BasicBlock* parent = ir_context->get_instr_block(use);
442
0
                assert(parent && "Invalid analysis");
443
0
                if (IsInsideLoop(parent)) return true;
444
0
                if (use->opcode() != spv::Op::OpPhi) return false;
445
0
                return exit_blocks.count(parent->id());
446
0
              }))
447
0
        return false;
448
0
    }
449
0
  }
450
0
  return true;
451
0
}
452
453
0
bool Loop::ShouldHoistInstruction(const Instruction& inst) const {
454
0
  return inst.IsOpcodeCodeMotionSafe() && AreAllOperandsOutsideLoop(inst) &&
455
0
         (!inst.IsLoad() || inst.IsReadOnlyLoad());
456
0
}
457
458
0
bool Loop::AreAllOperandsOutsideLoop(const Instruction& inst) const {
459
0
  analysis::DefUseManager* def_use_mgr = GetContext()->get_def_use_mgr();
460
461
0
  const std::function<bool(const uint32_t*)> operand_outside_loop =
462
0
      [this, &def_use_mgr](const uint32_t* id) {
463
0
        return !this->IsInsideLoop(def_use_mgr->GetDef(*id));
464
0
      };
465
466
0
  return inst.WhileEachInId(operand_outside_loop);
467
0
}
468
469
void Loop::ComputeLoopStructuredOrder(
470
    std::vector<BasicBlock*>* ordered_loop_blocks, bool include_pre_header,
471
2.74k
    bool include_merge) const {
472
2.74k
  CFG& cfg = *context_->cfg();
473
474
  // Reserve the memory: all blocks in the loop + extra if needed.
475
2.74k
  ordered_loop_blocks->reserve(GetBlocks().size() + include_pre_header +
476
2.74k
                               include_merge);
477
478
2.74k
  if (include_pre_header && GetPreHeaderBlock())
479
0
    ordered_loop_blocks->push_back(loop_preheader_);
480
481
2.74k
  bool is_shader =
482
2.74k
      context_->get_feature_mgr()->HasCapability(spv::Capability::Shader);
483
2.74k
  if (!is_shader) {
484
0
    cfg.ForEachBlockInReversePostOrder(
485
0
        loop_header_, [ordered_loop_blocks, this](BasicBlock* bb) {
486
0
          if (IsInsideLoop(bb)) ordered_loop_blocks->push_back(bb);
487
0
        });
488
2.74k
  } else {
489
    // If this is a shader, it is possible that there are unreachable merge and
490
    // continue blocks that must be copied to retain the structured order.
491
    // The structured order will include these.
492
2.74k
    std::list<BasicBlock*> order;
493
2.74k
    cfg.ComputeStructuredOrder(loop_header_->GetParent(), loop_header_,
494
2.74k
                               loop_merge_, &order);
495
88.4k
    for (BasicBlock* bb : order) {
496
88.4k
      if (bb == GetMergeBlock()) {
497
2.74k
        break;
498
2.74k
      }
499
85.7k
      ordered_loop_blocks->push_back(bb);
500
85.7k
    }
501
2.74k
  }
502
2.74k
  if (include_merge && GetMergeBlock())
503
0
    ordered_loop_blocks->push_back(loop_merge_);
504
2.74k
}
505
506
LoopDescriptor::LoopDescriptor(IRContext* context, const Function* f)
507
9.89k
    : loops_(), placeholder_top_loop_(nullptr) {
508
9.89k
  PopulateList(context, f);
509
9.89k
}
510
511
29.6k
LoopDescriptor::~LoopDescriptor() { ClearLoops(); }
512
513
9.89k
void LoopDescriptor::PopulateList(IRContext* context, const Function* f) {
514
9.89k
  DominatorAnalysis* dom_analysis = context->GetDominatorAnalysis(f);
515
516
9.89k
  ClearLoops();
517
518
  // Post-order traversal of the dominator tree to find all the OpLoopMerge
519
  // instructions.
520
9.89k
  DominatorTree& dom_tree = dom_analysis->GetDomTree();
521
9.89k
  for (DominatorTreeNode& node :
522
219k
       make_range(dom_tree.post_begin(), dom_tree.post_end())) {
523
219k
    Instruction* merge_inst = node.bb_->GetLoopMergeInst();
524
219k
    if (merge_inst) {
525
22.4k
      bool all_backedge_unreachable = true;
526
44.9k
      for (uint32_t pid : context->cfg()->preds(node.bb_->id())) {
527
44.9k
        if (dom_analysis->IsReachable(pid) &&
528
44.9k
            dom_analysis->Dominates(node.bb_->id(), pid)) {
529
18.9k
          all_backedge_unreachable = false;
530
18.9k
          break;
531
18.9k
        }
532
44.9k
      }
533
22.4k
      if (all_backedge_unreachable)
534
3.49k
        continue;  // ignore this one, we actually never branch back.
535
536
      // The id of the merge basic block of this loop.
537
18.9k
      uint32_t merge_bb_id = merge_inst->GetSingleWordOperand(0);
538
539
      // The id of the continue basic block of this loop.
540
18.9k
      uint32_t continue_bb_id = merge_inst->GetSingleWordOperand(1);
541
542
      // The merge target of this loop.
543
18.9k
      BasicBlock* merge_bb = context->cfg()->block(merge_bb_id);
544
545
      // The continue target of this loop.
546
18.9k
      BasicBlock* continue_bb = context->cfg()->block(continue_bb_id);
547
548
      // The basic block containing the merge instruction.
549
18.9k
      BasicBlock* header_bb = context->get_instr_block(merge_inst);
550
551
      // Add the loop to the list of all the loops in the function.
552
18.9k
      Loop* current_loop =
553
18.9k
          new Loop(context, dom_analysis, header_bb, continue_bb, merge_bb);
554
18.9k
      loops_.push_back(current_loop);
555
556
      // We have a bottom-up construction, so if this loop has nested-loops,
557
      // they are by construction at the tail of the loop list.
558
98.0k
      for (auto itr = loops_.rbegin() + 1; itr != loops_.rend(); ++itr) {
559
79.0k
        Loop* previous_loop = *itr;
560
561
        // If the loop already has a parent, then it has been processed.
562
79.0k
        if (previous_loop->HasParent()) continue;
563
564
        // If the current loop does not dominates the previous loop then it is
565
        // not nested loop.
566
68.7k
        if (!dom_analysis->Dominates(header_bb,
567
68.7k
                                     previous_loop->GetHeaderBlock()))
568
19.6k
          continue;
569
        // If the current loop merge dominates the previous loop then it is
570
        // not nested loop.
571
49.1k
        if (dom_analysis->Dominates(merge_bb, previous_loop->GetHeaderBlock()))
572
46.1k
          continue;
573
574
2.96k
        current_loop->AddNestedLoop(previous_loop);
575
2.96k
      }
576
18.9k
      DominatorTreeNode* dom_merge_node = dom_tree.GetTreeNode(merge_bb);
577
18.9k
      for (DominatorTreeNode& loop_node :
578
805k
           make_range(node.df_begin(), node.df_end())) {
579
        // Check if we are in the loop.
580
805k
        if (dom_tree.Dominates(dom_merge_node, &loop_node)) continue;
581
131k
        current_loop->AddBasicBlock(loop_node.bb_);
582
131k
        basic_block_to_loop_.insert(
583
131k
            std::make_pair(loop_node.bb_->id(), current_loop));
584
131k
      }
585
18.9k
    }
586
219k
  }
587
18.9k
  for (Loop* loop : loops_) {
588
18.9k
    if (!loop->HasParent()) placeholder_top_loop_.nested_loops_.push_back(loop);
589
18.9k
  }
590
9.89k
}
591
592
0
std::vector<Loop*> LoopDescriptor::GetLoopsInBinaryLayoutOrder() {
593
0
  std::vector<uint32_t> ids{};
594
595
0
  for (size_t i = 0; i < NumLoops(); ++i) {
596
0
    ids.push_back(GetLoopByIndex(i).GetHeaderBlock()->id());
597
0
  }
598
599
0
  std::vector<Loop*> loops{};
600
0
  if (!ids.empty()) {
601
0
    auto function = GetLoopByIndex(0).GetHeaderBlock()->GetParent();
602
0
    for (const auto& block : *function) {
603
0
      auto block_id = block.id();
604
605
0
      auto element = std::find(std::begin(ids), std::end(ids), block_id);
606
0
      if (element != std::end(ids)) {
607
0
        loops.push_back(&GetLoopByIndex(element - std::begin(ids)));
608
0
      }
609
0
    }
610
0
  }
611
612
0
  return loops;
613
0
}
614
615
9.82k
BasicBlock* Loop::FindConditionBlock() const {
616
9.82k
  if (!loop_merge_) {
617
0
    return nullptr;
618
0
  }
619
9.82k
  BasicBlock* condition_block = nullptr;
620
621
9.82k
  uint32_t in_loop_pred = 0;
622
10.1k
  for (uint32_t p : context_->cfg()->preds(loop_merge_->id())) {
623
10.1k
    if (IsInsideLoop(p)) {
624
9.99k
      if (in_loop_pred) {
625
        // 2 in-loop predecessors.
626
394
        return nullptr;
627
394
      }
628
9.60k
      in_loop_pred = p;
629
9.60k
    }
630
10.1k
  }
631
9.42k
  if (!in_loop_pred) {
632
    // Merge block is unreachable.
633
218
    return nullptr;
634
218
  }
635
636
9.20k
  BasicBlock* bb = context_->cfg()->block(in_loop_pred);
637
638
9.20k
  if (!bb) return nullptr;
639
640
9.20k
  const Instruction& branch = *bb->ctail();
641
642
  // Make sure the branch is a conditional branch.
643
9.20k
  if (branch.opcode() != spv::Op::OpBranchConditional) return nullptr;
644
645
  // Make sure one of the two possible branches is to the merge block.
646
9.18k
  if (branch.GetSingleWordInOperand(1) == loop_merge_->id() ||
647
9.18k
      branch.GetSingleWordInOperand(2) == loop_merge_->id()) {
648
9.18k
    condition_block = bb;
649
9.18k
  }
650
651
9.18k
  return condition_block;
652
9.20k
}
653
654
bool Loop::FindNumberOfIterations(const Instruction* induction,
655
                                  const Instruction* branch_inst,
656
                                  size_t* iterations_out,
657
                                  int64_t* step_value_out,
658
23.0k
                                  int64_t* init_value_out) const {
659
  // From the branch instruction find the branch condition.
660
23.0k
  analysis::DefUseManager* def_use_manager = context_->get_def_use_mgr();
661
662
  // Condition instruction from the OpConditionalBranch.
663
23.0k
  Instruction* condition =
664
23.0k
      def_use_manager->GetDef(branch_inst->GetSingleWordOperand(0));
665
666
23.0k
  assert(IsSupportedCondition(condition->opcode()));
667
668
  // Get the constant manager from the ir context.
669
23.0k
  analysis::ConstantManager* const_manager = context_->get_constant_mgr();
670
671
  // Find the constant value used by the condition variable. Exit out if it
672
  // isn't a constant int.
673
23.0k
  const analysis::Constant* upper_bound =
674
23.0k
      const_manager->FindDeclaredConstant(condition->GetSingleWordOperand(3));
675
23.0k
  if (!upper_bound) return false;
676
677
  // Must be integer because of the opcode on the condition.
678
22.9k
  const analysis::Integer* type = upper_bound->type()->AsInteger();
679
680
22.9k
  if (!type || type->width() > 64) {
681
0
    return false;
682
0
  }
683
684
22.9k
  int64_t condition_value = type->IsSigned()
685
22.9k
                                ? upper_bound->GetSignExtendedValue()
686
22.9k
                                : upper_bound->GetZeroExtendedValue();
687
688
  // Find the instruction which is stepping through the loop.
689
  //
690
  // GetInductionStepOperation returns nullptr if |step_inst| is OpConstantNull.
691
22.9k
  Instruction* step_inst = GetInductionStepOperation(induction);
692
22.9k
  if (!step_inst) return false;
693
694
  // Find the constant value used by the condition variable.
695
22.7k
  const analysis::Constant* step_constant =
696
22.7k
      const_manager->FindDeclaredConstant(step_inst->GetSingleWordOperand(3));
697
22.7k
  if (!step_constant) return false;
698
699
  // Must be integer because of the opcode on the condition.
700
22.7k
  int64_t step_value = 0;
701
702
22.7k
  const analysis::Integer* step_type =
703
22.7k
      step_constant->AsIntConstant()->type()->AsInteger();
704
705
22.7k
  if (step_type->IsSigned()) {
706
20.8k
    step_value = step_constant->AsIntConstant()->GetS32BitValue();
707
20.8k
  } else {
708
1.94k
    step_value = step_constant->AsIntConstant()->GetU32BitValue();
709
1.94k
  }
710
711
  // If this is a subtraction step we should negate the step value.
712
22.7k
  if (step_inst->opcode() == spv::Op::OpISub) {
713
7.91k
    step_value = -step_value;
714
7.91k
  }
715
716
  // Find the initial value of the loop and make sure it is a constant integer.
717
22.7k
  int64_t init_value = 0;
718
22.7k
  if (!GetInductionInitValue(induction, &init_value)) return false;
719
720
  // If iterations is non null then store the value in that.
721
22.7k
  int64_t num_itrs = GetIterations(condition->opcode(), condition_value,
722
22.7k
                                   init_value, step_value);
723
724
  // If the loop body will not be reached return false.
725
22.7k
  if (num_itrs <= 0) {
726
110
    return false;
727
110
  }
728
729
22.6k
  if (iterations_out) {
730
8.45k
    assert(static_cast<size_t>(num_itrs) <= std::numeric_limits<size_t>::max());
731
8.45k
    *iterations_out = static_cast<size_t>(num_itrs);
732
8.45k
  }
733
734
22.6k
  if (step_value_out) {
735
2.74k
    *step_value_out = step_value;
736
2.74k
  }
737
738
22.6k
  if (init_value_out) {
739
2.74k
    *init_value_out = init_value;
740
2.74k
  }
741
742
22.6k
  return true;
743
22.6k
}
744
745
// We retrieve the number of iterations using the following formula, diff /
746
// |step_value| where diff is calculated differently according to the
747
// |condition| and uses the |condition_value| and |init_value|. If diff /
748
// |step_value| is NOT cleanly divisible then we add one to the sum.
749
int64_t Loop::GetIterations(spv::Op condition, int64_t condition_value,
750
22.7k
                            int64_t init_value, int64_t step_value) const {
751
22.7k
  if (step_value == 0) {
752
4
    return 0;
753
4
  }
754
755
22.7k
  int64_t diff = 0;
756
757
22.7k
  switch (condition) {
758
12.2k
    case spv::Op::OpSLessThan:
759
13.6k
    case spv::Op::OpULessThan: {
760
      // If the condition is not met to begin with the loop will never iterate.
761
13.6k
      if (!(init_value < condition_value)) return 0;
762
763
13.6k
      diff = condition_value - init_value;
764
765
      // If the operation is a less then operation then the diff and step must
766
      // have the same sign otherwise the induction will never cross the
767
      // condition (either never true or always true).
768
13.6k
      if ((diff < 0 && step_value > 0) || (diff > 0 && step_value < 0)) {
769
37
        return 0;
770
37
      }
771
772
13.5k
      break;
773
13.6k
    }
774
13.5k
    case spv::Op::OpSGreaterThan:
775
5.28k
    case spv::Op::OpUGreaterThan: {
776
      // If the condition is not met to begin with the loop will never iterate.
777
5.28k
      if (!(init_value > condition_value)) return 0;
778
779
5.27k
      diff = init_value - condition_value;
780
781
      // If the operation is a greater than operation then the diff and step
782
      // must have opposite signs. Otherwise the condition will always be true
783
      // or will never be true.
784
5.27k
      if ((diff < 0 && step_value < 0) || (diff > 0 && step_value > 0)) {
785
11
        return 0;
786
11
      }
787
788
5.26k
      break;
789
5.27k
    }
790
791
5.26k
    case spv::Op::OpSGreaterThanEqual:
792
2.71k
    case spv::Op::OpUGreaterThanEqual: {
793
      // If the condition is not met to begin with the loop will never iterate.
794
2.71k
      if (!(init_value >= condition_value)) return 0;
795
796
      // We subtract one to make it the same as spv::Op::OpGreaterThan as it is
797
      // functionally equivalent.
798
2.70k
      diff = init_value - (condition_value - 1);
799
800
      // If the operation is a greater than operation then the diff and step
801
      // must have opposite signs. Otherwise the condition will always be true
802
      // or will never be true.
803
2.70k
      if ((diff > 0 && step_value > 0) || (diff < 0 && step_value < 0)) {
804
7
        return 0;
805
7
      }
806
807
2.70k
      break;
808
2.70k
    }
809
810
2.70k
    case spv::Op::OpSLessThanEqual:
811
1.08k
    case spv::Op::OpULessThanEqual: {
812
      // If the condition is not met to begin with the loop will never iterate.
813
1.08k
      if (!(init_value <= condition_value)) return 0;
814
815
      // We add one to make it the same as spv::Op::OpLessThan as it is
816
      // functionally equivalent.
817
1.08k
      diff = (condition_value + 1) - init_value;
818
819
      // If the operation is a less than operation then the diff and step must
820
      // have the same sign otherwise the induction will never cross the
821
      // condition (either never true or always true).
822
1.08k
      if ((diff < 0 && step_value > 0) || (diff > 0 && step_value < 0)) {
823
10
        return 0;
824
10
      }
825
826
1.07k
      break;
827
1.08k
    }
828
829
1.07k
    default:
830
0
      assert(false &&
831
22.7k
             "Could not retrieve number of iterations from the loop condition. "
832
22.7k
             "Condition is not supported.");
833
22.7k
  }
834
835
  // Take the abs of - step values.
836
22.6k
  step_value = llabs(step_value);
837
22.6k
  diff = llabs(diff);
838
22.6k
  int64_t result = diff / step_value;
839
840
22.6k
  if (diff % step_value != 0) {
841
13.3k
    result += 1;
842
13.3k
  }
843
22.6k
  return result;
844
22.7k
}
845
846
// Returns the list of induction variables within the loop.
847
void Loop::GetInductionVariables(
848
129k
    std::vector<Instruction*>& induction_variables) const {
849
541k
  for (Instruction& inst : *loop_header_) {
850
541k
    if (inst.opcode() == spv::Op::OpPhi) {
851
212k
      induction_variables.push_back(&inst);
852
212k
    }
853
541k
  }
854
129k
}
855
856
Instruction* Loop::FindConditionVariable(
857
9.18k
    const BasicBlock* condition_block) const {
858
  // Find the branch instruction.
859
9.18k
  const Instruction& branch_inst = *condition_block->ctail();
860
861
9.18k
  Instruction* induction = nullptr;
862
  // Verify that the branch instruction is a conditional branch.
863
9.18k
  if (branch_inst.opcode() == spv::Op::OpBranchConditional) {
864
    // From the branch instruction find the branch condition.
865
9.18k
    analysis::DefUseManager* def_use_manager = context_->get_def_use_mgr();
866
867
    // Find the instruction representing the condition used in the conditional
868
    // branch.
869
9.18k
    Instruction* condition =
870
9.18k
        def_use_manager->GetDef(branch_inst.GetSingleWordOperand(0));
871
872
    // Ensure that the condition is a less than operation.
873
9.18k
    if (condition && IsSupportedCondition(condition->opcode())) {
874
      // The left hand side operand of the operation.
875
8.98k
      Instruction* variable_inst =
876
8.98k
          def_use_manager->GetDef(condition->GetSingleWordOperand(2));
877
878
      // Make sure the variable instruction used is a phi.
879
8.98k
      if (!variable_inst || variable_inst->opcode() != spv::Op::OpPhi)
880
54
        return nullptr;
881
882
      // Make sure the phi instruction only has two incoming blocks. Each
883
      // incoming block will be represented by two in operands in the phi
884
      // instruction, the value and the block which that value came from. We
885
      // assume the cannocalised phi will have two incoming values, one from the
886
      // preheader and one from the continue block.
887
8.93k
      size_t max_supported_operands = 4;
888
8.93k
      if (variable_inst->NumInOperands() == max_supported_operands) {
889
        // The operand index of the first incoming block label.
890
8.93k
        uint32_t operand_label_1 = 1;
891
892
        // The operand index of the second incoming block label.
893
8.93k
        uint32_t operand_label_2 = 3;
894
895
        // Make sure one of them is the preheader.
896
8.93k
        if (!IsInsideLoop(
897
8.93k
                variable_inst->GetSingleWordInOperand(operand_label_1)) &&
898
8.93k
            !IsInsideLoop(
899
8.93k
                variable_inst->GetSingleWordInOperand(operand_label_2))) {
900
55
          return nullptr;
901
55
        }
902
903
        // And make sure that the other is the latch block.
904
8.87k
        if (variable_inst->GetSingleWordInOperand(operand_label_1) !=
905
8.87k
                loop_latch_->id() &&
906
8.87k
            variable_inst->GetSingleWordInOperand(operand_label_2) !=
907
8.87k
                loop_latch_->id()) {
908
0
          return nullptr;
909
0
        }
910
8.87k
      } else {
911
0
        return nullptr;
912
0
      }
913
914
8.87k
      if (!FindNumberOfIterations(variable_inst, &branch_inst, nullptr))
915
424
        return nullptr;
916
8.45k
      induction = variable_inst;
917
8.45k
    }
918
9.18k
  }
919
920
8.65k
  return induction;
921
9.18k
}
922
923
0
bool LoopDescriptor::CreatePreHeaderBlocksIfMissing() {
924
0
  auto modified = false;
925
926
0
  for (auto& loop : *this) {
927
0
    if (!loop.GetPreHeaderBlock()) {
928
0
      modified = true;
929
      // TODO(1841): Handle failure to create pre-header.
930
0
      loop.GetOrCreatePreHeaderBlock();
931
0
    }
932
0
  }
933
934
0
  return modified;
935
0
}
936
937
// Add and remove loops which have been marked for addition and removal to
938
// maintain the state of the loop descriptor class.
939
9.89k
void LoopDescriptor::PostModificationCleanup() {
940
9.89k
  LoopContainerType loops_to_remove_;
941
18.9k
  for (Loop* loop : loops_) {
942
18.9k
    if (loop->IsMarkedForRemoval()) {
943
2.74k
      loops_to_remove_.push_back(loop);
944
2.74k
      if (loop->HasParent()) {
945
789
        loop->GetParent()->RemoveChildLoop(loop);
946
789
      }
947
2.74k
    }
948
18.9k
  }
949
950
9.89k
  for (Loop* loop : loops_to_remove_) {
951
2.74k
    loops_.erase(std::find(loops_.begin(), loops_.end(), loop));
952
2.74k
    delete loop;
953
2.74k
  }
954
955
9.89k
  for (auto& pair : loops_to_add_) {
956
0
    Loop* parent = pair.first;
957
0
    std::unique_ptr<Loop> loop = std::move(pair.second);
958
959
0
    if (parent) {
960
0
      loop->SetParent(nullptr);
961
0
      parent->AddNestedLoop(loop.get());
962
963
0
      for (uint32_t block_id : loop->GetBlocks()) {
964
0
        parent->AddBasicBlock(block_id);
965
0
      }
966
0
    }
967
968
0
    loops_.emplace_back(loop.release());
969
0
  }
970
971
9.89k
  loops_to_add_.clear();
972
9.89k
}
973
974
39.5k
void LoopDescriptor::ClearLoops() {
975
39.5k
  for (Loop* loop : loops_) {
976
16.2k
    delete loop;
977
16.2k
  }
978
39.5k
  loops_.clear();
979
39.5k
}
980
981
// Adds a new loop nest to the descriptor set.
982
0
Loop* LoopDescriptor::AddLoopNest(std::unique_ptr<Loop> new_loop) {
983
0
  Loop* loop = new_loop.release();
984
0
  if (!loop->HasParent()) placeholder_top_loop_.nested_loops_.push_back(loop);
985
  // Iterate from inner to outer most loop, adding basic block to loop mapping
986
  // as we go.
987
0
  for (Loop& current_loop :
988
0
       make_range(iterator::begin(loop), iterator::end(nullptr))) {
989
0
    loops_.push_back(&current_loop);
990
0
    for (uint32_t bb_id : current_loop.GetBlocks())
991
0
      basic_block_to_loop_.insert(std::make_pair(bb_id, &current_loop));
992
0
  }
993
994
0
  return loop;
995
0
}
996
997
0
void LoopDescriptor::RemoveLoop(Loop* loop) {
998
0
  Loop* parent = loop->GetParent() ? loop->GetParent() : &placeholder_top_loop_;
999
0
  parent->nested_loops_.erase(std::find(parent->nested_loops_.begin(),
1000
0
                                        parent->nested_loops_.end(), loop));
1001
0
  std::for_each(
1002
0
      loop->nested_loops_.begin(), loop->nested_loops_.end(),
1003
0
      [loop](Loop* sub_loop) { sub_loop->SetParent(loop->GetParent()); });
1004
0
  parent->nested_loops_.insert(parent->nested_loops_.end(),
1005
0
                               loop->nested_loops_.begin(),
1006
0
                               loop->nested_loops_.end());
1007
0
  for (uint32_t bb_id : loop->GetBlocks()) {
1008
0
    Loop* l = FindLoopForBasicBlock(bb_id);
1009
0
    if (l == loop) {
1010
0
      SetBasicBlockToLoop(bb_id, l->GetParent());
1011
0
    } else {
1012
0
      ForgetBasicBlock(bb_id);
1013
0
    }
1014
0
  }
1015
1016
0
  LoopContainerType::iterator it =
1017
0
      std::find(loops_.begin(), loops_.end(), loop);
1018
0
  assert(it != loops_.end());
1019
0
  delete loop;
1020
0
  loops_.erase(it);
1021
0
}
1022
1023
}  // namespace opt
1024
}  // namespace spvtools