blob: a0760eff6916427ca2a536eb243a223fc11acf92 [file] [log] [blame]
Artem Serov121f2032017-10-23 19:19:06 +01001/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "loop_analysis.h"
18
Artem Serov72411e62017-10-19 16:18:07 +010019#include "base/bit_vector-inl.h"
20
Artem Serov121f2032017-10-23 19:19:06 +010021namespace art {
22
23void LoopAnalysis::CalculateLoopBasicProperties(HLoopInformation* loop_info,
24 LoopAnalysisInfo* analysis_results) {
25 for (HBlocksInLoopIterator block_it(*loop_info);
26 !block_it.Done();
27 block_it.Advance()) {
28 HBasicBlock* block = block_it.Current();
29
30 for (HBasicBlock* successor : block->GetSuccessors()) {
31 if (!loop_info->Contains(*successor)) {
32 analysis_results->exits_num_++;
33 }
34 }
35
36 for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
37 HInstruction* instruction = it.Current();
Artem Serov72411e62017-10-19 16:18:07 +010038 if (MakesScalarPeelingUnrollingNonBeneficial(instruction)) {
39 analysis_results->has_instructions_preventing_scalar_peeling_ = true;
Artem Serov121f2032017-10-23 19:19:06 +010040 analysis_results->has_instructions_preventing_scalar_unrolling_ = true;
41 }
42 analysis_results->instr_num_++;
43 }
44 analysis_results->bb_num_++;
45 }
46}
47
Artem Serov72411e62017-10-19 16:18:07 +010048bool LoopAnalysis::HasLoopAtLeastOneInvariantExit(HLoopInformation* loop_info) {
49 HGraph* graph = loop_info->GetHeader()->GetGraph();
50 for (uint32_t block_id : loop_info->GetBlocks().Indexes()) {
51 HBasicBlock* block = graph->GetBlocks()[block_id];
52 DCHECK(block != nullptr);
53 if (block->EndsWithIf()) {
54 HIf* hif = block->GetLastInstruction()->AsIf();
55 HInstruction* input = hif->InputAt(0);
56 if (IsLoopExit(loop_info, hif) && !loop_info->Contains(*input->GetBlock())) {
57 return true;
58 }
59 }
60 }
61 return false;
62}
63
Artem Serov121f2032017-10-23 19:19:06 +010064class Arm64LoopHelper : public ArchDefaultLoopHelper {
65 public:
66 // Scalar loop unrolling parameters and heuristics.
67 //
68 // Maximum possible unrolling factor.
69 static constexpr uint32_t kArm64ScalarMaxUnrollFactor = 2;
70 // Loop's maximum instruction count. Loops with higher count will not be peeled/unrolled.
71 static constexpr uint32_t kArm64ScalarHeuristicMaxBodySizeInstr = 40;
72 // Loop's maximum basic block count. Loops with higher count will not be peeled/unrolled.
73 static constexpr uint32_t kArm64ScalarHeuristicMaxBodySizeBlocks = 8;
74
75 // SIMD loop unrolling parameters and heuristics.
76 //
77 // Maximum possible unrolling factor.
78 static constexpr uint32_t kArm64SimdMaxUnrollFactor = 8;
79 // Loop's maximum instruction count. Loops with higher count will not be unrolled.
80 static constexpr uint32_t kArm64SimdHeuristicMaxBodySizeInstr = 50;
81
Artem Serov72411e62017-10-19 16:18:07 +010082 bool IsLoopTooBigForScalarPeelingUnrolling(LoopAnalysisInfo* loop_analysis_info) const OVERRIDE {
Artem Serov121f2032017-10-23 19:19:06 +010083 size_t instr_num = loop_analysis_info->GetNumberOfInstructions();
84 size_t bb_num = loop_analysis_info->GetNumberOfBasicBlocks();
85 return (instr_num >= kArm64ScalarHeuristicMaxBodySizeInstr ||
86 bb_num >= kArm64ScalarHeuristicMaxBodySizeBlocks);
87 }
88
89 uint32_t GetScalarUnrollingFactor(HLoopInformation* loop_info ATTRIBUTE_UNUSED,
90 uint64_t trip_count) const OVERRIDE {
91 uint32_t desired_unrolling_factor = kArm64ScalarMaxUnrollFactor;
92 if (trip_count < desired_unrolling_factor || trip_count % desired_unrolling_factor != 0) {
93 return kNoUnrollingFactor;
94 }
95
96 return desired_unrolling_factor;
97 }
98
Artem Serov72411e62017-10-19 16:18:07 +010099 bool IsLoopPeelingEnabled() const OVERRIDE { return true; }
100
Artem Serov121f2032017-10-23 19:19:06 +0100101 uint32_t GetSIMDUnrollingFactor(HBasicBlock* block,
102 int64_t trip_count,
103 uint32_t max_peel,
104 uint32_t vector_length) const OVERRIDE {
105 // Don't unroll with insufficient iterations.
106 // TODO: Unroll loops with unknown trip count.
107 DCHECK_NE(vector_length, 0u);
108 if (trip_count < (2 * vector_length + max_peel)) {
109 return kNoUnrollingFactor;
110 }
111 // Don't unroll for large loop body size.
112 uint32_t instruction_count = block->GetInstructions().CountSize();
113 if (instruction_count >= kArm64SimdHeuristicMaxBodySizeInstr) {
114 return kNoUnrollingFactor;
115 }
116 // Find a beneficial unroll factor with the following restrictions:
117 // - At least one iteration of the transformed loop should be executed.
118 // - The loop body shouldn't be "too big" (heuristic).
119
120 uint32_t uf1 = kArm64SimdHeuristicMaxBodySizeInstr / instruction_count;
121 uint32_t uf2 = (trip_count - max_peel) / vector_length;
122 uint32_t unroll_factor =
123 TruncToPowerOfTwo(std::min({uf1, uf2, kArm64SimdMaxUnrollFactor}));
124 DCHECK_GE(unroll_factor, 1u);
125 return unroll_factor;
126 }
127};
128
129ArchDefaultLoopHelper* ArchDefaultLoopHelper::Create(InstructionSet isa,
130 ArenaAllocator* allocator) {
131 switch (isa) {
132 case InstructionSet::kArm64: {
133 return new (allocator) Arm64LoopHelper;
134 }
135 default: {
136 return new (allocator) ArchDefaultLoopHelper;
137 }
138 }
139}
140
141} // namespace art