| // Copyright (c) 2021 Google LLC. | |
| // | |
| // Licensed under the Apache License, Version 2.0 (the "License"); | |
| // you may not use this file except in compliance with the License. | |
| // You may obtain a copy of the License at | |
| // | |
| // http://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, software | |
| // distributed under the License is distributed on an "AS IS" BASIS, | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| // See the License for the specific language governing permissions and | |
| // limitations under the License. | |
| #include "source/opt/dataflow.h" | |
| #include <cstdint> | |
| namespace spvtools { | |
| namespace opt { | |
| bool DataFlowAnalysis::Enqueue(Instruction* inst) { | |
| bool& is_enqueued = on_worklist_[inst]; | |
| if (is_enqueued) return false; | |
| is_enqueued = true; | |
| worklist_.push(inst); | |
| return true; | |
| } | |
| DataFlowAnalysis::VisitResult DataFlowAnalysis::RunOnce( | |
| Function* function, bool is_first_iteration) { | |
| InitializeWorklist(function, is_first_iteration); | |
| VisitResult ret = VisitResult::kResultFixed; | |
| while (!worklist_.empty()) { | |
| Instruction* top = worklist_.front(); | |
| worklist_.pop(); | |
| on_worklist_[top] = false; | |
| VisitResult result = Visit(top); | |
| if (result == VisitResult::kResultChanged) { | |
| EnqueueSuccessors(top); | |
| ret = VisitResult::kResultChanged; | |
| } | |
| } | |
| return ret; | |
| } | |
| void DataFlowAnalysis::Run(Function* function) { | |
| VisitResult result = RunOnce(function, true); | |
| while (result == VisitResult::kResultChanged) { | |
| result = RunOnce(function, false); | |
| } | |
| } | |
| void ForwardDataFlowAnalysis::InitializeWorklist(Function* function, | |
| bool /*is_first_iteration*/) { | |
| context().cfg()->ForEachBlockInReversePostOrder( | |
| function->entry().get(), [this](BasicBlock* bb) { | |
| if (label_position_ == LabelPosition::kLabelsOnly) { | |
| Enqueue(bb->GetLabelInst()); | |
| return; | |
| } | |
| if (label_position_ == LabelPosition::kLabelsAtBeginning) { | |
| Enqueue(bb->GetLabelInst()); | |
| } | |
| for (Instruction& inst : *bb) { | |
| Enqueue(&inst); | |
| } | |
| if (label_position_ == LabelPosition::kLabelsAtEnd) { | |
| Enqueue(bb->GetLabelInst()); | |
| } | |
| }); | |
| } | |
| void ForwardDataFlowAnalysis::EnqueueUsers(Instruction* inst) { | |
| context().get_def_use_mgr()->ForEachUser( | |
| inst, [this](Instruction* user) { Enqueue(user); }); | |
| } | |
| void ForwardDataFlowAnalysis::EnqueueBlockSuccessors(Instruction* inst) { | |
| if (inst->opcode() != spv::Op::OpLabel) return; | |
| context() | |
| .cfg() | |
| ->block(inst->result_id()) | |
| ->ForEachSuccessorLabel([this](uint32_t* label) { | |
| Enqueue(context().cfg()->block(*label)->GetLabelInst()); | |
| }); | |
| } | |
| } // namespace opt | |
| } // namespace spvtools |