As discussed in https://reviews.llvm.org/D119743 scf.parallel would continuously stack allocate since the alloca op was placd in the wsloop rather than the omp.parallel. This PR is the second stage of the fix for that problem. Specifically, we now introduce an alloca scope around the inlined body of the scf.parallel and enable a canonicalization to hoist the allocations to the surrounding allocation scope (e.g. omp.parallel).
Details
Diff Detail
- Repository
- rG LLVM Github Monorepo
Event Timeline
mlir/lib/Conversion/SCFToOpenMP/SCFToOpenMP.cpp | ||
---|---|---|
398–418 | Please run clang-format? |
Conversion changes look okay. Canonicalization changes less so. An explicit allocation scope forces deallocation at its end, and it looks like both canonicalizations would change the point where deallocation happens. It's okay to merge two nested allocation scopes if they are perfectly nested, otherwise the allocations from the nested scope will be live longer than before. Similarly, hoisting can change the lifetime of an allocation. I'm fine with such lifetime-extending transformations in a separate pass, but not as canonicalizations (which are not expected to change semantics).
Specifically about the hoisting pattern, I don't completely follow what it does and there are no tests specifically for it. It seems to be moving allocations from a scope operation a parent scope operation, which may not be always desirable.
mlir/include/mlir/Conversion/Passes.td | ||
---|---|---|
504–505 | 80 cols plz | |
mlir/lib/Dialect/MemRef/IR/MemRefOps.cpp | ||
2604 | Let's not spuriously move the code around. Op implementations were sorted alphabetically AFAICS. | |
2659 | Nit: make static + add documentation. | |
2660–2662 | This is too optimistic. If the operation, e.g., an unregistered one, doesn't implement the interface, it may still perform the allocation. We can only be sure that it does not allocate if it has the interface and does not declare the effect with it. | |
2664 | Why limit to the first result only? | |
2672 | Nit: /// for top-level comments. | |
2680–2684 | Could you extract the lambda or the walk from the if? | |
2699 | This pattern needs dedicated tests. | |
2704–2712 | This makes assumptions about the nesting structure of ops. In particular, it seems to assume there is always a parent op with the scope trait. This is not necessarily the case, e.g., one can have a custom function op that doesn't have the trait for whatever reason. Please check that the parent op exists before querying its properties. | |
2724–2725 | You shouldn't be needing to iterate over all regions of a parent op, you know which one of those contains the current op. |
mlir/lib/Dialect/MemRef/IR/MemRefOps.cpp | ||
---|---|---|
2699 | The two region-based scopeMerge2 and scopeMerge3 tests should test this canonicalizer (and ensure it does and/or doesn't run when relevant). |
mlir/lib/Dialect/MemRef/IR/MemRefOps.cpp | ||
---|---|---|
296–298 | I can't parse the "last non terminating block in a region", blocks are not terminators, ops are. | |
353 | if (lastParentWithoutScope == nullptr) return failure(); | |
362–363 | while (lastParentWIthoutScope->getParentOp() && the-curent-condition) or factor it out to a variable | |
mlir/test/Dialect/MemRef/canonicalize.mlir | ||
567 | Nit: we likely don't care about these operations being on consecutive lines, so no need for -NEXT here and below. |
80 cols plz