[llvm] [LoopInterchange] Improve profitability check for vectorization (PR #133672)

Michael Kruse via llvm-commits llvm-commits at lists.llvm.org
Mon Jul 14 06:13:16 PDT 2025


================
@@ -1197,27 +1209,57 @@ LoopInterchangeProfitability::isProfitablePerInstrOrderCost() {
   return std::nullopt;
 }
 
+static char flipDirection(char Dir) {
+  switch (Dir) {
+  case '<':
+    return '>';
+  case '>':
+    return '<';
+  case '=':
+  case 'I':
+  case '*':
+    return Dir;
+  default:
+    llvm_unreachable("Unknown direction");
+  }
+}
+
 /// Return true if we can vectorize the loop specified by \p LoopId.
-static bool canVectorize(const CharMatrix &DepMatrix, unsigned LoopId) {
+static bool canVectorize(const CharMatrix &DepMatrix,
+                         const BitVector &IsNegatedVec, unsigned LoopId) {
+  // The loop can be vectorized if there are no negative dependencies. Consider
+  // the dependency of `j` in the following example.
+  //
+  //   Positive: ... = A[i][j]       Negative: ... = A[i][j-1]
+  //             A[i][j-1] = ...               A[i][j] = ...
----------------
Meinersbur wrote:

postive/negative refers to the difference of (normalized) loop induction values (`i`, `j`)

forward/backward refers to the execution order of statements within the loop body. A forward dependence is just the normal execution flow, e.g.
```c
for (int i = 1; i < n; ++i) {
  A[i-1] = 42; // A[i] would still be a read-after-write forward dependency
  use(A[i]);
}
```
A backward dependence is when the source of a dependences is a statement that is located after the destination in the loop body, necessarily from a previous iteration:
```c
for (int i = 1; i < n; ++i) {
  use(A[i]);
  A[i-1] = 42; // A[i] would make this a write-after-read forward dependency
}
```
In the polyhedral model one just assigns numbers to the sequence of statements in the loop which allows doing calculations over statement order as if it was another loop:
```c
for (int i = 0; i < n; ++i) {
  for (int k = 0; k < 2; ++i) {
    switch (k) {
    case 0:
      use(A[i]);
      break;
    case 1:
      A[i-1] = 42; 
      break;
    }
  }
}
```
In this view, a forward dependency is when the innermost distance vector element (i.e. `k`) is positive, and a backward dependency is when the innermost dependence vector element is negative. I find this view helpful.

As mentioned, the execution order of statements is ambigious if the body is not straight-line code. I had lenghty discussions on the OpenMP language committee about it. For instance, assume an if/else construct:
```c
for (int i = 0; i < n; ++i) {
  if (i%2==0)
     use(A[i]);
  else
    A[i-1] = 42; 
}
```
Is this a forward or backward dependency? It is kind-of ill-defind because within the same body iteration, only one of the statements is ever executed, so there is no order between them. This become clearer if you consider that the following has the very same semantics:
```c
for (int i = 0; i < n; ++i) {
  if (i%2==1)
     A[i-1] = 42; 
  else
     use(A[i]);
}
```
So it does not matter? Well it does id you vectorize using predicated instructions. You can vectorize the latter, with simd width of 2 (and more if you allow store-to-load forwarding), but you cannot vectorize the former, at least not by just replacing every statement with its vector equivalent. If you want to keep it simple, just consider stright-line code within a single BB.

The entire forward/backward nomenclature also breaks down if you allow non-perfectly nested loops.

https://github.com/llvm/llvm-project/pull/133672


More information about the llvm-commits mailing list