| 1035 | * */ |
| 1036 | |
| 1037 | bool LoopUtils::CanPerformUnroll() { |
| 1038 | // The loop is expected to be in structured order. |
| 1039 | if (!loop_->GetHeaderBlock()->GetMergeInst()) { |
| 1040 | return false; |
| 1041 | } |
| 1042 | |
| 1043 | // Find check the loop has a condition we can find and evaluate. |
| 1044 | const BasicBlock* condition = loop_->FindConditionBlock(); |
| 1045 | if (!condition) return false; |
| 1046 | |
| 1047 | // Check that we can find and process the induction variable. |
| 1048 | const Instruction* induction = loop_->FindConditionVariable(condition); |
| 1049 | if (!induction || induction->opcode() != spv::Op::OpPhi) return false; |
| 1050 | |
| 1051 | // Check that we can find the number of loop iterations. |
| 1052 | if (!loop_->FindNumberOfIterations(induction, &*condition->ctail(), nullptr)) |
| 1053 | return false; |
| 1054 | |
| 1055 | #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION |
| 1056 | // ClusterFuzz/OSS-Fuzz is likely to yield examples with very high loop |
| 1057 | // iteration counts. This can cause timeouts and memouts during fuzzing that |
| 1058 | // are not classed as bugs. To avoid this noise, loop unrolling is not applied |
| 1059 | // to loops with large iteration counts when fuzzing. |
| 1060 | constexpr size_t kFuzzerIterationLimit = 100; |
| 1061 | size_t num_iterations; |
| 1062 | loop_->FindNumberOfIterations(induction, &*condition->ctail(), |
| 1063 | &num_iterations); |
| 1064 | if (num_iterations > kFuzzerIterationLimit) { |
| 1065 | return false; |
| 1066 | } |
| 1067 | #endif |
| 1068 | |
| 1069 | // Make sure the latch block is a unconditional branch to the header |
| 1070 | // block. |
| 1071 | const Instruction& branch = *loop_->GetLatchBlock()->ctail(); |
| 1072 | bool branching_assumption = |
| 1073 | branch.opcode() == spv::Op::OpBranch && |
| 1074 | branch.GetSingleWordInOperand(0) == loop_->GetHeaderBlock()->id(); |
| 1075 | if (!branching_assumption) { |
| 1076 | return false; |
| 1077 | } |
| 1078 | |
| 1079 | std::vector<Instruction*> inductions; |
| 1080 | loop_->GetInductionVariables(inductions); |
| 1081 | |
| 1082 | // Ban breaks within the loop. |
| 1083 | const std::vector<uint32_t>& merge_block_preds = |
| 1084 | context_->cfg()->preds(loop_->GetMergeBlock()->id()); |
| 1085 | if (merge_block_preds.size() != 1) { |
| 1086 | return false; |
| 1087 | } |
| 1088 | |
| 1089 | // Ban continues within the loop. |
| 1090 | const std::vector<uint32_t>& continue_block_preds = |
| 1091 | context_->cfg()->preds(loop_->GetContinueBlock()->id()); |
| 1092 | if (continue_block_preds.size() != 1) { |
| 1093 | return false; |
| 1094 | } |
no test coverage detected