diff --git a/flang/include/flang/Optimizer/Transforms/Passes.h b/flang/include/flang/Optimizer/Transforms/Passes.h --- a/flang/include/flang/Optimizer/Transforms/Passes.h +++ b/flang/include/flang/Optimizer/Transforms/Passes.h @@ -35,6 +35,8 @@ std::unique_ptr createMemDataFlowOptPass(); std::unique_ptr createPromoteToAffinePass(); std::unique_ptr createMemoryAllocationPass(); +std::unique_ptr +createMemoryAllocationPass(bool dynOnHeap, std::size_t maxStackSize); // declarative passes #define GEN_PASS_REGISTRATION diff --git a/flang/include/flang/Tools/CLOptions.inc b/flang/include/flang/Tools/CLOptions.inc --- a/flang/include/flang/Tools/CLOptions.inc +++ b/flang/include/flang/Tools/CLOptions.inc @@ -87,6 +87,13 @@ pm, disableFirAvc, fir::createArrayValueCopyPass); } +inline void addMemoryAllocationOpt(mlir::PassManager &pm) { + addNestedPassConditionally(pm, disableFirMao, [&]() { + return fir::createMemoryAllocationPass( + dynamicArrayStackToHeapAllocation, arrayStackAllocationThreshold); + }); +} + #if !defined(FLANG_EXCLUDE_CODEGEN) inline void addCodeGenRewritePass(mlir::PassManager &pm) { addPassConditionally( @@ -121,6 +128,7 @@ fir::addAVC(pm); pm.addNestedPass(fir::createCharacterConversionPass()); pm.addPass(mlir::createCanonicalizerPass(config)); + fir::addMemoryAllocationOpt(pm); // The default inliner pass adds the canonicalizer pass with the default // configuration. Create the inliner pass with tco config. diff --git a/flang/lib/Optimizer/Transforms/MemoryAllocation.cpp b/flang/lib/Optimizer/Transforms/MemoryAllocation.cpp --- a/flang/lib/Optimizer/Transforms/MemoryAllocation.cpp +++ b/flang/lib/Optimizer/Transforms/MemoryAllocation.cpp @@ -21,7 +21,7 @@ #define DEBUG_TYPE "flang-memory-allocation-opt" // Number of elements in an array does not determine where it is allocated. -static constexpr std::size_t UnlimitedArraySize = ~static_cast(0); +static constexpr std::size_t unlimitedArraySize = ~static_cast(0); namespace { struct MemoryAllocationOptions { @@ -32,7 +32,7 @@ // Number of elements in array threshold for moving to heap. In environments // with limited stack size, moving large arrays to the heap can avoid running // out of stack space. - std::size_t maxStackArraySize = UnlimitedArraySize; + std::size_t maxStackArraySize = unlimitedArraySize; }; class ReturnAnalysis { @@ -150,13 +150,36 @@ class MemoryAllocationOpt : public fir::MemoryAllocationOptBase { public: + MemoryAllocationOpt() { + // Set options with default values. (See Passes.td.) Note that the + // command-line options, e.g. dynamicArrayOnHeap, are not set yet. + options = {dynamicArrayOnHeap, maxStackArraySize}; + } + + MemoryAllocationOpt(bool dynOnHeap, std::size_t maxStackSize) { + // Set options with default values. (See Passes.td.) + options = {dynOnHeap, maxStackSize}; + } + + /// Override `options` if command-line options have been set. + inline void useCommandLineOptions() { + if (dynamicArrayOnHeap) + options.dynamicArrayOnHeap = dynamicArrayOnHeap; + if (maxStackArraySize != unlimitedArraySize) + options.maxStackArraySize = maxStackArraySize; + } + void runOnOperation() override { auto *context = &getContext(); auto func = getOperation(); mlir::OwningRewritePatternList patterns(context); mlir::ConversionTarget target(*context); - MemoryAllocationOptions options = {dynamicArrayOnHeap.getValue(), - maxStackArraySize.getValue()}; + + useCommandLineOptions(); + LLVM_DEBUG(llvm::dbgs() + << "dynamic arrays on heap: " << options.dynamicArrayOnHeap + << "\nmaximum number of elements of array on stack: " + << options.maxStackArraySize << '\n'); // If func is a declaration, skip it. if (func.empty()) @@ -178,9 +201,17 @@ signalPassFailure(); } } + +private: + MemoryAllocationOptions options; }; } // namespace std::unique_ptr fir::createMemoryAllocationPass() { return std::make_unique(); } + +std::unique_ptr +fir::createMemoryAllocationPass(bool dynOnHeap, std::size_t maxStackSize) { + return std::make_unique(dynOnHeap, maxStackSize); +}