Skip to content

Commit 29d857f

Browse files
authored
[flang] Add stack reclaim pass to reclaim allocas in loop (llvm#95309)
Some passes in the flang pipeline are creating `fir.alloca` operation like `hlfir.concat`. When these allocas are located in a loop, the stack can quickly be used too much leading to segfaults. This behavior can be seen in https://github.com/jacobwilliams/json-fortran/blob/master/src/tests/jf_test_36.F90 This patch insert a call to LLVM stacksave/stackrestore in the body of the loop to reclaim the alloca in its scope. This PR is an alternative implementation to llvm#95173
1 parent 38fd018 commit 29d857f

File tree

10 files changed

+94
-0
lines changed

10 files changed

+94
-0
lines changed

flang/include/flang/Optimizer/Transforms/Passes.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ namespace fir {
4949
#define GEN_PASS_DECL_OPENACCDATAOPERANDCONVERSION
5050
#define GEN_PASS_DECL_ADDDEBUGINFO
5151
#define GEN_PASS_DECL_STACKARRAYS
52+
#define GEN_PASS_DECL_STACKRECLAIM
5253
#define GEN_PASS_DECL_LOOPVERSIONING
5354
#define GEN_PASS_DECL_ADDALIASTAGS
5455
#define GEN_PASS_DECL_OMPMAPINFOFINALIZATIONPASS

flang/include/flang/Optimizer/Transforms/Passes.td

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,15 @@ def StackArrays : Pass<"stack-arrays", "mlir::ModuleOp"> {
260260
let dependentDialects = [ "fir::FIROpsDialect" ];
261261
}
262262

263+
def StackReclaim : Pass<"stack-reclaim"> {
264+
let summary = "Insert stacksave/stackrestore in region with allocas";
265+
let description = [{
266+
Insert stacksave/stackrestore in loop region to reclaim alloca done in its
267+
scope.
268+
}];
269+
let dependentDialects = [ "mlir::LLVM::LLVMDialect" ];
270+
}
271+
263272
def AddAliasTags : Pass<"fir-add-alias-tags", "mlir::ModuleOp"> {
264273
let summary = "Add tbaa tags to operations that implement FirAliasAnalysisOpInterface";
265274
let description = [{

flang/include/flang/Tools/CLOptions.inc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,7 @@ inline void createDefaultFIROptimizerPassPipeline(
295295
if (pc.AliasAnalysis && !disableFirAliasTags && !useOldAliasTags)
296296
pm.addPass(fir::createAddAliasTags());
297297

298+
addNestedPassToAllTopLevelOperations(pm, fir::createStackReclaim);
298299
// convert control flow to CFG form
299300
fir::addCfgConversionPass(pm, pc);
300301
pm.addPass(mlir::createConvertSCFToCFPass());

flang/lib/Optimizer/Transforms/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ add_flang_library(FIRTransforms
2121
OMPFunctionFiltering.cpp
2222
OMPMapInfoFinalization.cpp
2323
OMPMarkDeclareTarget.cpp
24+
StackReclaim.cpp
2425
VScaleAttr.cpp
2526
FunctionAttr.cpp
2627
DebugTypeGenerator.cpp
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
//===- StackReclaim.cpp -- Insert stacksave/stackrestore in region --------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "flang/Common/Fortran.h"
10+
#include "flang/Optimizer/Dialect/FIRDialect.h"
11+
#include "flang/Optimizer/Dialect/FIROps.h"
12+
#include "flang/Optimizer/Transforms/Passes.h"
13+
#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
14+
#include "mlir/IR/Matchers.h"
15+
#include "mlir/Pass/Pass.h"
16+
17+
namespace fir {
18+
#define GEN_PASS_DEF_STACKRECLAIM
19+
#include "flang/Optimizer/Transforms/Passes.h.inc"
20+
} // namespace fir
21+
22+
using namespace mlir;
23+
24+
namespace {
25+
26+
class StackReclaimPass : public fir::impl::StackReclaimBase<StackReclaimPass> {
27+
public:
28+
using StackReclaimBase<StackReclaimPass>::StackReclaimBase;
29+
30+
void runOnOperation() override;
31+
};
32+
} // namespace
33+
34+
void StackReclaimPass::runOnOperation() {
35+
auto *op = getOperation();
36+
auto *context = &getContext();
37+
mlir::OpBuilder builder(context);
38+
mlir::Type voidPtr = mlir::LLVM::LLVMPointerType::get(context);
39+
40+
op->walk([&](fir::DoLoopOp loopOp) {
41+
mlir::Location loc = loopOp.getLoc();
42+
43+
if (!loopOp.getRegion().getOps<fir::AllocaOp>().empty()) {
44+
builder.setInsertionPointToStart(&loopOp.getRegion().front());
45+
auto stackSaveOp = builder.create<LLVM::StackSaveOp>(loc, voidPtr);
46+
47+
auto *terminator = loopOp.getRegion().back().getTerminator();
48+
builder.setInsertionPoint(terminator);
49+
builder.create<LLVM::StackRestoreOp>(loc, stackSaveOp);
50+
}
51+
});
52+
}

flang/test/Driver/bbc-mlir-pass-pipeline.f90

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,16 @@
5050

5151
! CHECK-NEXT: Pipeline Collection : ['fir.global', 'func.func', 'omp.declare_reduction', 'omp.private']
5252
! CHECK-NEXT: 'fir.global' Pipeline
53+
! CHECK-NEXT: StackReclaim
5354
! CHECK-NEXT: CFGConversion
5455
! CHECK-NEXT: 'func.func' Pipeline
56+
! CHECK-NEXT: StackReclaim
5557
! CHECK-NEXT: CFGConversion
5658
! CHECK-NEXT: 'omp.declare_reduction' Pipeline
59+
! CHECK-NEXT: StackReclaim
5760
! CHECK-NEXT: CFGConversion
5861
! CHECK-NEXT: 'omp.private' Pipeline
62+
! CHECK-NEXT: StackReclaim
5963
! CHECK-NEXT: CFGConversion
6064

6165
! CHECK-NEXT: SCFToControlFlow

flang/test/Driver/mlir-debug-pass-pipeline.f90

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,12 +77,16 @@
7777

7878
! ALL-NEXT: Pipeline Collection : ['fir.global', 'func.func', 'omp.declare_reduction', 'omp.private']
7979
! ALL-NEXT: 'fir.global' Pipeline
80+
! ALL-NEXT: StackReclaim
8081
! ALL-NEXT: CFGConversion
8182
! ALL-NEXT: 'func.func' Pipeline
83+
! ALL-NEXT: StackReclaim
8284
! ALL-NEXT: CFGConversion
8385
! ALL-NEXT: 'omp.declare_reduction' Pipeline
86+
! ALL-NEXT: StackReclaim
8487
! ALL-NEXT: CFGConversion
8588
! ALL-NEXT: 'omp.private' Pipeline
89+
! ALL-NEXT: StackReclaim
8690
! ALL-NEXT: CFGConversion
8791
! ALL-NEXT: SCFToControlFlow
8892
! ALL-NEXT: Canonicalizer

flang/test/Driver/mlir-pass-pipeline.f90

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,12 +85,16 @@
8585

8686
! ALL-NEXT: Pipeline Collection : ['fir.global', 'func.func', 'omp.declare_reduction', 'omp.private']
8787
! ALL-NEXT: 'fir.global' Pipeline
88+
! ALL-NEXT: StackReclaim
8889
! ALL-NEXT: CFGConversion
8990
! ALL-NEXT: 'func.func' Pipeline
91+
! ALL-NEXT: StackReclaim
9092
! ALL-NEXT: CFGConversion
9193
! ALL-NEXT: 'omp.declare_reduction' Pipeline
94+
! ALL-NEXT: StackReclaim
9295
! ALL-NEXT: CFGConversion
9396
! ALL-NEXT: 'omp.private' Pipeline
97+
! ALL-NEXT: StackReclaim
9498
! ALL-NEXT: CFGConversion
9599

96100
! ALL-NEXT: SCFToControlFlow

flang/test/Fir/basic-program.fir

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,12 +85,16 @@ func.func @_QQmain() {
8585

8686
// PASSES-NEXT: Pipeline Collection : ['fir.global', 'func.func', 'omp.declare_reduction', 'omp.private']
8787
// PASSES-NEXT: 'fir.global' Pipeline
88+
// PASSES-NEXT: StackReclaim
8889
// PASSES-NEXT: CFGConversion
8990
// PASSES-NEXT: 'func.func' Pipeline
91+
// PASSES-NEXT: StackReclaim
9092
// PASSES-NEXT: CFGConversion
9193
// PASSES-NEXT: 'omp.declare_reduction' Pipeline
94+
// PASSES-NEXT: StackReclaim
9295
// PASSES-NEXT: CFGConversion
9396
// PASSES-NEXT: 'omp.private' Pipeline
97+
// PASSES-NEXT: StackReclaim
9498
// PASSES-NEXT: CFGConversion
9599

96100
// PASSES-NEXT: SCFToControlFlow
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// RUN: fir-opt --split-input-file --stack-reclaim %s | FileCheck %s
2+
3+
func.func @alloca_in_loop(%lb : index, %ub : index, %step : index, %b : i1, %addr : !fir.ref<index>) {
4+
fir.do_loop %iv = %lb to %ub step %step unordered {
5+
%0 = fir.alloca !fir.box<!fir.heap<!fir.char<1,?>>>
6+
}
7+
return
8+
}
9+
10+
// CHECK-LABEL: func.func @alloca_in_loop
11+
// CHECK: fir.do_loop
12+
// CHECK: %[[STACKPTR:.*]] = llvm.intr.stacksave : !llvm.ptr
13+
// CHECK: %{{.*}} = fir.alloca !fir.box<!fir.heap<!fir.char<1,?>>>
14+
// CHECK: llvm.intr.stackrestore %0 : !llvm.ptr

0 commit comments

Comments
 (0)