xref: /llvm-project/flang/lib/Optimizer/Builder/MutableBox.cpp (revision bbdb1e400f54527160f62a69f074f211ff03fab1)
1a2e7af75SValentin Clement //===-- MutableBox.cpp -- MutableBox utilities ----------------------------===//
2a2e7af75SValentin Clement //
3a2e7af75SValentin Clement // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4a2e7af75SValentin Clement // See https://llvm.org/LICENSE.txt for license information.
5a2e7af75SValentin Clement // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6a2e7af75SValentin Clement //
7a2e7af75SValentin Clement //===----------------------------------------------------------------------===//
8a2e7af75SValentin Clement //
9a2e7af75SValentin Clement // Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
10a2e7af75SValentin Clement //
11a2e7af75SValentin Clement //===----------------------------------------------------------------------===//
12a2e7af75SValentin Clement 
13a2e7af75SValentin Clement #include "flang/Optimizer/Builder/MutableBox.h"
14a2e7af75SValentin Clement #include "flang/Optimizer/Builder/Character.h"
15a2e7af75SValentin Clement #include "flang/Optimizer/Builder/FIRBuilder.h"
162a59ead1SValentin Clement #include "flang/Optimizer/Builder/Runtime/Derived.h"
172a59ead1SValentin Clement #include "flang/Optimizer/Builder/Runtime/Stop.h"
185b66cc10SValentin Clement #include "flang/Optimizer/Builder/Todo.h"
19cc14bf22STom Eccles #include "flang/Optimizer/Dialect/FIRAttr.h"
20a2e7af75SValentin Clement #include "flang/Optimizer/Dialect/FIROps.h"
21a2e7af75SValentin Clement #include "flang/Optimizer/Dialect/FIROpsSupport.h"
22a2e7af75SValentin Clement #include "flang/Optimizer/Support/FatalError.h"
23a2e7af75SValentin Clement 
242a59ead1SValentin Clement /// Create a fir.box describing the new address, bounds, and length parameters
252a59ead1SValentin Clement /// for a MutableBox \p box.
26880b37f1SValentin Clement static mlir::Value
27880b37f1SValentin Clement createNewFirBox(fir::FirOpBuilder &builder, mlir::Location loc,
28880b37f1SValentin Clement                 const fir::MutableBoxValue &box, mlir::Value addr,
29880b37f1SValentin Clement                 mlir::ValueRange lbounds, mlir::ValueRange extents,
30880b37f1SValentin Clement                 mlir::ValueRange lengths, mlir::Value tdesc = {}) {
31fac349a1SChristian Sigg   if (mlir::isa<fir::BaseBoxType>(addr.getType()))
322a59ead1SValentin Clement     // The entity is already boxed.
332a59ead1SValentin Clement     return builder.createConvert(loc, box.getBoxTy(), addr);
342a59ead1SValentin Clement 
352a59ead1SValentin Clement   mlir::Value shape;
362a59ead1SValentin Clement   if (!extents.empty()) {
372a59ead1SValentin Clement     if (lbounds.empty()) {
38b22fa865SJean Perier       shape = builder.create<fir::ShapeOp>(loc, extents);
392a59ead1SValentin Clement     } else {
402a59ead1SValentin Clement       llvm::SmallVector<mlir::Value> shapeShiftBounds;
412a59ead1SValentin Clement       for (auto [lb, extent] : llvm::zip(lbounds, extents)) {
422a59ead1SValentin Clement         shapeShiftBounds.emplace_back(lb);
432a59ead1SValentin Clement         shapeShiftBounds.emplace_back(extent);
442a59ead1SValentin Clement       }
452a59ead1SValentin Clement       auto shapeShiftType =
462a59ead1SValentin Clement           fir::ShapeShiftType::get(builder.getContext(), extents.size());
472a59ead1SValentin Clement       shape = builder.create<fir::ShapeShiftOp>(loc, shapeShiftType,
482a59ead1SValentin Clement                                                 shapeShiftBounds);
492a59ead1SValentin Clement     }
502a59ead1SValentin Clement   } // Otherwise, this a scalar. Leave the shape empty.
512a59ead1SValentin Clement 
522a59ead1SValentin Clement   // Ignore lengths if already constant in the box type (this would trigger an
532a59ead1SValentin Clement   // error in the embox).
542a59ead1SValentin Clement   llvm::SmallVector<mlir::Value> cleanedLengths;
552a59ead1SValentin Clement   auto cleanedAddr = addr;
56fac349a1SChristian Sigg   if (auto charTy = mlir::dyn_cast<fir::CharacterType>(box.getEleTy())) {
572a59ead1SValentin Clement     // Cast address to box type so that both input and output type have
582a59ead1SValentin Clement     // unknown or constant lengths.
592a59ead1SValentin Clement     auto bt = box.getBaseTy();
602a59ead1SValentin Clement     auto addrTy = addr.getType();
61fac349a1SChristian Sigg     auto type = mlir::isa<fir::HeapType>(addrTy) ? fir::HeapType::get(bt)
62fac349a1SChristian Sigg                 : mlir::isa<fir::PointerType>(addrTy)
63fac349a1SChristian Sigg                     ? fir::PointerType::get(bt)
642a59ead1SValentin Clement                     : builder.getRefType(bt);
652a59ead1SValentin Clement     cleanedAddr = builder.createConvert(loc, type, addr);
662a59ead1SValentin Clement     if (charTy.getLen() == fir::CharacterType::unknownLen())
672a59ead1SValentin Clement       cleanedLengths.append(lengths.begin(), lengths.end());
6839ad49ecSValentin Clement   } else if (fir::isUnlimitedPolymorphicType(box.getBoxTy())) {
69fac349a1SChristian Sigg     if (auto charTy = mlir::dyn_cast<fir::CharacterType>(
70fac349a1SChristian Sigg             fir::dyn_cast_ptrEleTy(addr.getType()))) {
7139ad49ecSValentin Clement       if (charTy.getLen() == fir::CharacterType::unknownLen())
7239ad49ecSValentin Clement         cleanedLengths.append(lengths.begin(), lengths.end());
7339ad49ecSValentin Clement     }
741bffc753SEric Schweitz   } else if (box.isDerivedWithLenParameters()) {
752a59ead1SValentin Clement     TODO(loc, "updating mutablebox of derived type with length parameters");
762a59ead1SValentin Clement     cleanedLengths = lengths;
772a59ead1SValentin Clement   }
782a59ead1SValentin Clement   mlir::Value emptySlice;
792a59ead1SValentin Clement   return builder.create<fir::EmboxOp>(loc, box.getBoxTy(), cleanedAddr, shape,
80880b37f1SValentin Clement                                       emptySlice, cleanedLengths, tdesc);
812a59ead1SValentin Clement }
822a59ead1SValentin Clement 
83a2e7af75SValentin Clement //===----------------------------------------------------------------------===//
84a2e7af75SValentin Clement // MutableBoxValue writer and reader
85a2e7af75SValentin Clement //===----------------------------------------------------------------------===//
86a2e7af75SValentin Clement 
87a2e7af75SValentin Clement namespace {
88a2e7af75SValentin Clement /// MutablePropertyWriter and MutablePropertyReader implementations are the only
89a2e7af75SValentin Clement /// places that depend on how the properties of MutableBoxValue (pointers and
90a2e7af75SValentin Clement /// allocatables) that can be modified in the lifetime of the entity (address,
91a2e7af75SValentin Clement /// extents, lower bounds, length parameters) are represented.
92a2e7af75SValentin Clement /// That is, the properties may be only stored in a fir.box in memory if we
93a2e7af75SValentin Clement /// need to enforce a single point of truth for the properties across calls.
94a2e7af75SValentin Clement /// Or, they can be tracked as independent local variables when it is safe to
95a2e7af75SValentin Clement /// do so. Using bare variables benefits from all optimization passes, even
96a2e7af75SValentin Clement /// when they are not aware of what a fir.box is and fir.box have not been
97a2e7af75SValentin Clement /// optimized out yet.
98a2e7af75SValentin Clement 
99a2e7af75SValentin Clement /// MutablePropertyWriter allows reading the properties of a MutableBoxValue.
100a2e7af75SValentin Clement class MutablePropertyReader {
101a2e7af75SValentin Clement public:
102a2e7af75SValentin Clement   MutablePropertyReader(fir::FirOpBuilder &builder, mlir::Location loc,
103a2e7af75SValentin Clement                         const fir::MutableBoxValue &box,
104a2e7af75SValentin Clement                         bool forceIRBoxRead = false)
105a2e7af75SValentin Clement       : builder{builder}, loc{loc}, box{box} {
106a2e7af75SValentin Clement     if (forceIRBoxRead || !box.isDescribedByVariables())
107a2e7af75SValentin Clement       irBox = builder.create<fir::LoadOp>(loc, box.getAddr());
108a2e7af75SValentin Clement   }
109a2e7af75SValentin Clement   /// Get base address of allocated/associated entity.
110a2e7af75SValentin Clement   mlir::Value readBaseAddress() {
111a2e7af75SValentin Clement     if (irBox) {
11296d9df41SValentin Clement       auto memrefTy = box.getBoxTy().getEleTy();
11396d9df41SValentin Clement       if (!fir::isa_ref_type(memrefTy))
11496d9df41SValentin Clement         memrefTy = builder.getRefType(memrefTy);
11596d9df41SValentin Clement       return builder.create<fir::BoxAddrOp>(loc, memrefTy, irBox);
116a2e7af75SValentin Clement     }
117a2e7af75SValentin Clement     auto addrVar = box.getMutableProperties().addr;
118a2e7af75SValentin Clement     return builder.create<fir::LoadOp>(loc, addrVar);
119a2e7af75SValentin Clement   }
120a2e7af75SValentin Clement   /// Return {lbound, extent} values read from the MutableBoxValue given
121a2e7af75SValentin Clement   /// the dimension.
122a2e7af75SValentin Clement   std::pair<mlir::Value, mlir::Value> readShape(unsigned dim) {
123a2e7af75SValentin Clement     auto idxTy = builder.getIndexType();
124a2e7af75SValentin Clement     if (irBox) {
125a2e7af75SValentin Clement       auto dimVal = builder.createIntegerConstant(loc, idxTy, dim);
126a2e7af75SValentin Clement       auto dimInfo = builder.create<fir::BoxDimsOp>(loc, idxTy, idxTy, idxTy,
127a2e7af75SValentin Clement                                                     irBox, dimVal);
128a2e7af75SValentin Clement       return {dimInfo.getResult(0), dimInfo.getResult(1)};
129a2e7af75SValentin Clement     }
130a2e7af75SValentin Clement     const auto &mutableProperties = box.getMutableProperties();
131a2e7af75SValentin Clement     auto lb = builder.create<fir::LoadOp>(loc, mutableProperties.lbounds[dim]);
132a2e7af75SValentin Clement     auto ext = builder.create<fir::LoadOp>(loc, mutableProperties.extents[dim]);
133a2e7af75SValentin Clement     return {lb, ext};
134a2e7af75SValentin Clement   }
135a2e7af75SValentin Clement 
136a2e7af75SValentin Clement   /// Return the character length. If the length was not deferred, the value
137a2e7af75SValentin Clement   /// that was specified is returned (The mutable fields is not read).
138a2e7af75SValentin Clement   mlir::Value readCharacterLength() {
139a2e7af75SValentin Clement     if (box.hasNonDeferredLenParams())
140a2e7af75SValentin Clement       return box.nonDeferredLenParams()[0];
141a2e7af75SValentin Clement     if (irBox)
142a2e7af75SValentin Clement       return fir::factory::CharacterExprHelper{builder, loc}.readLengthFromBox(
143a2e7af75SValentin Clement           irBox);
144a2e7af75SValentin Clement     const auto &deferred = box.getMutableProperties().deferredParams;
145a2e7af75SValentin Clement     if (deferred.empty())
146a2e7af75SValentin Clement       fir::emitFatalError(loc, "allocatable entity has no length property");
147a2e7af75SValentin Clement     return builder.create<fir::LoadOp>(loc, deferred[0]);
148a2e7af75SValentin Clement   }
149a2e7af75SValentin Clement 
150a2e7af75SValentin Clement   /// Read and return all extents. If \p lbounds vector is provided, lbounds are
151a2e7af75SValentin Clement   /// also read into it.
152a2e7af75SValentin Clement   llvm::SmallVector<mlir::Value>
153a2e7af75SValentin Clement   readShape(llvm::SmallVectorImpl<mlir::Value> *lbounds = nullptr) {
15496d9df41SValentin Clement     llvm::SmallVector<mlir::Value> extents;
155a2e7af75SValentin Clement     auto rank = box.rank();
156a2e7af75SValentin Clement     for (decltype(rank) dim = 0; dim < rank; ++dim) {
157a2e7af75SValentin Clement       auto [lb, extent] = readShape(dim);
158a2e7af75SValentin Clement       if (lbounds)
159a2e7af75SValentin Clement         lbounds->push_back(lb);
160a2e7af75SValentin Clement       extents.push_back(extent);
161a2e7af75SValentin Clement     }
162a2e7af75SValentin Clement     return extents;
163a2e7af75SValentin Clement   }
164a2e7af75SValentin Clement 
165a2e7af75SValentin Clement   /// Read all mutable properties. Return the base address.
166a2e7af75SValentin Clement   mlir::Value read(llvm::SmallVectorImpl<mlir::Value> &lbounds,
167a2e7af75SValentin Clement                    llvm::SmallVectorImpl<mlir::Value> &extents,
168a2e7af75SValentin Clement                    llvm::SmallVectorImpl<mlir::Value> &lengths) {
169a2e7af75SValentin Clement     extents = readShape(&lbounds);
170a2e7af75SValentin Clement     if (box.isCharacter())
171a2e7af75SValentin Clement       lengths.emplace_back(readCharacterLength());
1721bffc753SEric Schweitz     else if (box.isDerivedWithLenParameters())
173a2e7af75SValentin Clement       TODO(loc, "read allocatable or pointer derived type LEN parameters");
174a2e7af75SValentin Clement     return readBaseAddress();
175a2e7af75SValentin Clement   }
176a2e7af75SValentin Clement 
177a2e7af75SValentin Clement   /// Return the loaded fir.box.
178a2e7af75SValentin Clement   mlir::Value getIrBox() const {
179a2e7af75SValentin Clement     assert(irBox);
180a2e7af75SValentin Clement     return irBox;
181a2e7af75SValentin Clement   }
182a2e7af75SValentin Clement 
183a2e7af75SValentin Clement   /// Read the lower bounds
184a2e7af75SValentin Clement   void getLowerBounds(llvm::SmallVectorImpl<mlir::Value> &lbounds) {
185a2e7af75SValentin Clement     auto rank = box.rank();
186a2e7af75SValentin Clement     for (decltype(rank) dim = 0; dim < rank; ++dim)
187a2e7af75SValentin Clement       lbounds.push_back(std::get<0>(readShape(dim)));
188a2e7af75SValentin Clement   }
189a2e7af75SValentin Clement 
190a2e7af75SValentin Clement private:
191a2e7af75SValentin Clement   fir::FirOpBuilder &builder;
192a2e7af75SValentin Clement   mlir::Location loc;
193a2e7af75SValentin Clement   fir::MutableBoxValue box;
194a2e7af75SValentin Clement   mlir::Value irBox;
195a2e7af75SValentin Clement };
196a2e7af75SValentin Clement 
197a2e7af75SValentin Clement /// MutablePropertyWriter allows modifying the properties of a MutableBoxValue.
198a2e7af75SValentin Clement class MutablePropertyWriter {
199a2e7af75SValentin Clement public:
200a2e7af75SValentin Clement   MutablePropertyWriter(fir::FirOpBuilder &builder, mlir::Location loc,
2010b19ac83SValentin Clement                         const fir::MutableBoxValue &box,
202*bbdb1e40SValentin Clement (バレンタイン クレメン)                         mlir::Value typeSourceBox = {}, unsigned allocator = 0)
203*bbdb1e40SValentin Clement (バレンタイン クレメン)       : builder{builder}, loc{loc}, box{box}, typeSourceBox{typeSourceBox},
204*bbdb1e40SValentin Clement (バレンタイン クレメン)         allocator{allocator} {}
205a2e7af75SValentin Clement   /// Update MutableBoxValue with new address, shape and length parameters.
206a2e7af75SValentin Clement   /// Extents and lbounds must all have index type.
207a2e7af75SValentin Clement   /// lbounds can be empty in which case all ones is assumed.
208a2e7af75SValentin Clement   /// Length parameters must be provided for the length parameters that are
209a2e7af75SValentin Clement   /// deferred.
210a2e7af75SValentin Clement   void updateMutableBox(mlir::Value addr, mlir::ValueRange lbounds,
211880b37f1SValentin Clement                         mlir::ValueRange extents, mlir::ValueRange lengths,
212880b37f1SValentin Clement                         mlir::Value tdesc = {}) {
213a2e7af75SValentin Clement     if (box.isDescribedByVariables())
214a2e7af75SValentin Clement       updateMutableProperties(addr, lbounds, extents, lengths);
215a2e7af75SValentin Clement     else
216880b37f1SValentin Clement       updateIRBox(addr, lbounds, extents, lengths, tdesc);
217a2e7af75SValentin Clement   }
218a2e7af75SValentin Clement 
219a2e7af75SValentin Clement   /// Update MutableBoxValue with a new fir.box. This requires that the mutable
220a2e7af75SValentin Clement   /// box is not described by a set of variables, since they could not describe
221a2e7af75SValentin Clement   /// all that can be described in the new fir.box (e.g. non contiguous entity).
222a2e7af75SValentin Clement   void updateWithIrBox(mlir::Value newBox) {
223a2e7af75SValentin Clement     assert(!box.isDescribedByVariables());
224a2e7af75SValentin Clement     builder.create<fir::StoreOp>(loc, newBox, box.getAddr());
225a2e7af75SValentin Clement   }
226a2e7af75SValentin Clement   /// Set unallocated/disassociated status for the entity described by
227a2e7af75SValentin Clement   /// MutableBoxValue. Deallocation is not performed by this helper.
228a2e7af75SValentin Clement   void setUnallocatedStatus() {
229a2e7af75SValentin Clement     if (box.isDescribedByVariables()) {
230a2e7af75SValentin Clement       auto addrVar = box.getMutableProperties().addr;
231a2e7af75SValentin Clement       auto nullTy = fir::dyn_cast_ptrEleTy(addrVar.getType());
232a2e7af75SValentin Clement       builder.create<fir::StoreOp>(loc, builder.createNullConstant(loc, nullTy),
233a2e7af75SValentin Clement                                    addrVar);
234a2e7af75SValentin Clement     } else {
235a2e7af75SValentin Clement       // Note that the dynamic type of polymorphic entities must be reset to the
236a2e7af75SValentin Clement       // declaration type of the mutable box. See Fortran 2018 7.8.2 NOTE 1.
237a2e7af75SValentin Clement       // For those, we cannot simply set the address to zero. The way we are
238a2e7af75SValentin Clement       // currently unallocating fir.box guarantees that we are resetting the
239a2e7af75SValentin Clement       // type to the declared type. Beware if changing this.
240a2e7af75SValentin Clement       // Note: the standard is not clear in Deallocate and p => NULL semantics
241a2e7af75SValentin Clement       // regarding the new dynamic type the entity must have. So far, assume
242a2e7af75SValentin Clement       // this is just like NULLIFY and the dynamic type must be set to the
243a2e7af75SValentin Clement       // declared type, not retain the previous dynamic type.
244a2e7af75SValentin Clement       auto deallocatedBox = fir::factory::createUnallocatedBox(
2450b19ac83SValentin Clement           builder, loc, box.getBoxTy(), box.nonDeferredLenParams(),
246*bbdb1e40SValentin Clement (バレンタイン クレメン)           typeSourceBox, allocator);
247a2e7af75SValentin Clement       builder.create<fir::StoreOp>(loc, deallocatedBox, box.getAddr());
248a2e7af75SValentin Clement     }
249a2e7af75SValentin Clement   }
250a2e7af75SValentin Clement 
251a2e7af75SValentin Clement   /// Copy Values from the fir.box into the property variables if any.
252a2e7af75SValentin Clement   void syncMutablePropertiesFromIRBox() {
253a2e7af75SValentin Clement     if (!box.isDescribedByVariables())
254a2e7af75SValentin Clement       return;
255a2e7af75SValentin Clement     llvm::SmallVector<mlir::Value> lbounds;
256a2e7af75SValentin Clement     llvm::SmallVector<mlir::Value> extents;
257a2e7af75SValentin Clement     llvm::SmallVector<mlir::Value> lengths;
258a2e7af75SValentin Clement     auto addr =
259a2e7af75SValentin Clement         MutablePropertyReader{builder, loc, box, /*forceIRBoxRead=*/true}.read(
260a2e7af75SValentin Clement             lbounds, extents, lengths);
261a2e7af75SValentin Clement     updateMutableProperties(addr, lbounds, extents, lengths);
262a2e7af75SValentin Clement   }
263a2e7af75SValentin Clement 
264a2e7af75SValentin Clement   /// Copy Values from property variables, if any, into the fir.box.
265a2e7af75SValentin Clement   void syncIRBoxFromMutableProperties() {
266a2e7af75SValentin Clement     if (!box.isDescribedByVariables())
267a2e7af75SValentin Clement       return;
268a2e7af75SValentin Clement     llvm::SmallVector<mlir::Value> lbounds;
269a2e7af75SValentin Clement     llvm::SmallVector<mlir::Value> extents;
270a2e7af75SValentin Clement     llvm::SmallVector<mlir::Value> lengths;
271a2e7af75SValentin Clement     auto addr = MutablePropertyReader{builder, loc, box}.read(lbounds, extents,
272a2e7af75SValentin Clement                                                               lengths);
273a2e7af75SValentin Clement     updateIRBox(addr, lbounds, extents, lengths);
274a2e7af75SValentin Clement   }
275a2e7af75SValentin Clement 
276a2e7af75SValentin Clement private:
277a2e7af75SValentin Clement   /// Update the IR box (fir.ref<fir.box<T>>) of the MutableBoxValue.
278a2e7af75SValentin Clement   void updateIRBox(mlir::Value addr, mlir::ValueRange lbounds,
279880b37f1SValentin Clement                    mlir::ValueRange extents, mlir::ValueRange lengths,
280*bbdb1e40SValentin Clement (バレンタイン クレメン)                    mlir::Value tdesc = {},
281*bbdb1e40SValentin Clement (バレンタイン クレメン)                    unsigned allocator = kDefaultAllocator) {
282880b37f1SValentin Clement     mlir::Value irBox = createNewFirBox(builder, loc, box, addr, lbounds,
283880b37f1SValentin Clement                                         extents, lengths, tdesc);
284a2e7af75SValentin Clement     builder.create<fir::StoreOp>(loc, irBox, box.getAddr());
285a2e7af75SValentin Clement   }
286a2e7af75SValentin Clement 
287a2e7af75SValentin Clement   /// Update the set of property variables of the MutableBoxValue.
288a2e7af75SValentin Clement   void updateMutableProperties(mlir::Value addr, mlir::ValueRange lbounds,
289a2e7af75SValentin Clement                                mlir::ValueRange extents,
290a2e7af75SValentin Clement                                mlir::ValueRange lengths) {
291a2e7af75SValentin Clement     auto castAndStore = [&](mlir::Value val, mlir::Value addr) {
292a2e7af75SValentin Clement       auto type = fir::dyn_cast_ptrEleTy(addr.getType());
293a2e7af75SValentin Clement       builder.create<fir::StoreOp>(loc, builder.createConvert(loc, type, val),
294a2e7af75SValentin Clement                                    addr);
295a2e7af75SValentin Clement     };
296a2e7af75SValentin Clement     const auto &mutableProperties = box.getMutableProperties();
297a2e7af75SValentin Clement     castAndStore(addr, mutableProperties.addr);
298a2e7af75SValentin Clement     for (auto [extent, extentVar] :
299a2e7af75SValentin Clement          llvm::zip(extents, mutableProperties.extents))
300a2e7af75SValentin Clement       castAndStore(extent, extentVar);
301a2e7af75SValentin Clement     if (!mutableProperties.lbounds.empty()) {
302a2e7af75SValentin Clement       if (lbounds.empty()) {
303a2e7af75SValentin Clement         auto one =
304a2e7af75SValentin Clement             builder.createIntegerConstant(loc, builder.getIndexType(), 1);
305a2e7af75SValentin Clement         for (auto lboundVar : mutableProperties.lbounds)
306a2e7af75SValentin Clement           castAndStore(one, lboundVar);
307a2e7af75SValentin Clement       } else {
308a2e7af75SValentin Clement         for (auto [lbound, lboundVar] :
309a2e7af75SValentin Clement              llvm::zip(lbounds, mutableProperties.lbounds))
310a2e7af75SValentin Clement           castAndStore(lbound, lboundVar);
311a2e7af75SValentin Clement       }
312a2e7af75SValentin Clement     }
313a2e7af75SValentin Clement     if (box.isCharacter())
314a2e7af75SValentin Clement       // llvm::zip account for the fact that the length only needs to be stored
315a2e7af75SValentin Clement       // when it is specified in the allocation and deferred in the
316a2e7af75SValentin Clement       // MutableBoxValue.
317a2e7af75SValentin Clement       for (auto [len, lenVar] :
318a2e7af75SValentin Clement            llvm::zip(lengths, mutableProperties.deferredParams))
319a2e7af75SValentin Clement         castAndStore(len, lenVar);
3201bffc753SEric Schweitz     else if (box.isDerivedWithLenParameters())
321a2e7af75SValentin Clement       TODO(loc, "update allocatable derived type length parameters");
322a2e7af75SValentin Clement   }
323a2e7af75SValentin Clement   fir::FirOpBuilder &builder;
324a2e7af75SValentin Clement   mlir::Location loc;
325a2e7af75SValentin Clement   fir::MutableBoxValue box;
3260b19ac83SValentin Clement   mlir::Value typeSourceBox;
327*bbdb1e40SValentin Clement (バレンタイン クレメン)   unsigned allocator;
328a2e7af75SValentin Clement };
329a2e7af75SValentin Clement 
330a2e7af75SValentin Clement } // namespace
331a2e7af75SValentin Clement 
3320b19ac83SValentin Clement mlir::Value fir::factory::createUnallocatedBox(
3330b19ac83SValentin Clement     fir::FirOpBuilder &builder, mlir::Location loc, mlir::Type boxType,
334*bbdb1e40SValentin Clement (バレンタイン クレメン)     mlir::ValueRange nonDeferredParams, mlir::Value typeSourceBox,
335*bbdb1e40SValentin Clement (バレンタイン クレメン)     unsigned allocator) {
3364abbf995SjeanPerier   auto baseBoxType = mlir::cast<fir::BaseBoxType>(boxType);
3374abbf995SjeanPerier   // Giving unallocated/disassociated status to assumed-rank POINTER/
3384abbf995SjeanPerier   // ALLOCATABLE is not directly possible to a Fortran user. But the
3394abbf995SjeanPerier   // compiler may need to create such temporary descriptor to deal with
3404abbf995SjeanPerier   // cases like ENTRY or host association. In such case, all that mater
3414abbf995SjeanPerier   // is that the base address is set to zero and the rank is set to
3424abbf995SjeanPerier   // some defined value. Hence, a scalar descriptor is created and
3434abbf995SjeanPerier   // cast to assumed-rank.
3444abbf995SjeanPerier   const bool isAssumedRank = baseBoxType.isAssumedRank();
3454abbf995SjeanPerier   if (isAssumedRank)
3464abbf995SjeanPerier     baseBoxType = baseBoxType.getBoxTypeWithNewShape(/*rank=*/0);
3474abbf995SjeanPerier   auto baseAddrType = baseBoxType.getEleTy();
34894a11063SValentin Clement   if (!fir::isa_ref_type(baseAddrType))
34994a11063SValentin Clement     baseAddrType = builder.getRefType(baseAddrType);
35094a11063SValentin Clement   auto type = fir::unwrapRefType(baseAddrType);
35194a11063SValentin Clement   auto eleTy = fir::unwrapSequenceType(type);
352fac349a1SChristian Sigg   if (auto recTy = mlir::dyn_cast<fir::RecordType>(eleTy))
353a2e7af75SValentin Clement     if (recTy.getNumLenParams() > 0)
354a2e7af75SValentin Clement       TODO(loc, "creating unallocated fir.box of derived type with length "
355a2e7af75SValentin Clement                 "parameters");
35694a11063SValentin Clement   auto nullAddr = builder.createNullConstant(loc, baseAddrType);
357a2e7af75SValentin Clement   mlir::Value shape;
358fac349a1SChristian Sigg   if (auto seqTy = mlir::dyn_cast<fir::SequenceType>(type)) {
359a2e7af75SValentin Clement     auto zero = builder.createIntegerConstant(loc, builder.getIndexType(), 0);
360a2e7af75SValentin Clement     llvm::SmallVector<mlir::Value> extents(seqTy.getDimension(), zero);
361a2e7af75SValentin Clement     shape = builder.createShape(
3629a417395SKazu Hirata         loc, fir::ArrayBoxValue{nullAddr, extents, /*lbounds=*/std::nullopt});
363a2e7af75SValentin Clement   }
364a2e7af75SValentin Clement   // Provide dummy length parameters if they are dynamic. If a length parameter
365a2e7af75SValentin Clement   // is deferred. It is set to zero here and will be set on allocation.
366a2e7af75SValentin Clement   llvm::SmallVector<mlir::Value> lenParams;
367fac349a1SChristian Sigg   if (auto charTy = mlir::dyn_cast<fir::CharacterType>(eleTy)) {
368a2e7af75SValentin Clement     if (charTy.getLen() == fir::CharacterType::unknownLen()) {
369a2e7af75SValentin Clement       if (!nonDeferredParams.empty()) {
370a2e7af75SValentin Clement         lenParams.push_back(nonDeferredParams[0]);
371a2e7af75SValentin Clement       } else {
372a2e7af75SValentin Clement         auto zero = builder.createIntegerConstant(
373a2e7af75SValentin Clement             loc, builder.getCharacterLengthType(), 0);
374a2e7af75SValentin Clement         lenParams.push_back(zero);
375a2e7af75SValentin Clement       }
376a2e7af75SValentin Clement     }
377a2e7af75SValentin Clement   }
378a2e7af75SValentin Clement   mlir::Value emptySlice;
3794abbf995SjeanPerier   auto embox = builder.create<fir::EmboxOp>(
3804abbf995SjeanPerier       loc, baseBoxType, nullAddr, shape, emptySlice, lenParams, typeSourceBox);
381*bbdb1e40SValentin Clement (バレンタイン クレメン)   if (allocator != 0)
382*bbdb1e40SValentin Clement (バレンタイン クレメン)     embox.setAllocatorIdx(allocator);
3834abbf995SjeanPerier   if (isAssumedRank)
3844abbf995SjeanPerier     return builder.createConvert(loc, boxType, embox);
3854abbf995SjeanPerier   return embox;
386a2e7af75SValentin Clement }
387a2e7af75SValentin Clement 
3880b19ac83SValentin Clement fir::MutableBoxValue fir::factory::createTempMutableBox(
3890b19ac83SValentin Clement     fir::FirOpBuilder &builder, mlir::Location loc, mlir::Type type,
390658595d0SValentin Clement     llvm::StringRef name, mlir::Value typeSourceBox, bool isPolymorphic) {
3910b19ac83SValentin Clement   mlir::Type boxType;
392658595d0SValentin Clement   if (typeSourceBox || isPolymorphic)
3930b19ac83SValentin Clement     boxType = fir::ClassType::get(fir::HeapType::get(type));
3940b19ac83SValentin Clement   else
3950b19ac83SValentin Clement     boxType = fir::BoxType::get(fir::HeapType::get(type));
396a2e7af75SValentin Clement   auto boxAddr = builder.createTemporary(loc, boxType, name);
397a2e7af75SValentin Clement   auto box =
398a2e7af75SValentin Clement       fir::MutableBoxValue(boxAddr, /*nonDeferredParams=*/mlir::ValueRange(),
399a2e7af75SValentin Clement                            /*mutableProperties=*/{});
4000b19ac83SValentin Clement   MutablePropertyWriter{builder, loc, box, typeSourceBox}
4010b19ac83SValentin Clement       .setUnallocatedStatus();
402a2e7af75SValentin Clement   return box;
403a2e7af75SValentin Clement }
404a2e7af75SValentin Clement 
405a2e7af75SValentin Clement /// Helper to decide if a MutableBoxValue must be read to a BoxValue or
406a2e7af75SValentin Clement /// can be read to a reified box value.
407a2e7af75SValentin Clement static bool readToBoxValue(const fir::MutableBoxValue &box,
408a2e7af75SValentin Clement                            bool mayBePolymorphic) {
409a2e7af75SValentin Clement   // If this is described by a set of local variables, the value
410a2e7af75SValentin Clement   // should not be tracked as a fir.box.
411a2e7af75SValentin Clement   if (box.isDescribedByVariables())
412a2e7af75SValentin Clement     return false;
413a2e7af75SValentin Clement   // Polymorphism might be a source of discontiguity, even on allocatables.
414a2e7af75SValentin Clement   // Track value as fir.box
415a2e7af75SValentin Clement   if ((box.isDerived() && mayBePolymorphic) || box.isUnlimitedPolymorphic())
416a2e7af75SValentin Clement     return true;
417d99cf1b9SjeanPerier   if (box.hasAssumedRank())
418d99cf1b9SjeanPerier     return true;
419a2e7af75SValentin Clement   // Intrinsic allocatables are contiguous, no need to track the value by
420a2e7af75SValentin Clement   // fir.box.
421a2e7af75SValentin Clement   if (box.isAllocatable() || box.rank() == 0)
422a2e7af75SValentin Clement     return false;
423a2e7af75SValentin Clement   // Pointers are known to be contiguous at compile time iff they have the
424a2e7af75SValentin Clement   // CONTIGUOUS attribute.
425a2e7af75SValentin Clement   return !fir::valueHasFirAttribute(box.getAddr(),
426a2e7af75SValentin Clement                                     fir::getContiguousAttrName());
427a2e7af75SValentin Clement }
428a2e7af75SValentin Clement 
429a2e7af75SValentin Clement fir::ExtendedValue
430a2e7af75SValentin Clement fir::factory::genMutableBoxRead(fir::FirOpBuilder &builder, mlir::Location loc,
431a2e7af75SValentin Clement                                 const fir::MutableBoxValue &box,
43267402fe5SjeanPerier                                 bool mayBePolymorphic,
43367402fe5SjeanPerier                                 bool preserveLowerBounds) {
434a2e7af75SValentin Clement   llvm::SmallVector<mlir::Value> lbounds;
435a2e7af75SValentin Clement   llvm::SmallVector<mlir::Value> extents;
436a2e7af75SValentin Clement   llvm::SmallVector<mlir::Value> lengths;
437a2e7af75SValentin Clement   if (readToBoxValue(box, mayBePolymorphic)) {
438a2e7af75SValentin Clement     auto reader = MutablePropertyReader(builder, loc, box);
439d99cf1b9SjeanPerier     if (preserveLowerBounds && !box.hasAssumedRank())
440a2e7af75SValentin Clement       reader.getLowerBounds(lbounds);
441a2e7af75SValentin Clement     return fir::BoxValue{reader.getIrBox(), lbounds,
442a2e7af75SValentin Clement                          box.nonDeferredLenParams()};
443a2e7af75SValentin Clement   }
444a2e7af75SValentin Clement   // Contiguous intrinsic type entity: all the data can be extracted from the
445a2e7af75SValentin Clement   // fir.box.
446a2e7af75SValentin Clement   auto addr =
447a2e7af75SValentin Clement       MutablePropertyReader(builder, loc, box).read(lbounds, extents, lengths);
44867402fe5SjeanPerier   if (!preserveLowerBounds)
44967402fe5SjeanPerier     lbounds.clear();
450a2e7af75SValentin Clement   auto rank = box.rank();
451a2e7af75SValentin Clement   if (box.isCharacter()) {
452a2e7af75SValentin Clement     auto len = lengths.empty() ? mlir::Value{} : lengths[0];
453a2e7af75SValentin Clement     if (rank)
454a2e7af75SValentin Clement       return fir::CharArrayBoxValue{addr, len, extents, lbounds};
455a2e7af75SValentin Clement     return fir::CharBoxValue{addr, len};
456a2e7af75SValentin Clement   }
4579f1bb307SValentin Clement   mlir::Value sourceBox;
45821b82573SValentin Clement   if (box.isPolymorphic())
4599f1bb307SValentin Clement     sourceBox = builder.create<fir::LoadOp>(loc, box.getAddr());
4609f1bb307SValentin Clement   if (rank)
4619f1bb307SValentin Clement     return fir::ArrayBoxValue{addr, extents, lbounds, sourceBox};
4629f1bb307SValentin Clement   if (box.isPolymorphic())
4639f1bb307SValentin Clement     return fir::PolymorphicValue(addr, sourceBox);
464a2e7af75SValentin Clement   return addr;
465a2e7af75SValentin Clement }
466a2e7af75SValentin Clement 
467a2e7af75SValentin Clement mlir::Value
468a2e7af75SValentin Clement fir::factory::genIsAllocatedOrAssociatedTest(fir::FirOpBuilder &builder,
469a2e7af75SValentin Clement                                              mlir::Location loc,
470a2e7af75SValentin Clement                                              const fir::MutableBoxValue &box) {
471a2e7af75SValentin Clement   auto addr = MutablePropertyReader(builder, loc, box).readBaseAddress();
47270ade047Svdonaldson   return builder.genIsNotNullAddr(loc, addr);
473a2e7af75SValentin Clement }
474a2e7af75SValentin Clement 
475b2bf995cSValentin Clement mlir::Value fir::factory::genIsNotAllocatedOrAssociatedTest(
476b2bf995cSValentin Clement     fir::FirOpBuilder &builder, mlir::Location loc,
477b2bf995cSValentin Clement     const fir::MutableBoxValue &box) {
478b2bf995cSValentin Clement   auto addr = MutablePropertyReader(builder, loc, box).readBaseAddress();
479b2bf995cSValentin Clement   return builder.genIsNullAddr(loc, addr);
480b2bf995cSValentin Clement }
481b2bf995cSValentin Clement 
4822cb31fe8SjeanPerier /// Call freemem. This does not check that the
483a2e7af75SValentin Clement /// address was allocated.
4842cb31fe8SjeanPerier static void genFreemem(fir::FirOpBuilder &builder, mlir::Location loc,
485a2e7af75SValentin Clement                        mlir::Value addr) {
486a2e7af75SValentin Clement   // A heap (ALLOCATABLE) object may have been converted to a ptr (POINTER),
487a2e7af75SValentin Clement   // so make sure the heap type is restored before deallocation.
488a2e7af75SValentin Clement   auto cast = builder.createConvert(
489a2e7af75SValentin Clement       loc, fir::HeapType::get(fir::dyn_cast_ptrEleTy(addr.getType())), addr);
490a2e7af75SValentin Clement   builder.create<fir::FreeMemOp>(loc, cast);
491a2e7af75SValentin Clement }
492a2e7af75SValentin Clement 
4932cb31fe8SjeanPerier void fir::factory::genFreememIfAllocated(fir::FirOpBuilder &builder,
494a2e7af75SValentin Clement                                          mlir::Location loc,
495a2e7af75SValentin Clement                                          const fir::MutableBoxValue &box) {
496a2e7af75SValentin Clement   auto addr = MutablePropertyReader(builder, loc, box).readBaseAddress();
49770ade047Svdonaldson   auto isAllocated = builder.genIsNotNullAddr(loc, addr);
498a2e7af75SValentin Clement   auto ifOp = builder.create<fir::IfOp>(loc, isAllocated,
499a2e7af75SValentin Clement                                         /*withElseRegion=*/false);
500a2e7af75SValentin Clement   auto insPt = builder.saveInsertionPoint();
501149ad3d5SShraiysh Vaishay   builder.setInsertionPointToStart(&ifOp.getThenRegion().front());
5022cb31fe8SjeanPerier   ::genFreemem(builder, loc, addr);
503a2e7af75SValentin Clement   builder.restoreInsertionPoint(insPt);
504a2e7af75SValentin Clement }
505a2e7af75SValentin Clement 
506a2e7af75SValentin Clement //===----------------------------------------------------------------------===//
507a2e7af75SValentin Clement // MutableBoxValue writing interface implementation
508a2e7af75SValentin Clement //===----------------------------------------------------------------------===//
509a2e7af75SValentin Clement 
510a2e7af75SValentin Clement void fir::factory::associateMutableBox(fir::FirOpBuilder &builder,
511a2e7af75SValentin Clement                                        mlir::Location loc,
512a2e7af75SValentin Clement                                        const fir::MutableBoxValue &box,
513a2e7af75SValentin Clement                                        const fir::ExtendedValue &source,
514a2e7af75SValentin Clement                                        mlir::ValueRange lbounds) {
515a2e7af75SValentin Clement   MutablePropertyWriter writer(builder, loc, box);
516a2e7af75SValentin Clement   source.match(
517ea1e767aSValentin Clement       [&](const fir::PolymorphicValue &p) {
5189f1bb307SValentin Clement         mlir::Value sourceBox;
519880b37f1SValentin Clement         if (auto polyBox = source.getBoxOf<fir::PolymorphicValue>())
5209f1bb307SValentin Clement           sourceBox = polyBox->getSourceBox();
5219a417395SKazu Hirata         writer.updateMutableBox(p.getAddr(), /*lbounds=*/std::nullopt,
5229a417395SKazu Hirata                                 /*extents=*/std::nullopt,
5239f1bb307SValentin Clement                                 /*lengths=*/std::nullopt, sourceBox);
524ea1e767aSValentin Clement       },
525a2e7af75SValentin Clement       [&](const fir::UnboxedValue &addr) {
5269a417395SKazu Hirata         writer.updateMutableBox(addr, /*lbounds=*/std::nullopt,
5279a417395SKazu Hirata                                 /*extents=*/std::nullopt,
5289a417395SKazu Hirata                                 /*lengths=*/std::nullopt);
529a2e7af75SValentin Clement       },
530a2e7af75SValentin Clement       [&](const fir::CharBoxValue &ch) {
5319a417395SKazu Hirata         writer.updateMutableBox(ch.getAddr(), /*lbounds=*/std::nullopt,
5329a417395SKazu Hirata                                 /*extents=*/std::nullopt, {ch.getLen()});
533a2e7af75SValentin Clement       },
534a2e7af75SValentin Clement       [&](const fir::ArrayBoxValue &arr) {
535a2e7af75SValentin Clement         writer.updateMutableBox(arr.getAddr(),
536a2e7af75SValentin Clement                                 lbounds.empty() ? arr.getLBounds() : lbounds,
5379a417395SKazu Hirata                                 arr.getExtents(), /*lengths=*/std::nullopt);
538a2e7af75SValentin Clement       },
539a2e7af75SValentin Clement       [&](const fir::CharArrayBoxValue &arr) {
540a2e7af75SValentin Clement         writer.updateMutableBox(arr.getAddr(),
541a2e7af75SValentin Clement                                 lbounds.empty() ? arr.getLBounds() : lbounds,
542a2e7af75SValentin Clement                                 arr.getExtents(), {arr.getLen()});
543a2e7af75SValentin Clement       },
544a2e7af75SValentin Clement       [&](const fir::BoxValue &arr) {
545a2e7af75SValentin Clement         // Rebox array fir.box to the pointer type and apply potential new lower
546a2e7af75SValentin Clement         // bounds.
547a2e7af75SValentin Clement         mlir::ValueRange newLbounds = lbounds.empty()
548a2e7af75SValentin Clement                                           ? mlir::ValueRange{arr.getLBounds()}
549a2e7af75SValentin Clement                                           : mlir::ValueRange{lbounds};
550fa08e97dSjeanPerier         if (box.hasAssumedRank()) {
551fa08e97dSjeanPerier           assert(arr.hasAssumedRank() &&
552fa08e97dSjeanPerier                  "expect both arr and box to be assumed-rank");
553fa08e97dSjeanPerier           mlir::Value reboxed = builder.create<fir::ReboxAssumedRankOp>(
554fa08e97dSjeanPerier               loc, box.getBoxTy(), arr.getAddr(),
555fa08e97dSjeanPerier               fir::LowerBoundModifierAttribute::Preserve);
556fa08e97dSjeanPerier           writer.updateWithIrBox(reboxed);
557fa08e97dSjeanPerier         } else if (box.isDescribedByVariables()) {
558a2e7af75SValentin Clement           // LHS is a contiguous pointer described by local variables. Open RHS
559a2e7af75SValentin Clement           // fir.box to update the LHS.
560a2e7af75SValentin Clement           auto rawAddr = builder.create<fir::BoxAddrOp>(loc, arr.getMemTy(),
561a2e7af75SValentin Clement                                                         arr.getAddr());
5621bffc753SEric Schweitz           auto extents = fir::factory::getExtents(loc, builder, source);
563a2e7af75SValentin Clement           llvm::SmallVector<mlir::Value> lenParams;
564a2e7af75SValentin Clement           if (arr.isCharacter()) {
565a2e7af75SValentin Clement             lenParams.emplace_back(
566a2e7af75SValentin Clement                 fir::factory::readCharLen(builder, loc, source));
5671bffc753SEric Schweitz           } else if (arr.isDerivedWithLenParameters()) {
568a2e7af75SValentin Clement             TODO(loc, "pointer assignment to derived with length parameters");
569a2e7af75SValentin Clement           }
570a2e7af75SValentin Clement           writer.updateMutableBox(rawAddr, newLbounds, extents, lenParams);
571a2e7af75SValentin Clement         } else {
572a2e7af75SValentin Clement           mlir::Value shift;
573a2e7af75SValentin Clement           if (!newLbounds.empty()) {
574a2e7af75SValentin Clement             auto shiftType =
575a2e7af75SValentin Clement                 fir::ShiftType::get(builder.getContext(), newLbounds.size());
576a2e7af75SValentin Clement             shift = builder.create<fir::ShiftOp>(loc, shiftType, newLbounds);
577a2e7af75SValentin Clement           }
578a2e7af75SValentin Clement           auto reboxed =
579a2e7af75SValentin Clement               builder.create<fir::ReboxOp>(loc, box.getBoxTy(), arr.getAddr(),
580a2e7af75SValentin Clement                                            shift, /*slice=*/mlir::Value());
581a2e7af75SValentin Clement           writer.updateWithIrBox(reboxed);
582a2e7af75SValentin Clement         }
583a2e7af75SValentin Clement       },
584a2e7af75SValentin Clement       [&](const fir::MutableBoxValue &) {
585a2e7af75SValentin Clement         // No point implementing this, if right-hand side is a
586a2e7af75SValentin Clement         // pointer/allocatable, the related MutableBoxValue has been read into
587a2e7af75SValentin Clement         // another ExtendedValue category.
588a2e7af75SValentin Clement         fir::emitFatalError(loc,
589a2e7af75SValentin Clement                             "Cannot write MutableBox to another MutableBox");
590a2e7af75SValentin Clement       },
591a2e7af75SValentin Clement       [&](const fir::ProcBoxValue &) {
592331145e6SValentin Clement         TODO(loc, "procedure pointer assignment");
593a2e7af75SValentin Clement       });
594a2e7af75SValentin Clement }
595a2e7af75SValentin Clement 
596a2e7af75SValentin Clement void fir::factory::associateMutableBoxWithRemap(
597a2e7af75SValentin Clement     fir::FirOpBuilder &builder, mlir::Location loc,
598a2e7af75SValentin Clement     const fir::MutableBoxValue &box, const fir::ExtendedValue &source,
599a2e7af75SValentin Clement     mlir::ValueRange lbounds, mlir::ValueRange ubounds) {
600a2e7af75SValentin Clement   // Compute new extents
601a2e7af75SValentin Clement   llvm::SmallVector<mlir::Value> extents;
602a2e7af75SValentin Clement   auto idxTy = builder.getIndexType();
603a2e7af75SValentin Clement   if (!lbounds.empty()) {
604a2e7af75SValentin Clement     auto one = builder.createIntegerConstant(loc, idxTy, 1);
605a2e7af75SValentin Clement     for (auto [lb, ub] : llvm::zip(lbounds, ubounds)) {
606a2e7af75SValentin Clement       auto lbi = builder.createConvert(loc, idxTy, lb);
607a2e7af75SValentin Clement       auto ubi = builder.createConvert(loc, idxTy, ub);
608092601d4SAndrzej Warzynski       auto diff = builder.create<mlir::arith::SubIOp>(loc, idxTy, ubi, lbi);
609a2e7af75SValentin Clement       extents.emplace_back(
610092601d4SAndrzej Warzynski           builder.create<mlir::arith::AddIOp>(loc, idxTy, diff, one));
611a2e7af75SValentin Clement     }
612a2e7af75SValentin Clement   } else {
613a2e7af75SValentin Clement     // lbounds are default. Upper bounds and extents are the same.
614a2e7af75SValentin Clement     for (auto ub : ubounds) {
615a2e7af75SValentin Clement       auto cast = builder.createConvert(loc, idxTy, ub);
616a2e7af75SValentin Clement       extents.emplace_back(cast);
617a2e7af75SValentin Clement     }
618a2e7af75SValentin Clement   }
619a2e7af75SValentin Clement   const auto newRank = extents.size();
620a2e7af75SValentin Clement   auto cast = [&](mlir::Value addr) -> mlir::Value {
621a2e7af75SValentin Clement     // Cast base addr to new sequence type.
622a2e7af75SValentin Clement     auto ty = fir::dyn_cast_ptrEleTy(addr.getType());
623fac349a1SChristian Sigg     if (auto seqTy = mlir::dyn_cast<fir::SequenceType>(ty)) {
624a2e7af75SValentin Clement       fir::SequenceType::Shape shape(newRank,
625a2e7af75SValentin Clement                                      fir::SequenceType::getUnknownExtent());
626a2e7af75SValentin Clement       ty = fir::SequenceType::get(shape, seqTy.getEleTy());
627a2e7af75SValentin Clement     }
628a2e7af75SValentin Clement     return builder.createConvert(loc, builder.getRefType(ty), addr);
629a2e7af75SValentin Clement   };
630a2e7af75SValentin Clement   MutablePropertyWriter writer(builder, loc, box);
631a2e7af75SValentin Clement   source.match(
632ea1e767aSValentin Clement       [&](const fir::PolymorphicValue &p) {
633ea1e767aSValentin Clement         writer.updateMutableBox(cast(p.getAddr()), lbounds, extents,
6349a417395SKazu Hirata                                 /*lengths=*/std::nullopt);
635ea1e767aSValentin Clement       },
636a2e7af75SValentin Clement       [&](const fir::UnboxedValue &addr) {
637a2e7af75SValentin Clement         writer.updateMutableBox(cast(addr), lbounds, extents,
6389a417395SKazu Hirata                                 /*lengths=*/std::nullopt);
639a2e7af75SValentin Clement       },
640a2e7af75SValentin Clement       [&](const fir::CharBoxValue &ch) {
641a2e7af75SValentin Clement         writer.updateMutableBox(cast(ch.getAddr()), lbounds, extents,
642a2e7af75SValentin Clement                                 {ch.getLen()});
643a2e7af75SValentin Clement       },
644a2e7af75SValentin Clement       [&](const fir::ArrayBoxValue &arr) {
645a2e7af75SValentin Clement         writer.updateMutableBox(cast(arr.getAddr()), lbounds, extents,
6469a417395SKazu Hirata                                 /*lengths=*/std::nullopt);
647a2e7af75SValentin Clement       },
648a2e7af75SValentin Clement       [&](const fir::CharArrayBoxValue &arr) {
649a2e7af75SValentin Clement         writer.updateMutableBox(cast(arr.getAddr()), lbounds, extents,
650a2e7af75SValentin Clement                                 {arr.getLen()});
651a2e7af75SValentin Clement       },
652a2e7af75SValentin Clement       [&](const fir::BoxValue &arr) {
653a2e7af75SValentin Clement         // Rebox right-hand side fir.box with a new shape and type.
654a2e7af75SValentin Clement         if (box.isDescribedByVariables()) {
655a2e7af75SValentin Clement           // LHS is a contiguous pointer described by local variables. Open RHS
656a2e7af75SValentin Clement           // fir.box to update the LHS.
657a2e7af75SValentin Clement           auto rawAddr = builder.create<fir::BoxAddrOp>(loc, arr.getMemTy(),
658a2e7af75SValentin Clement                                                         arr.getAddr());
659a2e7af75SValentin Clement           llvm::SmallVector<mlir::Value> lenParams;
660a2e7af75SValentin Clement           if (arr.isCharacter()) {
661a2e7af75SValentin Clement             lenParams.emplace_back(
662a2e7af75SValentin Clement                 fir::factory::readCharLen(builder, loc, source));
6631bffc753SEric Schweitz           } else if (arr.isDerivedWithLenParameters()) {
664a2e7af75SValentin Clement             TODO(loc, "pointer assignment to derived with length parameters");
665a2e7af75SValentin Clement           }
666a2e7af75SValentin Clement           writer.updateMutableBox(rawAddr, lbounds, extents, lenParams);
667a2e7af75SValentin Clement         } else {
668a2e7af75SValentin Clement           auto shapeType =
669a2e7af75SValentin Clement               fir::ShapeShiftType::get(builder.getContext(), extents.size());
670a2e7af75SValentin Clement           llvm::SmallVector<mlir::Value> shapeArgs;
671a2e7af75SValentin Clement           auto idxTy = builder.getIndexType();
672a2e7af75SValentin Clement           for (auto [lbnd, ext] : llvm::zip(lbounds, extents)) {
673a2e7af75SValentin Clement             auto lb = builder.createConvert(loc, idxTy, lbnd);
674a2e7af75SValentin Clement             shapeArgs.push_back(lb);
675a2e7af75SValentin Clement             shapeArgs.push_back(ext);
676a2e7af75SValentin Clement           }
677a2e7af75SValentin Clement           auto shape =
678a2e7af75SValentin Clement               builder.create<fir::ShapeShiftOp>(loc, shapeType, shapeArgs);
679a2e7af75SValentin Clement           auto reboxed =
680a2e7af75SValentin Clement               builder.create<fir::ReboxOp>(loc, box.getBoxTy(), arr.getAddr(),
681a2e7af75SValentin Clement                                            shape, /*slice=*/mlir::Value());
682a2e7af75SValentin Clement           writer.updateWithIrBox(reboxed);
683a2e7af75SValentin Clement         }
684a2e7af75SValentin Clement       },
685a2e7af75SValentin Clement       [&](const fir::MutableBoxValue &) {
686a2e7af75SValentin Clement         // No point implementing this, if right-hand side is a pointer or
687a2e7af75SValentin Clement         // allocatable, the related MutableBoxValue has already been read into
688a2e7af75SValentin Clement         // another ExtendedValue category.
689a2e7af75SValentin Clement         fir::emitFatalError(loc,
690a2e7af75SValentin Clement                             "Cannot write MutableBox to another MutableBox");
691a2e7af75SValentin Clement       },
692a2e7af75SValentin Clement       [&](const fir::ProcBoxValue &) {
693331145e6SValentin Clement         TODO(loc, "procedure pointer assignment");
694a2e7af75SValentin Clement       });
695a2e7af75SValentin Clement }
696a2e7af75SValentin Clement 
697a2e7af75SValentin Clement void fir::factory::disassociateMutableBox(fir::FirOpBuilder &builder,
698a2e7af75SValentin Clement                                           mlir::Location loc,
69990e9fcbbSValentin Clement                                           const fir::MutableBoxValue &box,
700*bbdb1e40SValentin Clement (バレンタイン クレメン)                                           bool polymorphicSetType,
701*bbdb1e40SValentin Clement (バレンタイン クレメン)                                           unsigned allocator) {
70290e9fcbbSValentin Clement   if (box.isPolymorphic() && polymorphicSetType) {
70390e9fcbbSValentin Clement     // 7.3.2.3 point 7. The dynamic type of a disassociated pointer is the
70490e9fcbbSValentin Clement     // same as its declared type.
705fac349a1SChristian Sigg     auto boxTy = mlir::dyn_cast<fir::BaseBoxType>(box.getBoxTy());
706f81d5e54SjeanPerier     auto eleTy = fir::unwrapPassByRefType(boxTy.getEleTy());
707ef063270SValentin Clement     mlir::Type derivedType = fir::getDerivedType(eleTy);
708fac349a1SChristian Sigg     if (auto recTy = mlir::dyn_cast<fir::RecordType>(derivedType)) {
70990e9fcbbSValentin Clement       fir::runtime::genNullifyDerivedType(builder, loc, box.getAddr(), recTy,
71090e9fcbbSValentin Clement                                           box.rank());
71190e9fcbbSValentin Clement       return;
71290e9fcbbSValentin Clement     }
71304a920b7SJean Perier   }
714*bbdb1e40SValentin Clement (バレンタイン クレメン)   MutablePropertyWriter{builder, loc, box, {}, allocator}
715*bbdb1e40SValentin Clement (バレンタイン クレメン)       .setUnallocatedStatus();
716a2e7af75SValentin Clement }
717a2e7af75SValentin Clement 
7182a59ead1SValentin Clement static llvm::SmallVector<mlir::Value>
7192a59ead1SValentin Clement getNewLengths(fir::FirOpBuilder &builder, mlir::Location loc,
7202a59ead1SValentin Clement               const fir::MutableBoxValue &box, mlir::ValueRange lenParams) {
7212a59ead1SValentin Clement   llvm::SmallVector<mlir::Value> lengths;
7222a59ead1SValentin Clement   auto idxTy = builder.getIndexType();
723fac349a1SChristian Sigg   if (auto charTy = mlir::dyn_cast<fir::CharacterType>(box.getEleTy())) {
7242a59ead1SValentin Clement     if (charTy.getLen() == fir::CharacterType::unknownLen()) {
725c8a9afe7SJean Perier       if (box.hasNonDeferredLenParams()) {
7262a59ead1SValentin Clement         lengths.emplace_back(
7272a59ead1SValentin Clement             builder.createConvert(loc, idxTy, box.nonDeferredLenParams()[0]));
728c8a9afe7SJean Perier       } else if (!lenParams.empty()) {
729c8a9afe7SJean Perier         mlir::Value len =
730c8a9afe7SJean Perier             fir::factory::genMaxWithZero(builder, loc, lenParams[0]);
731c8a9afe7SJean Perier         lengths.emplace_back(builder.createConvert(loc, idxTy, len));
732c8a9afe7SJean Perier       } else {
7332a59ead1SValentin Clement         fir::emitFatalError(
7342a59ead1SValentin Clement             loc, "could not deduce character lengths in character allocation");
7352a59ead1SValentin Clement       }
7362a59ead1SValentin Clement     }
737c8a9afe7SJean Perier   }
7382a59ead1SValentin Clement   return lengths;
7392a59ead1SValentin Clement }
7402a59ead1SValentin Clement 
7412a59ead1SValentin Clement static mlir::Value allocateAndInitNewStorage(fir::FirOpBuilder &builder,
7422a59ead1SValentin Clement                                              mlir::Location loc,
7432a59ead1SValentin Clement                                              const fir::MutableBoxValue &box,
7442a59ead1SValentin Clement                                              mlir::ValueRange extents,
7452a59ead1SValentin Clement                                              mlir::ValueRange lenParams,
7462a59ead1SValentin Clement                                              llvm::StringRef allocName) {
7472a59ead1SValentin Clement   auto lengths = getNewLengths(builder, loc, box, lenParams);
7482a59ead1SValentin Clement   auto newStorage = builder.create<fir::AllocMemOp>(
7492a59ead1SValentin Clement       loc, box.getBaseTy(), allocName, lengths, extents);
750fac349a1SChristian Sigg   if (mlir::isa<fir::RecordType>(box.getEleTy())) {
7512a59ead1SValentin Clement     // TODO: skip runtime initialization if this is not required. Currently,
7522a59ead1SValentin Clement     // there is no way to know here if a derived type needs it or not. But the
7532a59ead1SValentin Clement     // information is available at compile time and could be reflected here
7542a59ead1SValentin Clement     // somehow.
7552a59ead1SValentin Clement     mlir::Value irBox = createNewFirBox(builder, loc, box, newStorage,
7569a417395SKazu Hirata                                         std::nullopt, extents, lengths);
7572a59ead1SValentin Clement     fir::runtime::genDerivedTypeInitialize(builder, loc, irBox);
7582a59ead1SValentin Clement   }
7592a59ead1SValentin Clement   return newStorage;
7602a59ead1SValentin Clement }
7612a59ead1SValentin Clement 
762cc14bf22STom Eccles void fir::factory::genInlinedAllocation(
763cc14bf22STom Eccles     fir::FirOpBuilder &builder, mlir::Location loc,
764cc14bf22STom Eccles     const fir::MutableBoxValue &box, mlir::ValueRange lbounds,
765cc14bf22STom Eccles     mlir::ValueRange extents, mlir::ValueRange lenParams,
766cc14bf22STom Eccles     llvm::StringRef allocName, bool mustBeHeap) {
767fe252f8eSValentin Clement   auto lengths = getNewLengths(builder, loc, box, lenParams);
768c8a9afe7SJean Perier   llvm::SmallVector<mlir::Value> safeExtents;
769c8a9afe7SJean Perier   for (mlir::Value extent : extents)
770c8a9afe7SJean Perier     safeExtents.push_back(fir::factory::genMaxWithZero(builder, loc, extent));
771fe252f8eSValentin Clement   auto heap = builder.create<fir::AllocMemOp>(loc, box.getBaseTy(), allocName,
772c8a9afe7SJean Perier                                               lengths, safeExtents);
773c8a9afe7SJean Perier   MutablePropertyWriter{builder, loc, box}.updateMutableBox(
774c8a9afe7SJean Perier       heap, lbounds, safeExtents, lengths);
775fac349a1SChristian Sigg   if (mlir::isa<fir::RecordType>(box.getEleTy())) {
776fe252f8eSValentin Clement     // TODO: skip runtime initialization if this is not required. Currently,
777fe252f8eSValentin Clement     // there is no way to know here if a derived type needs it or not. But the
778fe252f8eSValentin Clement     // information is available at compile time and could be reflected here
779fe252f8eSValentin Clement     // somehow.
780fe252f8eSValentin Clement     mlir::Value irBox = fir::factory::getMutableIRBox(builder, loc, box);
781fe252f8eSValentin Clement     fir::runtime::genDerivedTypeInitialize(builder, loc, irBox);
782fe252f8eSValentin Clement   }
783cc14bf22STom Eccles 
784cc14bf22STom Eccles   heap->setAttr(fir::MustBeHeapAttr::getAttrName(),
785cc14bf22STom Eccles                 fir::MustBeHeapAttr::get(builder.getContext(), mustBeHeap));
786a2e7af75SValentin Clement }
787a2e7af75SValentin Clement 
7882cb31fe8SjeanPerier mlir::Value fir::factory::genFreemem(fir::FirOpBuilder &builder,
789a2e7af75SValentin Clement                                      mlir::Location loc,
790a2e7af75SValentin Clement                                      const fir::MutableBoxValue &box) {
791a2e7af75SValentin Clement   auto addr = MutablePropertyReader(builder, loc, box).readBaseAddress();
7922cb31fe8SjeanPerier   ::genFreemem(builder, loc, addr);
793a2e7af75SValentin Clement   MutablePropertyWriter{builder, loc, box}.setUnallocatedStatus();
7942e1982f3SValentin Clement   return addr;
795a2e7af75SValentin Clement }
796a2e7af75SValentin Clement 
79773026a4fSSlava Zakharin fir::factory::MutableBoxReallocation fir::factory::genReallocIfNeeded(
79873026a4fSSlava Zakharin     fir::FirOpBuilder &builder, mlir::Location loc,
79973026a4fSSlava Zakharin     const fir::MutableBoxValue &box, mlir::ValueRange shape,
80073026a4fSSlava Zakharin     mlir::ValueRange lengthParams,
80173026a4fSSlava Zakharin     fir::factory::ReallocStorageHandlerFunc storageHandler) {
802a2e7af75SValentin Clement   // Implement 10.2.1.3 point 3 logic when lhs is an array.
803a2e7af75SValentin Clement   auto reader = MutablePropertyReader(builder, loc, box);
804a2e7af75SValentin Clement   auto addr = reader.readBaseAddress();
8052a59ead1SValentin Clement   auto i1Type = builder.getI1Type();
8062a59ead1SValentin Clement   auto addrType = addr.getType();
80770ade047Svdonaldson   auto isAllocated = builder.genIsNotNullAddr(loc, addr);
80873026a4fSSlava Zakharin   auto getExtValForStorage = [&](mlir::Value newAddr) -> fir::ExtendedValue {
80973026a4fSSlava Zakharin     mlir::SmallVector<mlir::Value> extents;
81073026a4fSSlava Zakharin     if (box.hasRank()) {
81173026a4fSSlava Zakharin       if (shape.empty())
81273026a4fSSlava Zakharin         extents = reader.readShape();
81373026a4fSSlava Zakharin       else
81473026a4fSSlava Zakharin         extents.append(shape.begin(), shape.end());
81573026a4fSSlava Zakharin     }
81673026a4fSSlava Zakharin     if (box.isCharacter()) {
81773026a4fSSlava Zakharin       auto len = box.hasNonDeferredLenParams() ? reader.readCharacterLength()
81873026a4fSSlava Zakharin                                                : lengthParams[0];
81973026a4fSSlava Zakharin       if (box.hasRank())
82073026a4fSSlava Zakharin         return fir::CharArrayBoxValue{newAddr, len, extents};
82173026a4fSSlava Zakharin       return fir::CharBoxValue{newAddr, len};
82273026a4fSSlava Zakharin     }
82373026a4fSSlava Zakharin     if (box.isDerivedWithLenParameters())
82473026a4fSSlava Zakharin       TODO(loc, "reallocation of derived type entities with length parameters");
82573026a4fSSlava Zakharin     if (box.hasRank())
82673026a4fSSlava Zakharin       return fir::ArrayBoxValue{newAddr, extents};
82773026a4fSSlava Zakharin     return newAddr;
82873026a4fSSlava Zakharin   };
8292a59ead1SValentin Clement   auto ifOp =
8302a59ead1SValentin Clement       builder
8312a59ead1SValentin Clement           .genIfOp(loc, {i1Type, addrType}, isAllocated,
8322a59ead1SValentin Clement                    /*withElseRegion=*/true)
833a2e7af75SValentin Clement           .genThen([&]() {
8342a59ead1SValentin Clement             // The box is allocated. Check if it must be reallocated and
8352a59ead1SValentin Clement             // reallocate.
8362a59ead1SValentin Clement             auto mustReallocate = builder.createBool(loc, false);
8372a59ead1SValentin Clement             auto compareProperty = [&](mlir::Value previous,
8382a59ead1SValentin Clement                                        mlir::Value required) {
839a2e7af75SValentin Clement               auto castPrevious =
840a2e7af75SValentin Clement                   builder.createConvert(loc, required.getType(), previous);
8412a59ead1SValentin Clement               auto cmp = builder.create<mlir::arith::CmpIOp>(
8422a59ead1SValentin Clement                   loc, mlir::arith::CmpIPredicate::ne, castPrevious, required);
843dec8af70SRiver Riddle               mustReallocate = builder.create<mlir::arith::SelectOp>(
844dec8af70SRiver Riddle                   loc, cmp, cmp, mustReallocate);
845a2e7af75SValentin Clement             };
8462a59ead1SValentin Clement             llvm::SmallVector<mlir::Value> previousExtents = reader.readShape();
847a2e7af75SValentin Clement             if (!shape.empty())
848a2e7af75SValentin Clement               for (auto [previousExtent, requested] :
849a2e7af75SValentin Clement                    llvm::zip(previousExtents, shape))
850a2e7af75SValentin Clement                 compareProperty(previousExtent, requested);
851a2e7af75SValentin Clement 
852a2e7af75SValentin Clement             if (box.isCharacter() && !box.hasNonDeferredLenParams()) {
853a2e7af75SValentin Clement               // When the allocatable length is not deferred, it must not be
8542a59ead1SValentin Clement               // reallocated in case of length mismatch, instead,
8552a59ead1SValentin Clement               // padding/trimming will occur in later assignment to it.
856a2e7af75SValentin Clement               assert(!lengthParams.empty() &&
857a2e7af75SValentin Clement                      "must provide length parameters for character");
858a2e7af75SValentin Clement               compareProperty(reader.readCharacterLength(), lengthParams[0]);
8591bffc753SEric Schweitz             } else if (box.isDerivedWithLenParameters()) {
8602a59ead1SValentin Clement               TODO(loc, "automatic allocation of derived type allocatable with "
8612a59ead1SValentin Clement                         "length parameters");
862a2e7af75SValentin Clement             }
86374d5c3c0SPeter Steinfeld             auto ifOp = builder
8642a59ead1SValentin Clement                             .genIfOp(loc, {addrType}, mustReallocate,
8652a59ead1SValentin Clement                                      /*withElseRegion=*/true)
866a2e7af75SValentin Clement                             .genThen([&]() {
86774d5c3c0SPeter Steinfeld                               // If shape or length mismatch, allocate new
86874d5c3c0SPeter Steinfeld                               // storage. When rhs is a scalar, keep the
86974d5c3c0SPeter Steinfeld                               // previous shape
87074d5c3c0SPeter Steinfeld                               auto extents =
87174d5c3c0SPeter Steinfeld                                   shape.empty()
8722a59ead1SValentin Clement                                       ? mlir::ValueRange(previousExtents)
8732a59ead1SValentin Clement                                       : shape;
8742a59ead1SValentin Clement                               auto heap = allocateAndInitNewStorage(
8752a59ead1SValentin Clement                                   builder, loc, box, extents, lengthParams,
8762a59ead1SValentin Clement                                   ".auto.alloc");
87773026a4fSSlava Zakharin                               if (storageHandler)
87873026a4fSSlava Zakharin                                 storageHandler(getExtValForStorage(heap));
8792a59ead1SValentin Clement                               builder.create<fir::ResultOp>(loc, heap);
880a2e7af75SValentin Clement                             })
88173026a4fSSlava Zakharin                             .genElse([&]() {
88273026a4fSSlava Zakharin                               if (storageHandler)
88373026a4fSSlava Zakharin                                 storageHandler(getExtValForStorage(addr));
88473026a4fSSlava Zakharin                               builder.create<fir::ResultOp>(loc, addr);
88573026a4fSSlava Zakharin                             });
8862a59ead1SValentin Clement             ifOp.end();
8872a59ead1SValentin Clement             auto newAddr = ifOp.getResults()[0];
8882a59ead1SValentin Clement             builder.create<fir::ResultOp>(
8892a59ead1SValentin Clement                 loc, mlir::ValueRange{mustReallocate, newAddr});
890a2e7af75SValentin Clement           })
891a2e7af75SValentin Clement           .genElse([&]() {
8922a59ead1SValentin Clement             auto trueValue = builder.createBool(loc, true);
893a2e7af75SValentin Clement             // The box is not yet allocated, simply allocate it.
894a2e7af75SValentin Clement             if (shape.empty() && box.rank() != 0) {
8952a59ead1SValentin Clement               // See 10.2.1.3 p3.
8962a59ead1SValentin Clement               fir::runtime::genReportFatalUserError(
8972a59ead1SValentin Clement                   builder, loc,
8982a59ead1SValentin Clement                   "array left hand side must be allocated when the right hand "
8992a59ead1SValentin Clement                   "side is a scalar");
9002a59ead1SValentin Clement               builder.create<fir::ResultOp>(loc,
9012a59ead1SValentin Clement                                             mlir::ValueRange{trueValue, addr});
902a2e7af75SValentin Clement             } else {
9032a59ead1SValentin Clement               auto heap = allocateAndInitNewStorage(
9042a59ead1SValentin Clement                   builder, loc, box, shape, lengthParams, ".auto.alloc");
90573026a4fSSlava Zakharin               if (storageHandler)
90673026a4fSSlava Zakharin                 storageHandler(getExtValForStorage(heap));
9072a59ead1SValentin Clement               builder.create<fir::ResultOp>(loc,
9082a59ead1SValentin Clement                                             mlir::ValueRange{trueValue, heap});
909a2e7af75SValentin Clement             }
9102a59ead1SValentin Clement           });
9112a59ead1SValentin Clement   ifOp.end();
9122a59ead1SValentin Clement   auto wasReallocated = ifOp.getResults()[0];
9132a59ead1SValentin Clement   auto newAddr = ifOp.getResults()[1];
9142a59ead1SValentin Clement   // Create an ExtentedValue for the new storage.
91573026a4fSSlava Zakharin   auto newValue = getExtValForStorage(newAddr);
9162a59ead1SValentin Clement   return {newValue, addr, wasReallocated, isAllocated};
9172a59ead1SValentin Clement }
9182a59ead1SValentin Clement 
9192a59ead1SValentin Clement void fir::factory::finalizeRealloc(fir::FirOpBuilder &builder,
9202a59ead1SValentin Clement                                    mlir::Location loc,
9212a59ead1SValentin Clement                                    const fir::MutableBoxValue &box,
9222a59ead1SValentin Clement                                    mlir::ValueRange lbounds,
9232a59ead1SValentin Clement                                    bool takeLboundsIfRealloc,
9242a59ead1SValentin Clement                                    const MutableBoxReallocation &realloc) {
9252a59ead1SValentin Clement   builder.genIfThen(loc, realloc.wasReallocated)
9262a59ead1SValentin Clement       .genThen([&]() {
9272a59ead1SValentin Clement         auto reader = MutablePropertyReader(builder, loc, box);
9282a59ead1SValentin Clement         llvm::SmallVector<mlir::Value> previousLbounds;
9292a59ead1SValentin Clement         if (!takeLboundsIfRealloc && box.hasRank())
9302a59ead1SValentin Clement           reader.readShape(&previousLbounds);
9312a59ead1SValentin Clement         auto lbs =
9322a59ead1SValentin Clement             takeLboundsIfRealloc ? lbounds : mlir::ValueRange{previousLbounds};
9332a59ead1SValentin Clement         llvm::SmallVector<mlir::Value> lenParams;
9342a59ead1SValentin Clement         if (box.isCharacter())
9352a59ead1SValentin Clement           lenParams.push_back(fir::getLen(realloc.newValue));
9361bffc753SEric Schweitz         if (box.isDerivedWithLenParameters())
9372a59ead1SValentin Clement           TODO(loc,
9382a59ead1SValentin Clement                "reallocation of derived type entities with length parameters");
9392a59ead1SValentin Clement         auto lengths = getNewLengths(builder, loc, box, lenParams);
9402a59ead1SValentin Clement         auto heap = fir::getBase(realloc.newValue);
9411bffc753SEric Schweitz         auto extents = fir::factory::getExtents(loc, builder, realloc.newValue);
9422a59ead1SValentin Clement         builder.genIfThen(loc, realloc.oldAddressWasAllocated)
9432cb31fe8SjeanPerier             .genThen([&]() { ::genFreemem(builder, loc, realloc.oldAddress); })
9442a59ead1SValentin Clement             .end();
9452a59ead1SValentin Clement         MutablePropertyWriter{builder, loc, box}.updateMutableBox(
9462a59ead1SValentin Clement             heap, lbs, extents, lengths);
947a2e7af75SValentin Clement       })
948a2e7af75SValentin Clement       .end();
949a2e7af75SValentin Clement }
950a2e7af75SValentin Clement 
951a2e7af75SValentin Clement //===----------------------------------------------------------------------===//
952a2e7af75SValentin Clement // MutableBoxValue syncing implementation
953a2e7af75SValentin Clement //===----------------------------------------------------------------------===//
954a2e7af75SValentin Clement 
955a2e7af75SValentin Clement /// Depending on the implementation, allocatable/pointer descriptor and the
956a2e7af75SValentin Clement /// MutableBoxValue need to be synced before and after calls passing the
957a2e7af75SValentin Clement /// descriptor. These calls will generate the syncing if needed or be no-op.
958a2e7af75SValentin Clement mlir::Value fir::factory::getMutableIRBox(fir::FirOpBuilder &builder,
959a2e7af75SValentin Clement                                           mlir::Location loc,
960a2e7af75SValentin Clement                                           const fir::MutableBoxValue &box) {
961a2e7af75SValentin Clement   MutablePropertyWriter{builder, loc, box}.syncIRBoxFromMutableProperties();
962a2e7af75SValentin Clement   return box.getAddr();
963a2e7af75SValentin Clement }
964a2e7af75SValentin Clement void fir::factory::syncMutableBoxFromIRBox(fir::FirOpBuilder &builder,
965a2e7af75SValentin Clement                                            mlir::Location loc,
966a2e7af75SValentin Clement                                            const fir::MutableBoxValue &box) {
967a2e7af75SValentin Clement   MutablePropertyWriter{builder, loc, box}.syncMutablePropertiesFromIRBox();
968a2e7af75SValentin Clement }
969498f706bSSlava Zakharin 
970498f706bSSlava Zakharin mlir::Value fir::factory::genNullBoxStorage(fir::FirOpBuilder &builder,
971498f706bSSlava Zakharin                                             mlir::Location loc,
972498f706bSSlava Zakharin                                             mlir::Type boxTy) {
973498f706bSSlava Zakharin   mlir::Value boxStorage = builder.createTemporary(loc, boxTy);
974498f706bSSlava Zakharin   mlir::Value nullBox = fir::factory::createUnallocatedBox(
975498f706bSSlava Zakharin       builder, loc, boxTy, /*nonDeferredParams=*/{});
976498f706bSSlava Zakharin   builder.create<fir::StoreOp>(loc, nullBox, boxStorage);
977498f706bSSlava Zakharin   return boxStorage;
978498f706bSSlava Zakharin }
979