| 1 | // Copyright (c) 2018 Google LLC. | 
|---|
| 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_fusion_pass.h" | 
|---|
| 16 |  | 
|---|
| 17 | #include "source/opt/ir_context.h" | 
|---|
| 18 | #include "source/opt/loop_descriptor.h" | 
|---|
| 19 | #include "source/opt/loop_fusion.h" | 
|---|
| 20 | #include "source/opt/register_pressure.h" | 
|---|
| 21 |  | 
|---|
| 22 | namespace spvtools { | 
|---|
| 23 | namespace opt { | 
|---|
| 24 |  | 
|---|
| 25 | Pass::Status LoopFusionPass::Process() { | 
|---|
| 26 | bool modified = false; | 
|---|
| 27 | Module* module = context()->module(); | 
|---|
| 28 |  | 
|---|
| 29 | // Process each function in the module | 
|---|
| 30 | for (Function& f : *module) { | 
|---|
| 31 | modified |= ProcessFunction(&f); | 
|---|
| 32 | } | 
|---|
| 33 |  | 
|---|
| 34 | return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange; | 
|---|
| 35 | } | 
|---|
| 36 |  | 
|---|
| 37 | bool LoopFusionPass::ProcessFunction(Function* function) { | 
|---|
| 38 | LoopDescriptor& ld = *context()->GetLoopDescriptor(function); | 
|---|
| 39 |  | 
|---|
| 40 | // If a loop doesn't have a preheader needs then it needs to be created. Make | 
|---|
| 41 | // sure to return Status::SuccessWithChange in that case. | 
|---|
| 42 | auto modified = ld.CreatePreHeaderBlocksIfMissing(); | 
|---|
| 43 |  | 
|---|
| 44 | // TODO(tremmelg): Could the only loop that |loop| could possibly be fused be | 
|---|
| 45 | // picked out so don't have to check every loop | 
|---|
| 46 | for (auto& loop_0 : ld) { | 
|---|
| 47 | for (auto& loop_1 : ld) { | 
|---|
| 48 | LoopFusion fusion(context(), &loop_0, &loop_1); | 
|---|
| 49 |  | 
|---|
| 50 | if (fusion.AreCompatible() && fusion.IsLegal()) { | 
|---|
| 51 | RegisterLiveness liveness(context(), function); | 
|---|
| 52 | RegisterLiveness::RegionRegisterLiveness reg_pressure{}; | 
|---|
| 53 | liveness.SimulateFusion(loop_0, loop_1, ®_pressure); | 
|---|
| 54 |  | 
|---|
| 55 | if (reg_pressure.used_registers_ <= max_registers_per_loop_) { | 
|---|
| 56 | fusion.Fuse(); | 
|---|
| 57 | // Recurse, as the current iterators will have been invalidated. | 
|---|
| 58 | ProcessFunction(function); | 
|---|
| 59 | return true; | 
|---|
| 60 | } | 
|---|
| 61 | } | 
|---|
| 62 | } | 
|---|
| 63 | } | 
|---|
| 64 |  | 
|---|
| 65 | return modified; | 
|---|
| 66 | } | 
|---|
| 67 |  | 
|---|
| 68 | }  // namespace opt | 
|---|
| 69 | }  // namespace spvtools | 
|---|
| 70 |  | 
|---|