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