1 //===-- StatementContext.h --------------------------------------*- C++ -*-===// 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 // Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/ 10 // 11 //===----------------------------------------------------------------------===// 12 13 #ifndef FORTRAN_LOWER_STATEMENTCONTEXT_H 14 #define FORTRAN_LOWER_STATEMENTCONTEXT_H 15 16 #include "llvm/ADT/STLExtras.h" 17 #include "llvm/ADT/SmallVector.h" 18 #include <functional> 19 #include <optional> 20 21 namespace mlir { 22 class Location; 23 class Region; 24 } // namespace mlir 25 26 namespace fir { 27 class FirOpBuilder; 28 } 29 30 namespace Fortran::lower { 31 32 /// When lowering a statement, temporaries for intermediate results may be 33 /// allocated on the heap. A StatementContext enables their deallocation 34 /// with one of several explicit finalize calls, or with an implicit 35 /// call to finalizeAndPop() at the end of the context. A context may prohibit 36 /// temporary allocation. Otherwise, an initial "outer" context scope may have 37 /// nested context scopes, which must make explicit subscope finalize calls. 38 /// 39 /// In addition to being useful for individual action statement contexts, a 40 /// StatementContext is also useful for construct blocks delimited by a pair 41 /// of statements such as (block-stmt, end-block-stmt), or a program unit 42 /// delimited by a pair of statements such as (subroutine-stmt, end-subroutine- 43 /// stmt). Attached cleanup code for these contexts may include stack 44 /// management code, deallocation code, and finalization of derived type 45 /// entities in the context. 46 class StatementContext { 47 public: 48 explicit StatementContext(bool cleanupProhibited = false) { 49 if (cleanupProhibited) 50 return; 51 cufs.push_back({}); 52 } 53 54 ~StatementContext() { 55 if (!cufs.empty()) 56 finalizeAndPop(); 57 assert(cufs.empty() && "invalid StatementContext destructor call"); 58 } 59 60 using CleanupFunction = std::function<void()>; 61 62 /// Push a context subscope. 63 void pushScope() { 64 assert(!cufs.empty() && "invalid pushScope statement context"); 65 cufs.push_back({}); 66 } 67 68 /// Append a cleanup function to the "list" of cleanup functions. 69 void attachCleanup(CleanupFunction cuf) { 70 assert(!cufs.empty() && "invalid attachCleanup statement context"); 71 if (cufs.back()) { 72 CleanupFunction oldCleanup = *cufs.back(); 73 cufs.back() = [=]() { 74 cuf(); 75 oldCleanup(); 76 }; 77 } else { 78 cufs.back() = cuf; 79 } 80 } 81 82 /// Make cleanup calls. Retain the stack top list for a repeat call. 83 void finalizeAndKeep() { 84 assert(!cufs.empty() && "invalid finalize statement context"); 85 if (cufs.back()) 86 (*cufs.back())(); 87 } 88 89 /// Make cleanup calls. Clear the stack top list. 90 void finalizeAndReset() { 91 finalizeAndKeep(); 92 cufs.back().reset(); 93 } 94 95 /// Pop the stack top list. 96 void pop() { cufs.pop_back(); } 97 98 /// Make cleanup calls. Pop the stack top list. 99 void finalizeAndPop() { 100 finalizeAndKeep(); 101 pop(); 102 } 103 104 bool hasCode() const { 105 return !cufs.empty() && llvm::any_of(cufs, [](auto &opt) -> bool { 106 return opt.has_value(); 107 }); 108 } 109 110 private: 111 // A statement context should never be copied or moved. 112 StatementContext(const StatementContext &) = delete; 113 StatementContext &operator=(const StatementContext &) = delete; 114 StatementContext(StatementContext &&) = delete; 115 116 // Stack of cleanup function "lists" (nested cleanup function calls). 117 llvm::SmallVector<std::optional<CleanupFunction>> cufs; 118 }; 119 120 /// If \p context contains any cleanups, ensure \p region has a block, and 121 /// generate the cleanup inside that block. 122 void genCleanUpInRegionIfAny(mlir::Location loc, fir::FirOpBuilder &builder, 123 mlir::Region ®ion, StatementContext &context); 124 125 } // namespace Fortran::lower 126 127 #endif // FORTRAN_LOWER_STATEMENTCONTEXT_H 128