/src/spirv-tools/source/opt/loop_dependence_helpers.cpp
Line | Count | Source |
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 <ostream> |
16 | | #include <set> |
17 | | #include <string> |
18 | | #include <unordered_set> |
19 | | #include <utility> |
20 | | #include <vector> |
21 | | |
22 | | #include "source/opt/basic_block.h" |
23 | | #include "source/opt/instruction.h" |
24 | | #include "source/opt/loop_dependence.h" |
25 | | #include "source/opt/scalar_analysis_nodes.h" |
26 | | |
27 | | namespace spvtools { |
28 | | namespace opt { |
29 | | |
30 | | bool LoopDependenceAnalysis::IsZIV( |
31 | 0 | const std::pair<SENode*, SENode*>& subscript_pair) { |
32 | 0 | return CountInductionVariables(subscript_pair.first, subscript_pair.second) == |
33 | 0 | 0; |
34 | 0 | } |
35 | | |
36 | | bool LoopDependenceAnalysis::IsSIV( |
37 | 0 | const std::pair<SENode*, SENode*>& subscript_pair) { |
38 | 0 | return CountInductionVariables(subscript_pair.first, subscript_pair.second) == |
39 | 0 | 1; |
40 | 0 | } |
41 | | |
42 | | bool LoopDependenceAnalysis::IsMIV( |
43 | 0 | const std::pair<SENode*, SENode*>& subscript_pair) { |
44 | 0 | return CountInductionVariables(subscript_pair.first, subscript_pair.second) > |
45 | 0 | 1; |
46 | 0 | } |
47 | | |
48 | 0 | SENode* LoopDependenceAnalysis::GetLowerBound(const Loop* loop) { |
49 | 0 | Instruction* cond_inst = loop->GetConditionInst(); |
50 | 0 | if (!cond_inst) { |
51 | 0 | return nullptr; |
52 | 0 | } |
53 | 0 | Instruction* lower_inst = GetOperandDefinition(cond_inst, 0); |
54 | 0 | switch (cond_inst->opcode()) { |
55 | 0 | case spv::Op::OpULessThan: |
56 | 0 | case spv::Op::OpSLessThan: |
57 | 0 | case spv::Op::OpULessThanEqual: |
58 | 0 | case spv::Op::OpSLessThanEqual: |
59 | 0 | case spv::Op::OpUGreaterThan: |
60 | 0 | case spv::Op::OpSGreaterThan: |
61 | 0 | case spv::Op::OpUGreaterThanEqual: |
62 | 0 | case spv::Op::OpSGreaterThanEqual: { |
63 | | // If we have a phi we are looking at the induction variable. We look |
64 | | // through the phi to the initial value of the phi upon entering the loop. |
65 | 0 | if (lower_inst->opcode() == spv::Op::OpPhi) { |
66 | 0 | lower_inst = GetOperandDefinition(lower_inst, 0); |
67 | | // We don't handle looking through multiple phis. |
68 | 0 | if (lower_inst->opcode() == spv::Op::OpPhi) { |
69 | 0 | return nullptr; |
70 | 0 | } |
71 | 0 | } |
72 | 0 | return scalar_evolution_.SimplifyExpression( |
73 | 0 | scalar_evolution_.AnalyzeInstruction(lower_inst)); |
74 | 0 | } |
75 | 0 | default: |
76 | 0 | return nullptr; |
77 | 0 | } |
78 | 0 | } |
79 | | |
80 | 0 | SENode* LoopDependenceAnalysis::GetUpperBound(const Loop* loop) { |
81 | 0 | Instruction* cond_inst = loop->GetConditionInst(); |
82 | 0 | if (!cond_inst) { |
83 | 0 | return nullptr; |
84 | 0 | } |
85 | 0 | Instruction* upper_inst = GetOperandDefinition(cond_inst, 1); |
86 | 0 | switch (cond_inst->opcode()) { |
87 | 0 | case spv::Op::OpULessThan: |
88 | 0 | case spv::Op::OpSLessThan: { |
89 | | // When we have a < condition we must subtract 1 from the analyzed upper |
90 | | // instruction. |
91 | 0 | SENode* upper_bound = scalar_evolution_.SimplifyExpression( |
92 | 0 | scalar_evolution_.CreateSubtraction( |
93 | 0 | scalar_evolution_.AnalyzeInstruction(upper_inst), |
94 | 0 | scalar_evolution_.CreateConstant(1))); |
95 | 0 | return upper_bound; |
96 | 0 | } |
97 | 0 | case spv::Op::OpUGreaterThan: |
98 | 0 | case spv::Op::OpSGreaterThan: { |
99 | | // When we have a > condition we must add 1 to the analyzed upper |
100 | | // instruction. |
101 | 0 | SENode* upper_bound = |
102 | 0 | scalar_evolution_.SimplifyExpression(scalar_evolution_.CreateAddNode( |
103 | 0 | scalar_evolution_.AnalyzeInstruction(upper_inst), |
104 | 0 | scalar_evolution_.CreateConstant(1))); |
105 | 0 | return upper_bound; |
106 | 0 | } |
107 | 0 | case spv::Op::OpULessThanEqual: |
108 | 0 | case spv::Op::OpSLessThanEqual: |
109 | 0 | case spv::Op::OpUGreaterThanEqual: |
110 | 0 | case spv::Op::OpSGreaterThanEqual: { |
111 | | // We don't need to modify the results of analyzing when we have <= or >=. |
112 | 0 | SENode* upper_bound = scalar_evolution_.SimplifyExpression( |
113 | 0 | scalar_evolution_.AnalyzeInstruction(upper_inst)); |
114 | 0 | return upper_bound; |
115 | 0 | } |
116 | 0 | default: |
117 | 0 | return nullptr; |
118 | 0 | } |
119 | 0 | } |
120 | | |
121 | | bool LoopDependenceAnalysis::IsWithinBounds(int64_t value, int64_t bound_one, |
122 | 0 | int64_t bound_two) { |
123 | 0 | if (bound_one < bound_two) { |
124 | | // If |bound_one| is the lower bound. |
125 | 0 | return (value >= bound_one && value <= bound_two); |
126 | 0 | } else if (bound_one > bound_two) { |
127 | | // If |bound_two| is the lower bound. |
128 | 0 | return (value >= bound_two && value <= bound_one); |
129 | 0 | } else { |
130 | | // Both bounds have the same value. |
131 | 0 | return value == bound_one; |
132 | 0 | } |
133 | 0 | } |
134 | | |
135 | | bool LoopDependenceAnalysis::IsProvablyOutsideOfLoopBounds( |
136 | 0 | const Loop* loop, SENode* distance, SENode* coefficient) { |
137 | | // We test to see if we can reduce the coefficient to an integral constant. |
138 | 0 | SEConstantNode* coefficient_constant = coefficient->AsSEConstantNode(); |
139 | 0 | if (!coefficient_constant) { |
140 | 0 | PrintDebug( |
141 | 0 | "IsProvablyOutsideOfLoopBounds could not reduce coefficient to a " |
142 | 0 | "SEConstantNode so must exit."); |
143 | 0 | return false; |
144 | 0 | } |
145 | | |
146 | 0 | SENode* lower_bound = GetLowerBound(loop); |
147 | 0 | SENode* upper_bound = GetUpperBound(loop); |
148 | 0 | if (!lower_bound || !upper_bound) { |
149 | 0 | PrintDebug( |
150 | 0 | "IsProvablyOutsideOfLoopBounds could not get both the lower and upper " |
151 | 0 | "bounds so must exit."); |
152 | 0 | return false; |
153 | 0 | } |
154 | | // If the coefficient is positive we calculate bounds as upper - lower |
155 | | // If the coefficient is negative we calculate bounds as lower - upper |
156 | 0 | SENode* bounds = nullptr; |
157 | 0 | if (coefficient_constant->FoldToSingleValue() >= 0) { |
158 | 0 | PrintDebug( |
159 | 0 | "IsProvablyOutsideOfLoopBounds found coefficient >= 0.\n" |
160 | 0 | "Using bounds as upper - lower."); |
161 | 0 | bounds = scalar_evolution_.SimplifyExpression( |
162 | 0 | scalar_evolution_.CreateSubtraction(upper_bound, lower_bound)); |
163 | 0 | } else { |
164 | 0 | PrintDebug( |
165 | 0 | "IsProvablyOutsideOfLoopBounds found coefficient < 0.\n" |
166 | 0 | "Using bounds as lower - upper."); |
167 | 0 | bounds = scalar_evolution_.SimplifyExpression( |
168 | 0 | scalar_evolution_.CreateSubtraction(lower_bound, upper_bound)); |
169 | 0 | } |
170 | | |
171 | | // We can attempt to deal with symbolic cases by subtracting |distance| and |
172 | | // the bound nodes. If we can subtract, simplify and produce a SEConstantNode |
173 | | // we can produce some information. |
174 | 0 | SEConstantNode* distance_minus_bounds = |
175 | 0 | scalar_evolution_ |
176 | 0 | .SimplifyExpression( |
177 | 0 | scalar_evolution_.CreateSubtraction(distance, bounds)) |
178 | 0 | ->AsSEConstantNode(); |
179 | 0 | if (distance_minus_bounds) { |
180 | 0 | PrintDebug( |
181 | 0 | "IsProvablyOutsideOfLoopBounds found distance - bounds as a " |
182 | 0 | "SEConstantNode with value " + |
183 | 0 | ToString(distance_minus_bounds->FoldToSingleValue())); |
184 | | // If distance - bounds > 0 we prove the distance is outwith the loop |
185 | | // bounds. |
186 | 0 | if (distance_minus_bounds->FoldToSingleValue() > 0) { |
187 | 0 | PrintDebug( |
188 | 0 | "IsProvablyOutsideOfLoopBounds found distance escaped the loop " |
189 | 0 | "bounds."); |
190 | 0 | return true; |
191 | 0 | } |
192 | 0 | } |
193 | | |
194 | 0 | return false; |
195 | 0 | } |
196 | | |
197 | | const Loop* LoopDependenceAnalysis::GetLoopForSubscriptPair( |
198 | 0 | const std::pair<SENode*, SENode*>& subscript_pair) { |
199 | | // Collect all the SERecurrentNodes. |
200 | 0 | std::vector<SERecurrentNode*> source_nodes = |
201 | 0 | std::get<0>(subscript_pair)->CollectRecurrentNodes(); |
202 | 0 | std::vector<SERecurrentNode*> destination_nodes = |
203 | 0 | std::get<1>(subscript_pair)->CollectRecurrentNodes(); |
204 | | |
205 | | // Collect all the loops stored by the SERecurrentNodes. |
206 | 0 | std::unordered_set<const Loop*> loops{}; |
207 | 0 | for (auto source_nodes_it = source_nodes.begin(); |
208 | 0 | source_nodes_it != source_nodes.end(); ++source_nodes_it) { |
209 | 0 | loops.insert((*source_nodes_it)->GetLoop()); |
210 | 0 | } |
211 | 0 | for (auto destination_nodes_it = destination_nodes.begin(); |
212 | 0 | destination_nodes_it != destination_nodes.end(); |
213 | 0 | ++destination_nodes_it) { |
214 | 0 | loops.insert((*destination_nodes_it)->GetLoop()); |
215 | 0 | } |
216 | | |
217 | | // If we didn't find 1 loop |subscript_pair| is a subscript over multiple or 0 |
218 | | // loops. We don't handle this so return nullptr. |
219 | 0 | if (loops.size() != 1) { |
220 | 0 | PrintDebug("GetLoopForSubscriptPair found loops.size() != 1."); |
221 | 0 | return nullptr; |
222 | 0 | } |
223 | 0 | return *loops.begin(); |
224 | 0 | } |
225 | | |
226 | | DistanceEntry* LoopDependenceAnalysis::GetDistanceEntryForLoop( |
227 | 0 | const Loop* loop, DistanceVector* distance_vector) { |
228 | 0 | if (!loop) { |
229 | 0 | return nullptr; |
230 | 0 | } |
231 | | |
232 | 0 | DistanceEntry* distance_entry = nullptr; |
233 | 0 | for (size_t loop_index = 0; loop_index < loops_.size(); ++loop_index) { |
234 | 0 | if (loop == loops_[loop_index]) { |
235 | 0 | distance_entry = &(distance_vector->GetEntries()[loop_index]); |
236 | 0 | break; |
237 | 0 | } |
238 | 0 | } |
239 | |
|
240 | 0 | return distance_entry; |
241 | 0 | } |
242 | | |
243 | | DistanceEntry* LoopDependenceAnalysis::GetDistanceEntryForSubscriptPair( |
244 | | const std::pair<SENode*, SENode*>& subscript_pair, |
245 | 0 | DistanceVector* distance_vector) { |
246 | 0 | const Loop* loop = GetLoopForSubscriptPair(subscript_pair); |
247 | |
|
248 | 0 | return GetDistanceEntryForLoop(loop, distance_vector); |
249 | 0 | } |
250 | | |
251 | 0 | SENode* LoopDependenceAnalysis::GetTripCount(const Loop* loop) { |
252 | 0 | BasicBlock* condition_block = loop->FindConditionBlock(); |
253 | 0 | if (!condition_block) { |
254 | 0 | return nullptr; |
255 | 0 | } |
256 | 0 | Instruction* induction_instr = loop->FindConditionVariable(condition_block); |
257 | 0 | if (!induction_instr) { |
258 | 0 | return nullptr; |
259 | 0 | } |
260 | 0 | Instruction* cond_instr = loop->GetConditionInst(); |
261 | 0 | if (!cond_instr) { |
262 | 0 | return nullptr; |
263 | 0 | } |
264 | | |
265 | 0 | size_t iteration_count = 0; |
266 | | |
267 | | // We have to check the instruction type here. If the condition instruction |
268 | | // isn't a supported type we can't calculate the trip count. |
269 | 0 | if (loop->IsSupportedCondition(cond_instr->opcode())) { |
270 | 0 | if (loop->FindNumberOfIterations(induction_instr, &*condition_block->tail(), |
271 | 0 | &iteration_count)) { |
272 | 0 | return scalar_evolution_.CreateConstant( |
273 | 0 | static_cast<int64_t>(iteration_count)); |
274 | 0 | } |
275 | 0 | } |
276 | | |
277 | 0 | return nullptr; |
278 | 0 | } |
279 | | |
280 | 0 | SENode* LoopDependenceAnalysis::GetFirstTripInductionNode(const Loop* loop) { |
281 | 0 | BasicBlock* condition_block = loop->FindConditionBlock(); |
282 | 0 | if (!condition_block) { |
283 | 0 | return nullptr; |
284 | 0 | } |
285 | 0 | Instruction* induction_instr = loop->FindConditionVariable(condition_block); |
286 | 0 | if (!induction_instr) { |
287 | 0 | return nullptr; |
288 | 0 | } |
289 | 0 | int64_t induction_initial_value = 0; |
290 | 0 | if (!loop->GetInductionInitValue(induction_instr, &induction_initial_value)) { |
291 | 0 | return nullptr; |
292 | 0 | } |
293 | | |
294 | 0 | SENode* induction_init_SENode = scalar_evolution_.SimplifyExpression( |
295 | 0 | scalar_evolution_.CreateConstant(induction_initial_value)); |
296 | 0 | return induction_init_SENode; |
297 | 0 | } |
298 | | |
299 | | SENode* LoopDependenceAnalysis::GetFinalTripInductionNode( |
300 | 0 | const Loop* loop, SENode* induction_coefficient) { |
301 | 0 | SENode* first_trip_induction_node = GetFirstTripInductionNode(loop); |
302 | 0 | if (!first_trip_induction_node) { |
303 | 0 | return nullptr; |
304 | 0 | } |
305 | | // Get trip_count as GetTripCount - 1 |
306 | | // This is because the induction variable is not stepped on the first |
307 | | // iteration of the loop |
308 | 0 | SENode* trip_count = |
309 | 0 | scalar_evolution_.SimplifyExpression(scalar_evolution_.CreateSubtraction( |
310 | 0 | GetTripCount(loop), scalar_evolution_.CreateConstant(1))); |
311 | | // Return first_trip_induction_node + trip_count * induction_coefficient |
312 | 0 | return scalar_evolution_.SimplifyExpression(scalar_evolution_.CreateAddNode( |
313 | 0 | first_trip_induction_node, |
314 | 0 | scalar_evolution_.CreateMultiplyNode(trip_count, induction_coefficient))); |
315 | 0 | } |
316 | | |
317 | | std::set<const Loop*> LoopDependenceAnalysis::CollectLoops( |
318 | 0 | const std::vector<SERecurrentNode*>& recurrent_nodes) { |
319 | | // We don't handle loops with more than one induction variable. Therefore we |
320 | | // can identify the number of induction variables by collecting all of the |
321 | | // loops the collected recurrent nodes belong to. |
322 | 0 | std::set<const Loop*> loops{}; |
323 | 0 | for (auto recurrent_nodes_it = recurrent_nodes.begin(); |
324 | 0 | recurrent_nodes_it != recurrent_nodes.end(); ++recurrent_nodes_it) { |
325 | 0 | loops.insert((*recurrent_nodes_it)->GetLoop()); |
326 | 0 | } |
327 | |
|
328 | 0 | return loops; |
329 | 0 | } |
330 | | |
331 | 0 | int64_t LoopDependenceAnalysis::CountInductionVariables(SENode* node) { |
332 | 0 | if (!node) { |
333 | 0 | return -1; |
334 | 0 | } |
335 | | |
336 | 0 | std::vector<SERecurrentNode*> recurrent_nodes = node->CollectRecurrentNodes(); |
337 | | |
338 | | // We don't handle loops with more than one induction variable. Therefore we |
339 | | // can identify the number of induction variables by collecting all of the |
340 | | // loops the collected recurrent nodes belong to. |
341 | 0 | std::set<const Loop*> loops = CollectLoops(recurrent_nodes); |
342 | |
|
343 | 0 | return static_cast<int64_t>(loops.size()); |
344 | 0 | } |
345 | | |
346 | | std::set<const Loop*> LoopDependenceAnalysis::CollectLoops( |
347 | 0 | SENode* source, SENode* destination) { |
348 | 0 | if (!source || !destination) { |
349 | 0 | return std::set<const Loop*>{}; |
350 | 0 | } |
351 | | |
352 | 0 | std::vector<SERecurrentNode*> source_nodes = source->CollectRecurrentNodes(); |
353 | 0 | std::vector<SERecurrentNode*> destination_nodes = |
354 | 0 | destination->CollectRecurrentNodes(); |
355 | |
|
356 | 0 | std::set<const Loop*> loops = CollectLoops(source_nodes); |
357 | 0 | std::set<const Loop*> destination_loops = CollectLoops(destination_nodes); |
358 | |
|
359 | 0 | loops.insert(std::begin(destination_loops), std::end(destination_loops)); |
360 | |
|
361 | 0 | return loops; |
362 | 0 | } |
363 | | |
364 | | int64_t LoopDependenceAnalysis::CountInductionVariables(SENode* source, |
365 | 0 | SENode* destination) { |
366 | 0 | if (!source || !destination) { |
367 | 0 | return -1; |
368 | 0 | } |
369 | | |
370 | 0 | std::set<const Loop*> loops = CollectLoops(source, destination); |
371 | |
|
372 | 0 | return static_cast<int64_t>(loops.size()); |
373 | 0 | } |
374 | | |
375 | | Instruction* LoopDependenceAnalysis::GetOperandDefinition( |
376 | 0 | const Instruction* instruction, int id) { |
377 | 0 | return context_->get_def_use_mgr()->GetDef( |
378 | 0 | instruction->GetSingleWordInOperand(id)); |
379 | 0 | } |
380 | | |
381 | | std::vector<Instruction*> LoopDependenceAnalysis::GetSubscripts( |
382 | 0 | const Instruction* instruction) { |
383 | 0 | Instruction* access_chain = GetOperandDefinition(instruction, 0); |
384 | |
|
385 | 0 | std::vector<Instruction*> subscripts; |
386 | |
|
387 | 0 | for (auto i = 1u; i < access_chain->NumInOperandWords(); ++i) { |
388 | 0 | subscripts.push_back(GetOperandDefinition(access_chain, i)); |
389 | 0 | } |
390 | |
|
391 | 0 | return subscripts; |
392 | 0 | } |
393 | | |
394 | | SENode* LoopDependenceAnalysis::GetConstantTerm(const Loop* loop, |
395 | 0 | SERecurrentNode* induction) { |
396 | 0 | SENode* offset = induction->GetOffset(); |
397 | 0 | SENode* lower_bound = GetLowerBound(loop); |
398 | 0 | if (!offset || !lower_bound) { |
399 | 0 | return nullptr; |
400 | 0 | } |
401 | 0 | SENode* constant_term = scalar_evolution_.SimplifyExpression( |
402 | 0 | scalar_evolution_.CreateSubtraction(offset, lower_bound)); |
403 | 0 | return constant_term; |
404 | 0 | } |
405 | | |
406 | | bool LoopDependenceAnalysis::CheckSupportedLoops( |
407 | 0 | std::vector<const Loop*> loops) { |
408 | 0 | for (auto loop : loops) { |
409 | 0 | if (!IsSupportedLoop(loop)) { |
410 | 0 | return false; |
411 | 0 | } |
412 | 0 | } |
413 | 0 | return true; |
414 | 0 | } |
415 | | |
416 | | void LoopDependenceAnalysis::MarkUnsusedDistanceEntriesAsIrrelevant( |
417 | | const Instruction* source, const Instruction* destination, |
418 | 0 | DistanceVector* distance_vector) { |
419 | 0 | std::vector<Instruction*> source_subscripts = GetSubscripts(source); |
420 | 0 | std::vector<Instruction*> destination_subscripts = GetSubscripts(destination); |
421 | |
|
422 | 0 | std::set<const Loop*> used_loops{}; |
423 | |
|
424 | 0 | for (Instruction* source_inst : source_subscripts) { |
425 | 0 | SENode* source_node = scalar_evolution_.SimplifyExpression( |
426 | 0 | scalar_evolution_.AnalyzeInstruction(source_inst)); |
427 | 0 | std::vector<SERecurrentNode*> recurrent_nodes = |
428 | 0 | source_node->CollectRecurrentNodes(); |
429 | 0 | for (SERecurrentNode* recurrent_node : recurrent_nodes) { |
430 | 0 | used_loops.insert(recurrent_node->GetLoop()); |
431 | 0 | } |
432 | 0 | } |
433 | |
|
434 | 0 | for (Instruction* destination_inst : destination_subscripts) { |
435 | 0 | SENode* destination_node = scalar_evolution_.SimplifyExpression( |
436 | 0 | scalar_evolution_.AnalyzeInstruction(destination_inst)); |
437 | 0 | std::vector<SERecurrentNode*> recurrent_nodes = |
438 | 0 | destination_node->CollectRecurrentNodes(); |
439 | 0 | for (SERecurrentNode* recurrent_node : recurrent_nodes) { |
440 | 0 | used_loops.insert(recurrent_node->GetLoop()); |
441 | 0 | } |
442 | 0 | } |
443 | |
|
444 | 0 | for (size_t i = 0; i < loops_.size(); ++i) { |
445 | 0 | if (used_loops.find(loops_[i]) == used_loops.end()) { |
446 | 0 | distance_vector->GetEntries()[i].dependence_information = |
447 | 0 | DistanceEntry::DependenceInformation::IRRELEVANT; |
448 | 0 | } |
449 | 0 | } |
450 | 0 | } |
451 | | |
452 | 0 | bool LoopDependenceAnalysis::IsSupportedLoop(const Loop* loop) { |
453 | 0 | std::vector<Instruction*> inductions{}; |
454 | 0 | loop->GetInductionVariables(inductions); |
455 | 0 | if (inductions.size() != 1) { |
456 | 0 | return false; |
457 | 0 | } |
458 | 0 | Instruction* induction = inductions[0]; |
459 | 0 | SENode* induction_node = scalar_evolution_.SimplifyExpression( |
460 | 0 | scalar_evolution_.AnalyzeInstruction(induction)); |
461 | 0 | if (!induction_node->AsSERecurrentNode()) { |
462 | 0 | return false; |
463 | 0 | } |
464 | 0 | SENode* induction_step = |
465 | 0 | induction_node->AsSERecurrentNode()->GetCoefficient(); |
466 | 0 | if (!induction_step->AsSEConstantNode()) { |
467 | 0 | return false; |
468 | 0 | } |
469 | 0 | if (!(induction_step->AsSEConstantNode()->FoldToSingleValue() == 1 || |
470 | 0 | induction_step->AsSEConstantNode()->FoldToSingleValue() == -1)) { |
471 | 0 | return false; |
472 | 0 | } |
473 | 0 | return true; |
474 | 0 | } |
475 | | |
476 | 0 | void LoopDependenceAnalysis::PrintDebug(std::string debug_msg) { |
477 | 0 | if (debug_stream_) { |
478 | 0 | (*debug_stream_) << debug_msg << "\n"; |
479 | 0 | } |
480 | 0 | } |
481 | | |
482 | 0 | bool Constraint::operator==(const Constraint& other) const { |
483 | | // A distance of |d| is equivalent to a line |x - y = -d| |
484 | 0 | if ((GetType() == ConstraintType::Distance && |
485 | 0 | other.GetType() == ConstraintType::Line) || |
486 | 0 | (GetType() == ConstraintType::Line && |
487 | 0 | other.GetType() == ConstraintType::Distance)) { |
488 | 0 | auto is_distance = AsDependenceLine() != nullptr; |
489 | |
|
490 | 0 | auto as_distance = |
491 | 0 | is_distance ? AsDependenceDistance() : other.AsDependenceDistance(); |
492 | 0 | auto distance = as_distance->GetDistance(); |
493 | |
|
494 | 0 | auto line = other.AsDependenceLine(); |
495 | |
|
496 | 0 | auto scalar_evolution = distance->GetParentAnalysis(); |
497 | |
|
498 | 0 | auto neg_distance = scalar_evolution->SimplifyExpression( |
499 | 0 | scalar_evolution->CreateNegation(distance)); |
500 | |
|
501 | 0 | return *scalar_evolution->CreateConstant(1) == *line->GetA() && |
502 | 0 | *scalar_evolution->CreateConstant(-1) == *line->GetB() && |
503 | 0 | *neg_distance == *line->GetC(); |
504 | 0 | } |
505 | | |
506 | 0 | if (GetType() != other.GetType()) { |
507 | 0 | return false; |
508 | 0 | } |
509 | | |
510 | 0 | if (AsDependenceDistance()) { |
511 | 0 | return *AsDependenceDistance()->GetDistance() == |
512 | 0 | *other.AsDependenceDistance()->GetDistance(); |
513 | 0 | } |
514 | | |
515 | 0 | if (AsDependenceLine()) { |
516 | 0 | auto this_line = AsDependenceLine(); |
517 | 0 | auto other_line = other.AsDependenceLine(); |
518 | 0 | return *this_line->GetA() == *other_line->GetA() && |
519 | 0 | *this_line->GetB() == *other_line->GetB() && |
520 | 0 | *this_line->GetC() == *other_line->GetC(); |
521 | 0 | } |
522 | | |
523 | 0 | if (AsDependencePoint()) { |
524 | 0 | auto this_point = AsDependencePoint(); |
525 | 0 | auto other_point = other.AsDependencePoint(); |
526 | |
|
527 | 0 | return *this_point->GetSource() == *other_point->GetSource() && |
528 | 0 | *this_point->GetDestination() == *other_point->GetDestination(); |
529 | 0 | } |
530 | | |
531 | 0 | return true; |
532 | 0 | } |
533 | | |
534 | 0 | bool Constraint::operator!=(const Constraint& other) const { |
535 | 0 | return !(*this == other); |
536 | 0 | } |
537 | | |
538 | | } // namespace opt |
539 | | } // namespace spvtools |