| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539 |
- // Copyright (c) 2018 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 <ostream>
- #include <set>
- #include <string>
- #include <unordered_set>
- #include <utility>
- #include <vector>
- #include "source/opt/basic_block.h"
- #include "source/opt/instruction.h"
- #include "source/opt/loop_dependence.h"
- #include "source/opt/scalar_analysis_nodes.h"
- namespace spvtools {
- namespace opt {
- bool LoopDependenceAnalysis::IsZIV(
- const std::pair<SENode*, SENode*>& subscript_pair) {
- return CountInductionVariables(subscript_pair.first, subscript_pair.second) ==
- 0;
- }
- bool LoopDependenceAnalysis::IsSIV(
- const std::pair<SENode*, SENode*>& subscript_pair) {
- return CountInductionVariables(subscript_pair.first, subscript_pair.second) ==
- 1;
- }
- bool LoopDependenceAnalysis::IsMIV(
- const std::pair<SENode*, SENode*>& subscript_pair) {
- return CountInductionVariables(subscript_pair.first, subscript_pair.second) >
- 1;
- }
- SENode* LoopDependenceAnalysis::GetLowerBound(const Loop* loop) {
- Instruction* cond_inst = loop->GetConditionInst();
- if (!cond_inst) {
- return nullptr;
- }
- Instruction* lower_inst = GetOperandDefinition(cond_inst, 0);
- switch (cond_inst->opcode()) {
- case spv::Op::OpULessThan:
- case spv::Op::OpSLessThan:
- case spv::Op::OpULessThanEqual:
- case spv::Op::OpSLessThanEqual:
- case spv::Op::OpUGreaterThan:
- case spv::Op::OpSGreaterThan:
- case spv::Op::OpUGreaterThanEqual:
- case spv::Op::OpSGreaterThanEqual: {
- // If we have a phi we are looking at the induction variable. We look
- // through the phi to the initial value of the phi upon entering the loop.
- if (lower_inst->opcode() == spv::Op::OpPhi) {
- lower_inst = GetOperandDefinition(lower_inst, 0);
- // We don't handle looking through multiple phis.
- if (lower_inst->opcode() == spv::Op::OpPhi) {
- return nullptr;
- }
- }
- return scalar_evolution_.SimplifyExpression(
- scalar_evolution_.AnalyzeInstruction(lower_inst));
- }
- default:
- return nullptr;
- }
- }
- SENode* LoopDependenceAnalysis::GetUpperBound(const Loop* loop) {
- Instruction* cond_inst = loop->GetConditionInst();
- if (!cond_inst) {
- return nullptr;
- }
- Instruction* upper_inst = GetOperandDefinition(cond_inst, 1);
- switch (cond_inst->opcode()) {
- case spv::Op::OpULessThan:
- case spv::Op::OpSLessThan: {
- // When we have a < condition we must subtract 1 from the analyzed upper
- // instruction.
- SENode* upper_bound = scalar_evolution_.SimplifyExpression(
- scalar_evolution_.CreateSubtraction(
- scalar_evolution_.AnalyzeInstruction(upper_inst),
- scalar_evolution_.CreateConstant(1)));
- return upper_bound;
- }
- case spv::Op::OpUGreaterThan:
- case spv::Op::OpSGreaterThan: {
- // When we have a > condition we must add 1 to the analyzed upper
- // instruction.
- SENode* upper_bound =
- scalar_evolution_.SimplifyExpression(scalar_evolution_.CreateAddNode(
- scalar_evolution_.AnalyzeInstruction(upper_inst),
- scalar_evolution_.CreateConstant(1)));
- return upper_bound;
- }
- case spv::Op::OpULessThanEqual:
- case spv::Op::OpSLessThanEqual:
- case spv::Op::OpUGreaterThanEqual:
- case spv::Op::OpSGreaterThanEqual: {
- // We don't need to modify the results of analyzing when we have <= or >=.
- SENode* upper_bound = scalar_evolution_.SimplifyExpression(
- scalar_evolution_.AnalyzeInstruction(upper_inst));
- return upper_bound;
- }
- default:
- return nullptr;
- }
- }
- bool LoopDependenceAnalysis::IsWithinBounds(int64_t value, int64_t bound_one,
- int64_t bound_two) {
- if (bound_one < bound_two) {
- // If |bound_one| is the lower bound.
- return (value >= bound_one && value <= bound_two);
- } else if (bound_one > bound_two) {
- // If |bound_two| is the lower bound.
- return (value >= bound_two && value <= bound_one);
- } else {
- // Both bounds have the same value.
- return value == bound_one;
- }
- }
- bool LoopDependenceAnalysis::IsProvablyOutsideOfLoopBounds(
- const Loop* loop, SENode* distance, SENode* coefficient) {
- // We test to see if we can reduce the coefficient to an integral constant.
- SEConstantNode* coefficient_constant = coefficient->AsSEConstantNode();
- if (!coefficient_constant) {
- PrintDebug(
- "IsProvablyOutsideOfLoopBounds could not reduce coefficient to a "
- "SEConstantNode so must exit.");
- return false;
- }
- SENode* lower_bound = GetLowerBound(loop);
- SENode* upper_bound = GetUpperBound(loop);
- if (!lower_bound || !upper_bound) {
- PrintDebug(
- "IsProvablyOutsideOfLoopBounds could not get both the lower and upper "
- "bounds so must exit.");
- return false;
- }
- // If the coefficient is positive we calculate bounds as upper - lower
- // If the coefficient is negative we calculate bounds as lower - upper
- SENode* bounds = nullptr;
- if (coefficient_constant->FoldToSingleValue() >= 0) {
- PrintDebug(
- "IsProvablyOutsideOfLoopBounds found coefficient >= 0.\n"
- "Using bounds as upper - lower.");
- bounds = scalar_evolution_.SimplifyExpression(
- scalar_evolution_.CreateSubtraction(upper_bound, lower_bound));
- } else {
- PrintDebug(
- "IsProvablyOutsideOfLoopBounds found coefficient < 0.\n"
- "Using bounds as lower - upper.");
- bounds = scalar_evolution_.SimplifyExpression(
- scalar_evolution_.CreateSubtraction(lower_bound, upper_bound));
- }
- // We can attempt to deal with symbolic cases by subtracting |distance| and
- // the bound nodes. If we can subtract, simplify and produce a SEConstantNode
- // we can produce some information.
- SEConstantNode* distance_minus_bounds =
- scalar_evolution_
- .SimplifyExpression(
- scalar_evolution_.CreateSubtraction(distance, bounds))
- ->AsSEConstantNode();
- if (distance_minus_bounds) {
- PrintDebug(
- "IsProvablyOutsideOfLoopBounds found distance - bounds as a "
- "SEConstantNode with value " +
- ToString(distance_minus_bounds->FoldToSingleValue()));
- // If distance - bounds > 0 we prove the distance is outwith the loop
- // bounds.
- if (distance_minus_bounds->FoldToSingleValue() > 0) {
- PrintDebug(
- "IsProvablyOutsideOfLoopBounds found distance escaped the loop "
- "bounds.");
- return true;
- }
- }
- return false;
- }
- const Loop* LoopDependenceAnalysis::GetLoopForSubscriptPair(
- const std::pair<SENode*, SENode*>& subscript_pair) {
- // Collect all the SERecurrentNodes.
- std::vector<SERecurrentNode*> source_nodes =
- std::get<0>(subscript_pair)->CollectRecurrentNodes();
- std::vector<SERecurrentNode*> destination_nodes =
- std::get<1>(subscript_pair)->CollectRecurrentNodes();
- // Collect all the loops stored by the SERecurrentNodes.
- std::unordered_set<const Loop*> loops{};
- for (auto source_nodes_it = source_nodes.begin();
- source_nodes_it != source_nodes.end(); ++source_nodes_it) {
- loops.insert((*source_nodes_it)->GetLoop());
- }
- for (auto destination_nodes_it = destination_nodes.begin();
- destination_nodes_it != destination_nodes.end();
- ++destination_nodes_it) {
- loops.insert((*destination_nodes_it)->GetLoop());
- }
- // If we didn't find 1 loop |subscript_pair| is a subscript over multiple or 0
- // loops. We don't handle this so return nullptr.
- if (loops.size() != 1) {
- PrintDebug("GetLoopForSubscriptPair found loops.size() != 1.");
- return nullptr;
- }
- return *loops.begin();
- }
- DistanceEntry* LoopDependenceAnalysis::GetDistanceEntryForLoop(
- const Loop* loop, DistanceVector* distance_vector) {
- if (!loop) {
- return nullptr;
- }
- DistanceEntry* distance_entry = nullptr;
- for (size_t loop_index = 0; loop_index < loops_.size(); ++loop_index) {
- if (loop == loops_[loop_index]) {
- distance_entry = &(distance_vector->GetEntries()[loop_index]);
- break;
- }
- }
- return distance_entry;
- }
- DistanceEntry* LoopDependenceAnalysis::GetDistanceEntryForSubscriptPair(
- const std::pair<SENode*, SENode*>& subscript_pair,
- DistanceVector* distance_vector) {
- const Loop* loop = GetLoopForSubscriptPair(subscript_pair);
- return GetDistanceEntryForLoop(loop, distance_vector);
- }
- SENode* LoopDependenceAnalysis::GetTripCount(const Loop* loop) {
- BasicBlock* condition_block = loop->FindConditionBlock();
- if (!condition_block) {
- return nullptr;
- }
- Instruction* induction_instr = loop->FindConditionVariable(condition_block);
- if (!induction_instr) {
- return nullptr;
- }
- Instruction* cond_instr = loop->GetConditionInst();
- if (!cond_instr) {
- return nullptr;
- }
- size_t iteration_count = 0;
- // We have to check the instruction type here. If the condition instruction
- // isn't a supported type we can't calculate the trip count.
- if (loop->IsSupportedCondition(cond_instr->opcode())) {
- if (loop->FindNumberOfIterations(induction_instr, &*condition_block->tail(),
- &iteration_count)) {
- return scalar_evolution_.CreateConstant(
- static_cast<int64_t>(iteration_count));
- }
- }
- return nullptr;
- }
- SENode* LoopDependenceAnalysis::GetFirstTripInductionNode(const Loop* loop) {
- BasicBlock* condition_block = loop->FindConditionBlock();
- if (!condition_block) {
- return nullptr;
- }
- Instruction* induction_instr = loop->FindConditionVariable(condition_block);
- if (!induction_instr) {
- return nullptr;
- }
- int64_t induction_initial_value = 0;
- if (!loop->GetInductionInitValue(induction_instr, &induction_initial_value)) {
- return nullptr;
- }
- SENode* induction_init_SENode = scalar_evolution_.SimplifyExpression(
- scalar_evolution_.CreateConstant(induction_initial_value));
- return induction_init_SENode;
- }
- SENode* LoopDependenceAnalysis::GetFinalTripInductionNode(
- const Loop* loop, SENode* induction_coefficient) {
- SENode* first_trip_induction_node = GetFirstTripInductionNode(loop);
- if (!first_trip_induction_node) {
- return nullptr;
- }
- // Get trip_count as GetTripCount - 1
- // This is because the induction variable is not stepped on the first
- // iteration of the loop
- SENode* trip_count =
- scalar_evolution_.SimplifyExpression(scalar_evolution_.CreateSubtraction(
- GetTripCount(loop), scalar_evolution_.CreateConstant(1)));
- // Return first_trip_induction_node + trip_count * induction_coefficient
- return scalar_evolution_.SimplifyExpression(scalar_evolution_.CreateAddNode(
- first_trip_induction_node,
- scalar_evolution_.CreateMultiplyNode(trip_count, induction_coefficient)));
- }
- std::set<const Loop*> LoopDependenceAnalysis::CollectLoops(
- const std::vector<SERecurrentNode*>& recurrent_nodes) {
- // We don't handle loops with more than one induction variable. Therefore we
- // can identify the number of induction variables by collecting all of the
- // loops the collected recurrent nodes belong to.
- std::set<const Loop*> loops{};
- for (auto recurrent_nodes_it = recurrent_nodes.begin();
- recurrent_nodes_it != recurrent_nodes.end(); ++recurrent_nodes_it) {
- loops.insert((*recurrent_nodes_it)->GetLoop());
- }
- return loops;
- }
- int64_t LoopDependenceAnalysis::CountInductionVariables(SENode* node) {
- if (!node) {
- return -1;
- }
- std::vector<SERecurrentNode*> recurrent_nodes = node->CollectRecurrentNodes();
- // We don't handle loops with more than one induction variable. Therefore we
- // can identify the number of induction variables by collecting all of the
- // loops the collected recurrent nodes belong to.
- std::set<const Loop*> loops = CollectLoops(recurrent_nodes);
- return static_cast<int64_t>(loops.size());
- }
- std::set<const Loop*> LoopDependenceAnalysis::CollectLoops(
- SENode* source, SENode* destination) {
- if (!source || !destination) {
- return std::set<const Loop*>{};
- }
- std::vector<SERecurrentNode*> source_nodes = source->CollectRecurrentNodes();
- std::vector<SERecurrentNode*> destination_nodes =
- destination->CollectRecurrentNodes();
- std::set<const Loop*> loops = CollectLoops(source_nodes);
- std::set<const Loop*> destination_loops = CollectLoops(destination_nodes);
- loops.insert(std::begin(destination_loops), std::end(destination_loops));
- return loops;
- }
- int64_t LoopDependenceAnalysis::CountInductionVariables(SENode* source,
- SENode* destination) {
- if (!source || !destination) {
- return -1;
- }
- std::set<const Loop*> loops = CollectLoops(source, destination);
- return static_cast<int64_t>(loops.size());
- }
- Instruction* LoopDependenceAnalysis::GetOperandDefinition(
- const Instruction* instruction, int id) {
- return context_->get_def_use_mgr()->GetDef(
- instruction->GetSingleWordInOperand(id));
- }
- std::vector<Instruction*> LoopDependenceAnalysis::GetSubscripts(
- const Instruction* instruction) {
- Instruction* access_chain = GetOperandDefinition(instruction, 0);
- std::vector<Instruction*> subscripts;
- for (auto i = 1u; i < access_chain->NumInOperandWords(); ++i) {
- subscripts.push_back(GetOperandDefinition(access_chain, i));
- }
- return subscripts;
- }
- SENode* LoopDependenceAnalysis::GetConstantTerm(const Loop* loop,
- SERecurrentNode* induction) {
- SENode* offset = induction->GetOffset();
- SENode* lower_bound = GetLowerBound(loop);
- if (!offset || !lower_bound) {
- return nullptr;
- }
- SENode* constant_term = scalar_evolution_.SimplifyExpression(
- scalar_evolution_.CreateSubtraction(offset, lower_bound));
- return constant_term;
- }
- bool LoopDependenceAnalysis::CheckSupportedLoops(
- std::vector<const Loop*> loops) {
- for (auto loop : loops) {
- if (!IsSupportedLoop(loop)) {
- return false;
- }
- }
- return true;
- }
- void LoopDependenceAnalysis::MarkUnsusedDistanceEntriesAsIrrelevant(
- const Instruction* source, const Instruction* destination,
- DistanceVector* distance_vector) {
- std::vector<Instruction*> source_subscripts = GetSubscripts(source);
- std::vector<Instruction*> destination_subscripts = GetSubscripts(destination);
- std::set<const Loop*> used_loops{};
- for (Instruction* source_inst : source_subscripts) {
- SENode* source_node = scalar_evolution_.SimplifyExpression(
- scalar_evolution_.AnalyzeInstruction(source_inst));
- std::vector<SERecurrentNode*> recurrent_nodes =
- source_node->CollectRecurrentNodes();
- for (SERecurrentNode* recurrent_node : recurrent_nodes) {
- used_loops.insert(recurrent_node->GetLoop());
- }
- }
- for (Instruction* destination_inst : destination_subscripts) {
- SENode* destination_node = scalar_evolution_.SimplifyExpression(
- scalar_evolution_.AnalyzeInstruction(destination_inst));
- std::vector<SERecurrentNode*> recurrent_nodes =
- destination_node->CollectRecurrentNodes();
- for (SERecurrentNode* recurrent_node : recurrent_nodes) {
- used_loops.insert(recurrent_node->GetLoop());
- }
- }
- for (size_t i = 0; i < loops_.size(); ++i) {
- if (used_loops.find(loops_[i]) == used_loops.end()) {
- distance_vector->GetEntries()[i].dependence_information =
- DistanceEntry::DependenceInformation::IRRELEVANT;
- }
- }
- }
- bool LoopDependenceAnalysis::IsSupportedLoop(const Loop* loop) {
- std::vector<Instruction*> inductions{};
- loop->GetInductionVariables(inductions);
- if (inductions.size() != 1) {
- return false;
- }
- Instruction* induction = inductions[0];
- SENode* induction_node = scalar_evolution_.SimplifyExpression(
- scalar_evolution_.AnalyzeInstruction(induction));
- if (!induction_node->AsSERecurrentNode()) {
- return false;
- }
- SENode* induction_step =
- induction_node->AsSERecurrentNode()->GetCoefficient();
- if (!induction_step->AsSEConstantNode()) {
- return false;
- }
- if (!(induction_step->AsSEConstantNode()->FoldToSingleValue() == 1 ||
- induction_step->AsSEConstantNode()->FoldToSingleValue() == -1)) {
- return false;
- }
- return true;
- }
- void LoopDependenceAnalysis::PrintDebug(std::string debug_msg) {
- if (debug_stream_) {
- (*debug_stream_) << debug_msg << "\n";
- }
- }
- bool Constraint::operator==(const Constraint& other) const {
- // A distance of |d| is equivalent to a line |x - y = -d|
- if ((GetType() == ConstraintType::Distance &&
- other.GetType() == ConstraintType::Line) ||
- (GetType() == ConstraintType::Line &&
- other.GetType() == ConstraintType::Distance)) {
- auto is_distance = AsDependenceLine() != nullptr;
- auto as_distance =
- is_distance ? AsDependenceDistance() : other.AsDependenceDistance();
- auto distance = as_distance->GetDistance();
- auto line = other.AsDependenceLine();
- auto scalar_evolution = distance->GetParentAnalysis();
- auto neg_distance = scalar_evolution->SimplifyExpression(
- scalar_evolution->CreateNegation(distance));
- return *scalar_evolution->CreateConstant(1) == *line->GetA() &&
- *scalar_evolution->CreateConstant(-1) == *line->GetB() &&
- *neg_distance == *line->GetC();
- }
- if (GetType() != other.GetType()) {
- return false;
- }
- if (AsDependenceDistance()) {
- return *AsDependenceDistance()->GetDistance() ==
- *other.AsDependenceDistance()->GetDistance();
- }
- if (AsDependenceLine()) {
- auto this_line = AsDependenceLine();
- auto other_line = other.AsDependenceLine();
- return *this_line->GetA() == *other_line->GetA() &&
- *this_line->GetB() == *other_line->GetB() &&
- *this_line->GetC() == *other_line->GetC();
- }
- if (AsDependencePoint()) {
- auto this_point = AsDependencePoint();
- auto other_point = other.AsDependencePoint();
- return *this_point->GetSource() == *other_point->GetSource() &&
- *this_point->GetDestination() == *other_point->GetDestination();
- }
- return true;
- }
- bool Constraint::operator!=(const Constraint& other) const {
- return !(*this == other);
- }
- } // namespace opt
- } // namespace spvtools
|