Coverage Report

Created: 2024-10-22 16:19

/home/runner/work/DirectXShaderCompiler/DirectXShaderCompiler/external/SPIRV-Tools/source/opt/loop_dependence.cpp
Line
Count
Source (jump to first uncovered line)
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_dependence.h"
16
17
#include <functional>
18
#include <numeric>
19
#include <string>
20
#include <utility>
21
#include <vector>
22
23
#include "source/opt/instruction.h"
24
#include "source/opt/scalar_analysis_nodes.h"
25
26
namespace spvtools {
27
namespace opt {
28
29
using SubscriptPair = std::pair<SENode*, SENode*>;
30
31
namespace {
32
33
// Calculate the greatest common divisor of a & b using Stein's algorithm.
34
// https://en.wikipedia.org/wiki/Binary_GCD_algorithm
35
0
int64_t GreatestCommonDivisor(int64_t a, int64_t b) {
36
  // Simple cases
37
0
  if (a == b) {
38
0
    return a;
39
0
  } else if (a == 0) {
40
0
    return b;
41
0
  } else if (b == 0) {
42
0
    return a;
43
0
  }
44
45
  // Both even
46
0
  if (a % 2 == 0 && b % 2 == 0) {
47
0
    return 2 * GreatestCommonDivisor(a / 2, b / 2);
48
0
  }
49
50
  // Even a, odd b
51
0
  if (a % 2 == 0 && b % 2 == 1) {
52
0
    return GreatestCommonDivisor(a / 2, b);
53
0
  }
54
55
  // Odd a, even b
56
0
  if (a % 2 == 1 && b % 2 == 0) {
57
0
    return GreatestCommonDivisor(a, b / 2);
58
0
  }
59
60
  // Both odd, reduce the larger argument
61
0
  if (a > b) {
62
0
    return GreatestCommonDivisor((a - b) / 2, b);
63
0
  } else {
64
0
    return GreatestCommonDivisor((b - a) / 2, a);
65
0
  }
66
0
}
67
68
// Check if node is affine, ie in the form: a0*i0 + a1*i1 + ... an*in + c
69
// and contains only the following types of nodes: SERecurrentNode, SEAddNode
70
// and SEConstantNode
71
0
bool IsInCorrectFormForGCDTest(SENode* node) {
72
0
  bool children_ok = true;
73
74
0
  if (auto add_node = node->AsSEAddNode()) {
75
0
    for (auto child : add_node->GetChildren()) {
76
0
      children_ok &= IsInCorrectFormForGCDTest(child);
77
0
    }
78
0
  }
79
80
0
  bool this_ok = node->AsSERecurrentNode() || node->AsSEAddNode() ||
81
0
                 node->AsSEConstantNode();
82
83
0
  return children_ok && this_ok;
84
0
}
85
86
// If |node| is an SERecurrentNode then returns |node| or if |node| is an
87
// SEAddNode returns a vector of SERecurrentNode that are its children.
88
0
std::vector<SERecurrentNode*> GetAllTopLevelRecurrences(SENode* node) {
89
0
  auto nodes = std::vector<SERecurrentNode*>{};
90
0
  if (auto recurrent_node = node->AsSERecurrentNode()) {
91
0
    nodes.push_back(recurrent_node);
92
0
  }
93
94
0
  if (auto add_node = node->AsSEAddNode()) {
95
0
    for (auto child : add_node->GetChildren()) {
96
0
      auto child_nodes = GetAllTopLevelRecurrences(child);
97
0
      nodes.insert(nodes.end(), child_nodes.begin(), child_nodes.end());
98
0
    }
99
0
  }
100
101
0
  return nodes;
102
0
}
103
104
// If |node| is an SEConstantNode then returns |node| or if |node| is an
105
// SEAddNode returns a vector of SEConstantNode that are its children.
106
0
std::vector<SEConstantNode*> GetAllTopLevelConstants(SENode* node) {
107
0
  auto nodes = std::vector<SEConstantNode*>{};
108
0
  if (auto recurrent_node = node->AsSEConstantNode()) {
109
0
    nodes.push_back(recurrent_node);
110
0
  }
111
112
0
  if (auto add_node = node->AsSEAddNode()) {
113
0
    for (auto child : add_node->GetChildren()) {
114
0
      auto child_nodes = GetAllTopLevelConstants(child);
115
0
      nodes.insert(nodes.end(), child_nodes.begin(), child_nodes.end());
116
0
    }
117
0
  }
118
119
0
  return nodes;
120
0
}
121
122
bool AreOffsetsAndCoefficientsConstant(
123
0
    const std::vector<SERecurrentNode*>& nodes) {
124
0
  for (auto node : nodes) {
125
0
    if (!node->GetOffset()->AsSEConstantNode() ||
126
0
        !node->GetOffset()->AsSEConstantNode()) {
127
0
      return false;
128
0
    }
129
0
  }
130
0
  return true;
131
0
}
132
133
// Fold all SEConstantNode that appear in |recurrences| and |constants| into a
134
// single integer value.
135
int64_t CalculateConstantTerm(const std::vector<SERecurrentNode*>& recurrences,
136
0
                              const std::vector<SEConstantNode*>& constants) {
137
0
  int64_t constant_term = 0;
138
0
  for (auto recurrence : recurrences) {
139
0
    constant_term +=
140
0
        recurrence->GetOffset()->AsSEConstantNode()->FoldToSingleValue();
141
0
  }
142
143
0
  for (auto constant : constants) {
144
0
    constant_term += constant->FoldToSingleValue();
145
0
  }
146
147
0
  return constant_term;
148
0
}
149
150
int64_t CalculateGCDFromCoefficients(
151
0
    const std::vector<SERecurrentNode*>& recurrences, int64_t running_gcd) {
152
0
  for (SERecurrentNode* recurrence : recurrences) {
153
0
    auto coefficient = recurrence->GetCoefficient()->AsSEConstantNode();
154
155
0
    running_gcd = GreatestCommonDivisor(
156
0
        running_gcd, std::abs(coefficient->FoldToSingleValue()));
157
0
  }
158
159
0
  return running_gcd;
160
0
}
161
162
// Compare 2 fractions while first normalizing them, e.g. 2/4 and 4/8 will both
163
// be simplified to 1/2 and then determined to be equal.
164
bool NormalizeAndCompareFractions(int64_t numerator_0, int64_t denominator_0,
165
0
                                  int64_t numerator_1, int64_t denominator_1) {
166
0
  auto gcd_0 =
167
0
      GreatestCommonDivisor(std::abs(numerator_0), std::abs(denominator_0));
168
0
  auto gcd_1 =
169
0
      GreatestCommonDivisor(std::abs(numerator_1), std::abs(denominator_1));
170
171
0
  auto normalized_numerator_0 = numerator_0 / gcd_0;
172
0
  auto normalized_denominator_0 = denominator_0 / gcd_0;
173
0
  auto normalized_numerator_1 = numerator_1 / gcd_1;
174
0
  auto normalized_denominator_1 = denominator_1 / gcd_1;
175
176
0
  return normalized_numerator_0 == normalized_numerator_1 &&
177
0
         normalized_denominator_0 == normalized_denominator_1;
178
0
}
179
180
}  // namespace
181
182
bool LoopDependenceAnalysis::GetDependence(const Instruction* source,
183
                                           const Instruction* destination,
184
0
                                           DistanceVector* distance_vector) {
185
  // Start off by finding and marking all the loops in |loops_| that are
186
  // irrelevant to the dependence analysis.
187
0
  MarkUnsusedDistanceEntriesAsIrrelevant(source, destination, distance_vector);
188
189
0
  Instruction* source_access_chain = GetOperandDefinition(source, 0);
190
0
  Instruction* destination_access_chain = GetOperandDefinition(destination, 0);
191
192
0
  auto num_access_chains =
193
0
      (source_access_chain->opcode() == spv::Op::OpAccessChain) +
194
0
      (destination_access_chain->opcode() == spv::Op::OpAccessChain);
195
196
  // If neither is an access chain, then they are load/store to a variable.
197
0
  if (num_access_chains == 0) {
198
0
    if (source_access_chain != destination_access_chain) {
199
      // Not the same location, report independence
200
0
      return true;
201
0
    } else {
202
      // Accessing the same variable
203
0
      for (auto& entry : distance_vector->GetEntries()) {
204
0
        entry = DistanceEntry();
205
0
      }
206
0
      return false;
207
0
    }
208
0
  }
209
210
  // If only one is an access chain, it could be accessing a part of a struct
211
0
  if (num_access_chains == 1) {
212
0
    auto source_is_chain =
213
0
        source_access_chain->opcode() == spv::Op::OpAccessChain;
214
0
    auto access_chain =
215
0
        source_is_chain ? source_access_chain : destination_access_chain;
216
0
    auto variable =
217
0
        source_is_chain ? destination_access_chain : source_access_chain;
218
219
0
    auto location_in_chain = GetOperandDefinition(access_chain, 0);
220
221
0
    if (variable != location_in_chain) {
222
      // Not the same location, report independence
223
0
      return true;
224
0
    } else {
225
      // Accessing the same variable
226
0
      for (auto& entry : distance_vector->GetEntries()) {
227
0
        entry = DistanceEntry();
228
0
      }
229
0
      return false;
230
0
    }
231
0
  }
232
233
  // If the access chains aren't collecting from the same structure there is no
234
  // dependence.
235
0
  Instruction* source_array = GetOperandDefinition(source_access_chain, 0);
236
0
  Instruction* destination_array =
237
0
      GetOperandDefinition(destination_access_chain, 0);
238
239
  // Nested access chains are not supported yet, bail out.
240
0
  if (source_array->opcode() == spv::Op::OpAccessChain ||
241
0
      destination_array->opcode() == spv::Op::OpAccessChain) {
242
0
    for (auto& entry : distance_vector->GetEntries()) {
243
0
      entry = DistanceEntry();
244
0
    }
245
0
    return false;
246
0
  }
247
248
0
  if (source_array != destination_array) {
249
0
    PrintDebug("Proved independence through different arrays.");
250
0
    return true;
251
0
  }
252
253
  // To handle multiple subscripts we must get every operand in the access
254
  // chains past the first.
255
0
  std::vector<Instruction*> source_subscripts = GetSubscripts(source);
256
0
  std::vector<Instruction*> destination_subscripts = GetSubscripts(destination);
257
258
0
  auto sets_of_subscripts =
259
0
      PartitionSubscripts(source_subscripts, destination_subscripts);
260
261
0
  auto first_coupled = std::partition(
262
0
      std::begin(sets_of_subscripts), std::end(sets_of_subscripts),
263
0
      [](const std::set<std::pair<Instruction*, Instruction*>>& set) {
264
0
        return set.size() == 1;
265
0
      });
266
267
  // Go through each subscript testing for independence.
268
  // If any subscript results in independence, we prove independence between the
269
  // load and store.
270
  // If we can't prove independence we store what information we can gather in
271
  // a DistanceVector.
272
0
  for (auto it = std::begin(sets_of_subscripts); it < first_coupled; ++it) {
273
0
    auto source_subscript = std::get<0>(*(*it).begin());
274
0
    auto destination_subscript = std::get<1>(*(*it).begin());
275
276
0
    SENode* source_node = scalar_evolution_.SimplifyExpression(
277
0
        scalar_evolution_.AnalyzeInstruction(source_subscript));
278
0
    SENode* destination_node = scalar_evolution_.SimplifyExpression(
279
0
        scalar_evolution_.AnalyzeInstruction(destination_subscript));
280
281
    // Check the loops are in a form we support.
282
0
    auto subscript_pair = std::make_pair(source_node, destination_node);
283
284
0
    const Loop* loop = GetLoopForSubscriptPair(subscript_pair);
285
0
    if (loop) {
286
0
      if (!IsSupportedLoop(loop)) {
287
0
        PrintDebug(
288
0
            "GetDependence found an unsupported loop form. Assuming <=> for "
289
0
            "loop.");
290
0
        DistanceEntry* distance_entry =
291
0
            GetDistanceEntryForSubscriptPair(subscript_pair, distance_vector);
292
0
        if (distance_entry) {
293
0
          distance_entry->direction = DistanceEntry::Directions::ALL;
294
0
        }
295
0
        continue;
296
0
      }
297
0
    }
298
299
    // If either node is simplified to a CanNotCompute we can't perform any
300
    // analysis so must assume <=> dependence and return.
301
0
    if (source_node->GetType() == SENode::CanNotCompute ||
302
0
        destination_node->GetType() == SENode::CanNotCompute) {
303
      // Record the <=> dependence if we can get a DistanceEntry
304
0
      PrintDebug(
305
0
          "GetDependence found source_node || destination_node as "
306
0
          "CanNotCompute. Abandoning evaluation for this subscript.");
307
0
      DistanceEntry* distance_entry =
308
0
          GetDistanceEntryForSubscriptPair(subscript_pair, distance_vector);
309
0
      if (distance_entry) {
310
0
        distance_entry->direction = DistanceEntry::Directions::ALL;
311
0
      }
312
0
      continue;
313
0
    }
314
315
    // We have no induction variables so can apply a ZIV test.
316
0
    if (IsZIV(subscript_pair)) {
317
0
      PrintDebug("Found a ZIV subscript pair");
318
0
      if (ZIVTest(subscript_pair)) {
319
0
        PrintDebug("Proved independence with ZIVTest.");
320
0
        return true;
321
0
      }
322
0
    }
323
324
    // We have only one induction variable so should attempt an SIV test.
325
0
    if (IsSIV(subscript_pair)) {
326
0
      PrintDebug("Found a SIV subscript pair.");
327
0
      if (SIVTest(subscript_pair, distance_vector)) {
328
0
        PrintDebug("Proved independence with SIVTest.");
329
0
        return true;
330
0
      }
331
0
    }
332
333
    // We have multiple induction variables so should attempt an MIV test.
334
0
    if (IsMIV(subscript_pair)) {
335
0
      PrintDebug("Found a MIV subscript pair.");
336
0
      if (GCDMIVTest(subscript_pair)) {
337
0
        PrintDebug("Proved independence with the GCD test.");
338
0
        auto current_loops = CollectLoops(source_node, destination_node);
339
340
0
        for (auto current_loop : current_loops) {
341
0
          auto distance_entry =
342
0
              GetDistanceEntryForLoop(current_loop, distance_vector);
343
0
          distance_entry->direction = DistanceEntry::Directions::NONE;
344
0
        }
345
0
        return true;
346
0
      }
347
0
    }
348
0
  }
349
350
0
  for (auto it = first_coupled; it < std::end(sets_of_subscripts); ++it) {
351
0
    auto coupled_instructions = *it;
352
0
    std::vector<SubscriptPair> coupled_subscripts{};
353
354
0
    for (const auto& elem : coupled_instructions) {
355
0
      auto source_subscript = std::get<0>(elem);
356
0
      auto destination_subscript = std::get<1>(elem);
357
358
0
      SENode* source_node = scalar_evolution_.SimplifyExpression(
359
0
          scalar_evolution_.AnalyzeInstruction(source_subscript));
360
0
      SENode* destination_node = scalar_evolution_.SimplifyExpression(
361
0
          scalar_evolution_.AnalyzeInstruction(destination_subscript));
362
363
0
      coupled_subscripts.push_back({source_node, destination_node});
364
0
    }
365
366
0
    auto supported = true;
367
368
0
    for (const auto& subscript : coupled_subscripts) {
369
0
      auto loops = CollectLoops(std::get<0>(subscript), std::get<1>(subscript));
370
371
0
      auto is_subscript_supported =
372
0
          std::all_of(std::begin(loops), std::end(loops),
373
0
                      [this](const Loop* l) { return IsSupportedLoop(l); });
374
375
0
      supported = supported && is_subscript_supported;
376
0
    }
377
378
0
    if (DeltaTest(coupled_subscripts, distance_vector)) {
379
0
      return true;
380
0
    }
381
0
  }
382
383
  // We were unable to prove independence so must gather all of the direction
384
  // information we found.
385
0
  PrintDebug(
386
0
      "Couldn't prove independence.\n"
387
0
      "All possible direction information has been collected in the input "
388
0
      "DistanceVector.");
389
390
0
  return false;
391
0
}
392
393
bool LoopDependenceAnalysis::ZIVTest(
394
0
    const std::pair<SENode*, SENode*>& subscript_pair) {
395
0
  auto source = std::get<0>(subscript_pair);
396
0
  auto destination = std::get<1>(subscript_pair);
397
398
0
  PrintDebug("Performing ZIVTest");
399
  // If source == destination, dependence with direction = and distance 0.
400
0
  if (source == destination) {
401
0
    PrintDebug("ZIVTest found EQ dependence.");
402
0
    return false;
403
0
  } else {
404
0
    PrintDebug("ZIVTest found independence.");
405
    // Otherwise we prove independence.
406
0
    return true;
407
0
  }
408
0
}
409
410
bool LoopDependenceAnalysis::SIVTest(
411
    const std::pair<SENode*, SENode*>& subscript_pair,
412
0
    DistanceVector* distance_vector) {
413
0
  DistanceEntry* distance_entry =
414
0
      GetDistanceEntryForSubscriptPair(subscript_pair, distance_vector);
415
0
  if (!distance_entry) {
416
0
    PrintDebug(
417
0
        "SIVTest could not find a DistanceEntry for subscript_pair. Exiting");
418
0
  }
419
420
0
  SENode* source_node = std::get<0>(subscript_pair);
421
0
  SENode* destination_node = std::get<1>(subscript_pair);
422
423
0
  int64_t source_induction_count = CountInductionVariables(source_node);
424
0
  int64_t destination_induction_count =
425
0
      CountInductionVariables(destination_node);
426
427
  // If the source node has no induction variables we can apply a
428
  // WeakZeroSrcTest.
429
0
  if (source_induction_count == 0) {
430
0
    PrintDebug("Found source has no induction variable.");
431
0
    if (WeakZeroSourceSIVTest(
432
0
            source_node, destination_node->AsSERecurrentNode(),
433
0
            destination_node->AsSERecurrentNode()->GetCoefficient(),
434
0
            distance_entry)) {
435
0
      PrintDebug("Proved independence with WeakZeroSourceSIVTest.");
436
0
      distance_entry->dependence_information =
437
0
          DistanceEntry::DependenceInformation::DIRECTION;
438
0
      distance_entry->direction = DistanceEntry::Directions::NONE;
439
0
      return true;
440
0
    }
441
0
  }
442
443
  // If the destination has no induction variables we can apply a
444
  // WeakZeroDestTest.
445
0
  if (destination_induction_count == 0) {
446
0
    PrintDebug("Found destination has no induction variable.");
447
0
    if (WeakZeroDestinationSIVTest(
448
0
            source_node->AsSERecurrentNode(), destination_node,
449
0
            source_node->AsSERecurrentNode()->GetCoefficient(),
450
0
            distance_entry)) {
451
0
      PrintDebug("Proved independence with WeakZeroDestinationSIVTest.");
452
0
      distance_entry->dependence_information =
453
0
          DistanceEntry::DependenceInformation::DIRECTION;
454
0
      distance_entry->direction = DistanceEntry::Directions::NONE;
455
0
      return true;
456
0
    }
457
0
  }
458
459
  // We now need to collect the SERecurrentExpr nodes from source and
460
  // destination. We do not handle cases where source or destination have
461
  // multiple SERecurrentExpr nodes.
462
0
  std::vector<SERecurrentNode*> source_recurrent_nodes =
463
0
      source_node->CollectRecurrentNodes();
464
0
  std::vector<SERecurrentNode*> destination_recurrent_nodes =
465
0
      destination_node->CollectRecurrentNodes();
466
467
0
  if (source_recurrent_nodes.size() == 1 &&
468
0
      destination_recurrent_nodes.size() == 1) {
469
0
    PrintDebug("Found source and destination have 1 induction variable.");
470
0
    SERecurrentNode* source_recurrent_expr = *source_recurrent_nodes.begin();
471
0
    SERecurrentNode* destination_recurrent_expr =
472
0
        *destination_recurrent_nodes.begin();
473
474
    // If the coefficients are identical we can apply a StrongSIVTest.
475
0
    if (source_recurrent_expr->GetCoefficient() ==
476
0
        destination_recurrent_expr->GetCoefficient()) {
477
0
      PrintDebug("Found source and destination share coefficient.");
478
0
      if (StrongSIVTest(source_node, destination_node,
479
0
                        source_recurrent_expr->GetCoefficient(),
480
0
                        distance_entry)) {
481
0
        PrintDebug("Proved independence with StrongSIVTest");
482
0
        distance_entry->dependence_information =
483
0
            DistanceEntry::DependenceInformation::DIRECTION;
484
0
        distance_entry->direction = DistanceEntry::Directions::NONE;
485
0
        return true;
486
0
      }
487
0
    }
488
489
    // If the coefficients are of equal magnitude and opposite sign we can
490
    // apply a WeakCrossingSIVTest.
491
0
    if (source_recurrent_expr->GetCoefficient() ==
492
0
        scalar_evolution_.CreateNegation(
493
0
            destination_recurrent_expr->GetCoefficient())) {
494
0
      PrintDebug("Found source coefficient = -destination coefficient.");
495
0
      if (WeakCrossingSIVTest(source_node, destination_node,
496
0
                              source_recurrent_expr->GetCoefficient(),
497
0
                              distance_entry)) {
498
0
        PrintDebug("Proved independence with WeakCrossingSIVTest");
499
0
        distance_entry->dependence_information =
500
0
            DistanceEntry::DependenceInformation::DIRECTION;
501
0
        distance_entry->direction = DistanceEntry::Directions::NONE;
502
0
        return true;
503
0
      }
504
0
    }
505
0
  }
506
507
0
  return false;
508
0
}
509
510
bool LoopDependenceAnalysis::StrongSIVTest(SENode* source, SENode* destination,
511
                                           SENode* coefficient,
512
0
                                           DistanceEntry* distance_entry) {
513
0
  PrintDebug("Performing StrongSIVTest.");
514
  // If both source and destination are SERecurrentNodes we can perform tests
515
  // based on distance.
516
  // If either source or destination contain value unknown nodes or if one or
517
  // both are not SERecurrentNodes we must attempt a symbolic test.
518
0
  std::vector<SEValueUnknown*> source_value_unknown_nodes =
519
0
      source->CollectValueUnknownNodes();
520
0
  std::vector<SEValueUnknown*> destination_value_unknown_nodes =
521
0
      destination->CollectValueUnknownNodes();
522
0
  if (source_value_unknown_nodes.size() > 0 ||
523
0
      destination_value_unknown_nodes.size() > 0) {
524
0
    PrintDebug(
525
0
        "StrongSIVTest found symbolics. Will attempt SymbolicStrongSIVTest.");
526
0
    return SymbolicStrongSIVTest(source, destination, coefficient,
527
0
                                 distance_entry);
528
0
  }
529
530
0
  if (!source->AsSERecurrentNode() || !destination->AsSERecurrentNode()) {
531
0
    PrintDebug(
532
0
        "StrongSIVTest could not simplify source and destination to "
533
0
        "SERecurrentNodes so will exit.");
534
0
    distance_entry->direction = DistanceEntry::Directions::ALL;
535
0
    return false;
536
0
  }
537
538
  // Build an SENode for distance.
539
0
  std::pair<SENode*, SENode*> subscript_pair =
540
0
      std::make_pair(source, destination);
541
0
  const Loop* subscript_loop = GetLoopForSubscriptPair(subscript_pair);
542
0
  SENode* source_constant_term =
543
0
      GetConstantTerm(subscript_loop, source->AsSERecurrentNode());
544
0
  SENode* destination_constant_term =
545
0
      GetConstantTerm(subscript_loop, destination->AsSERecurrentNode());
546
0
  if (!source_constant_term || !destination_constant_term) {
547
0
    PrintDebug(
548
0
        "StrongSIVTest could not collect the constant terms of either source "
549
0
        "or destination so will exit.");
550
0
    return false;
551
0
  }
552
0
  SENode* constant_term_delta =
553
0
      scalar_evolution_.SimplifyExpression(scalar_evolution_.CreateSubtraction(
554
0
          destination_constant_term, source_constant_term));
555
556
  // Scalar evolution doesn't perform division, so we must fold to constants and
557
  // do it manually.
558
  // We must check the offset delta and coefficient are constants.
559
0
  int64_t distance = 0;
560
0
  SEConstantNode* delta_constant = constant_term_delta->AsSEConstantNode();
561
0
  SEConstantNode* coefficient_constant = coefficient->AsSEConstantNode();
562
0
  if (delta_constant && coefficient_constant) {
563
0
    int64_t delta_value = delta_constant->FoldToSingleValue();
564
0
    int64_t coefficient_value = coefficient_constant->FoldToSingleValue();
565
0
    PrintDebug(
566
0
        "StrongSIVTest found delta value and coefficient value as constants "
567
0
        "with values:\n"
568
0
        "\tdelta value: " +
569
0
        ToString(delta_value) +
570
0
        "\n\tcoefficient value: " + ToString(coefficient_value) + "\n");
571
    // Check if the distance is not integral to try to prove independence.
572
0
    if (delta_value % coefficient_value != 0) {
573
0
      PrintDebug(
574
0
          "StrongSIVTest proved independence through distance not being an "
575
0
          "integer.");
576
0
      distance_entry->dependence_information =
577
0
          DistanceEntry::DependenceInformation::DIRECTION;
578
0
      distance_entry->direction = DistanceEntry::Directions::NONE;
579
0
      return true;
580
0
    } else {
581
0
      distance = delta_value / coefficient_value;
582
0
      PrintDebug("StrongSIV test found distance as " + ToString(distance));
583
0
    }
584
0
  } else {
585
    // If we can't fold delta and coefficient to single values we can't produce
586
    // distance.
587
    // As a result we can't perform the rest of the pass and must assume
588
    // dependence in all directions.
589
0
    PrintDebug("StrongSIVTest could not produce a distance. Must exit.");
590
0
    distance_entry->distance = DistanceEntry::Directions::ALL;
591
0
    return false;
592
0
  }
593
594
  // Next we gather the upper and lower bounds as constants if possible. If
595
  // distance > upper_bound - lower_bound we prove independence.
596
0
  SENode* lower_bound = GetLowerBound(subscript_loop);
597
0
  SENode* upper_bound = GetUpperBound(subscript_loop);
598
0
  if (lower_bound && upper_bound) {
599
0
    PrintDebug("StrongSIVTest found bounds.");
600
0
    SENode* bounds = scalar_evolution_.SimplifyExpression(
601
0
        scalar_evolution_.CreateSubtraction(upper_bound, lower_bound));
602
603
0
    if (bounds->GetType() == SENode::SENodeType::Constant) {
604
0
      int64_t bounds_value = bounds->AsSEConstantNode()->FoldToSingleValue();
605
0
      PrintDebug(
606
0
          "StrongSIVTest found upper_bound - lower_bound as a constant with "
607
0
          "value " +
608
0
          ToString(bounds_value));
609
610
      // If the absolute value of the distance is > upper bound - lower bound
611
      // then we prove independence.
612
0
      if (llabs(distance) > llabs(bounds_value)) {
613
0
        PrintDebug(
614
0
            "StrongSIVTest proved independence through distance escaping the "
615
0
            "loop bounds.");
616
0
        distance_entry->dependence_information =
617
0
            DistanceEntry::DependenceInformation::DISTANCE;
618
0
        distance_entry->direction = DistanceEntry::Directions::NONE;
619
0
        distance_entry->distance = distance;
620
0
        return true;
621
0
      }
622
0
    }
623
0
  } else {
624
0
    PrintDebug("StrongSIVTest was unable to gather lower and upper bounds.");
625
0
  }
626
627
  // Otherwise we can get a direction as follows
628
  //             { < if distance > 0
629
  // direction = { = if distance == 0
630
  //             { > if distance < 0
631
0
  PrintDebug(
632
0
      "StrongSIVTest could not prove independence. Gathering direction "
633
0
      "information.");
634
0
  if (distance > 0) {
635
0
    distance_entry->dependence_information =
636
0
        DistanceEntry::DependenceInformation::DISTANCE;
637
0
    distance_entry->direction = DistanceEntry::Directions::LT;
638
0
    distance_entry->distance = distance;
639
0
    return false;
640
0
  }
641
0
  if (distance == 0) {
642
0
    distance_entry->dependence_information =
643
0
        DistanceEntry::DependenceInformation::DISTANCE;
644
0
    distance_entry->direction = DistanceEntry::Directions::EQ;
645
0
    distance_entry->distance = 0;
646
0
    return false;
647
0
  }
648
0
  if (distance < 0) {
649
0
    distance_entry->dependence_information =
650
0
        DistanceEntry::DependenceInformation::DISTANCE;
651
0
    distance_entry->direction = DistanceEntry::Directions::GT;
652
0
    distance_entry->distance = distance;
653
0
    return false;
654
0
  }
655
656
  // We were unable to prove independence or discern any additional information
657
  // Must assume <=> direction.
658
0
  PrintDebug(
659
0
      "StrongSIVTest was unable to determine any dependence information.");
660
0
  distance_entry->direction = DistanceEntry::Directions::ALL;
661
0
  return false;
662
0
}
663
664
bool LoopDependenceAnalysis::SymbolicStrongSIVTest(
665
    SENode* source, SENode* destination, SENode* coefficient,
666
0
    DistanceEntry* distance_entry) {
667
0
  PrintDebug("Performing SymbolicStrongSIVTest.");
668
0
  SENode* source_destination_delta = scalar_evolution_.SimplifyExpression(
669
0
      scalar_evolution_.CreateSubtraction(source, destination));
670
  // By cancelling out the induction variables by subtracting the source and
671
  // destination we can produce an expression of symbolics and constants. This
672
  // expression can be compared to the loop bounds to find if the offset is
673
  // outwith the bounds.
674
0
  std::pair<SENode*, SENode*> subscript_pair =
675
0
      std::make_pair(source, destination);
676
0
  const Loop* subscript_loop = GetLoopForSubscriptPair(subscript_pair);
677
0
  if (IsProvablyOutsideOfLoopBounds(subscript_loop, source_destination_delta,
678
0
                                    coefficient)) {
679
0
    PrintDebug(
680
0
        "SymbolicStrongSIVTest proved independence through loop bounds.");
681
0
    distance_entry->dependence_information =
682
0
        DistanceEntry::DependenceInformation::DIRECTION;
683
0
    distance_entry->direction = DistanceEntry::Directions::NONE;
684
0
    return true;
685
0
  }
686
  // We were unable to prove independence or discern any additional information.
687
  // Must assume <=> direction.
688
0
  PrintDebug(
689
0
      "SymbolicStrongSIVTest was unable to determine any dependence "
690
0
      "information.");
691
0
  distance_entry->direction = DistanceEntry::Directions::ALL;
692
0
  return false;
693
0
}
694
695
bool LoopDependenceAnalysis::WeakZeroSourceSIVTest(
696
    SENode* source, SERecurrentNode* destination, SENode* coefficient,
697
0
    DistanceEntry* distance_entry) {
698
0
  PrintDebug("Performing WeakZeroSourceSIVTest.");
699
0
  std::pair<SENode*, SENode*> subscript_pair =
700
0
      std::make_pair(source, destination);
701
0
  const Loop* subscript_loop = GetLoopForSubscriptPair(subscript_pair);
702
  // Build an SENode for distance.
703
0
  SENode* destination_constant_term =
704
0
      GetConstantTerm(subscript_loop, destination);
705
0
  SENode* delta = scalar_evolution_.SimplifyExpression(
706
0
      scalar_evolution_.CreateSubtraction(source, destination_constant_term));
707
708
  // Scalar evolution doesn't perform division, so we must fold to constants and
709
  // do it manually.
710
0
  int64_t distance = 0;
711
0
  SEConstantNode* delta_constant = delta->AsSEConstantNode();
712
0
  SEConstantNode* coefficient_constant = coefficient->AsSEConstantNode();
713
0
  if (delta_constant && coefficient_constant) {
714
0
    PrintDebug(
715
0
        "WeakZeroSourceSIVTest folding delta and coefficient to constants.");
716
0
    int64_t delta_value = delta_constant->FoldToSingleValue();
717
0
    int64_t coefficient_value = coefficient_constant->FoldToSingleValue();
718
    // Check if the distance is not integral.
719
0
    if (delta_value % coefficient_value != 0) {
720
0
      PrintDebug(
721
0
          "WeakZeroSourceSIVTest proved independence through distance not "
722
0
          "being an integer.");
723
0
      distance_entry->dependence_information =
724
0
          DistanceEntry::DependenceInformation::DIRECTION;
725
0
      distance_entry->direction = DistanceEntry::Directions::NONE;
726
0
      return true;
727
0
    } else {
728
0
      distance = delta_value / coefficient_value;
729
0
      PrintDebug(
730
0
          "WeakZeroSourceSIVTest calculated distance with the following "
731
0
          "values\n"
732
0
          "\tdelta value: " +
733
0
          ToString(delta_value) +
734
0
          "\n\tcoefficient value: " + ToString(coefficient_value) +
735
0
          "\n\tdistance: " + ToString(distance) + "\n");
736
0
    }
737
0
  } else {
738
0
    PrintDebug(
739
0
        "WeakZeroSourceSIVTest was unable to fold delta and coefficient to "
740
0
        "constants.");
741
0
  }
742
743
  // If we can prove the distance is outside the bounds we prove independence.
744
0
  SEConstantNode* lower_bound =
745
0
      GetLowerBound(subscript_loop)->AsSEConstantNode();
746
0
  SEConstantNode* upper_bound =
747
0
      GetUpperBound(subscript_loop)->AsSEConstantNode();
748
0
  if (lower_bound && upper_bound) {
749
0
    PrintDebug("WeakZeroSourceSIVTest found bounds as SEConstantNodes.");
750
0
    int64_t lower_bound_value = lower_bound->FoldToSingleValue();
751
0
    int64_t upper_bound_value = upper_bound->FoldToSingleValue();
752
0
    if (!IsWithinBounds(llabs(distance), lower_bound_value,
753
0
                        upper_bound_value)) {
754
0
      PrintDebug(
755
0
          "WeakZeroSourceSIVTest proved independence through distance escaping "
756
0
          "the loop bounds.");
757
0
      PrintDebug(
758
0
          "Bound values were as follow\n"
759
0
          "\tlower bound value: " +
760
0
          ToString(lower_bound_value) +
761
0
          "\n\tupper bound value: " + ToString(upper_bound_value) +
762
0
          "\n\tdistance value: " + ToString(distance) + "\n");
763
0
      distance_entry->dependence_information =
764
0
          DistanceEntry::DependenceInformation::DISTANCE;
765
0
      distance_entry->direction = DistanceEntry::Directions::NONE;
766
0
      distance_entry->distance = distance;
767
0
      return true;
768
0
    }
769
0
  } else {
770
0
    PrintDebug(
771
0
        "WeakZeroSourceSIVTest was unable to find lower and upper bound as "
772
0
        "SEConstantNodes.");
773
0
  }
774
775
  // Now we want to see if we can detect to peel the first or last iterations.
776
777
  // We get the FirstTripValue as GetFirstTripInductionNode() +
778
  // GetConstantTerm(destination)
779
0
  SENode* first_trip_SENode =
780
0
      scalar_evolution_.SimplifyExpression(scalar_evolution_.CreateAddNode(
781
0
          GetFirstTripInductionNode(subscript_loop),
782
0
          GetConstantTerm(subscript_loop, destination)));
783
784
  // If source == FirstTripValue, peel_first.
785
0
  if (first_trip_SENode) {
786
0
    PrintDebug("WeakZeroSourceSIVTest built first_trip_SENode.");
787
0
    if (first_trip_SENode->AsSEConstantNode()) {
788
0
      PrintDebug(
789
0
          "WeakZeroSourceSIVTest has found first_trip_SENode as an "
790
0
          "SEConstantNode with value: " +
791
0
          ToString(first_trip_SENode->AsSEConstantNode()->FoldToSingleValue()) +
792
0
          "\n");
793
0
    }
794
0
    if (source == first_trip_SENode) {
795
      // We have found that peeling the first iteration will break dependency.
796
0
      PrintDebug(
797
0
          "WeakZeroSourceSIVTest has found peeling first iteration will break "
798
0
          "dependency");
799
0
      distance_entry->dependence_information =
800
0
          DistanceEntry::DependenceInformation::PEEL;
801
0
      distance_entry->peel_first = true;
802
0
      return false;
803
0
    }
804
0
  } else {
805
0
    PrintDebug("WeakZeroSourceSIVTest was unable to build first_trip_SENode");
806
0
  }
807
808
  // We get the LastTripValue as GetFinalTripInductionNode(coefficient) +
809
  // GetConstantTerm(destination)
810
0
  SENode* final_trip_SENode =
811
0
      scalar_evolution_.SimplifyExpression(scalar_evolution_.CreateAddNode(
812
0
          GetFinalTripInductionNode(subscript_loop, coefficient),
813
0
          GetConstantTerm(subscript_loop, destination)));
814
815
  // If source == LastTripValue, peel_last.
816
0
  if (final_trip_SENode) {
817
0
    PrintDebug("WeakZeroSourceSIVTest built final_trip_SENode.");
818
0
    if (first_trip_SENode->AsSEConstantNode()) {
819
0
      PrintDebug(
820
0
          "WeakZeroSourceSIVTest has found final_trip_SENode as an "
821
0
          "SEConstantNode with value: " +
822
0
          ToString(final_trip_SENode->AsSEConstantNode()->FoldToSingleValue()) +
823
0
          "\n");
824
0
    }
825
0
    if (source == final_trip_SENode) {
826
      // We have found that peeling the last iteration will break dependency.
827
0
      PrintDebug(
828
0
          "WeakZeroSourceSIVTest has found peeling final iteration will break "
829
0
          "dependency");
830
0
      distance_entry->dependence_information =
831
0
          DistanceEntry::DependenceInformation::PEEL;
832
0
      distance_entry->peel_last = true;
833
0
      return false;
834
0
    }
835
0
  } else {
836
0
    PrintDebug("WeakZeroSourceSIVTest was unable to build final_trip_SENode");
837
0
  }
838
839
  // We were unable to prove independence or discern any additional information.
840
  // Must assume <=> direction.
841
0
  PrintDebug(
842
0
      "WeakZeroSourceSIVTest was unable to determine any dependence "
843
0
      "information.");
844
0
  distance_entry->direction = DistanceEntry::Directions::ALL;
845
0
  return false;
846
0
}
847
848
bool LoopDependenceAnalysis::WeakZeroDestinationSIVTest(
849
    SERecurrentNode* source, SENode* destination, SENode* coefficient,
850
0
    DistanceEntry* distance_entry) {
851
0
  PrintDebug("Performing WeakZeroDestinationSIVTest.");
852
  // Build an SENode for distance.
853
0
  std::pair<SENode*, SENode*> subscript_pair =
854
0
      std::make_pair(source, destination);
855
0
  const Loop* subscript_loop = GetLoopForSubscriptPair(subscript_pair);
856
0
  SENode* source_constant_term = GetConstantTerm(subscript_loop, source);
857
0
  SENode* delta = scalar_evolution_.SimplifyExpression(
858
0
      scalar_evolution_.CreateSubtraction(destination, source_constant_term));
859
860
  // Scalar evolution doesn't perform division, so we must fold to constants and
861
  // do it manually.
862
0
  int64_t distance = 0;
863
0
  SEConstantNode* delta_constant = delta->AsSEConstantNode();
864
0
  SEConstantNode* coefficient_constant = coefficient->AsSEConstantNode();
865
0
  if (delta_constant && coefficient_constant) {
866
0
    PrintDebug(
867
0
        "WeakZeroDestinationSIVTest folding delta and coefficient to "
868
0
        "constants.");
869
0
    int64_t delta_value = delta_constant->FoldToSingleValue();
870
0
    int64_t coefficient_value = coefficient_constant->FoldToSingleValue();
871
    // Check if the distance is not integral.
872
0
    if (delta_value % coefficient_value != 0) {
873
0
      PrintDebug(
874
0
          "WeakZeroDestinationSIVTest proved independence through distance not "
875
0
          "being an integer.");
876
0
      distance_entry->dependence_information =
877
0
          DistanceEntry::DependenceInformation::DIRECTION;
878
0
      distance_entry->direction = DistanceEntry::Directions::NONE;
879
0
      return true;
880
0
    } else {
881
0
      distance = delta_value / coefficient_value;
882
0
      PrintDebug(
883
0
          "WeakZeroDestinationSIVTest calculated distance with the following "
884
0
          "values\n"
885
0
          "\tdelta value: " +
886
0
          ToString(delta_value) +
887
0
          "\n\tcoefficient value: " + ToString(coefficient_value) +
888
0
          "\n\tdistance: " + ToString(distance) + "\n");
889
0
    }
890
0
  } else {
891
0
    PrintDebug(
892
0
        "WeakZeroDestinationSIVTest was unable to fold delta and coefficient "
893
0
        "to constants.");
894
0
  }
895
896
  // If we can prove the distance is outside the bounds we prove independence.
897
0
  SEConstantNode* lower_bound =
898
0
      GetLowerBound(subscript_loop)->AsSEConstantNode();
899
0
  SEConstantNode* upper_bound =
900
0
      GetUpperBound(subscript_loop)->AsSEConstantNode();
901
0
  if (lower_bound && upper_bound) {
902
0
    PrintDebug("WeakZeroDestinationSIVTest found bounds as SEConstantNodes.");
903
0
    int64_t lower_bound_value = lower_bound->FoldToSingleValue();
904
0
    int64_t upper_bound_value = upper_bound->FoldToSingleValue();
905
0
    if (!IsWithinBounds(llabs(distance), lower_bound_value,
906
0
                        upper_bound_value)) {
907
0
      PrintDebug(
908
0
          "WeakZeroDestinationSIVTest proved independence through distance "
909
0
          "escaping the loop bounds.");
910
0
      PrintDebug(
911
0
          "Bound values were as follows\n"
912
0
          "\tlower bound value: " +
913
0
          ToString(lower_bound_value) +
914
0
          "\n\tupper bound value: " + ToString(upper_bound_value) +
915
0
          "\n\tdistance value: " + ToString(distance));
916
0
      distance_entry->dependence_information =
917
0
          DistanceEntry::DependenceInformation::DISTANCE;
918
0
      distance_entry->direction = DistanceEntry::Directions::NONE;
919
0
      distance_entry->distance = distance;
920
0
      return true;
921
0
    }
922
0
  } else {
923
0
    PrintDebug(
924
0
        "WeakZeroDestinationSIVTest was unable to find lower and upper bound "
925
0
        "as SEConstantNodes.");
926
0
  }
927
928
  // Now we want to see if we can detect to peel the first or last iterations.
929
930
  // We get the FirstTripValue as GetFirstTripInductionNode() +
931
  // GetConstantTerm(source)
932
0
  SENode* first_trip_SENode = scalar_evolution_.SimplifyExpression(
933
0
      scalar_evolution_.CreateAddNode(GetFirstTripInductionNode(subscript_loop),
934
0
                                      GetConstantTerm(subscript_loop, source)));
935
936
  // If destination == FirstTripValue, peel_first.
937
0
  if (first_trip_SENode) {
938
0
    PrintDebug("WeakZeroDestinationSIVTest built first_trip_SENode.");
939
0
    if (first_trip_SENode->AsSEConstantNode()) {
940
0
      PrintDebug(
941
0
          "WeakZeroDestinationSIVTest has found first_trip_SENode as an "
942
0
          "SEConstantNode with value: " +
943
0
          ToString(first_trip_SENode->AsSEConstantNode()->FoldToSingleValue()) +
944
0
          "\n");
945
0
    }
946
0
    if (destination == first_trip_SENode) {
947
      // We have found that peeling the first iteration will break dependency.
948
0
      PrintDebug(
949
0
          "WeakZeroDestinationSIVTest has found peeling first iteration will "
950
0
          "break dependency");
951
0
      distance_entry->dependence_information =
952
0
          DistanceEntry::DependenceInformation::PEEL;
953
0
      distance_entry->peel_first = true;
954
0
      return false;
955
0
    }
956
0
  } else {
957
0
    PrintDebug(
958
0
        "WeakZeroDestinationSIVTest was unable to build first_trip_SENode");
959
0
  }
960
961
  // We get the LastTripValue as GetFinalTripInductionNode(coefficient) +
962
  // GetConstantTerm(source)
963
0
  SENode* final_trip_SENode =
964
0
      scalar_evolution_.SimplifyExpression(scalar_evolution_.CreateAddNode(
965
0
          GetFinalTripInductionNode(subscript_loop, coefficient),
966
0
          GetConstantTerm(subscript_loop, source)));
967
968
  // If destination == LastTripValue, peel_last.
969
0
  if (final_trip_SENode) {
970
0
    PrintDebug("WeakZeroDestinationSIVTest built final_trip_SENode.");
971
0
    if (final_trip_SENode->AsSEConstantNode()) {
972
0
      PrintDebug(
973
0
          "WeakZeroDestinationSIVTest has found final_trip_SENode as an "
974
0
          "SEConstantNode with value: " +
975
0
          ToString(final_trip_SENode->AsSEConstantNode()->FoldToSingleValue()) +
976
0
          "\n");
977
0
    }
978
0
    if (destination == final_trip_SENode) {
979
      // We have found that peeling the last iteration will break dependency.
980
0
      PrintDebug(
981
0
          "WeakZeroDestinationSIVTest has found peeling final iteration will "
982
0
          "break dependency");
983
0
      distance_entry->dependence_information =
984
0
          DistanceEntry::DependenceInformation::PEEL;
985
0
      distance_entry->peel_last = true;
986
0
      return false;
987
0
    }
988
0
  } else {
989
0
    PrintDebug(
990
0
        "WeakZeroDestinationSIVTest was unable to build final_trip_SENode");
991
0
  }
992
993
  // We were unable to prove independence or discern any additional information.
994
  // Must assume <=> direction.
995
0
  PrintDebug(
996
0
      "WeakZeroDestinationSIVTest was unable to determine any dependence "
997
0
      "information.");
998
0
  distance_entry->direction = DistanceEntry::Directions::ALL;
999
0
  return false;
1000
0
}
1001
1002
bool LoopDependenceAnalysis::WeakCrossingSIVTest(
1003
    SENode* source, SENode* destination, SENode* coefficient,
1004
0
    DistanceEntry* distance_entry) {
1005
0
  PrintDebug("Performing WeakCrossingSIVTest.");
1006
  // We currently can't handle symbolic WeakCrossingSIVTests. If either source
1007
  // or destination are not SERecurrentNodes we must exit.
1008
0
  if (!source->AsSERecurrentNode() || !destination->AsSERecurrentNode()) {
1009
0
    PrintDebug(
1010
0
        "WeakCrossingSIVTest found source or destination != SERecurrentNode. "
1011
0
        "Exiting");
1012
0
    distance_entry->direction = DistanceEntry::Directions::ALL;
1013
0
    return false;
1014
0
  }
1015
1016
  // Build an SENode for distance.
1017
0
  SENode* offset_delta =
1018
0
      scalar_evolution_.SimplifyExpression(scalar_evolution_.CreateSubtraction(
1019
0
          destination->AsSERecurrentNode()->GetOffset(),
1020
0
          source->AsSERecurrentNode()->GetOffset()));
1021
1022
  // Scalar evolution doesn't perform division, so we must fold to constants and
1023
  // do it manually.
1024
0
  int64_t distance = 0;
1025
0
  SEConstantNode* delta_constant = offset_delta->AsSEConstantNode();
1026
0
  SEConstantNode* coefficient_constant = coefficient->AsSEConstantNode();
1027
0
  if (delta_constant && coefficient_constant) {
1028
0
    PrintDebug(
1029
0
        "WeakCrossingSIVTest folding offset_delta and coefficient to "
1030
0
        "constants.");
1031
0
    int64_t delta_value = delta_constant->FoldToSingleValue();
1032
0
    int64_t coefficient_value = coefficient_constant->FoldToSingleValue();
1033
    // Check if the distance is not integral or if it has a non-integral part
1034
    // equal to 1/2.
1035
0
    if (delta_value % (2 * coefficient_value) != 0 &&
1036
0
        static_cast<float>(delta_value % (2 * coefficient_value)) /
1037
0
                static_cast<float>(2 * coefficient_value) !=
1038
0
            0.5) {
1039
0
      PrintDebug(
1040
0
          "WeakCrossingSIVTest proved independence through distance escaping "
1041
0
          "the loop bounds.");
1042
0
      distance_entry->dependence_information =
1043
0
          DistanceEntry::DependenceInformation::DIRECTION;
1044
0
      distance_entry->direction = DistanceEntry::Directions::NONE;
1045
0
      return true;
1046
0
    } else {
1047
0
      distance = delta_value / (2 * coefficient_value);
1048
0
    }
1049
1050
0
    if (distance == 0) {
1051
0
      PrintDebug("WeakCrossingSIVTest found EQ dependence.");
1052
0
      distance_entry->dependence_information =
1053
0
          DistanceEntry::DependenceInformation::DISTANCE;
1054
0
      distance_entry->direction = DistanceEntry::Directions::EQ;
1055
0
      distance_entry->distance = 0;
1056
0
      return false;
1057
0
    }
1058
0
  } else {
1059
0
    PrintDebug(
1060
0
        "WeakCrossingSIVTest was unable to fold offset_delta and coefficient "
1061
0
        "to constants.");
1062
0
  }
1063
1064
  // We were unable to prove independence or discern any additional information.
1065
  // Must assume <=> direction.
1066
0
  PrintDebug(
1067
0
      "WeakCrossingSIVTest was unable to determine any dependence "
1068
0
      "information.");
1069
0
  distance_entry->direction = DistanceEntry::Directions::ALL;
1070
0
  return false;
1071
0
}
1072
1073
// Perform the GCD test if both, the source and the destination nodes, are in
1074
// the form a0*i0 + a1*i1 + ... an*in + c.
1075
bool LoopDependenceAnalysis::GCDMIVTest(
1076
0
    const std::pair<SENode*, SENode*>& subscript_pair) {
1077
0
  auto source = std::get<0>(subscript_pair);
1078
0
  auto destination = std::get<1>(subscript_pair);
1079
1080
  // Bail out if source/destination is in an unexpected form.
1081
0
  if (!IsInCorrectFormForGCDTest(source) ||
1082
0
      !IsInCorrectFormForGCDTest(destination)) {
1083
0
    return false;
1084
0
  }
1085
1086
0
  auto source_recurrences = GetAllTopLevelRecurrences(source);
1087
0
  auto dest_recurrences = GetAllTopLevelRecurrences(destination);
1088
1089
  // Bail out if all offsets and coefficients aren't constant.
1090
0
  if (!AreOffsetsAndCoefficientsConstant(source_recurrences) ||
1091
0
      !AreOffsetsAndCoefficientsConstant(dest_recurrences)) {
1092
0
    return false;
1093
0
  }
1094
1095
  // Calculate the GCD of all coefficients.
1096
0
  auto source_constants = GetAllTopLevelConstants(source);
1097
0
  int64_t source_constant =
1098
0
      CalculateConstantTerm(source_recurrences, source_constants);
1099
1100
0
  auto dest_constants = GetAllTopLevelConstants(destination);
1101
0
  int64_t destination_constant =
1102
0
      CalculateConstantTerm(dest_recurrences, dest_constants);
1103
1104
0
  int64_t delta = std::abs(source_constant - destination_constant);
1105
1106
0
  int64_t running_gcd = 0;
1107
1108
0
  running_gcd = CalculateGCDFromCoefficients(source_recurrences, running_gcd);
1109
0
  running_gcd = CalculateGCDFromCoefficients(dest_recurrences, running_gcd);
1110
1111
0
  return delta % running_gcd != 0;
1112
0
}
1113
1114
using PartitionedSubscripts =
1115
    std::vector<std::set<std::pair<Instruction*, Instruction*>>>;
1116
PartitionedSubscripts LoopDependenceAnalysis::PartitionSubscripts(
1117
    const std::vector<Instruction*>& source_subscripts,
1118
0
    const std::vector<Instruction*>& destination_subscripts) {
1119
0
  PartitionedSubscripts partitions{};
1120
1121
0
  auto num_subscripts = source_subscripts.size();
1122
1123
  // Create initial partitions with one subscript pair per partition.
1124
0
  for (size_t i = 0; i < num_subscripts; ++i) {
1125
0
    partitions.push_back({{source_subscripts[i], destination_subscripts[i]}});
1126
0
  }
1127
1128
  // Iterate over the loops to create all partitions
1129
0
  for (auto loop : loops_) {
1130
0
    int64_t k = -1;
1131
1132
0
    for (size_t j = 0; j < partitions.size(); ++j) {
1133
0
      auto& current_partition = partitions[j];
1134
1135
      // Does |loop| appear in |current_partition|
1136
0
      auto it = std::find_if(
1137
0
          current_partition.begin(), current_partition.end(),
1138
0
          [loop,
1139
0
           this](const std::pair<Instruction*, Instruction*>& elem) -> bool {
1140
0
            auto source_recurrences =
1141
0
                scalar_evolution_.AnalyzeInstruction(std::get<0>(elem))
1142
0
                    ->CollectRecurrentNodes();
1143
0
            auto destination_recurrences =
1144
0
                scalar_evolution_.AnalyzeInstruction(std::get<1>(elem))
1145
0
                    ->CollectRecurrentNodes();
1146
1147
0
            source_recurrences.insert(source_recurrences.end(),
1148
0
                                      destination_recurrences.begin(),
1149
0
                                      destination_recurrences.end());
1150
1151
0
            auto loops_in_pair = CollectLoops(source_recurrences);
1152
0
            auto end_it = loops_in_pair.end();
1153
1154
0
            return std::find(loops_in_pair.begin(), end_it, loop) != end_it;
1155
0
          });
1156
1157
0
      auto has_loop = it != current_partition.end();
1158
1159
0
      if (has_loop) {
1160
0
        if (k == -1) {
1161
0
          k = j;
1162
0
        } else {
1163
          // Add |partitions[j]| to |partitions[k]| and discard |partitions[j]|
1164
0
          partitions[static_cast<size_t>(k)].insert(current_partition.begin(),
1165
0
                                                    current_partition.end());
1166
0
          current_partition.clear();
1167
0
        }
1168
0
      }
1169
0
    }
1170
0
  }
1171
1172
  // Remove empty (discarded) partitions
1173
0
  partitions.erase(
1174
0
      std::remove_if(
1175
0
          partitions.begin(), partitions.end(),
1176
0
          [](const std::set<std::pair<Instruction*, Instruction*>>& partition) {
1177
0
            return partition.empty();
1178
0
          }),
1179
0
      partitions.end());
1180
1181
0
  return partitions;
1182
0
}
1183
1184
Constraint* LoopDependenceAnalysis::IntersectConstraints(
1185
    Constraint* constraint_0, Constraint* constraint_1,
1186
0
    const SENode* lower_bound, const SENode* upper_bound) {
1187
0
  if (constraint_0->AsDependenceNone()) {
1188
0
    return constraint_1;
1189
0
  } else if (constraint_1->AsDependenceNone()) {
1190
0
    return constraint_0;
1191
0
  }
1192
1193
  // Both constraints are distances. Either the same distance or independent.
1194
0
  if (constraint_0->AsDependenceDistance() &&
1195
0
      constraint_1->AsDependenceDistance()) {
1196
0
    auto dist_0 = constraint_0->AsDependenceDistance();
1197
0
    auto dist_1 = constraint_1->AsDependenceDistance();
1198
1199
0
    if (*dist_0->GetDistance() == *dist_1->GetDistance()) {
1200
0
      return constraint_0;
1201
0
    } else {
1202
0
      return make_constraint<DependenceEmpty>();
1203
0
    }
1204
0
  }
1205
1206
  // Both constraints are points. Either the same point or independent.
1207
0
  if (constraint_0->AsDependencePoint() && constraint_1->AsDependencePoint()) {
1208
0
    auto point_0 = constraint_0->AsDependencePoint();
1209
0
    auto point_1 = constraint_1->AsDependencePoint();
1210
1211
0
    if (*point_0->GetSource() == *point_1->GetSource() &&
1212
0
        *point_0->GetDestination() == *point_1->GetDestination()) {
1213
0
      return constraint_0;
1214
0
    } else {
1215
0
      return make_constraint<DependenceEmpty>();
1216
0
    }
1217
0
  }
1218
1219
  // Both constraints are lines/distances.
1220
0
  if ((constraint_0->AsDependenceDistance() ||
1221
0
       constraint_0->AsDependenceLine()) &&
1222
0
      (constraint_1->AsDependenceDistance() ||
1223
0
       constraint_1->AsDependenceLine())) {
1224
0
    auto is_distance_0 = constraint_0->AsDependenceDistance() != nullptr;
1225
0
    auto is_distance_1 = constraint_1->AsDependenceDistance() != nullptr;
1226
1227
0
    auto a0 = is_distance_0 ? scalar_evolution_.CreateConstant(1)
1228
0
                            : constraint_0->AsDependenceLine()->GetA();
1229
0
    auto b0 = is_distance_0 ? scalar_evolution_.CreateConstant(-1)
1230
0
                            : constraint_0->AsDependenceLine()->GetB();
1231
0
    auto c0 =
1232
0
        is_distance_0
1233
0
            ? scalar_evolution_.SimplifyExpression(
1234
0
                  scalar_evolution_.CreateNegation(
1235
0
                      constraint_0->AsDependenceDistance()->GetDistance()))
1236
0
            : constraint_0->AsDependenceLine()->GetC();
1237
1238
0
    auto a1 = is_distance_1 ? scalar_evolution_.CreateConstant(1)
1239
0
                            : constraint_1->AsDependenceLine()->GetA();
1240
0
    auto b1 = is_distance_1 ? scalar_evolution_.CreateConstant(-1)
1241
0
                            : constraint_1->AsDependenceLine()->GetB();
1242
0
    auto c1 =
1243
0
        is_distance_1
1244
0
            ? scalar_evolution_.SimplifyExpression(
1245
0
                  scalar_evolution_.CreateNegation(
1246
0
                      constraint_1->AsDependenceDistance()->GetDistance()))
1247
0
            : constraint_1->AsDependenceLine()->GetC();
1248
1249
0
    if (a0->AsSEConstantNode() && b0->AsSEConstantNode() &&
1250
0
        c0->AsSEConstantNode() && a1->AsSEConstantNode() &&
1251
0
        b1->AsSEConstantNode() && c1->AsSEConstantNode()) {
1252
0
      auto constant_a0 = a0->AsSEConstantNode()->FoldToSingleValue();
1253
0
      auto constant_b0 = b0->AsSEConstantNode()->FoldToSingleValue();
1254
0
      auto constant_c0 = c0->AsSEConstantNode()->FoldToSingleValue();
1255
1256
0
      auto constant_a1 = a1->AsSEConstantNode()->FoldToSingleValue();
1257
0
      auto constant_b1 = b1->AsSEConstantNode()->FoldToSingleValue();
1258
0
      auto constant_c1 = c1->AsSEConstantNode()->FoldToSingleValue();
1259
1260
      // a & b can't both be zero, otherwise it wouldn't be line.
1261
0
      if (NormalizeAndCompareFractions(constant_a0, constant_b0, constant_a1,
1262
0
                                       constant_b1)) {
1263
        // Slopes are equal, either parallel lines or the same line.
1264
1265
0
        if (constant_b0 == 0 && constant_b1 == 0) {
1266
0
          if (NormalizeAndCompareFractions(constant_c0, constant_a0,
1267
0
                                           constant_c1, constant_a1)) {
1268
0
            return constraint_0;
1269
0
          }
1270
1271
0
          return make_constraint<DependenceEmpty>();
1272
0
        } else if (NormalizeAndCompareFractions(constant_c0, constant_b0,
1273
0
                                                constant_c1, constant_b1)) {
1274
          // Same line.
1275
0
          return constraint_0;
1276
0
        } else {
1277
          // Parallel lines can't intersect, report independence.
1278
0
          return make_constraint<DependenceEmpty>();
1279
0
        }
1280
1281
0
      } else {
1282
        // Lines are not parallel, therefore, they must intersect.
1283
1284
        // Calculate intersection.
1285
0
        if (upper_bound->AsSEConstantNode() &&
1286
0
            lower_bound->AsSEConstantNode()) {
1287
0
          auto constant_lower_bound =
1288
0
              lower_bound->AsSEConstantNode()->FoldToSingleValue();
1289
0
          auto constant_upper_bound =
1290
0
              upper_bound->AsSEConstantNode()->FoldToSingleValue();
1291
1292
0
          auto up = constant_b1 * constant_c0 - constant_b0 * constant_c1;
1293
          // Both b or both a can't be 0, so down is never 0
1294
          // otherwise would have entered the parallel line section.
1295
0
          auto down = constant_b1 * constant_a0 - constant_b0 * constant_a1;
1296
1297
0
          auto x_coord = up / down;
1298
1299
0
          int64_t y_coord = 0;
1300
0
          int64_t arg1 = 0;
1301
0
          int64_t const_b_to_use = 0;
1302
1303
0
          if (constant_b1 != 0) {
1304
0
            arg1 = constant_c1 - constant_a1 * x_coord;
1305
0
            y_coord = arg1 / constant_b1;
1306
0
            const_b_to_use = constant_b1;
1307
0
          } else if (constant_b0 != 0) {
1308
0
            arg1 = constant_c0 - constant_a0 * x_coord;
1309
0
            y_coord = arg1 / constant_b0;
1310
0
            const_b_to_use = constant_b0;
1311
0
          }
1312
1313
0
          if (up % down == 0 &&
1314
0
              arg1 % const_b_to_use == 0 &&  // Coordinates are integers.
1315
0
              constant_lower_bound <=
1316
0
                  x_coord &&  // x_coord is within loop bounds.
1317
0
              x_coord <= constant_upper_bound &&
1318
0
              constant_lower_bound <=
1319
0
                  y_coord &&  // y_coord is within loop bounds.
1320
0
              y_coord <= constant_upper_bound) {
1321
            // Lines intersect at integer coordinates.
1322
0
            return make_constraint<DependencePoint>(
1323
0
                scalar_evolution_.CreateConstant(x_coord),
1324
0
                scalar_evolution_.CreateConstant(y_coord),
1325
0
                constraint_0->GetLoop());
1326
1327
0
          } else {
1328
0
            return make_constraint<DependenceEmpty>();
1329
0
          }
1330
1331
0
        } else {
1332
          // Not constants, bail out.
1333
0
          return make_constraint<DependenceNone>();
1334
0
        }
1335
0
      }
1336
1337
0
    } else {
1338
      // Not constants, bail out.
1339
0
      return make_constraint<DependenceNone>();
1340
0
    }
1341
0
  }
1342
1343
  // One constraint is a line/distance and the other is a point.
1344
0
  if ((constraint_0->AsDependencePoint() &&
1345
0
       (constraint_1->AsDependenceLine() ||
1346
0
        constraint_1->AsDependenceDistance())) ||
1347
0
      (constraint_1->AsDependencePoint() &&
1348
0
       (constraint_0->AsDependenceLine() ||
1349
0
        constraint_0->AsDependenceDistance()))) {
1350
0
    auto point_0 = constraint_0->AsDependencePoint() != nullptr;
1351
1352
0
    auto point = point_0 ? constraint_0->AsDependencePoint()
1353
0
                         : constraint_1->AsDependencePoint();
1354
1355
0
    auto line_or_distance = point_0 ? constraint_1 : constraint_0;
1356
1357
0
    auto is_distance = line_or_distance->AsDependenceDistance() != nullptr;
1358
1359
0
    auto a = is_distance ? scalar_evolution_.CreateConstant(1)
1360
0
                         : line_or_distance->AsDependenceLine()->GetA();
1361
0
    auto b = is_distance ? scalar_evolution_.CreateConstant(-1)
1362
0
                         : line_or_distance->AsDependenceLine()->GetB();
1363
0
    auto c =
1364
0
        is_distance
1365
0
            ? scalar_evolution_.SimplifyExpression(
1366
0
                  scalar_evolution_.CreateNegation(
1367
0
                      line_or_distance->AsDependenceDistance()->GetDistance()))
1368
0
            : line_or_distance->AsDependenceLine()->GetC();
1369
1370
0
    auto x = point->GetSource();
1371
0
    auto y = point->GetDestination();
1372
1373
0
    if (a->AsSEConstantNode() && b->AsSEConstantNode() &&
1374
0
        c->AsSEConstantNode() && x->AsSEConstantNode() &&
1375
0
        y->AsSEConstantNode()) {
1376
0
      auto constant_a = a->AsSEConstantNode()->FoldToSingleValue();
1377
0
      auto constant_b = b->AsSEConstantNode()->FoldToSingleValue();
1378
0
      auto constant_c = c->AsSEConstantNode()->FoldToSingleValue();
1379
1380
0
      auto constant_x = x->AsSEConstantNode()->FoldToSingleValue();
1381
0
      auto constant_y = y->AsSEConstantNode()->FoldToSingleValue();
1382
1383
0
      auto left_hand_side = constant_a * constant_x + constant_b * constant_y;
1384
1385
0
      if (left_hand_side == constant_c) {
1386
        // Point is on line, return point
1387
0
        return point_0 ? constraint_0 : constraint_1;
1388
0
      } else {
1389
        // Point not on line, report independence (empty constraint).
1390
0
        return make_constraint<DependenceEmpty>();
1391
0
      }
1392
1393
0
    } else {
1394
      // Not constants, bail out.
1395
0
      return make_constraint<DependenceNone>();
1396
0
    }
1397
0
  }
1398
1399
0
  return nullptr;
1400
0
}
1401
1402
// Propagate constraints function as described in section 5 of Practical
1403
// Dependence Testing, Goff, Kennedy, Tseng, 1991.
1404
SubscriptPair LoopDependenceAnalysis::PropagateConstraints(
1405
    const SubscriptPair& subscript_pair,
1406
0
    const std::vector<Constraint*>& constraints) {
1407
0
  SENode* new_first = subscript_pair.first;
1408
0
  SENode* new_second = subscript_pair.second;
1409
1410
0
  for (auto& constraint : constraints) {
1411
    // In the paper this is a[k]. We're extracting the coefficient ('a') of a
1412
    // recurrent expression with respect to the loop 'k'.
1413
0
    SENode* coefficient_of_recurrent =
1414
0
        scalar_evolution_.GetCoefficientFromRecurrentTerm(
1415
0
            new_first, constraint->GetLoop());
1416
1417
    // In the paper this is a'[k].
1418
0
    SENode* coefficient_of_recurrent_prime =
1419
0
        scalar_evolution_.GetCoefficientFromRecurrentTerm(
1420
0
            new_second, constraint->GetLoop());
1421
1422
0
    if (constraint->GetType() == Constraint::Distance) {
1423
0
      DependenceDistance* as_distance = constraint->AsDependenceDistance();
1424
1425
      // In the paper this is a[k]*d
1426
0
      SENode* rhs = scalar_evolution_.CreateMultiplyNode(
1427
0
          coefficient_of_recurrent, as_distance->GetDistance());
1428
1429
      // In the paper this is a[k] <- 0
1430
0
      SENode* zeroed_coefficient =
1431
0
          scalar_evolution_.BuildGraphWithoutRecurrentTerm(
1432
0
              new_first, constraint->GetLoop());
1433
1434
      // In the paper this is e <- e - a[k]*d.
1435
0
      new_first = scalar_evolution_.CreateSubtraction(zeroed_coefficient, rhs);
1436
0
      new_first = scalar_evolution_.SimplifyExpression(new_first);
1437
1438
      // In the paper this is a'[k] - a[k].
1439
0
      SENode* new_child = scalar_evolution_.SimplifyExpression(
1440
0
          scalar_evolution_.CreateSubtraction(coefficient_of_recurrent_prime,
1441
0
                                              coefficient_of_recurrent));
1442
1443
      // In the paper this is a'[k]'i[k].
1444
0
      SERecurrentNode* prime_recurrent =
1445
0
          scalar_evolution_.GetRecurrentTerm(new_second, constraint->GetLoop());
1446
1447
0
      if (!prime_recurrent) continue;
1448
1449
      // As we hash the nodes we need to create a new node when we update a
1450
      // child.
1451
0
      SENode* new_recurrent = scalar_evolution_.CreateRecurrentExpression(
1452
0
          constraint->GetLoop(), prime_recurrent->GetOffset(), new_child);
1453
      // In the paper this is a'[k] <- a'[k] - a[k].
1454
0
      new_second = scalar_evolution_.UpdateChildNode(
1455
0
          new_second, prime_recurrent, new_recurrent);
1456
0
    }
1457
0
  }
1458
1459
0
  new_second = scalar_evolution_.SimplifyExpression(new_second);
1460
0
  return std::make_pair(new_first, new_second);
1461
0
}
1462
1463
bool LoopDependenceAnalysis::DeltaTest(
1464
    const std::vector<SubscriptPair>& coupled_subscripts,
1465
0
    DistanceVector* dv_entry) {
1466
0
  std::vector<Constraint*> constraints(loops_.size());
1467
1468
0
  std::vector<bool> loop_appeared(loops_.size());
1469
1470
0
  std::generate(std::begin(constraints), std::end(constraints),
1471
0
                [this]() { return make_constraint<DependenceNone>(); });
1472
1473
  // Separate SIV and MIV subscripts
1474
0
  std::vector<SubscriptPair> siv_subscripts{};
1475
0
  std::vector<SubscriptPair> miv_subscripts{};
1476
1477
0
  for (const auto& subscript_pair : coupled_subscripts) {
1478
0
    if (IsSIV(subscript_pair)) {
1479
0
      siv_subscripts.push_back(subscript_pair);
1480
0
    } else {
1481
0
      miv_subscripts.push_back(subscript_pair);
1482
0
    }
1483
0
  }
1484
1485
  // Delta Test
1486
0
  while (!siv_subscripts.empty()) {
1487
0
    std::vector<bool> results(siv_subscripts.size());
1488
1489
0
    std::vector<DistanceVector> current_distances(
1490
0
        siv_subscripts.size(), DistanceVector(loops_.size()));
1491
1492
    // Apply SIV test to all SIV subscripts, report independence if any of them
1493
    // is independent
1494
0
    std::transform(
1495
0
        std::begin(siv_subscripts), std::end(siv_subscripts),
1496
0
        std::begin(current_distances), std::begin(results),
1497
0
        [this](SubscriptPair& p, DistanceVector& d) { return SIVTest(p, &d); });
1498
1499
0
    if (std::accumulate(std::begin(results), std::end(results), false,
1500
0
                        std::logical_or<bool>{})) {
1501
0
      return true;
1502
0
    }
1503
1504
    // Derive new constraint vector.
1505
0
    std::vector<std::pair<Constraint*, size_t>> all_new_constrants{};
1506
1507
0
    for (size_t i = 0; i < siv_subscripts.size(); ++i) {
1508
0
      auto loop = GetLoopForSubscriptPair(siv_subscripts[i]);
1509
1510
0
      auto loop_id =
1511
0
          std::distance(std::begin(loops_),
1512
0
                        std::find(std::begin(loops_), std::end(loops_), loop));
1513
1514
0
      loop_appeared[loop_id] = true;
1515
0
      auto distance_entry = current_distances[i].GetEntries()[loop_id];
1516
1517
0
      if (distance_entry.dependence_information ==
1518
0
          DistanceEntry::DependenceInformation::DISTANCE) {
1519
        // Construct a DependenceDistance.
1520
0
        auto node = scalar_evolution_.CreateConstant(distance_entry.distance);
1521
1522
0
        all_new_constrants.push_back(
1523
0
            {make_constraint<DependenceDistance>(node, loop), loop_id});
1524
0
      } else {
1525
        // Construct a DependenceLine.
1526
0
        const auto& subscript_pair = siv_subscripts[i];
1527
0
        SENode* source_node = std::get<0>(subscript_pair);
1528
0
        SENode* destination_node = std::get<1>(subscript_pair);
1529
1530
0
        int64_t source_induction_count = CountInductionVariables(source_node);
1531
0
        int64_t destination_induction_count =
1532
0
            CountInductionVariables(destination_node);
1533
1534
0
        SENode* a = nullptr;
1535
0
        SENode* b = nullptr;
1536
0
        SENode* c = nullptr;
1537
1538
0
        if (destination_induction_count != 0) {
1539
0
          a = destination_node->AsSERecurrentNode()->GetCoefficient();
1540
0
          c = scalar_evolution_.CreateNegation(
1541
0
              destination_node->AsSERecurrentNode()->GetOffset());
1542
0
        } else {
1543
0
          a = scalar_evolution_.CreateConstant(0);
1544
0
          c = scalar_evolution_.CreateNegation(destination_node);
1545
0
        }
1546
1547
0
        if (source_induction_count != 0) {
1548
0
          b = scalar_evolution_.CreateNegation(
1549
0
              source_node->AsSERecurrentNode()->GetCoefficient());
1550
0
          c = scalar_evolution_.CreateAddNode(
1551
0
              c, source_node->AsSERecurrentNode()->GetOffset());
1552
0
        } else {
1553
0
          b = scalar_evolution_.CreateConstant(0);
1554
0
          c = scalar_evolution_.CreateAddNode(c, source_node);
1555
0
        }
1556
1557
0
        a = scalar_evolution_.SimplifyExpression(a);
1558
0
        b = scalar_evolution_.SimplifyExpression(b);
1559
0
        c = scalar_evolution_.SimplifyExpression(c);
1560
1561
0
        all_new_constrants.push_back(
1562
0
            {make_constraint<DependenceLine>(a, b, c, loop), loop_id});
1563
0
      }
1564
0
    }
1565
1566
    // Calculate the intersection between the new and existing constraints.
1567
0
    std::vector<Constraint*> intersection = constraints;
1568
0
    for (const auto& constraint_to_intersect : all_new_constrants) {
1569
0
      auto loop_id = std::get<1>(constraint_to_intersect);
1570
0
      auto loop = loops_[loop_id];
1571
0
      intersection[loop_id] = IntersectConstraints(
1572
0
          intersection[loop_id], std::get<0>(constraint_to_intersect),
1573
0
          GetLowerBound(loop), GetUpperBound(loop));
1574
0
    }
1575
1576
    // Report independence if an empty constraint (DependenceEmpty) is found.
1577
0
    auto first_empty =
1578
0
        std::find_if(std::begin(intersection), std::end(intersection),
1579
0
                     [](Constraint* constraint) {
1580
0
                       return constraint->AsDependenceEmpty() != nullptr;
1581
0
                     });
1582
0
    if (first_empty != std::end(intersection)) {
1583
0
      return true;
1584
0
    }
1585
0
    std::vector<SubscriptPair> new_siv_subscripts{};
1586
0
    std::vector<SubscriptPair> new_miv_subscripts{};
1587
1588
0
    auto equal =
1589
0
        std::equal(std::begin(constraints), std::end(constraints),
1590
0
                   std::begin(intersection),
1591
0
                   [](Constraint* a, Constraint* b) { return *a == *b; });
1592
1593
    // If any constraints have changed, propagate them into the rest of the
1594
    // subscripts possibly creating new ZIV/SIV subscripts.
1595
0
    if (!equal) {
1596
0
      std::vector<SubscriptPair> new_subscripts(miv_subscripts.size());
1597
1598
      // Propagate constraints into MIV subscripts
1599
0
      std::transform(std::begin(miv_subscripts), std::end(miv_subscripts),
1600
0
                     std::begin(new_subscripts),
1601
0
                     [this, &intersection](SubscriptPair& subscript_pair) {
1602
0
                       return PropagateConstraints(subscript_pair,
1603
0
                                                   intersection);
1604
0
                     });
1605
1606
      // If a ZIV subscript is returned, apply test, otherwise, update untested
1607
      // subscripts.
1608
0
      for (auto& subscript : new_subscripts) {
1609
0
        if (IsZIV(subscript) && ZIVTest(subscript)) {
1610
0
          return true;
1611
0
        } else if (IsSIV(subscript)) {
1612
0
          new_siv_subscripts.push_back(subscript);
1613
0
        } else {
1614
0
          new_miv_subscripts.push_back(subscript);
1615
0
        }
1616
0
      }
1617
0
    }
1618
1619
    // Set new constraints and subscripts to test.
1620
0
    std::swap(siv_subscripts, new_siv_subscripts);
1621
0
    std::swap(miv_subscripts, new_miv_subscripts);
1622
0
    std::swap(constraints, intersection);
1623
0
  }
1624
1625
  // Create the dependence vector from the constraints.
1626
0
  for (size_t i = 0; i < loops_.size(); ++i) {
1627
    // Don't touch entries for loops that weren't tested.
1628
0
    if (loop_appeared[i]) {
1629
0
      auto current_constraint = constraints[i];
1630
0
      auto& current_distance_entry = (*dv_entry).GetEntries()[i];
1631
1632
0
      if (auto dependence_distance =
1633
0
              current_constraint->AsDependenceDistance()) {
1634
0
        if (auto constant_node =
1635
0
                dependence_distance->GetDistance()->AsSEConstantNode()) {
1636
0
          current_distance_entry.dependence_information =
1637
0
              DistanceEntry::DependenceInformation::DISTANCE;
1638
1639
0
          current_distance_entry.distance = constant_node->FoldToSingleValue();
1640
0
          if (current_distance_entry.distance == 0) {
1641
0
            current_distance_entry.direction = DistanceEntry::Directions::EQ;
1642
0
          } else if (current_distance_entry.distance < 0) {
1643
0
            current_distance_entry.direction = DistanceEntry::Directions::GT;
1644
0
          } else {
1645
0
            current_distance_entry.direction = DistanceEntry::Directions::LT;
1646
0
          }
1647
0
        }
1648
0
      } else if (auto dependence_point =
1649
0
                     current_constraint->AsDependencePoint()) {
1650
0
        auto source = dependence_point->GetSource();
1651
0
        auto destination = dependence_point->GetDestination();
1652
1653
0
        if (source->AsSEConstantNode() && destination->AsSEConstantNode()) {
1654
0
          current_distance_entry = DistanceEntry(
1655
0
              source->AsSEConstantNode()->FoldToSingleValue(),
1656
0
              destination->AsSEConstantNode()->FoldToSingleValue());
1657
0
        }
1658
0
      }
1659
0
    }
1660
0
  }
1661
1662
  // Test any remaining MIV subscripts and report independence if found.
1663
0
  std::vector<bool> results(miv_subscripts.size());
1664
1665
0
  std::transform(std::begin(miv_subscripts), std::end(miv_subscripts),
1666
0
                 std::begin(results),
1667
0
                 [this](const SubscriptPair& p) { return GCDMIVTest(p); });
1668
1669
0
  return std::accumulate(std::begin(results), std::end(results), false,
1670
0
                         std::logical_or<bool>{});
1671
0
}
1672
1673
}  // namespace opt
1674
}  // namespace spvtools