@@ -123,6 +123,105 @@ static fir::GlobalOp declareGlobal(Fortran::lower::AbstractConverter &converter,
123
123
return builder.createGlobal (loc, converter.genType (var), globalName, linkage);
124
124
}
125
125
126
+ // / Temporary helper to catch todos in initial data target lowering.
127
+ static bool
128
+ hasDerivedTypeWithLengthParameters (const Fortran::semantics::Symbol &sym) {
129
+ if (const auto *declTy = sym.GetType ())
130
+ if (const auto *derived = declTy->AsDerived ())
131
+ return Fortran::semantics::CountLenParameters (*derived) > 0 ;
132
+ return false ;
133
+ }
134
+
135
+ static mlir::Type unwrapElementType (mlir::Type type) {
136
+ if (auto ty = fir::dyn_cast_ptrOrBoxEleTy (type))
137
+ type = ty;
138
+ if (auto seqType = type.dyn_cast <fir::SequenceType>())
139
+ type = seqType.getEleTy ();
140
+ return type;
141
+ }
142
+
143
+ // / Helper to create initial-data-target fir.box in a global initializer region.
144
+ static mlir::Value
145
+ genInitialDataTarget (Fortran::lower::AbstractConverter &converter,
146
+ mlir::Location loc, mlir::Type boxType,
147
+ const Fortran::lower::SomeExpr &initialTarget) {
148
+ Fortran::lower::SymMap globalOpSymMap;
149
+ Fortran::lower::AggregateStoreMap storeMap;
150
+ Fortran::lower::StatementContext stmtCtx;
151
+ auto &builder = converter.getFirOpBuilder ();
152
+ if (Fortran::common::Unwrap<Fortran::evaluate::NullPointer>(initialTarget))
153
+ return Fortran::lower::createUnallocatedBox (
154
+ builder, loc, boxType, /* nonDeferredParams*/ llvm::None);
155
+ // Pointer initial data target, and NULL(mold).
156
+ if (const auto *sym = Fortran::evaluate::GetFirstSymbol (initialTarget)) {
157
+ // Length parameters processing will need care in global initializer
158
+ // context.
159
+ if (hasDerivedTypeWithLengthParameters (*sym))
160
+ TODO (loc, " initial-data-target with derived type length parameters" );
161
+
162
+ auto var = Fortran::lower::pft::Variable (*sym, /* global*/ true );
163
+ Fortran::lower::instantiateVariable (converter, var, globalOpSymMap,
164
+ storeMap);
165
+ }
166
+ mlir::Value box;
167
+ if (initialTarget.Rank () > 0 ) {
168
+ box = fir::getBase (Fortran::lower::createSomeArrayBox (
169
+ converter, initialTarget, globalOpSymMap, stmtCtx));
170
+ } else {
171
+ auto addr = Fortran::lower::createSomeExtendedAddress (
172
+ loc, converter, initialTarget, globalOpSymMap, stmtCtx);
173
+ box = builder.createBox (loc, addr);
174
+ }
175
+ // box is a fir.box<T>, not a fir.box<fir.ptr<T>> as it should to be used
176
+ // for pointers. A fir.convert should not be used here, because it would
177
+ // not actually set the pointer attribute in the descriptor.
178
+ // In a normal context, fir.rebox would be used to set the pointer attribute
179
+ // while copying the projection from another fir.box. But fir.rebox cannot be
180
+ // used in initializer because its current codegen expects that the input
181
+ // fir.box is in memory, which is not the case in initializers.
182
+ // So, just replace the fir.embox that created addr with one with
183
+ // fir.box<fir.ptr<T>> result type.
184
+ // Note that the descriptor cannot have been created with fir.rebox because
185
+ // the initial-data-target cannot be a fir.box itself (it cannot be
186
+ // assumed-shape, deferred-shape, or polymorphic as per C765). However the
187
+ // case where the initial data target is a derived type with length parameters
188
+ // will most likely be a bit trickier, hence the TODO above.
189
+
190
+ auto *op = box.getDefiningOp ();
191
+ if (!op || !mlir::isa<fir::EmboxOp>(*op))
192
+ fir::emitFatalError (
193
+ loc, " fir.box must be created with embox in global initializers" );
194
+ auto targetEleTy = unwrapElementType (box.getType ());
195
+ if (!targetEleTy.isa <fir::CharacterType>())
196
+ return builder.create <fir::EmboxOp>(loc, boxType, op->getOperands (),
197
+ op->getAttrs ());
198
+
199
+ // Handle the character case length particularities: embox takes a length
200
+ // value argument when the result type has unknown length, but not when the
201
+ // result type has constant length. The type of the initial target must be
202
+ // constant length, but the one of the pointer may not be. In this case, a
203
+ // length operand must be added.
204
+ auto targetLen = targetEleTy.cast <fir::CharacterType>().getLen ();
205
+ auto ptrLen = unwrapElementType (boxType).cast <fir::CharacterType>().getLen ();
206
+ if (ptrLen == targetLen)
207
+ // Nothing to do
208
+ return builder.create <fir::EmboxOp>(loc, boxType, op->getOperands (),
209
+ op->getAttrs ());
210
+ auto embox = mlir::cast<fir::EmboxOp>(*op);
211
+ auto ptrType = boxType.cast <fir::BoxType>().getEleTy ();
212
+ auto memref = builder.createConvert (loc, ptrType, embox.memref ());
213
+ if (targetLen == fir::CharacterType::unknownLen ())
214
+ // Drop the length argument.
215
+ return builder.create <fir::EmboxOp>(loc, boxType, memref, embox.shape (),
216
+ embox.slice ());
217
+ // targetLen is constant and ptrLen is unknown. Add a length argument.
218
+ auto targetLenValue =
219
+ builder.createIntegerConstant (loc, builder.getIndexType (), targetLen);
220
+ return builder.create <fir::EmboxOp>(loc, boxType, memref, embox.shape (),
221
+ embox.slice (),
222
+ mlir::ValueRange{targetLenValue});
223
+ }
224
+
126
225
// / Create the global op and its init if it has one
127
226
static fir::GlobalOp defineGlobal (Fortran::lower::AbstractConverter &converter,
128
227
const Fortran::lower::pft::Variable &var,
@@ -135,20 +234,27 @@ static fir::GlobalOp defineGlobal(Fortran::lower::AbstractConverter &converter,
135
234
fir::GlobalOp global;
136
235
if (Fortran::semantics::IsAllocatableOrPointer (sym)) {
137
236
auto symTy = converter.genType (var);
138
- // Pointers may have an initial target
139
- if (Fortran::semantics::IsPointer (sym)) {
140
- const auto *details =
141
- sym.detailsIf <Fortran::semantics::ObjectEntityDetails>();
142
- if (details && details->init ())
143
- mlir::emitError (loc, " TODO: global pointer initialization" );
237
+ const auto *details =
238
+ sym.detailsIf <Fortran::semantics::ObjectEntityDetails>();
239
+ if (details && details->init ()) {
240
+ auto expr = *details->init ();
241
+ auto init = [&](Fortran::lower::FirOpBuilder &b) {
242
+ auto box = genInitialDataTarget (converter, loc, symTy, expr);
243
+ b.create <fir::HasValueOp>(loc, box);
244
+ };
245
+ global =
246
+ builder.createGlobal (loc, symTy, globalName, isConst, init, linkage);
247
+ } else {
248
+ // Create unallocated/disassociated descriptor if no explicit init
249
+ auto init = [&](Fortran::lower::FirOpBuilder &b) {
250
+ auto box =
251
+ Fortran::lower::createUnallocatedBox (b, loc, symTy, llvm::None);
252
+ b.create <fir::HasValueOp>(loc, box);
253
+ };
254
+ global =
255
+ builder.createGlobal (loc, symTy, globalName, isConst, init, linkage);
144
256
}
145
- auto init = [&](Fortran::lower::FirOpBuilder &b) {
146
- auto box =
147
- Fortran::lower::createUnallocatedBox (b, loc, symTy, llvm::None);
148
- b.create <fir::HasValueOp>(loc, box);
149
- };
150
- global =
151
- builder.createGlobal (loc, symTy, globalName, isConst, init, linkage);
257
+
152
258
} else if (const auto *details =
153
259
sym.detailsIf <Fortran::semantics::ObjectEntityDetails>()) {
154
260
if (details->init ()) {
@@ -621,8 +727,12 @@ defineCommonBlock(Fortran::lower::AbstractConverter &converter,
621
727
LLVM_DEBUG (llvm::dbgs ()
622
728
<< " offset: " << mem->offset () << " is " << *mem << ' \n ' );
623
729
Fortran::lower::StatementContext stmtCtx;
624
- auto initVal = genInitializerExprValue (
625
- converter, loc, memDet->init ().value (), stmtCtx);
730
+ auto initExpr = memDet->init ().value ();
731
+ auto initVal =
732
+ Fortran::semantics::IsPointer (*mem)
733
+ ? genInitialDataTarget (converter, loc,
734
+ converter.genType (*mem), initExpr)
735
+ : genInitializerExprValue (converter, loc, initExpr, stmtCtx);
626
736
auto offVal = builder.createIntegerConstant (loc, idxTy, tupIdx);
627
737
auto castVal = builder.createConvert (loc, commonTy.getType (tupIdx),
628
738
fir::getBase (initVal));
0 commit comments