[PATCH] D34397: [SCEV] Make MulOpsInlineThreshold lower to avoid excessive compilation time

Max Kazantsev via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Tue Jun 20 23:33:43 PDT 2017


mkazantsev added a comment.

In https://reviews.llvm.org/D34397#786272, @mkazantsev wrote:

> Sanjoy, actually merging operand Muls into patent Mul is O(N^2) by itself: you need a linear time to merge each of them (and if we sort them by time, it is N log(N)). So if you have a parent Mul of max ops amount, and which op is also a Mul node with max Ops amount, then oops - we will merge them for long.
>
> This is where we spend a lot of time in this particular test, but I don't exclude that there are other algorithms that will die on this step.


Maybe not the best explanation, let me be more specific.

  while (const SCEVMulExpr *Mul = dyn_cast<SCEVMulExpr>(Ops[Idx])) { 
    if (Ops.size() > MulOpsInlineThreshold)
      break;
    // If we have an mul, expand the mul operands onto the end of the
    // operands list.
    Ops.erase(Ops.begin()+Idx);                                    // Erase
    Ops.append(Mul->op_begin(), Mul->op_end());    // Append
    DeletedMul = true;
  }

If we have N ops on current level, each of these ops is a Mul with M ops (and N * M = MulOpsInlineThreshold), we:

1. Make N appends of M elements, with total cost N * M;
2. Make N erases, cost of each one is linear from number of ops on current level. On i-th iteration, we have N + M * (i - 1) ops on current level. The overall cost of these erases is O(sum(i = 1 ... N) (N + M * (i - 1))), which is O(N^2 + N*M).

The overall complexity is O(N^2 + N*M), which is extremely bad if (for example) N = 500, M = 2. Maybe we should consider rewriting this algorithm so that we don't make these erases.

And again, I don't see why similar problems shouldn't happen in other places.


https://reviews.llvm.org/D34397





More information about the llvm-commits mailing list