1 //===-- HLFIRTools.cpp ----------------------------------------------------===// 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 // Tools to manipulate HLFIR variable and expressions 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "flang/Optimizer/Builder/HLFIRTools.h" 14 #include "flang/Optimizer/Builder/Character.h" 15 #include "flang/Optimizer/Builder/FIRBuilder.h" 16 #include "flang/Optimizer/Builder/MutableBox.h" 17 #include "flang/Optimizer/Builder/Runtime/Allocatable.h" 18 #include "flang/Optimizer/Builder/Todo.h" 19 #include "flang/Optimizer/HLFIR/HLFIROps.h" 20 #include "mlir/IR/IRMapping.h" 21 #include "mlir/Support/LLVM.h" 22 #include "llvm/ADT/TypeSwitch.h" 23 #include <mlir/Dialect/OpenMP/OpenMPDialect.h> 24 #include <optional> 25 26 // Return explicit extents. If the base is a fir.box, this won't read it to 27 // return the extents and will instead return an empty vector. 28 llvm::SmallVector<mlir::Value> 29 hlfir::getExplicitExtentsFromShape(mlir::Value shape, 30 fir::FirOpBuilder &builder) { 31 llvm::SmallVector<mlir::Value> result; 32 auto *shapeOp = shape.getDefiningOp(); 33 if (auto s = mlir::dyn_cast_or_null<fir::ShapeOp>(shapeOp)) { 34 auto e = s.getExtents(); 35 result.append(e.begin(), e.end()); 36 } else if (auto s = mlir::dyn_cast_or_null<fir::ShapeShiftOp>(shapeOp)) { 37 auto e = s.getExtents(); 38 result.append(e.begin(), e.end()); 39 } else if (mlir::dyn_cast_or_null<fir::ShiftOp>(shapeOp)) { 40 return {}; 41 } else if (auto s = mlir::dyn_cast_or_null<hlfir::ShapeOfOp>(shapeOp)) { 42 hlfir::ExprType expr = mlir::cast<hlfir::ExprType>(s.getExpr().getType()); 43 llvm::ArrayRef<int64_t> exprShape = expr.getShape(); 44 mlir::Type indexTy = builder.getIndexType(); 45 fir::ShapeType shapeTy = mlir::cast<fir::ShapeType>(shape.getType()); 46 result.reserve(shapeTy.getRank()); 47 for (unsigned i = 0; i < shapeTy.getRank(); ++i) { 48 int64_t extent = exprShape[i]; 49 mlir::Value extentVal; 50 if (extent == expr.getUnknownExtent()) { 51 auto op = builder.create<hlfir::GetExtentOp>(shape.getLoc(), shape, i); 52 extentVal = op.getResult(); 53 } else { 54 extentVal = 55 builder.createIntegerConstant(shape.getLoc(), indexTy, extent); 56 } 57 result.emplace_back(extentVal); 58 } 59 } else { 60 TODO(shape.getLoc(), "read fir.shape to get extents"); 61 } 62 return result; 63 } 64 static llvm::SmallVector<mlir::Value> 65 getExplicitExtents(fir::FortranVariableOpInterface var, 66 fir::FirOpBuilder &builder) { 67 if (mlir::Value shape = var.getShape()) 68 return hlfir::getExplicitExtentsFromShape(var.getShape(), builder); 69 return {}; 70 } 71 72 // Return explicit lower bounds. For pointers and allocatables, this will not 73 // read the lower bounds and instead return an empty vector. 74 static llvm::SmallVector<mlir::Value> 75 getExplicitLboundsFromShape(mlir::Value shape) { 76 llvm::SmallVector<mlir::Value> result; 77 auto *shapeOp = shape.getDefiningOp(); 78 if (auto s = mlir::dyn_cast_or_null<fir::ShapeOp>(shapeOp)) { 79 return {}; 80 } else if (auto s = mlir::dyn_cast_or_null<fir::ShapeShiftOp>(shapeOp)) { 81 auto e = s.getOrigins(); 82 result.append(e.begin(), e.end()); 83 } else if (auto s = mlir::dyn_cast_or_null<fir::ShiftOp>(shapeOp)) { 84 auto e = s.getOrigins(); 85 result.append(e.begin(), e.end()); 86 } else { 87 TODO(shape.getLoc(), "read fir.shape to get lower bounds"); 88 } 89 return result; 90 } 91 static llvm::SmallVector<mlir::Value> 92 getExplicitLbounds(fir::FortranVariableOpInterface var) { 93 if (mlir::Value shape = var.getShape()) 94 return getExplicitLboundsFromShape(shape); 95 return {}; 96 } 97 98 static void 99 genLboundsAndExtentsFromBox(mlir::Location loc, fir::FirOpBuilder &builder, 100 hlfir::Entity boxEntity, 101 llvm::SmallVectorImpl<mlir::Value> &lbounds, 102 llvm::SmallVectorImpl<mlir::Value> *extents) { 103 assert(mlir::isa<fir::BaseBoxType>(boxEntity.getType()) && "must be a box"); 104 mlir::Type idxTy = builder.getIndexType(); 105 const int rank = boxEntity.getRank(); 106 for (int i = 0; i < rank; ++i) { 107 mlir::Value dim = builder.createIntegerConstant(loc, idxTy, i); 108 auto dimInfo = builder.create<fir::BoxDimsOp>(loc, idxTy, idxTy, idxTy, 109 boxEntity, dim); 110 lbounds.push_back(dimInfo.getLowerBound()); 111 if (extents) 112 extents->push_back(dimInfo.getExtent()); 113 } 114 } 115 116 static llvm::SmallVector<mlir::Value> 117 getNonDefaultLowerBounds(mlir::Location loc, fir::FirOpBuilder &builder, 118 hlfir::Entity entity) { 119 assert(!entity.isAssumedRank() && 120 "cannot compute assumed rank bounds statically"); 121 if (!entity.mayHaveNonDefaultLowerBounds()) 122 return {}; 123 if (auto varIface = entity.getIfVariableInterface()) { 124 llvm::SmallVector<mlir::Value> lbounds = getExplicitLbounds(varIface); 125 if (!lbounds.empty()) 126 return lbounds; 127 } 128 if (entity.isMutableBox()) 129 entity = hlfir::derefPointersAndAllocatables(loc, builder, entity); 130 llvm::SmallVector<mlir::Value> lowerBounds; 131 genLboundsAndExtentsFromBox(loc, builder, entity, lowerBounds, 132 /*extents=*/nullptr); 133 return lowerBounds; 134 } 135 136 static llvm::SmallVector<mlir::Value> toSmallVector(mlir::ValueRange range) { 137 llvm::SmallVector<mlir::Value> res; 138 res.append(range.begin(), range.end()); 139 return res; 140 } 141 142 static llvm::SmallVector<mlir::Value> getExplicitTypeParams(hlfir::Entity var) { 143 if (auto varIface = var.getMaybeDereferencedVariableInterface()) 144 return toSmallVector(varIface.getExplicitTypeParams()); 145 return {}; 146 } 147 148 static mlir::Value tryGettingNonDeferredCharLen(hlfir::Entity var) { 149 if (auto varIface = var.getMaybeDereferencedVariableInterface()) 150 if (!varIface.getExplicitTypeParams().empty()) 151 return varIface.getExplicitTypeParams()[0]; 152 return mlir::Value{}; 153 } 154 155 static mlir::Value genCharacterVariableLength(mlir::Location loc, 156 fir::FirOpBuilder &builder, 157 hlfir::Entity var) { 158 if (mlir::Value len = tryGettingNonDeferredCharLen(var)) 159 return len; 160 auto charType = mlir::cast<fir::CharacterType>(var.getFortranElementType()); 161 if (charType.hasConstantLen()) 162 return builder.createIntegerConstant(loc, builder.getIndexType(), 163 charType.getLen()); 164 if (var.isMutableBox()) 165 var = hlfir::Entity{builder.create<fir::LoadOp>(loc, var)}; 166 mlir::Value len = fir::factory::CharacterExprHelper{builder, loc}.getLength( 167 var.getFirBase()); 168 assert(len && "failed to retrieve length"); 169 return len; 170 } 171 172 static fir::CharBoxValue genUnboxChar(mlir::Location loc, 173 fir::FirOpBuilder &builder, 174 mlir::Value boxChar) { 175 if (auto emboxChar = boxChar.getDefiningOp<fir::EmboxCharOp>()) 176 return {emboxChar.getMemref(), emboxChar.getLen()}; 177 mlir::Type refType = fir::ReferenceType::get( 178 mlir::cast<fir::BoxCharType>(boxChar.getType()).getEleTy()); 179 auto unboxed = builder.create<fir::UnboxCharOp>( 180 loc, refType, builder.getIndexType(), boxChar); 181 mlir::Value addr = unboxed.getResult(0); 182 mlir::Value len = unboxed.getResult(1); 183 if (auto varIface = boxChar.getDefiningOp<fir::FortranVariableOpInterface>()) 184 if (mlir::Value explicitlen = varIface.getExplicitCharLen()) 185 len = explicitlen; 186 return {addr, len}; 187 } 188 189 mlir::Value hlfir::Entity::getFirBase() const { 190 if (fir::FortranVariableOpInterface variable = getIfVariableInterface()) { 191 if (auto declareOp = 192 mlir::dyn_cast<hlfir::DeclareOp>(variable.getOperation())) 193 return declareOp.getOriginalBase(); 194 if (auto associateOp = 195 mlir::dyn_cast<hlfir::AssociateOp>(variable.getOperation())) 196 return associateOp.getFirBase(); 197 } 198 return getBase(); 199 } 200 201 static bool isShapeWithLowerBounds(mlir::Value shape) { 202 if (!shape) 203 return false; 204 auto shapeTy = shape.getType(); 205 return mlir::isa<fir::ShiftType>(shapeTy) || 206 mlir::isa<fir::ShapeShiftType>(shapeTy); 207 } 208 209 bool hlfir::Entity::mayHaveNonDefaultLowerBounds() const { 210 if (!isBoxAddressOrValue() || isScalar()) 211 return false; 212 if (isMutableBox()) 213 return true; 214 if (auto varIface = getIfVariableInterface()) 215 return isShapeWithLowerBounds(varIface.getShape()); 216 // Go through chain of fir.box converts. 217 if (auto convert = getDefiningOp<fir::ConvertOp>()) 218 return hlfir::Entity{convert.getValue()}.mayHaveNonDefaultLowerBounds(); 219 // TODO: Embox and Rebox do not have hlfir variable interface, but are 220 // easy to reason about. 221 return true; 222 } 223 224 fir::FortranVariableOpInterface 225 hlfir::genDeclare(mlir::Location loc, fir::FirOpBuilder &builder, 226 const fir::ExtendedValue &exv, llvm::StringRef name, 227 fir::FortranVariableFlagsAttr flags, mlir::Value dummyScope, 228 cuf::DataAttributeAttr dataAttr) { 229 230 mlir::Value base = fir::getBase(exv); 231 assert(fir::conformsWithPassByRef(base.getType()) && 232 "entity being declared must be in memory"); 233 mlir::Value shapeOrShift; 234 llvm::SmallVector<mlir::Value> lenParams; 235 exv.match( 236 [&](const fir::CharBoxValue &box) { 237 lenParams.emplace_back(box.getLen()); 238 }, 239 [&](const fir::ArrayBoxValue &) { 240 shapeOrShift = builder.createShape(loc, exv); 241 }, 242 [&](const fir::CharArrayBoxValue &box) { 243 shapeOrShift = builder.createShape(loc, exv); 244 lenParams.emplace_back(box.getLen()); 245 }, 246 [&](const fir::BoxValue &box) { 247 if (!box.getLBounds().empty()) 248 shapeOrShift = builder.createShape(loc, exv); 249 lenParams.append(box.getExplicitParameters().begin(), 250 box.getExplicitParameters().end()); 251 }, 252 [&](const fir::MutableBoxValue &box) { 253 lenParams.append(box.nonDeferredLenParams().begin(), 254 box.nonDeferredLenParams().end()); 255 }, 256 [](const auto &) {}); 257 auto declareOp = builder.create<hlfir::DeclareOp>( 258 loc, base, name, shapeOrShift, lenParams, dummyScope, flags, dataAttr); 259 return mlir::cast<fir::FortranVariableOpInterface>(declareOp.getOperation()); 260 } 261 262 hlfir::AssociateOp 263 hlfir::genAssociateExpr(mlir::Location loc, fir::FirOpBuilder &builder, 264 hlfir::Entity value, mlir::Type variableType, 265 llvm::StringRef name, 266 std::optional<mlir::NamedAttribute> attr) { 267 assert(value.isValue() && "must not be a variable"); 268 mlir::Value shape{}; 269 if (value.isArray()) 270 shape = genShape(loc, builder, value); 271 272 mlir::Value source = value; 273 // Lowered scalar expression values for numerical and logical may have a 274 // different type than what is required for the type in memory (logical 275 // expressions are typically manipulated as i1, but needs to be stored 276 // according to the fir.logical<kind> so that the storage size is correct). 277 // Character length mismatches are ignored (it is ok for one to be dynamic 278 // and the other static). 279 mlir::Type varEleTy = getFortranElementType(variableType); 280 mlir::Type valueEleTy = getFortranElementType(value.getType()); 281 if (varEleTy != valueEleTy && !(mlir::isa<fir::CharacterType>(valueEleTy) && 282 mlir::isa<fir::CharacterType>(varEleTy))) { 283 assert(value.isScalar() && fir::isa_trivial(value.getType())); 284 source = builder.createConvert(loc, fir::unwrapPassByRefType(variableType), 285 value); 286 } 287 llvm::SmallVector<mlir::Value> lenParams; 288 genLengthParameters(loc, builder, value, lenParams); 289 if (attr) { 290 assert(name.empty() && "It attribute is provided, no-name is expected"); 291 return builder.create<hlfir::AssociateOp>(loc, source, shape, lenParams, 292 fir::FortranVariableFlagsAttr{}, 293 llvm::ArrayRef{*attr}); 294 } 295 return builder.create<hlfir::AssociateOp>(loc, source, name, shape, lenParams, 296 fir::FortranVariableFlagsAttr{}); 297 } 298 299 mlir::Value hlfir::genVariableRawAddress(mlir::Location loc, 300 fir::FirOpBuilder &builder, 301 hlfir::Entity var) { 302 assert(var.isVariable() && "only address of variables can be taken"); 303 mlir::Value baseAddr = var.getFirBase(); 304 if (var.isMutableBox()) 305 baseAddr = builder.create<fir::LoadOp>(loc, baseAddr); 306 // Get raw address. 307 if (mlir::isa<fir::BoxCharType>(var.getType())) 308 baseAddr = genUnboxChar(loc, builder, var.getBase()).getAddr(); 309 if (mlir::isa<fir::BaseBoxType>(baseAddr.getType())) 310 baseAddr = builder.create<fir::BoxAddrOp>(loc, baseAddr); 311 return baseAddr; 312 } 313 314 mlir::Value hlfir::genVariableBoxChar(mlir::Location loc, 315 fir::FirOpBuilder &builder, 316 hlfir::Entity var) { 317 assert(var.isVariable() && "only address of variables can be taken"); 318 if (mlir::isa<fir::BoxCharType>(var.getType())) 319 return var; 320 mlir::Value addr = genVariableRawAddress(loc, builder, var); 321 llvm::SmallVector<mlir::Value> lengths; 322 genLengthParameters(loc, builder, var, lengths); 323 assert(lengths.size() == 1); 324 auto charType = mlir::cast<fir::CharacterType>(var.getFortranElementType()); 325 auto boxCharType = 326 fir::BoxCharType::get(builder.getContext(), charType.getFKind()); 327 auto scalarAddr = 328 builder.createConvert(loc, fir::ReferenceType::get(charType), addr); 329 return builder.create<fir::EmboxCharOp>(loc, boxCharType, scalarAddr, 330 lengths[0]); 331 } 332 333 hlfir::Entity hlfir::genVariableBox(mlir::Location loc, 334 fir::FirOpBuilder &builder, 335 hlfir::Entity var) { 336 assert(var.isVariable() && "must be a variable"); 337 var = hlfir::derefPointersAndAllocatables(loc, builder, var); 338 if (mlir::isa<fir::BaseBoxType>(var.getType())) 339 return var; 340 // Note: if the var is not a fir.box/fir.class at that point, it has default 341 // lower bounds and is not polymorphic. 342 mlir::Value shape = 343 var.isArray() ? hlfir::genShape(loc, builder, var) : mlir::Value{}; 344 llvm::SmallVector<mlir::Value> typeParams; 345 auto maybeCharType = 346 mlir::dyn_cast<fir::CharacterType>(var.getFortranElementType()); 347 if (!maybeCharType || maybeCharType.hasDynamicLen()) 348 hlfir::genLengthParameters(loc, builder, var, typeParams); 349 mlir::Value addr = var.getBase(); 350 if (mlir::isa<fir::BoxCharType>(var.getType())) 351 addr = genVariableRawAddress(loc, builder, var); 352 mlir::Type boxType = fir::BoxType::get(var.getElementOrSequenceType()); 353 auto embox = 354 builder.create<fir::EmboxOp>(loc, boxType, addr, shape, 355 /*slice=*/mlir::Value{}, typeParams); 356 return hlfir::Entity{embox.getResult()}; 357 } 358 359 hlfir::Entity hlfir::loadTrivialScalar(mlir::Location loc, 360 fir::FirOpBuilder &builder, 361 Entity entity) { 362 entity = derefPointersAndAllocatables(loc, builder, entity); 363 if (entity.isVariable() && entity.isScalar() && 364 fir::isa_trivial(entity.getFortranElementType())) { 365 return Entity{builder.create<fir::LoadOp>(loc, entity)}; 366 } 367 return entity; 368 } 369 370 hlfir::Entity hlfir::getElementAt(mlir::Location loc, 371 fir::FirOpBuilder &builder, Entity entity, 372 mlir::ValueRange oneBasedIndices) { 373 if (entity.isScalar()) 374 return entity; 375 llvm::SmallVector<mlir::Value> lenParams; 376 genLengthParameters(loc, builder, entity, lenParams); 377 if (mlir::isa<hlfir::ExprType>(entity.getType())) 378 return hlfir::Entity{builder.create<hlfir::ApplyOp>( 379 loc, entity, oneBasedIndices, lenParams)}; 380 // Build hlfir.designate. The lower bounds may need to be added to 381 // the oneBasedIndices since hlfir.designate expect indices 382 // based on the array operand lower bounds. 383 mlir::Type resultType = hlfir::getVariableElementType(entity); 384 hlfir::DesignateOp designate; 385 llvm::SmallVector<mlir::Value> lbounds = 386 getNonDefaultLowerBounds(loc, builder, entity); 387 if (!lbounds.empty()) { 388 llvm::SmallVector<mlir::Value> indices; 389 mlir::Type idxTy = builder.getIndexType(); 390 mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1); 391 for (auto [oneBased, lb] : llvm::zip(oneBasedIndices, lbounds)) { 392 auto lbIdx = builder.createConvert(loc, idxTy, lb); 393 auto oneBasedIdx = builder.createConvert(loc, idxTy, oneBased); 394 auto shift = builder.create<mlir::arith::SubIOp>(loc, lbIdx, one); 395 mlir::Value index = 396 builder.create<mlir::arith::AddIOp>(loc, oneBasedIdx, shift); 397 indices.push_back(index); 398 } 399 designate = builder.create<hlfir::DesignateOp>(loc, resultType, entity, 400 indices, lenParams); 401 } else { 402 designate = builder.create<hlfir::DesignateOp>(loc, resultType, entity, 403 oneBasedIndices, lenParams); 404 } 405 return mlir::cast<fir::FortranVariableOpInterface>(designate.getOperation()); 406 } 407 408 static mlir::Value genUBound(mlir::Location loc, fir::FirOpBuilder &builder, 409 mlir::Value lb, mlir::Value extent, 410 mlir::Value one) { 411 if (auto constantLb = fir::getIntIfConstant(lb)) 412 if (*constantLb == 1) 413 return extent; 414 extent = builder.createConvert(loc, one.getType(), extent); 415 lb = builder.createConvert(loc, one.getType(), lb); 416 auto add = builder.create<mlir::arith::AddIOp>(loc, lb, extent); 417 return builder.create<mlir::arith::SubIOp>(loc, add, one); 418 } 419 420 llvm::SmallVector<std::pair<mlir::Value, mlir::Value>> 421 hlfir::genBounds(mlir::Location loc, fir::FirOpBuilder &builder, 422 Entity entity) { 423 if (mlir::isa<hlfir::ExprType>(entity.getType())) 424 TODO(loc, "bounds of expressions in hlfir"); 425 auto [exv, cleanup] = translateToExtendedValue(loc, builder, entity); 426 assert(!cleanup && "translation of entity should not yield cleanup"); 427 if (const auto *mutableBox = exv.getBoxOf<fir::MutableBoxValue>()) 428 exv = fir::factory::genMutableBoxRead(builder, loc, *mutableBox); 429 mlir::Type idxTy = builder.getIndexType(); 430 mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1); 431 llvm::SmallVector<std::pair<mlir::Value, mlir::Value>> result; 432 for (unsigned dim = 0; dim < exv.rank(); ++dim) { 433 mlir::Value extent = fir::factory::readExtent(builder, loc, exv, dim); 434 mlir::Value lb = fir::factory::readLowerBound(builder, loc, exv, dim, one); 435 mlir::Value ub = genUBound(loc, builder, lb, extent, one); 436 result.push_back({lb, ub}); 437 } 438 return result; 439 } 440 441 llvm::SmallVector<std::pair<mlir::Value, mlir::Value>> 442 hlfir::genBounds(mlir::Location loc, fir::FirOpBuilder &builder, 443 mlir::Value shape) { 444 assert((mlir::isa<fir::ShapeShiftType>(shape.getType()) || 445 mlir::isa<fir::ShapeType>(shape.getType())) && 446 "shape must contain extents"); 447 auto extents = hlfir::getExplicitExtentsFromShape(shape, builder); 448 auto lowers = getExplicitLboundsFromShape(shape); 449 assert(lowers.empty() || lowers.size() == extents.size()); 450 mlir::Type idxTy = builder.getIndexType(); 451 mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1); 452 llvm::SmallVector<std::pair<mlir::Value, mlir::Value>> result; 453 for (auto extent : llvm::enumerate(extents)) { 454 mlir::Value lb = lowers.empty() ? one : lowers[extent.index()]; 455 mlir::Value ub = lowers.empty() 456 ? extent.value() 457 : genUBound(loc, builder, lb, extent.value(), one); 458 result.push_back({lb, ub}); 459 } 460 return result; 461 } 462 463 llvm::SmallVector<mlir::Value> hlfir::genLowerbounds(mlir::Location loc, 464 fir::FirOpBuilder &builder, 465 mlir::Value shape, 466 unsigned rank) { 467 llvm::SmallVector<mlir::Value> lbounds; 468 if (shape) 469 lbounds = getExplicitLboundsFromShape(shape); 470 if (!lbounds.empty()) 471 return lbounds; 472 mlir::Value one = 473 builder.createIntegerConstant(loc, builder.getIndexType(), 1); 474 return llvm::SmallVector<mlir::Value>(rank, one); 475 } 476 477 static hlfir::Entity followShapeInducingSource(hlfir::Entity entity) { 478 while (true) { 479 if (auto reassoc = entity.getDefiningOp<hlfir::NoReassocOp>()) { 480 entity = hlfir::Entity{reassoc.getVal()}; 481 continue; 482 } 483 if (auto asExpr = entity.getDefiningOp<hlfir::AsExprOp>()) { 484 entity = hlfir::Entity{asExpr.getVar()}; 485 continue; 486 } 487 break; 488 } 489 return entity; 490 } 491 492 static mlir::Value computeVariableExtent(mlir::Location loc, 493 fir::FirOpBuilder &builder, 494 hlfir::Entity variable, 495 fir::SequenceType seqTy, 496 unsigned dim) { 497 mlir::Type idxTy = builder.getIndexType(); 498 if (seqTy.getShape().size() > dim) { 499 fir::SequenceType::Extent typeExtent = seqTy.getShape()[dim]; 500 if (typeExtent != fir::SequenceType::getUnknownExtent()) 501 return builder.createIntegerConstant(loc, idxTy, typeExtent); 502 } 503 assert(mlir::isa<fir::BaseBoxType>(variable.getType()) && 504 "array variable with dynamic extent must be boxed"); 505 mlir::Value dimVal = builder.createIntegerConstant(loc, idxTy, dim); 506 auto dimInfo = builder.create<fir::BoxDimsOp>(loc, idxTy, idxTy, idxTy, 507 variable, dimVal); 508 return dimInfo.getExtent(); 509 } 510 llvm::SmallVector<mlir::Value> getVariableExtents(mlir::Location loc, 511 fir::FirOpBuilder &builder, 512 hlfir::Entity variable) { 513 llvm::SmallVector<mlir::Value> extents; 514 if (fir::FortranVariableOpInterface varIface = 515 variable.getIfVariableInterface()) { 516 extents = getExplicitExtents(varIface, builder); 517 if (!extents.empty()) 518 return extents; 519 } 520 521 if (variable.isMutableBox()) 522 variable = hlfir::derefPointersAndAllocatables(loc, builder, variable); 523 // Use the type shape information, and/or the fir.box/fir.class shape 524 // information if any extents are not static. 525 fir::SequenceType seqTy = mlir::cast<fir::SequenceType>( 526 hlfir::getFortranElementOrSequenceType(variable.getType())); 527 unsigned rank = seqTy.getShape().size(); 528 for (unsigned dim = 0; dim < rank; ++dim) 529 extents.push_back( 530 computeVariableExtent(loc, builder, variable, seqTy, dim)); 531 return extents; 532 } 533 534 static mlir::Value tryRetrievingShapeOrShift(hlfir::Entity entity) { 535 if (mlir::isa<hlfir::ExprType>(entity.getType())) { 536 if (auto elemental = entity.getDefiningOp<hlfir::ElementalOp>()) 537 return elemental.getShape(); 538 if (auto evalInMem = entity.getDefiningOp<hlfir::EvaluateInMemoryOp>()) 539 return evalInMem.getShape(); 540 return mlir::Value{}; 541 } 542 if (auto varIface = entity.getIfVariableInterface()) 543 return varIface.getShape(); 544 return {}; 545 } 546 547 mlir::Value hlfir::genShape(mlir::Location loc, fir::FirOpBuilder &builder, 548 hlfir::Entity entity) { 549 assert(entity.isArray() && "entity must be an array"); 550 entity = followShapeInducingSource(entity); 551 assert(entity && "what?"); 552 if (auto shape = tryRetrievingShapeOrShift(entity)) { 553 if (mlir::isa<fir::ShapeType>(shape.getType())) 554 return shape; 555 if (mlir::isa<fir::ShapeShiftType>(shape.getType())) 556 if (auto s = shape.getDefiningOp<fir::ShapeShiftOp>()) 557 return builder.create<fir::ShapeOp>(loc, s.getExtents()); 558 } 559 if (mlir::isa<hlfir::ExprType>(entity.getType())) 560 return builder.create<hlfir::ShapeOfOp>(loc, entity.getBase()); 561 // There is no shape lying around for this entity. Retrieve the extents and 562 // build a new fir.shape. 563 return builder.create<fir::ShapeOp>(loc, 564 getVariableExtents(loc, builder, entity)); 565 } 566 567 llvm::SmallVector<mlir::Value> 568 hlfir::getIndexExtents(mlir::Location loc, fir::FirOpBuilder &builder, 569 mlir::Value shape) { 570 llvm::SmallVector<mlir::Value> extents = 571 hlfir::getExplicitExtentsFromShape(shape, builder); 572 mlir::Type indexType = builder.getIndexType(); 573 for (auto &extent : extents) 574 extent = builder.createConvert(loc, indexType, extent); 575 return extents; 576 } 577 578 mlir::Value hlfir::genExtent(mlir::Location loc, fir::FirOpBuilder &builder, 579 hlfir::Entity entity, unsigned dim) { 580 entity = followShapeInducingSource(entity); 581 if (auto shape = tryRetrievingShapeOrShift(entity)) { 582 auto extents = hlfir::getExplicitExtentsFromShape(shape, builder); 583 if (!extents.empty()) { 584 assert(extents.size() > dim && "bad inquiry"); 585 return extents[dim]; 586 } 587 } 588 if (entity.isVariable()) { 589 if (entity.isMutableBox()) 590 entity = hlfir::derefPointersAndAllocatables(loc, builder, entity); 591 // Use the type shape information, and/or the fir.box/fir.class shape 592 // information if any extents are not static. 593 fir::SequenceType seqTy = mlir::cast<fir::SequenceType>( 594 hlfir::getFortranElementOrSequenceType(entity.getType())); 595 return computeVariableExtent(loc, builder, entity, seqTy, dim); 596 } 597 TODO(loc, "get extent from HLFIR expr without producer holding the shape"); 598 } 599 600 mlir::Value hlfir::genLBound(mlir::Location loc, fir::FirOpBuilder &builder, 601 hlfir::Entity entity, unsigned dim) { 602 if (!entity.mayHaveNonDefaultLowerBounds()) 603 return builder.createIntegerConstant(loc, builder.getIndexType(), 1); 604 if (auto shape = tryRetrievingShapeOrShift(entity)) { 605 auto lbounds = getExplicitLboundsFromShape(shape); 606 if (!lbounds.empty()) { 607 assert(lbounds.size() > dim && "bad inquiry"); 608 return lbounds[dim]; 609 } 610 } 611 if (entity.isMutableBox()) 612 entity = hlfir::derefPointersAndAllocatables(loc, builder, entity); 613 assert(mlir::isa<fir::BaseBoxType>(entity.getType()) && "must be a box"); 614 mlir::Type idxTy = builder.getIndexType(); 615 mlir::Value dimVal = builder.createIntegerConstant(loc, idxTy, dim); 616 auto dimInfo = 617 builder.create<fir::BoxDimsOp>(loc, idxTy, idxTy, idxTy, entity, dimVal); 618 return dimInfo.getLowerBound(); 619 } 620 621 void hlfir::genLengthParameters(mlir::Location loc, fir::FirOpBuilder &builder, 622 Entity entity, 623 llvm::SmallVectorImpl<mlir::Value> &result) { 624 if (!entity.hasLengthParameters()) 625 return; 626 if (mlir::isa<hlfir::ExprType>(entity.getType())) { 627 mlir::Value expr = entity; 628 if (auto reassoc = expr.getDefiningOp<hlfir::NoReassocOp>()) 629 expr = reassoc.getVal(); 630 // Going through fir::ExtendedValue would create a temp, 631 // which is not desired for an inquiry. 632 // TODO: make this an interface when adding further character producing ops. 633 if (auto concat = expr.getDefiningOp<hlfir::ConcatOp>()) { 634 result.push_back(concat.getLength()); 635 return; 636 } else if (auto concat = expr.getDefiningOp<hlfir::SetLengthOp>()) { 637 result.push_back(concat.getLength()); 638 return; 639 } else if (auto asExpr = expr.getDefiningOp<hlfir::AsExprOp>()) { 640 hlfir::genLengthParameters(loc, builder, hlfir::Entity{asExpr.getVar()}, 641 result); 642 return; 643 } else if (auto elemental = expr.getDefiningOp<hlfir::ElementalOp>()) { 644 result.append(elemental.getTypeparams().begin(), 645 elemental.getTypeparams().end()); 646 return; 647 } else if (auto evalInMem = 648 expr.getDefiningOp<hlfir::EvaluateInMemoryOp>()) { 649 result.append(evalInMem.getTypeparams().begin(), 650 evalInMem.getTypeparams().end()); 651 return; 652 } else if (auto apply = expr.getDefiningOp<hlfir::ApplyOp>()) { 653 result.append(apply.getTypeparams().begin(), apply.getTypeparams().end()); 654 return; 655 } 656 if (entity.isCharacter()) { 657 result.push_back(builder.create<hlfir::GetLengthOp>(loc, expr)); 658 return; 659 } 660 TODO(loc, "inquire PDTs length parameters of hlfir.expr"); 661 } 662 663 if (entity.isCharacter()) { 664 result.push_back(genCharacterVariableLength(loc, builder, entity)); 665 return; 666 } 667 TODO(loc, "inquire PDTs length parameters in HLFIR"); 668 } 669 670 mlir::Value hlfir::genCharLength(mlir::Location loc, fir::FirOpBuilder &builder, 671 hlfir::Entity entity) { 672 llvm::SmallVector<mlir::Value, 1> lenParams; 673 genLengthParameters(loc, builder, entity, lenParams); 674 assert(lenParams.size() == 1 && "characters must have one length parameters"); 675 return lenParams[0]; 676 } 677 678 mlir::Value hlfir::genRank(mlir::Location loc, fir::FirOpBuilder &builder, 679 hlfir::Entity entity, mlir::Type resultType) { 680 if (!entity.isAssumedRank()) 681 return builder.createIntegerConstant(loc, resultType, entity.getRank()); 682 assert(entity.isBoxAddressOrValue() && 683 "assumed-ranks are box addresses or values"); 684 return builder.create<fir::BoxRankOp>(loc, resultType, entity); 685 } 686 687 // Return a "shape" that can be used in fir.embox/fir.rebox with \p exv base. 688 static mlir::Value asEmboxShape(mlir::Location loc, fir::FirOpBuilder &builder, 689 const fir::ExtendedValue &exv, 690 mlir::Value shape) { 691 if (!shape) 692 return shape; 693 // fir.rebox does not need and does not accept extents (fir.shape or 694 // fir.shape_shift) since this information is already in the input fir.box, 695 // it only accepts fir.shift because local lower bounds may not be reflected 696 // in the fir.box. 697 if (mlir::isa<fir::BaseBoxType>(fir::getBase(exv).getType()) && 698 !mlir::isa<fir::ShiftType>(shape.getType())) 699 return builder.createShape(loc, exv); 700 return shape; 701 } 702 703 std::pair<mlir::Value, mlir::Value> hlfir::genVariableFirBaseShapeAndParams( 704 mlir::Location loc, fir::FirOpBuilder &builder, Entity entity, 705 llvm::SmallVectorImpl<mlir::Value> &typeParams) { 706 auto [exv, cleanup] = translateToExtendedValue(loc, builder, entity); 707 assert(!cleanup && "variable to Exv should not produce cleanup"); 708 if (entity.hasLengthParameters()) { 709 auto params = fir::getTypeParams(exv); 710 typeParams.append(params.begin(), params.end()); 711 } 712 if (entity.isScalar()) 713 return {fir::getBase(exv), mlir::Value{}}; 714 if (auto variableInterface = entity.getIfVariableInterface()) 715 return {fir::getBase(exv), 716 asEmboxShape(loc, builder, exv, variableInterface.getShape())}; 717 return {fir::getBase(exv), builder.createShape(loc, exv)}; 718 } 719 720 hlfir::Entity hlfir::derefPointersAndAllocatables(mlir::Location loc, 721 fir::FirOpBuilder &builder, 722 Entity entity) { 723 if (entity.isMutableBox()) { 724 hlfir::Entity boxLoad{builder.create<fir::LoadOp>(loc, entity)}; 725 if (entity.isScalar()) { 726 if (!entity.isPolymorphic() && !entity.hasLengthParameters()) 727 return hlfir::Entity{builder.create<fir::BoxAddrOp>(loc, boxLoad)}; 728 mlir::Type elementType = boxLoad.getFortranElementType(); 729 if (auto charType = mlir::dyn_cast<fir::CharacterType>(elementType)) { 730 mlir::Value base = builder.create<fir::BoxAddrOp>(loc, boxLoad); 731 if (charType.hasConstantLen()) 732 return hlfir::Entity{base}; 733 mlir::Value len = genCharacterVariableLength(loc, builder, entity); 734 auto boxCharType = 735 fir::BoxCharType::get(builder.getContext(), charType.getFKind()); 736 return hlfir::Entity{ 737 builder.create<fir::EmboxCharOp>(loc, boxCharType, base, len) 738 .getResult()}; 739 } 740 } 741 // Otherwise, the entity is either an array, a polymorphic entity, or a 742 // derived type with length parameters. All these entities require a fir.box 743 // or fir.class to hold bounds, dynamic type or length parameter 744 // information. Keep them boxed. 745 return boxLoad; 746 } else if (entity.isProcedurePointer()) { 747 return hlfir::Entity{builder.create<fir::LoadOp>(loc, entity)}; 748 } 749 return entity; 750 } 751 752 mlir::Type hlfir::getVariableElementType(hlfir::Entity variable) { 753 assert(variable.isVariable() && "entity must be a variable"); 754 if (variable.isScalar()) 755 return variable.getType(); 756 mlir::Type eleTy = variable.getFortranElementType(); 757 if (variable.isPolymorphic()) 758 return fir::ClassType::get(eleTy); 759 if (auto charType = mlir::dyn_cast<fir::CharacterType>(eleTy)) { 760 if (charType.hasDynamicLen()) 761 return fir::BoxCharType::get(charType.getContext(), charType.getFKind()); 762 } else if (fir::isRecordWithTypeParameters(eleTy)) { 763 return fir::BoxType::get(eleTy); 764 } 765 return fir::ReferenceType::get(eleTy); 766 } 767 768 mlir::Type hlfir::getEntityElementType(hlfir::Entity entity) { 769 if (entity.isVariable()) 770 return getVariableElementType(entity); 771 if (entity.isScalar()) 772 return entity.getType(); 773 auto exprType = mlir::dyn_cast<hlfir::ExprType>(entity.getType()); 774 assert(exprType && "array value must be an hlfir.expr"); 775 return exprType.getElementExprType(); 776 } 777 778 static hlfir::ExprType getArrayExprType(mlir::Type elementType, 779 mlir::Value shape, bool isPolymorphic) { 780 unsigned rank = mlir::cast<fir::ShapeType>(shape.getType()).getRank(); 781 hlfir::ExprType::Shape typeShape(rank, hlfir::ExprType::getUnknownExtent()); 782 if (auto shapeOp = shape.getDefiningOp<fir::ShapeOp>()) 783 for (auto extent : llvm::enumerate(shapeOp.getExtents())) 784 if (auto cstExtent = fir::getIntIfConstant(extent.value())) 785 typeShape[extent.index()] = *cstExtent; 786 return hlfir::ExprType::get(elementType.getContext(), typeShape, elementType, 787 isPolymorphic); 788 } 789 790 hlfir::ElementalOp hlfir::genElementalOp( 791 mlir::Location loc, fir::FirOpBuilder &builder, mlir::Type elementType, 792 mlir::Value shape, mlir::ValueRange typeParams, 793 const ElementalKernelGenerator &genKernel, bool isUnordered, 794 mlir::Value polymorphicMold, mlir::Type exprType) { 795 if (!exprType) 796 exprType = getArrayExprType(elementType, shape, !!polymorphicMold); 797 auto elementalOp = builder.create<hlfir::ElementalOp>( 798 loc, exprType, shape, polymorphicMold, typeParams, isUnordered); 799 auto insertPt = builder.saveInsertionPoint(); 800 builder.setInsertionPointToStart(elementalOp.getBody()); 801 mlir::Value elementResult = genKernel(loc, builder, elementalOp.getIndices()); 802 // Numerical and logical scalars may be lowered to another type than the 803 // Fortran expression type (e.g i1 instead of fir.logical). Array expression 804 // values are typed according to their Fortran type. Insert a cast if needed 805 // here. 806 if (fir::isa_trivial(elementResult.getType())) 807 elementResult = builder.createConvert(loc, elementType, elementResult); 808 builder.create<hlfir::YieldElementOp>(loc, elementResult); 809 builder.restoreInsertionPoint(insertPt); 810 return elementalOp; 811 } 812 813 // TODO: we do not actually need to clone the YieldElementOp, 814 // because returning its getElementValue() operand should be enough 815 // for all callers of this function. 816 hlfir::YieldElementOp 817 hlfir::inlineElementalOp(mlir::Location loc, fir::FirOpBuilder &builder, 818 hlfir::ElementalOp elemental, 819 mlir::ValueRange oneBasedIndices) { 820 // hlfir.elemental region is a SizedRegion<1>. 821 assert(elemental.getRegion().hasOneBlock() && 822 "expect elemental region to have one block"); 823 mlir::IRMapping mapper; 824 mapper.map(elemental.getIndices(), oneBasedIndices); 825 mlir::Operation *newOp; 826 for (auto &op : elemental.getRegion().back().getOperations()) 827 newOp = builder.clone(op, mapper); 828 auto yield = mlir::dyn_cast_or_null<hlfir::YieldElementOp>(newOp); 829 assert(yield && "last ElementalOp operation must be am hlfir.yield_element"); 830 return yield; 831 } 832 833 mlir::Value hlfir::inlineElementalOp( 834 mlir::Location loc, fir::FirOpBuilder &builder, 835 hlfir::ElementalOpInterface elemental, mlir::ValueRange oneBasedIndices, 836 mlir::IRMapping &mapper, 837 const std::function<bool(hlfir::ElementalOp)> &mustRecursivelyInline) { 838 mlir::Region ®ion = elemental.getElementalRegion(); 839 // hlfir.elemental region is a SizedRegion<1>. 840 assert(region.hasOneBlock() && "elemental region must have one block"); 841 mapper.map(elemental.getIndices(), oneBasedIndices); 842 for (auto &op : region.front().without_terminator()) { 843 if (auto apply = mlir::dyn_cast<hlfir::ApplyOp>(op)) 844 if (auto appliedElemental = 845 apply.getExpr().getDefiningOp<hlfir::ElementalOp>()) 846 if (mustRecursivelyInline(appliedElemental)) { 847 llvm::SmallVector<mlir::Value> clonedApplyIndices; 848 for (auto indice : apply.getIndices()) 849 clonedApplyIndices.push_back(mapper.lookupOrDefault(indice)); 850 hlfir::ElementalOpInterface elementalIface = 851 mlir::cast<hlfir::ElementalOpInterface>( 852 appliedElemental.getOperation()); 853 mlir::Value inlined = inlineElementalOp(loc, builder, elementalIface, 854 clonedApplyIndices, mapper, 855 mustRecursivelyInline); 856 mapper.map(apply.getResult(), inlined); 857 continue; 858 } 859 (void)builder.clone(op, mapper); 860 } 861 return mapper.lookupOrDefault(elemental.getElementEntity()); 862 } 863 864 hlfir::LoopNest hlfir::genLoopNest(mlir::Location loc, 865 fir::FirOpBuilder &builder, 866 mlir::ValueRange extents, bool isUnordered, 867 bool emitWorkshareLoop) { 868 emitWorkshareLoop = emitWorkshareLoop && isUnordered; 869 hlfir::LoopNest loopNest; 870 assert(!extents.empty() && "must have at least one extent"); 871 mlir::OpBuilder::InsertionGuard guard(builder); 872 loopNest.oneBasedIndices.assign(extents.size(), mlir::Value{}); 873 // Build loop nest from column to row. 874 auto one = builder.create<mlir::arith::ConstantIndexOp>(loc, 1); 875 mlir::Type indexType = builder.getIndexType(); 876 if (emitWorkshareLoop) { 877 auto wslw = builder.create<mlir::omp::WorkshareLoopWrapperOp>(loc); 878 loopNest.outerOp = wslw; 879 builder.createBlock(&wslw.getRegion()); 880 mlir::omp::LoopNestOperands lnops; 881 lnops.loopInclusive = builder.getUnitAttr(); 882 for (auto extent : llvm::reverse(extents)) { 883 lnops.loopLowerBounds.push_back(one); 884 lnops.loopUpperBounds.push_back(extent); 885 lnops.loopSteps.push_back(one); 886 } 887 auto lnOp = builder.create<mlir::omp::LoopNestOp>(loc, lnops); 888 mlir::Block *block = builder.createBlock(&lnOp.getRegion()); 889 for (auto extent : llvm::reverse(extents)) 890 block->addArgument(extent.getType(), extent.getLoc()); 891 loopNest.body = block; 892 builder.create<mlir::omp::YieldOp>(loc); 893 for (unsigned dim = 0; dim < extents.size(); dim++) 894 loopNest.oneBasedIndices[extents.size() - dim - 1] = 895 lnOp.getRegion().front().getArgument(dim); 896 } else { 897 unsigned dim = extents.size() - 1; 898 for (auto extent : llvm::reverse(extents)) { 899 auto ub = builder.createConvert(loc, indexType, extent); 900 auto doLoop = 901 builder.create<fir::DoLoopOp>(loc, one, ub, one, isUnordered); 902 loopNest.body = doLoop.getBody(); 903 builder.setInsertionPointToStart(loopNest.body); 904 // Reverse the indices so they are in column-major order. 905 loopNest.oneBasedIndices[dim--] = doLoop.getInductionVar(); 906 if (!loopNest.outerOp) 907 loopNest.outerOp = doLoop; 908 } 909 } 910 return loopNest; 911 } 912 913 llvm::SmallVector<mlir::Value> hlfir::genLoopNestWithReductions( 914 mlir::Location loc, fir::FirOpBuilder &builder, mlir::ValueRange extents, 915 mlir::ValueRange reductionInits, const ReductionLoopBodyGenerator &genBody, 916 bool isUnordered) { 917 assert(!extents.empty() && "must have at least one extent"); 918 // Build loop nest from column to row. 919 auto one = builder.create<mlir::arith::ConstantIndexOp>(loc, 1); 920 mlir::Type indexType = builder.getIndexType(); 921 unsigned dim = extents.size() - 1; 922 fir::DoLoopOp outerLoop = nullptr; 923 fir::DoLoopOp parentLoop = nullptr; 924 llvm::SmallVector<mlir::Value> oneBasedIndices; 925 oneBasedIndices.resize(dim + 1); 926 for (auto extent : llvm::reverse(extents)) { 927 auto ub = builder.createConvert(loc, indexType, extent); 928 929 // The outermost loop takes reductionInits as the initial 930 // values of its iter-args. 931 // A child loop takes its iter-args from the region iter-args 932 // of its parent loop. 933 fir::DoLoopOp doLoop; 934 if (!parentLoop) { 935 doLoop = builder.create<fir::DoLoopOp>(loc, one, ub, one, isUnordered, 936 /*finalCountValue=*/false, 937 reductionInits); 938 } else { 939 doLoop = builder.create<fir::DoLoopOp>(loc, one, ub, one, isUnordered, 940 /*finalCountValue=*/false, 941 parentLoop.getRegionIterArgs()); 942 if (!reductionInits.empty()) { 943 // Return the results of the child loop from its parent loop. 944 builder.create<fir::ResultOp>(loc, doLoop.getResults()); 945 } 946 } 947 948 builder.setInsertionPointToStart(doLoop.getBody()); 949 // Reverse the indices so they are in column-major order. 950 oneBasedIndices[dim--] = doLoop.getInductionVar(); 951 if (!outerLoop) 952 outerLoop = doLoop; 953 parentLoop = doLoop; 954 } 955 956 llvm::SmallVector<mlir::Value> reductionValues; 957 reductionValues = 958 genBody(loc, builder, oneBasedIndices, parentLoop.getRegionIterArgs()); 959 builder.setInsertionPointToEnd(parentLoop.getBody()); 960 if (!reductionValues.empty()) 961 builder.create<fir::ResultOp>(loc, reductionValues); 962 builder.setInsertionPointAfter(outerLoop); 963 return outerLoop->getResults(); 964 } 965 966 static fir::ExtendedValue translateVariableToExtendedValue( 967 mlir::Location loc, fir::FirOpBuilder &builder, hlfir::Entity variable, 968 bool forceHlfirBase = false, bool contiguousHint = false) { 969 assert(variable.isVariable() && "must be a variable"); 970 // When going towards FIR, use the original base value to avoid 971 // introducing descriptors at runtime when they are not required. 972 // This is not done for assumed-rank since the fir::ExtendedValue cannot 973 // held the related lower bounds in an vector. The lower bounds of the 974 // descriptor must always be used instead. 975 976 mlir::Value base = (forceHlfirBase || variable.isAssumedRank()) 977 ? variable.getBase() 978 : variable.getFirBase(); 979 if (variable.isMutableBox()) 980 return fir::MutableBoxValue(base, getExplicitTypeParams(variable), 981 fir::MutableProperties{}); 982 983 if (mlir::isa<fir::BaseBoxType>(base.getType())) { 984 const bool contiguous = variable.isSimplyContiguous() || contiguousHint; 985 const bool isAssumedRank = variable.isAssumedRank(); 986 if (!contiguous || variable.isPolymorphic() || 987 variable.isDerivedWithLengthParameters() || variable.isOptional() || 988 isAssumedRank) { 989 llvm::SmallVector<mlir::Value> nonDefaultLbounds; 990 if (!isAssumedRank) 991 nonDefaultLbounds = getNonDefaultLowerBounds(loc, builder, variable); 992 return fir::BoxValue(base, nonDefaultLbounds, 993 getExplicitTypeParams(variable)); 994 } 995 // Otherwise, the variable can be represented in a fir::ExtendedValue 996 // without the overhead of a fir.box. 997 base = genVariableRawAddress(loc, builder, variable); 998 } 999 1000 if (variable.isScalar()) { 1001 if (variable.isCharacter()) { 1002 if (mlir::isa<fir::BoxCharType>(base.getType())) 1003 return genUnboxChar(loc, builder, base); 1004 mlir::Value len = genCharacterVariableLength(loc, builder, variable); 1005 return fir::CharBoxValue{base, len}; 1006 } 1007 return base; 1008 } 1009 llvm::SmallVector<mlir::Value> extents; 1010 llvm::SmallVector<mlir::Value> nonDefaultLbounds; 1011 if (mlir::isa<fir::BaseBoxType>(variable.getType()) && 1012 !variable.getIfVariableInterface() && 1013 variable.mayHaveNonDefaultLowerBounds()) { 1014 // This special case avoids generating two sets of identical 1015 // fir.box_dim to get both the lower bounds and extents. 1016 genLboundsAndExtentsFromBox(loc, builder, variable, nonDefaultLbounds, 1017 &extents); 1018 } else { 1019 extents = getVariableExtents(loc, builder, variable); 1020 nonDefaultLbounds = getNonDefaultLowerBounds(loc, builder, variable); 1021 } 1022 if (variable.isCharacter()) 1023 return fir::CharArrayBoxValue{ 1024 base, genCharacterVariableLength(loc, builder, variable), extents, 1025 nonDefaultLbounds}; 1026 return fir::ArrayBoxValue{base, extents, nonDefaultLbounds}; 1027 } 1028 1029 fir::ExtendedValue 1030 hlfir::translateToExtendedValue(mlir::Location loc, fir::FirOpBuilder &builder, 1031 fir::FortranVariableOpInterface var, 1032 bool forceHlfirBase) { 1033 return translateVariableToExtendedValue(loc, builder, var, forceHlfirBase); 1034 } 1035 1036 std::pair<fir::ExtendedValue, std::optional<hlfir::CleanupFunction>> 1037 hlfir::translateToExtendedValue(mlir::Location loc, fir::FirOpBuilder &builder, 1038 hlfir::Entity entity, bool contiguousHint) { 1039 if (entity.isVariable()) 1040 return {translateVariableToExtendedValue(loc, builder, entity, false, 1041 contiguousHint), 1042 std::nullopt}; 1043 1044 if (entity.isProcedure()) { 1045 if (fir::isCharacterProcedureTuple(entity.getType())) { 1046 auto [boxProc, len] = fir::factory::extractCharacterProcedureTuple( 1047 builder, loc, entity, /*openBoxProc=*/false); 1048 return {fir::CharBoxValue{boxProc, len}, std::nullopt}; 1049 } 1050 return {static_cast<mlir::Value>(entity), std::nullopt}; 1051 } 1052 1053 if (mlir::isa<hlfir::ExprType>(entity.getType())) { 1054 mlir::NamedAttribute byRefAttr = fir::getAdaptToByRefAttr(builder); 1055 hlfir::AssociateOp associate = hlfir::genAssociateExpr( 1056 loc, builder, entity, entity.getType(), "", byRefAttr); 1057 auto *bldr = &builder; 1058 hlfir::CleanupFunction cleanup = [bldr, loc, associate]() -> void { 1059 bldr->create<hlfir::EndAssociateOp>(loc, associate); 1060 }; 1061 hlfir::Entity temp{associate.getBase()}; 1062 return {translateToExtendedValue(loc, builder, temp).first, cleanup}; 1063 } 1064 return {{static_cast<mlir::Value>(entity)}, {}}; 1065 } 1066 1067 std::pair<fir::ExtendedValue, std::optional<hlfir::CleanupFunction>> 1068 hlfir::convertToValue(mlir::Location loc, fir::FirOpBuilder &builder, 1069 hlfir::Entity entity) { 1070 // Load scalar references to integer, logical, real, or complex value 1071 // to an mlir value, dereference allocatable and pointers, and get rid 1072 // of fir.box that are not needed or create a copy into contiguous memory. 1073 auto derefedAndLoadedEntity = loadTrivialScalar(loc, builder, entity); 1074 return translateToExtendedValue(loc, builder, derefedAndLoadedEntity); 1075 } 1076 1077 static fir::ExtendedValue placeTrivialInMemory(mlir::Location loc, 1078 fir::FirOpBuilder &builder, 1079 mlir::Value val, 1080 mlir::Type targetType) { 1081 auto temp = builder.createTemporary(loc, targetType); 1082 if (targetType != val.getType()) 1083 builder.createStoreWithConvert(loc, val, temp); 1084 else 1085 builder.create<fir::StoreOp>(loc, val, temp); 1086 return temp; 1087 } 1088 1089 std::pair<fir::ExtendedValue, std::optional<hlfir::CleanupFunction>> 1090 hlfir::convertToBox(mlir::Location loc, fir::FirOpBuilder &builder, 1091 hlfir::Entity entity, mlir::Type targetType) { 1092 // fir::factory::createBoxValue is not meant to deal with procedures. 1093 // Dereference procedure pointers here. 1094 if (entity.isProcedurePointer()) 1095 entity = hlfir::derefPointersAndAllocatables(loc, builder, entity); 1096 1097 auto [exv, cleanup] = translateToExtendedValue(loc, builder, entity); 1098 // Procedure entities should not go through createBoxValue that embox 1099 // object entities. Return the fir.boxproc directly. 1100 if (entity.isProcedure()) 1101 return {exv, cleanup}; 1102 mlir::Value base = fir::getBase(exv); 1103 if (fir::isa_trivial(base.getType())) 1104 exv = placeTrivialInMemory(loc, builder, base, targetType); 1105 fir::BoxValue box = fir::factory::createBoxValue(builder, loc, exv); 1106 return {box, cleanup}; 1107 } 1108 1109 std::pair<fir::ExtendedValue, std::optional<hlfir::CleanupFunction>> 1110 hlfir::convertToAddress(mlir::Location loc, fir::FirOpBuilder &builder, 1111 hlfir::Entity entity, mlir::Type targetType) { 1112 hlfir::Entity derefedEntity = 1113 hlfir::derefPointersAndAllocatables(loc, builder, entity); 1114 auto [exv, cleanup] = 1115 hlfir::translateToExtendedValue(loc, builder, derefedEntity); 1116 mlir::Value base = fir::getBase(exv); 1117 if (fir::isa_trivial(base.getType())) 1118 exv = placeTrivialInMemory(loc, builder, base, targetType); 1119 return {exv, cleanup}; 1120 } 1121 1122 /// Clone: 1123 /// ``` 1124 /// hlfir.elemental_addr %shape : !fir.shape<1> { 1125 /// ^bb0(%i : index) 1126 /// ..... 1127 /// %hlfir.yield %scalarAddress : fir.ref<T> 1128 /// } 1129 /// ``` 1130 // 1131 /// into 1132 /// 1133 /// ``` 1134 /// %expr = hlfir.elemental %shape : (!fir.shape<1>) -> hlfir.expr<?xT> { 1135 /// ^bb0(%i : index) 1136 /// ..... 1137 /// %value = fir.load %scalarAddress : fir.ref<T> 1138 /// %hlfir.yield_element %value : T 1139 /// } 1140 /// ``` 1141 hlfir::ElementalOp 1142 hlfir::cloneToElementalOp(mlir::Location loc, fir::FirOpBuilder &builder, 1143 hlfir::ElementalAddrOp elementalAddrOp) { 1144 hlfir::Entity scalarAddress = 1145 hlfir::Entity{mlir::cast<hlfir::YieldOp>( 1146 elementalAddrOp.getBody().back().getTerminator()) 1147 .getEntity()}; 1148 llvm::SmallVector<mlir::Value, 1> typeParams; 1149 hlfir::genLengthParameters(loc, builder, scalarAddress, typeParams); 1150 1151 builder.setInsertionPointAfter(elementalAddrOp); 1152 auto genKernel = [&](mlir::Location l, fir::FirOpBuilder &b, 1153 mlir::ValueRange oneBasedIndices) -> hlfir::Entity { 1154 mlir::IRMapping mapper; 1155 mapper.map(elementalAddrOp.getIndices(), oneBasedIndices); 1156 mlir::Operation *newOp = nullptr; 1157 for (auto &op : elementalAddrOp.getBody().back().getOperations()) 1158 newOp = b.clone(op, mapper); 1159 auto newYielOp = mlir::dyn_cast_or_null<hlfir::YieldOp>(newOp); 1160 assert(newYielOp && "hlfir.elemental_addr is ill formed"); 1161 hlfir::Entity newAddr{newYielOp.getEntity()}; 1162 newYielOp->erase(); 1163 return hlfir::loadTrivialScalar(l, b, newAddr); 1164 }; 1165 mlir::Type elementType = scalarAddress.getFortranElementType(); 1166 return hlfir::genElementalOp( 1167 loc, builder, elementType, elementalAddrOp.getShape(), typeParams, 1168 genKernel, !elementalAddrOp.isOrdered(), elementalAddrOp.getMold()); 1169 } 1170 1171 bool hlfir::elementalOpMustProduceTemp(hlfir::ElementalOp elemental) { 1172 for (mlir::Operation *useOp : elemental->getUsers()) 1173 if (auto destroy = mlir::dyn_cast<hlfir::DestroyOp>(useOp)) 1174 if (destroy.mustFinalizeExpr()) 1175 return true; 1176 1177 return false; 1178 } 1179 1180 std::pair<hlfir::Entity, mlir::Value> 1181 hlfir::createTempFromMold(mlir::Location loc, fir::FirOpBuilder &builder, 1182 hlfir::Entity mold) { 1183 llvm::SmallVector<mlir::Value> lenParams; 1184 hlfir::genLengthParameters(loc, builder, mold, lenParams); 1185 llvm::StringRef tmpName{".tmp"}; 1186 mlir::Value alloc; 1187 mlir::Value isHeapAlloc; 1188 mlir::Value shape{}; 1189 fir::FortranVariableFlagsAttr declAttrs; 1190 1191 if (mold.isPolymorphic()) { 1192 // Create unallocated polymorphic temporary using the dynamic type 1193 // of the mold. The static type of the temporary matches 1194 // the static type of the mold, but then the dynamic type 1195 // of the mold is applied to the temporary's descriptor. 1196 1197 if (mold.isArray()) 1198 hlfir::genShape(loc, builder, mold); 1199 1200 // Create polymorphic allocatable box on the stack. 1201 mlir::Type boxHeapType = fir::HeapType::get(fir::unwrapRefType( 1202 mlir::cast<fir::BaseBoxType>(mold.getType()).getEleTy())); 1203 // The box must be initialized, because AllocatableApplyMold 1204 // may read its contents (e.g. for checking whether it is allocated). 1205 alloc = fir::factory::genNullBoxStorage(builder, loc, 1206 fir::ClassType::get(boxHeapType)); 1207 // The temporary is unallocated even after AllocatableApplyMold below. 1208 // If the temporary is used as assignment LHS it will be automatically 1209 // allocated on the heap, as long as we use Assign family 1210 // runtime functions. So set MustFree to true. 1211 isHeapAlloc = builder.createBool(loc, true); 1212 declAttrs = fir::FortranVariableFlagsAttr::get( 1213 builder.getContext(), fir::FortranVariableFlagsEnum::allocatable); 1214 } else if (mold.isArray()) { 1215 mlir::Type sequenceType = 1216 hlfir::getFortranElementOrSequenceType(mold.getType()); 1217 shape = hlfir::genShape(loc, builder, mold); 1218 auto extents = hlfir::getIndexExtents(loc, builder, shape); 1219 alloc = builder.createHeapTemporary(loc, sequenceType, tmpName, extents, 1220 lenParams); 1221 isHeapAlloc = builder.createBool(loc, true); 1222 } else { 1223 alloc = builder.createTemporary(loc, mold.getFortranElementType(), tmpName, 1224 /*shape=*/std::nullopt, lenParams); 1225 isHeapAlloc = builder.createBool(loc, false); 1226 } 1227 auto declareOp = 1228 builder.create<hlfir::DeclareOp>(loc, alloc, tmpName, shape, lenParams, 1229 /*dummy_scope=*/nullptr, declAttrs); 1230 if (mold.isPolymorphic()) { 1231 int rank = mold.getRank(); 1232 // TODO: should probably read rank from the mold. 1233 if (rank < 0) 1234 TODO(loc, "create temporary for assumed rank polymorphic"); 1235 fir::runtime::genAllocatableApplyMold(builder, loc, alloc, 1236 mold.getFirBase(), rank); 1237 } 1238 1239 return {hlfir::Entity{declareOp.getBase()}, isHeapAlloc}; 1240 } 1241 1242 hlfir::Entity hlfir::createStackTempFromMold(mlir::Location loc, 1243 fir::FirOpBuilder &builder, 1244 hlfir::Entity mold) { 1245 llvm::SmallVector<mlir::Value> lenParams; 1246 hlfir::genLengthParameters(loc, builder, mold, lenParams); 1247 llvm::StringRef tmpName{".tmp"}; 1248 mlir::Value alloc; 1249 mlir::Value shape{}; 1250 fir::FortranVariableFlagsAttr declAttrs; 1251 1252 if (mold.isPolymorphic()) { 1253 // genAllocatableApplyMold does heap allocation 1254 TODO(loc, "createStackTempFromMold for polymorphic type"); 1255 } else if (mold.isArray()) { 1256 mlir::Type sequenceType = 1257 hlfir::getFortranElementOrSequenceType(mold.getType()); 1258 shape = hlfir::genShape(loc, builder, mold); 1259 auto extents = hlfir::getIndexExtents(loc, builder, shape); 1260 alloc = 1261 builder.createTemporary(loc, sequenceType, tmpName, extents, lenParams); 1262 } else { 1263 alloc = builder.createTemporary(loc, mold.getFortranElementType(), tmpName, 1264 /*shape=*/std::nullopt, lenParams); 1265 } 1266 auto declareOp = 1267 builder.create<hlfir::DeclareOp>(loc, alloc, tmpName, shape, lenParams, 1268 /*dummy_scope=*/nullptr, declAttrs); 1269 return hlfir::Entity{declareOp.getBase()}; 1270 } 1271 1272 hlfir::EntityWithAttributes 1273 hlfir::convertCharacterKind(mlir::Location loc, fir::FirOpBuilder &builder, 1274 hlfir::Entity scalarChar, int toKind) { 1275 auto src = hlfir::convertToAddress(loc, builder, scalarChar, 1276 scalarChar.getFortranElementType()); 1277 assert(src.first.getCharBox() && "must be scalar character"); 1278 fir::CharBoxValue res = fir::factory::convertCharacterKind( 1279 builder, loc, *src.first.getCharBox(), toKind); 1280 if (src.second.has_value()) 1281 src.second.value()(); 1282 1283 return hlfir::EntityWithAttributes{builder.create<hlfir::DeclareOp>( 1284 loc, res.getAddr(), ".temp.kindconvert", /*shape=*/nullptr, 1285 /*typeparams=*/mlir::ValueRange{res.getLen()}, 1286 /*dummy_scope=*/nullptr, fir::FortranVariableFlagsAttr{})}; 1287 } 1288 1289 std::pair<hlfir::Entity, std::optional<hlfir::CleanupFunction>> 1290 hlfir::genTypeAndKindConvert(mlir::Location loc, fir::FirOpBuilder &builder, 1291 hlfir::Entity source, mlir::Type toType, 1292 bool preserveLowerBounds) { 1293 mlir::Type fromType = source.getFortranElementType(); 1294 toType = hlfir::getFortranElementType(toType); 1295 if (!toType || fromType == toType || 1296 !(fir::isa_trivial(toType) || mlir::isa<fir::CharacterType>(toType))) 1297 return {source, std::nullopt}; 1298 1299 std::optional<int> toKindCharConvert; 1300 if (auto toCharTy = mlir::dyn_cast<fir::CharacterType>(toType)) { 1301 if (auto fromCharTy = mlir::dyn_cast<fir::CharacterType>(fromType)) 1302 if (toCharTy.getFKind() != fromCharTy.getFKind()) { 1303 toKindCharConvert = toCharTy.getFKind(); 1304 // Preserve source length (padding/truncation will occur in assignment 1305 // if needed). 1306 toType = fir::CharacterType::get( 1307 fromType.getContext(), toCharTy.getFKind(), fromCharTy.getLen()); 1308 } 1309 // Do not convert in case of character length mismatch only, hlfir.assign 1310 // deals with it. 1311 if (!toKindCharConvert) 1312 return {source, std::nullopt}; 1313 } 1314 1315 if (source.getRank() == 0) { 1316 mlir::Value cast = toKindCharConvert 1317 ? mlir::Value{hlfir::convertCharacterKind( 1318 loc, builder, source, *toKindCharConvert)} 1319 : builder.convertWithSemantics(loc, toType, source); 1320 return {hlfir::Entity{cast}, std::nullopt}; 1321 } 1322 1323 mlir::Value shape = hlfir::genShape(loc, builder, source); 1324 auto genKernel = [source, toType, toKindCharConvert]( 1325 mlir::Location loc, fir::FirOpBuilder &builder, 1326 mlir::ValueRange oneBasedIndices) -> hlfir::Entity { 1327 auto elementPtr = 1328 hlfir::getElementAt(loc, builder, source, oneBasedIndices); 1329 auto val = hlfir::loadTrivialScalar(loc, builder, elementPtr); 1330 if (toKindCharConvert) 1331 return hlfir::convertCharacterKind(loc, builder, val, *toKindCharConvert); 1332 return hlfir::EntityWithAttributes{ 1333 builder.convertWithSemantics(loc, toType, val)}; 1334 }; 1335 llvm::SmallVector<mlir::Value, 1> lenParams; 1336 hlfir::genLengthParameters(loc, builder, source, lenParams); 1337 mlir::Value convertedRhs = 1338 hlfir::genElementalOp(loc, builder, toType, shape, lenParams, genKernel, 1339 /*isUnordered=*/true); 1340 1341 if (preserveLowerBounds && source.mayHaveNonDefaultLowerBounds()) { 1342 hlfir::AssociateOp associate = 1343 genAssociateExpr(loc, builder, hlfir::Entity{convertedRhs}, 1344 convertedRhs.getType(), ".tmp.keeplbounds"); 1345 fir::ShapeOp shapeOp = associate.getShape().getDefiningOp<fir::ShapeOp>(); 1346 assert(shapeOp && "associate shape must be a fir.shape"); 1347 const unsigned rank = shapeOp.getExtents().size(); 1348 llvm::SmallVector<mlir::Value> lbAndExtents; 1349 for (unsigned dim = 0; dim < rank; ++dim) { 1350 lbAndExtents.push_back(hlfir::genLBound(loc, builder, source, dim)); 1351 lbAndExtents.push_back(shapeOp.getExtents()[dim]); 1352 } 1353 auto shapeShiftType = fir::ShapeShiftType::get(builder.getContext(), rank); 1354 mlir::Value shapeShift = 1355 builder.create<fir::ShapeShiftOp>(loc, shapeShiftType, lbAndExtents); 1356 auto declareOp = builder.create<hlfir::DeclareOp>( 1357 loc, associate.getFirBase(), *associate.getUniqName(), shapeShift, 1358 associate.getTypeparams(), /*dummy_scope=*/nullptr, 1359 /*flags=*/fir::FortranVariableFlagsAttr{}); 1360 hlfir::Entity castWithLbounds = 1361 mlir::cast<fir::FortranVariableOpInterface>(declareOp.getOperation()); 1362 fir::FirOpBuilder *bldr = &builder; 1363 auto cleanup = [loc, bldr, convertedRhs, associate]() { 1364 bldr->create<hlfir::EndAssociateOp>(loc, associate); 1365 bldr->create<hlfir::DestroyOp>(loc, convertedRhs); 1366 }; 1367 return {castWithLbounds, cleanup}; 1368 } 1369 1370 fir::FirOpBuilder *bldr = &builder; 1371 auto cleanup = [loc, bldr, convertedRhs]() { 1372 bldr->create<hlfir::DestroyOp>(loc, convertedRhs); 1373 }; 1374 return {hlfir::Entity{convertedRhs}, cleanup}; 1375 } 1376 1377 std::pair<hlfir::Entity, bool> hlfir::computeEvaluateOpInNewTemp( 1378 mlir::Location loc, fir::FirOpBuilder &builder, 1379 hlfir::EvaluateInMemoryOp evalInMem, mlir::Value shape, 1380 mlir::ValueRange typeParams) { 1381 llvm::StringRef tmpName{".tmp.expr_result"}; 1382 llvm::SmallVector<mlir::Value> extents = 1383 hlfir::getIndexExtents(loc, builder, shape); 1384 mlir::Type baseType = 1385 hlfir::getFortranElementOrSequenceType(evalInMem.getType()); 1386 bool heapAllocated = fir::hasDynamicSize(baseType); 1387 // Note: temporaries are stack allocated here when possible (do not require 1388 // stack save/restore) because flang has always stack allocated function 1389 // results. 1390 mlir::Value temp = heapAllocated 1391 ? builder.createHeapTemporary(loc, baseType, tmpName, 1392 extents, typeParams) 1393 : builder.createTemporary(loc, baseType, tmpName, 1394 extents, typeParams); 1395 mlir::Value innerMemory = evalInMem.getMemory(); 1396 temp = builder.createConvert(loc, innerMemory.getType(), temp); 1397 auto declareOp = builder.create<hlfir::DeclareOp>( 1398 loc, temp, tmpName, shape, typeParams, 1399 /*dummy_scope=*/nullptr, fir::FortranVariableFlagsAttr{}); 1400 computeEvaluateOpIn(loc, builder, evalInMem, declareOp.getOriginalBase()); 1401 return {hlfir::Entity{declareOp.getBase()}, /*heapAllocated=*/heapAllocated}; 1402 } 1403 1404 void hlfir::computeEvaluateOpIn(mlir::Location loc, fir::FirOpBuilder &builder, 1405 hlfir::EvaluateInMemoryOp evalInMem, 1406 mlir::Value storage) { 1407 mlir::Value innerMemory = evalInMem.getMemory(); 1408 mlir::Value storageCast = 1409 builder.createConvert(loc, innerMemory.getType(), storage); 1410 mlir::IRMapping mapper; 1411 mapper.map(innerMemory, storageCast); 1412 for (auto &op : evalInMem.getBody().front().without_terminator()) 1413 builder.clone(op, mapper); 1414 return; 1415 } 1416 1417 hlfir::Entity hlfir::loadElementAt(mlir::Location loc, 1418 fir::FirOpBuilder &builder, 1419 hlfir::Entity entity, 1420 mlir::ValueRange oneBasedIndices) { 1421 return loadTrivialScalar(loc, builder, 1422 getElementAt(loc, builder, entity, oneBasedIndices)); 1423 } 1424 1425 llvm::SmallVector<mlir::Value, Fortran::common::maxRank> 1426 hlfir::genExtentsVector(mlir::Location loc, fir::FirOpBuilder &builder, 1427 hlfir::Entity entity) { 1428 entity = hlfir::derefPointersAndAllocatables(loc, builder, entity); 1429 mlir::Value shape = hlfir::genShape(loc, builder, entity); 1430 llvm::SmallVector<mlir::Value, Fortran::common::maxRank> extents = 1431 hlfir::getExplicitExtentsFromShape(shape, builder); 1432 if (shape.getUses().empty()) 1433 shape.getDefiningOp()->erase(); 1434 return extents; 1435 } 1436