1 //===-- MutableBox.h -- MutableBox utilities  -----------------------------===//
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_OPTIMIZER_BUILDER_MUTABLEBOX_H
14 #define FORTRAN_OPTIMIZER_BUILDER_MUTABLEBOX_H
15 
16 #include "flang/Optimizer/Builder/BoxValue.h"
17 #include "llvm/ADT/StringRef.h"
18 
19 namespace mlir {
20 class Value;
21 class ValueRange;
22 class Type;
23 class Location;
24 } // namespace mlir
25 
26 namespace fir {
27 class FirOpBuilder;
28 class MutableBoxValue;
29 class ExtendedValue;
30 } // namespace fir
31 
32 namespace fir::factory {
33 
34 /// Create a fir.box of type \p boxType that can be used to initialize an
35 /// allocatable variable. Initialization of such variable has to be done at the
36 /// beginning of the variable lifetime by storing the created box in the memory
37 /// for the variable box.
38 /// \p nonDeferredParams must provide the non deferred LEN parameters so that
39 /// they can already be placed in the unallocated box (inquiries about these
40 /// parameters are legal even in unallocated state).
41 mlir::Value createUnallocatedBox(fir::FirOpBuilder &builder, mlir::Location loc,
42                                  mlir::Type boxType,
43                                  mlir::ValueRange nonDeferredParams);
44 
45 /// Create a MutableBoxValue for a temporary allocatable.
46 /// The created MutableBoxValue wraps a fir.ref<fir.box<fir.heap<type>>> and is
47 /// initialized to unallocated/diassociated status. An optional name can be
48 /// given to the created !fir.ref<fir.box>.
49 fir::MutableBoxValue createTempMutableBox(fir::FirOpBuilder &builder,
50                                           mlir::Location loc, mlir::Type type,
51                                           llvm::StringRef name = {});
52 
53 /// Update a MutableBoxValue to describe entity \p source (that must be in
54 /// memory). If \lbounds is not empty, it is used to defined the MutableBoxValue
55 /// lower bounds, otherwise, the lower bounds from \p source are used.
56 void associateMutableBox(fir::FirOpBuilder &builder, mlir::Location loc,
57                          const fir::MutableBoxValue &box,
58                          const fir::ExtendedValue &source,
59                          mlir::ValueRange lbounds);
60 
61 /// Update a MutableBoxValue to describe entity \p source (that must be in
62 /// memory) with a new array layout given by \p lbounds and \p ubounds.
63 /// \p source must be known to be contiguous at compile time, or it must have
64 /// rank 1 (constraint from Fortran 2018 standard 10.2.2.3 point 9).
65 void associateMutableBoxWithRemap(fir::FirOpBuilder &builder,
66                                   mlir::Location loc,
67                                   const fir::MutableBoxValue &box,
68                                   const fir::ExtendedValue &source,
69                                   mlir::ValueRange lbounds,
70                                   mlir::ValueRange ubounds);
71 
72 /// Set the association status of a MutableBoxValue to
73 /// disassociated/unallocated. Nothing is done with the entity that was
74 /// previously associated/allocated. The function generates code that sets the
75 /// address field of the MutableBoxValue to zero.
76 void disassociateMutableBox(fir::FirOpBuilder &builder, mlir::Location loc,
77                             const fir::MutableBoxValue &box);
78 
79 /// Generate code to conditionally reallocate a MutableBoxValue with a new
80 /// shape, lower bounds, and LEN parameters if it is unallocated or if its
81 /// current shape or deferred  LEN parameters do not match the provided ones.
82 /// Lower bounds are only used if the entity needs to be allocated, otherwise,
83 /// the MutableBoxValue will keep its current lower bounds.
84 /// If the MutableBoxValue is an array, the provided shape can be empty, in
85 /// which case the MutableBoxValue must already be allocated at runtime and its
86 /// shape and lower bounds will be kept. If \p shape is empty, only a LEN
87 /// parameter mismatch can trigger a reallocation. See Fortran 10.2.1.3 point 3
88 /// that this function is implementing for more details. The polymorphic
89 /// requirements are not yet covered by this function.
90 struct MutableBoxReallocation {
91   fir::ExtendedValue newValue;
92   mlir::Value oldAddress;
93   mlir::Value wasReallocated;
94   mlir::Value oldAddressWasAllocated;
95 };
96 
97 /// Type of a callback invoked on every storage pointer produced
98 /// in different branches by genReallocIfNeeded(). The argument
99 /// is an ExtendedValue for the storage pointer.
100 /// For example, when genReallocIfNeeded() is used for a LHS allocatable
101 /// array in an assignment, the callback performs the actual assignment
102 /// via the given storage pointer, so we end up generating array_updates and
103 /// array_merge_stores in each branch.
104 using ReallocStorageHandlerFunc = std::function<void(fir::ExtendedValue)>;
105 
106 MutableBoxReallocation
107 genReallocIfNeeded(fir::FirOpBuilder &builder, mlir::Location loc,
108                    const fir::MutableBoxValue &box, mlir::ValueRange shape,
109                    mlir::ValueRange lenParams,
110                    ReallocStorageHandlerFunc storageHandler = {});
111 
112 void finalizeRealloc(fir::FirOpBuilder &builder, mlir::Location loc,
113                      const fir::MutableBoxValue &box, mlir::ValueRange lbounds,
114                      bool takeLboundsIfRealloc,
115                      const MutableBoxReallocation &realloc);
116 
117 /// Finalize a mutable box if it is allocated or associated. This includes both
118 /// calling the finalizer, if any, and deallocating the storage.
119 void genFinalization(fir::FirOpBuilder &builder, mlir::Location loc,
120                      const fir::MutableBoxValue &box);
121 
122 void genInlinedAllocation(fir::FirOpBuilder &builder, mlir::Location loc,
123                           const fir::MutableBoxValue &box,
124                           mlir::ValueRange lbounds, mlir::ValueRange extents,
125                           mlir::ValueRange lenParams,
126                           llvm::StringRef allocName);
127 
128 void genInlinedDeallocate(fir::FirOpBuilder &builder, mlir::Location loc,
129                           const fir::MutableBoxValue &box);
130 
131 /// When the MutableBoxValue was passed as a fir.ref<fir.box> to a call that may
132 /// have modified it, update the MutableBoxValue according to the
133 /// fir.ref<fir.box> value.
134 void syncMutableBoxFromIRBox(fir::FirOpBuilder &builder, mlir::Location loc,
135                              const fir::MutableBoxValue &box);
136 
137 /// Read all mutable properties into a normal symbol box.
138 /// It is OK to call this on unassociated/unallocated boxes but any use of the
139 /// resulting values will be undefined (only the base address will be guaranteed
140 /// to be null).
141 fir::ExtendedValue genMutableBoxRead(fir::FirOpBuilder &builder,
142                                      mlir::Location loc,
143                                      const fir::MutableBoxValue &box,
144                                      bool mayBePolymorphic = true);
145 
146 /// Returns the fir.ref<fir.box<T>> of a MutableBoxValue filled with the current
147 /// association / allocation properties. If the fir.ref<fir.box> already exists
148 /// and is-up to date, this is a no-op, otherwise, code will be generated to
149 /// fill it.
150 mlir::Value getMutableIRBox(fir::FirOpBuilder &builder, mlir::Location loc,
151                             const fir::MutableBoxValue &box);
152 
153 /// Generate allocation or association status test and returns the resulting
154 /// i1. This is testing this for a valid/non-null base address value.
155 mlir::Value genIsAllocatedOrAssociatedTest(fir::FirOpBuilder &builder,
156                                            mlir::Location loc,
157                                            const fir::MutableBoxValue &box);
158 
159 } // namespace fir::factory
160 
161 #endif // FORTRAN_OPTIMIZER_BUILDER_MUTABLEBOX_H
162