1 //===-- FIRBuilder.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 #include "flang/Optimizer/Builder/FIRBuilder.h" 10 #include "flang/Lower/Todo.h" 11 #include "flang/Optimizer/Builder/BoxValue.h" 12 #include "flang/Optimizer/Builder/Character.h" 13 #include "flang/Optimizer/Builder/Complex.h" 14 #include "flang/Optimizer/Builder/MutableBox.h" 15 #include "flang/Optimizer/Builder/Runtime/Assign.h" 16 #include "flang/Optimizer/Dialect/FIRAttr.h" 17 #include "flang/Optimizer/Dialect/FIROpsSupport.h" 18 #include "flang/Optimizer/Support/FatalError.h" 19 #include "flang/Optimizer/Support/InternalNames.h" 20 #include "mlir/Dialect/OpenMP/OpenMPDialect.h" 21 #include "llvm/ADT/ArrayRef.h" 22 #include "llvm/ADT/StringExtras.h" 23 #include "llvm/Support/CommandLine.h" 24 #include "llvm/Support/ErrorHandling.h" 25 #include "llvm/Support/MD5.h" 26 27 static constexpr std::size_t nameLengthHashSize = 32; 28 29 mlir::FuncOp fir::FirOpBuilder::createFunction(mlir::Location loc, 30 mlir::ModuleOp module, 31 llvm::StringRef name, 32 mlir::FunctionType ty) { 33 return fir::createFuncOp(loc, module, name, ty); 34 } 35 36 mlir::FuncOp fir::FirOpBuilder::getNamedFunction(mlir::ModuleOp modOp, 37 llvm::StringRef name) { 38 return modOp.lookupSymbol<mlir::FuncOp>(name); 39 } 40 41 mlir::FuncOp fir::FirOpBuilder::getNamedFunction(mlir::ModuleOp modOp, 42 mlir::SymbolRefAttr symbol) { 43 return modOp.lookupSymbol<mlir::FuncOp>(symbol); 44 } 45 46 fir::GlobalOp fir::FirOpBuilder::getNamedGlobal(mlir::ModuleOp modOp, 47 llvm::StringRef name) { 48 return modOp.lookupSymbol<fir::GlobalOp>(name); 49 } 50 51 mlir::Type fir::FirOpBuilder::getRefType(mlir::Type eleTy) { 52 assert(!eleTy.isa<fir::ReferenceType>() && "cannot be a reference type"); 53 return fir::ReferenceType::get(eleTy); 54 } 55 56 mlir::Type fir::FirOpBuilder::getVarLenSeqTy(mlir::Type eleTy, unsigned rank) { 57 fir::SequenceType::Shape shape(rank, fir::SequenceType::getUnknownExtent()); 58 return fir::SequenceType::get(shape, eleTy); 59 } 60 61 mlir::Type fir::FirOpBuilder::getRealType(int kind) { 62 switch (kindMap.getRealTypeID(kind)) { 63 case llvm::Type::TypeID::HalfTyID: 64 return mlir::FloatType::getF16(getContext()); 65 case llvm::Type::TypeID::FloatTyID: 66 return mlir::FloatType::getF32(getContext()); 67 case llvm::Type::TypeID::DoubleTyID: 68 return mlir::FloatType::getF64(getContext()); 69 case llvm::Type::TypeID::X86_FP80TyID: 70 return mlir::FloatType::getF80(getContext()); 71 case llvm::Type::TypeID::FP128TyID: 72 return mlir::FloatType::getF128(getContext()); 73 default: 74 fir::emitFatalError(UnknownLoc::get(getContext()), 75 "unsupported type !fir.real<kind>"); 76 } 77 } 78 79 mlir::Value fir::FirOpBuilder::createNullConstant(mlir::Location loc, 80 mlir::Type ptrType) { 81 auto ty = ptrType ? ptrType : getRefType(getNoneType()); 82 return create<fir::ZeroOp>(loc, ty); 83 } 84 85 mlir::Value fir::FirOpBuilder::createIntegerConstant(mlir::Location loc, 86 mlir::Type ty, 87 std::int64_t cst) { 88 return create<mlir::arith::ConstantOp>(loc, ty, getIntegerAttr(ty, cst)); 89 } 90 91 mlir::Value 92 fir::FirOpBuilder::createRealConstant(mlir::Location loc, mlir::Type fltTy, 93 llvm::APFloat::integerPart val) { 94 auto apf = [&]() -> llvm::APFloat { 95 if (auto ty = fltTy.dyn_cast<fir::RealType>()) 96 return llvm::APFloat(kindMap.getFloatSemantics(ty.getFKind()), val); 97 if (fltTy.isF16()) 98 return llvm::APFloat(llvm::APFloat::IEEEhalf(), val); 99 if (fltTy.isBF16()) 100 return llvm::APFloat(llvm::APFloat::BFloat(), val); 101 if (fltTy.isF32()) 102 return llvm::APFloat(llvm::APFloat::IEEEsingle(), val); 103 if (fltTy.isF64()) 104 return llvm::APFloat(llvm::APFloat::IEEEdouble(), val); 105 if (fltTy.isF80()) 106 return llvm::APFloat(llvm::APFloat::x87DoubleExtended(), val); 107 if (fltTy.isF128()) 108 return llvm::APFloat(llvm::APFloat::IEEEquad(), val); 109 llvm_unreachable("unhandled MLIR floating-point type"); 110 }; 111 return createRealConstant(loc, fltTy, apf()); 112 } 113 114 mlir::Value fir::FirOpBuilder::createRealConstant(mlir::Location loc, 115 mlir::Type fltTy, 116 const llvm::APFloat &value) { 117 if (fltTy.isa<mlir::FloatType>()) { 118 auto attr = getFloatAttr(fltTy, value); 119 return create<mlir::arith::ConstantOp>(loc, fltTy, attr); 120 } 121 llvm_unreachable("should use builtin floating-point type"); 122 } 123 124 static llvm::SmallVector<mlir::Value> 125 elideExtentsAlreadyInType(mlir::Type type, mlir::ValueRange shape) { 126 auto arrTy = type.dyn_cast<fir::SequenceType>(); 127 if (shape.empty() || !arrTy) 128 return {}; 129 // elide the constant dimensions before construction 130 assert(shape.size() == arrTy.getDimension()); 131 llvm::SmallVector<mlir::Value> dynamicShape; 132 auto typeShape = arrTy.getShape(); 133 for (unsigned i = 0, end = arrTy.getDimension(); i < end; ++i) 134 if (typeShape[i] == fir::SequenceType::getUnknownExtent()) 135 dynamicShape.push_back(shape[i]); 136 return dynamicShape; 137 } 138 139 static llvm::SmallVector<mlir::Value> 140 elideLengthsAlreadyInType(mlir::Type type, mlir::ValueRange lenParams) { 141 if (lenParams.empty()) 142 return {}; 143 if (auto arrTy = type.dyn_cast<fir::SequenceType>()) 144 type = arrTy.getEleTy(); 145 if (fir::hasDynamicSize(type)) 146 return lenParams; 147 return {}; 148 } 149 150 /// Allocate a local variable. 151 /// A local variable ought to have a name in the source code. 152 mlir::Value fir::FirOpBuilder::allocateLocal( 153 mlir::Location loc, mlir::Type ty, llvm::StringRef uniqName, 154 llvm::StringRef name, bool pinned, llvm::ArrayRef<mlir::Value> shape, 155 llvm::ArrayRef<mlir::Value> lenParams, bool asTarget) { 156 // Convert the shape extents to `index`, as needed. 157 llvm::SmallVector<mlir::Value> indices; 158 llvm::SmallVector<mlir::Value> elidedShape = 159 elideExtentsAlreadyInType(ty, shape); 160 llvm::SmallVector<mlir::Value> elidedLenParams = 161 elideLengthsAlreadyInType(ty, lenParams); 162 auto idxTy = getIndexType(); 163 llvm::for_each(elidedShape, [&](mlir::Value sh) { 164 indices.push_back(createConvert(loc, idxTy, sh)); 165 }); 166 // Add a target attribute, if needed. 167 llvm::SmallVector<mlir::NamedAttribute> attrs; 168 if (asTarget) 169 attrs.emplace_back( 170 mlir::StringAttr::get(getContext(), fir::getTargetAttrName()), 171 getUnitAttr()); 172 // Create the local variable. 173 if (name.empty()) { 174 if (uniqName.empty()) 175 return create<fir::AllocaOp>(loc, ty, pinned, elidedLenParams, indices, 176 attrs); 177 return create<fir::AllocaOp>(loc, ty, uniqName, pinned, elidedLenParams, 178 indices, attrs); 179 } 180 return create<fir::AllocaOp>(loc, ty, uniqName, name, pinned, elidedLenParams, 181 indices, attrs); 182 } 183 184 mlir::Value fir::FirOpBuilder::allocateLocal( 185 mlir::Location loc, mlir::Type ty, llvm::StringRef uniqName, 186 llvm::StringRef name, llvm::ArrayRef<mlir::Value> shape, 187 llvm::ArrayRef<mlir::Value> lenParams, bool asTarget) { 188 return allocateLocal(loc, ty, uniqName, name, /*pinned=*/false, shape, 189 lenParams, asTarget); 190 } 191 192 /// Get the block for adding Allocas. 193 mlir::Block *fir::FirOpBuilder::getAllocaBlock() { 194 // auto iface = 195 // getRegion().getParentOfType<mlir::omp::OutlineableOpenMPOpInterface>(); 196 // return iface ? iface.getAllocaBlock() : getEntryBlock(); 197 return getEntryBlock(); 198 } 199 200 /// Create a temporary variable on the stack. Anonymous temporaries have no 201 /// `name` value. Temporaries do not require a uniqued name. 202 mlir::Value 203 fir::FirOpBuilder::createTemporary(mlir::Location loc, mlir::Type type, 204 llvm::StringRef name, mlir::ValueRange shape, 205 mlir::ValueRange lenParams, 206 llvm::ArrayRef<mlir::NamedAttribute> attrs) { 207 llvm::SmallVector<mlir::Value> dynamicShape = 208 elideExtentsAlreadyInType(type, shape); 209 llvm::SmallVector<mlir::Value> dynamicLength = 210 elideLengthsAlreadyInType(type, lenParams); 211 InsertPoint insPt; 212 const bool hoistAlloc = dynamicShape.empty() && dynamicLength.empty(); 213 if (hoistAlloc) { 214 insPt = saveInsertionPoint(); 215 setInsertionPointToStart(getAllocaBlock()); 216 } 217 218 // If the alloca is inside an OpenMP Op which will be outlined then pin the 219 // alloca here. 220 const bool pinned = 221 getRegion().getParentOfType<mlir::omp::OutlineableOpenMPOpInterface>(); 222 assert(!type.isa<fir::ReferenceType>() && "cannot be a reference"); 223 auto ae = 224 create<fir::AllocaOp>(loc, type, /*unique_name=*/llvm::StringRef{}, name, 225 pinned, dynamicLength, dynamicShape, attrs); 226 if (hoistAlloc) 227 restoreInsertionPoint(insPt); 228 return ae; 229 } 230 231 /// Create a global variable in the (read-only) data section. A global variable 232 /// must have a unique name to identify and reference it. 233 fir::GlobalOp 234 fir::FirOpBuilder::createGlobal(mlir::Location loc, mlir::Type type, 235 llvm::StringRef name, mlir::StringAttr linkage, 236 mlir::Attribute value, bool isConst) { 237 auto module = getModule(); 238 auto insertPt = saveInsertionPoint(); 239 if (auto glob = module.lookupSymbol<fir::GlobalOp>(name)) 240 return glob; 241 setInsertionPoint(module.getBody(), module.getBody()->end()); 242 auto glob = create<fir::GlobalOp>(loc, name, isConst, type, value, linkage); 243 restoreInsertionPoint(insertPt); 244 return glob; 245 } 246 247 fir::GlobalOp fir::FirOpBuilder::createGlobal( 248 mlir::Location loc, mlir::Type type, llvm::StringRef name, bool isConst, 249 std::function<void(FirOpBuilder &)> bodyBuilder, mlir::StringAttr linkage) { 250 auto module = getModule(); 251 auto insertPt = saveInsertionPoint(); 252 if (auto glob = module.lookupSymbol<fir::GlobalOp>(name)) 253 return glob; 254 setInsertionPoint(module.getBody(), module.getBody()->end()); 255 auto glob = create<fir::GlobalOp>(loc, name, isConst, type, mlir::Attribute{}, 256 linkage); 257 auto ®ion = glob.getRegion(); 258 region.push_back(new mlir::Block); 259 auto &block = glob.getRegion().back(); 260 setInsertionPointToStart(&block); 261 bodyBuilder(*this); 262 restoreInsertionPoint(insertPt); 263 return glob; 264 } 265 266 mlir::Value 267 fir::FirOpBuilder::convertWithSemantics(mlir::Location loc, mlir::Type toTy, 268 mlir::Value val, 269 bool allowCharacterConversion) { 270 assert(toTy && "store location must be typed"); 271 auto fromTy = val.getType(); 272 if (fromTy == toTy) 273 return val; 274 fir::factory::Complex helper{*this, loc}; 275 if ((fir::isa_real(fromTy) || fir::isa_integer(fromTy)) && 276 fir::isa_complex(toTy)) { 277 // imaginary part is zero 278 auto eleTy = helper.getComplexPartType(toTy); 279 auto cast = createConvert(loc, eleTy, val); 280 llvm::APFloat zero{ 281 kindMap.getFloatSemantics(toTy.cast<fir::ComplexType>().getFKind()), 0}; 282 auto imag = createRealConstant(loc, eleTy, zero); 283 return helper.createComplex(toTy, cast, imag); 284 } 285 if (fir::isa_complex(fromTy) && 286 (fir::isa_integer(toTy) || fir::isa_real(toTy))) { 287 // drop the imaginary part 288 auto rp = helper.extractComplexPart(val, /*isImagPart=*/false); 289 return createConvert(loc, toTy, rp); 290 } 291 if (allowCharacterConversion) { 292 if (fromTy.isa<fir::BoxCharType>()) { 293 // Extract the address of the character string and pass it 294 fir::factory::CharacterExprHelper charHelper{*this, loc}; 295 std::pair<mlir::Value, mlir::Value> unboxchar = 296 charHelper.createUnboxChar(val); 297 return createConvert(loc, toTy, unboxchar.first); 298 } 299 if (auto boxType = toTy.dyn_cast<fir::BoxCharType>()) { 300 // Extract the address of the actual argument and create a boxed 301 // character value with an undefined length 302 // TODO: We should really calculate the total size of the actual 303 // argument in characters and use it as the length of the string 304 auto refType = getRefType(boxType.getEleTy()); 305 mlir::Value charBase = createConvert(loc, refType, val); 306 mlir::Value unknownLen = create<fir::UndefOp>(loc, getIndexType()); 307 fir::factory::CharacterExprHelper charHelper{*this, loc}; 308 return charHelper.createEmboxChar(charBase, unknownLen); 309 } 310 } 311 if (fir::isa_ref_type(toTy) && fir::isa_box_type(fromTy)) { 312 // Call is expecting a raw data pointer, not a box. Get the data pointer out 313 // of the box and pass that. 314 assert((fir::unwrapRefType(toTy) == 315 fir::unwrapRefType(fir::unwrapPassByRefType(fromTy)) && 316 "element types expected to match")); 317 return create<fir::BoxAddrOp>(loc, toTy, val); 318 } 319 320 return createConvert(loc, toTy, val); 321 } 322 323 mlir::Value fir::FirOpBuilder::createConvert(mlir::Location loc, 324 mlir::Type toTy, mlir::Value val) { 325 if (val.getType() != toTy) { 326 assert(!fir::isa_derived(toTy)); 327 return create<fir::ConvertOp>(loc, toTy, val); 328 } 329 return val; 330 } 331 332 fir::StringLitOp fir::FirOpBuilder::createStringLitOp(mlir::Location loc, 333 llvm::StringRef data) { 334 auto type = fir::CharacterType::get(getContext(), 1, data.size()); 335 auto strAttr = mlir::StringAttr::get(getContext(), data); 336 auto valTag = mlir::StringAttr::get(getContext(), fir::StringLitOp::value()); 337 mlir::NamedAttribute dataAttr(valTag, strAttr); 338 auto sizeTag = mlir::StringAttr::get(getContext(), fir::StringLitOp::size()); 339 mlir::NamedAttribute sizeAttr(sizeTag, getI64IntegerAttr(data.size())); 340 llvm::SmallVector<mlir::NamedAttribute> attrs{dataAttr, sizeAttr}; 341 return create<fir::StringLitOp>(loc, llvm::ArrayRef<mlir::Type>{type}, 342 llvm::None, attrs); 343 } 344 345 mlir::Value fir::FirOpBuilder::genShape(mlir::Location loc, 346 llvm::ArrayRef<mlir::Value> exts) { 347 auto shapeType = fir::ShapeType::get(getContext(), exts.size()); 348 return create<fir::ShapeOp>(loc, shapeType, exts); 349 } 350 351 mlir::Value fir::FirOpBuilder::genShape(mlir::Location loc, 352 llvm::ArrayRef<mlir::Value> shift, 353 llvm::ArrayRef<mlir::Value> exts) { 354 auto shapeType = fir::ShapeShiftType::get(getContext(), exts.size()); 355 llvm::SmallVector<mlir::Value> shapeArgs; 356 auto idxTy = getIndexType(); 357 for (auto [lbnd, ext] : llvm::zip(shift, exts)) { 358 auto lb = createConvert(loc, idxTy, lbnd); 359 shapeArgs.push_back(lb); 360 shapeArgs.push_back(ext); 361 } 362 return create<fir::ShapeShiftOp>(loc, shapeType, shapeArgs); 363 } 364 365 mlir::Value fir::FirOpBuilder::genShape(mlir::Location loc, 366 const fir::AbstractArrayBox &arr) { 367 if (arr.lboundsAllOne()) 368 return genShape(loc, arr.getExtents()); 369 return genShape(loc, arr.getLBounds(), arr.getExtents()); 370 } 371 372 mlir::Value fir::FirOpBuilder::createShape(mlir::Location loc, 373 const fir::ExtendedValue &exv) { 374 return exv.match( 375 [&](const fir::ArrayBoxValue &box) { return genShape(loc, box); }, 376 [&](const fir::CharArrayBoxValue &box) { return genShape(loc, box); }, 377 [&](const fir::BoxValue &box) -> mlir::Value { 378 if (!box.getLBounds().empty()) { 379 auto shiftType = 380 fir::ShiftType::get(getContext(), box.getLBounds().size()); 381 return create<fir::ShiftOp>(loc, shiftType, box.getLBounds()); 382 } 383 return {}; 384 }, 385 [&](const fir::MutableBoxValue &) -> mlir::Value { 386 // MutableBoxValue must be read into another category to work with them 387 // outside of allocation/assignment contexts. 388 fir::emitFatalError(loc, "createShape on MutableBoxValue"); 389 }, 390 [&](auto) -> mlir::Value { fir::emitFatalError(loc, "not an array"); }); 391 } 392 393 mlir::Value fir::FirOpBuilder::createSlice(mlir::Location loc, 394 const fir::ExtendedValue &exv, 395 mlir::ValueRange triples, 396 mlir::ValueRange path) { 397 if (triples.empty()) { 398 // If there is no slicing by triple notation, then take the whole array. 399 auto fullShape = [&](const llvm::ArrayRef<mlir::Value> lbounds, 400 llvm::ArrayRef<mlir::Value> extents) -> mlir::Value { 401 llvm::SmallVector<mlir::Value> trips; 402 auto idxTy = getIndexType(); 403 auto one = createIntegerConstant(loc, idxTy, 1); 404 if (lbounds.empty()) { 405 for (auto v : extents) { 406 trips.push_back(one); 407 trips.push_back(v); 408 trips.push_back(one); 409 } 410 return create<fir::SliceOp>(loc, trips, path); 411 } 412 for (auto [lbnd, extent] : llvm::zip(lbounds, extents)) { 413 auto lb = createConvert(loc, idxTy, lbnd); 414 auto ext = createConvert(loc, idxTy, extent); 415 auto shift = create<mlir::arith::SubIOp>(loc, lb, one); 416 auto ub = create<mlir::arith::AddIOp>(loc, ext, shift); 417 trips.push_back(lb); 418 trips.push_back(ub); 419 trips.push_back(one); 420 } 421 return create<fir::SliceOp>(loc, trips, path); 422 }; 423 return exv.match( 424 [&](const fir::ArrayBoxValue &box) { 425 return fullShape(box.getLBounds(), box.getExtents()); 426 }, 427 [&](const fir::CharArrayBoxValue &box) { 428 return fullShape(box.getLBounds(), box.getExtents()); 429 }, 430 [&](const fir::BoxValue &box) { 431 auto extents = fir::factory::readExtents(*this, loc, box); 432 return fullShape(box.getLBounds(), extents); 433 }, 434 [&](const fir::MutableBoxValue &) -> mlir::Value { 435 // MutableBoxValue must be read into another category to work with 436 // them outside of allocation/assignment contexts. 437 fir::emitFatalError(loc, "createSlice on MutableBoxValue"); 438 }, 439 [&](auto) -> mlir::Value { fir::emitFatalError(loc, "not an array"); }); 440 } 441 return create<fir::SliceOp>(loc, triples, path); 442 } 443 444 mlir::Value fir::FirOpBuilder::createBox(mlir::Location loc, 445 const fir::ExtendedValue &exv) { 446 mlir::Value itemAddr = fir::getBase(exv); 447 if (itemAddr.getType().isa<fir::BoxType>()) 448 return itemAddr; 449 auto elementType = fir::dyn_cast_ptrEleTy(itemAddr.getType()); 450 if (!elementType) { 451 mlir::emitError(loc, "internal: expected a memory reference type ") 452 << itemAddr.getType(); 453 llvm_unreachable("not a memory reference type"); 454 } 455 mlir::Type boxTy = fir::BoxType::get(elementType); 456 return exv.match( 457 [&](const fir::ArrayBoxValue &box) -> mlir::Value { 458 mlir::Value s = createShape(loc, exv); 459 return create<fir::EmboxOp>(loc, boxTy, itemAddr, s); 460 }, 461 [&](const fir::CharArrayBoxValue &box) -> mlir::Value { 462 mlir::Value s = createShape(loc, exv); 463 if (fir::factory::CharacterExprHelper::hasConstantLengthInType(exv)) 464 return create<fir::EmboxOp>(loc, boxTy, itemAddr, s); 465 466 mlir::Value emptySlice; 467 llvm::SmallVector<mlir::Value> lenParams{box.getLen()}; 468 return create<fir::EmboxOp>(loc, boxTy, itemAddr, s, emptySlice, 469 lenParams); 470 }, 471 [&](const fir::CharBoxValue &box) -> mlir::Value { 472 if (fir::factory::CharacterExprHelper::hasConstantLengthInType(exv)) 473 return create<fir::EmboxOp>(loc, boxTy, itemAddr); 474 mlir::Value emptyShape, emptySlice; 475 llvm::SmallVector<mlir::Value> lenParams{box.getLen()}; 476 return create<fir::EmboxOp>(loc, boxTy, itemAddr, emptyShape, 477 emptySlice, lenParams); 478 }, 479 [&](const fir::MutableBoxValue &x) -> mlir::Value { 480 return create<fir::LoadOp>( 481 loc, fir::factory::getMutableIRBox(*this, loc, x)); 482 }, 483 // UnboxedValue, ProcBoxValue or BoxValue. 484 [&](const auto &) -> mlir::Value { 485 return create<fir::EmboxOp>(loc, boxTy, itemAddr); 486 }); 487 } 488 489 static mlir::Value 490 genNullPointerComparison(fir::FirOpBuilder &builder, mlir::Location loc, 491 mlir::Value addr, 492 mlir::arith::CmpIPredicate condition) { 493 auto intPtrTy = builder.getIntPtrType(); 494 auto ptrToInt = builder.createConvert(loc, intPtrTy, addr); 495 auto c0 = builder.createIntegerConstant(loc, intPtrTy, 0); 496 return builder.create<mlir::arith::CmpIOp>(loc, condition, ptrToInt, c0); 497 } 498 499 mlir::Value fir::FirOpBuilder::genIsNotNull(mlir::Location loc, 500 mlir::Value addr) { 501 return genNullPointerComparison(*this, loc, addr, 502 mlir::arith::CmpIPredicate::ne); 503 } 504 505 mlir::Value fir::FirOpBuilder::genIsNull(mlir::Location loc, mlir::Value addr) { 506 return genNullPointerComparison(*this, loc, addr, 507 mlir::arith::CmpIPredicate::eq); 508 } 509 510 //===--------------------------------------------------------------------===// 511 // ExtendedValue inquiry helper implementation 512 //===--------------------------------------------------------------------===// 513 514 mlir::Value fir::factory::readCharLen(fir::FirOpBuilder &builder, 515 mlir::Location loc, 516 const fir::ExtendedValue &box) { 517 return box.match( 518 [&](const fir::CharBoxValue &x) -> mlir::Value { return x.getLen(); }, 519 [&](const fir::CharArrayBoxValue &x) -> mlir::Value { 520 return x.getLen(); 521 }, 522 [&](const fir::BoxValue &x) -> mlir::Value { 523 assert(x.isCharacter()); 524 if (!x.getExplicitParameters().empty()) 525 return x.getExplicitParameters()[0]; 526 return fir::factory::CharacterExprHelper{builder, loc} 527 .readLengthFromBox(x.getAddr()); 528 }, 529 [&](const fir::MutableBoxValue &) -> mlir::Value { 530 // MutableBoxValue must be read into another category to work with them 531 // outside of allocation/assignment contexts. 532 fir::emitFatalError(loc, "readCharLen on MutableBoxValue"); 533 }, 534 [&](const auto &) -> mlir::Value { 535 fir::emitFatalError( 536 loc, "Character length inquiry on a non-character entity"); 537 }); 538 } 539 540 mlir::Value fir::factory::readExtent(fir::FirOpBuilder &builder, 541 mlir::Location loc, 542 const fir::ExtendedValue &box, 543 unsigned dim) { 544 assert(box.rank() > dim); 545 return box.match( 546 [&](const fir::ArrayBoxValue &x) -> mlir::Value { 547 return x.getExtents()[dim]; 548 }, 549 [&](const fir::CharArrayBoxValue &x) -> mlir::Value { 550 return x.getExtents()[dim]; 551 }, 552 [&](const fir::BoxValue &x) -> mlir::Value { 553 if (!x.getExplicitExtents().empty()) 554 return x.getExplicitExtents()[dim]; 555 auto idxTy = builder.getIndexType(); 556 auto dimVal = builder.createIntegerConstant(loc, idxTy, dim); 557 return builder 558 .create<fir::BoxDimsOp>(loc, idxTy, idxTy, idxTy, x.getAddr(), 559 dimVal) 560 .getResult(1); 561 }, 562 [&](const fir::MutableBoxValue &x) -> mlir::Value { 563 // MutableBoxValue must be read into another category to work with them 564 // outside of allocation/assignment contexts. 565 fir::emitFatalError(loc, "readExtents on MutableBoxValue"); 566 }, 567 [&](const auto &) -> mlir::Value { 568 fir::emitFatalError(loc, "extent inquiry on scalar"); 569 }); 570 } 571 572 mlir::Value fir::factory::readLowerBound(fir::FirOpBuilder &builder, 573 mlir::Location loc, 574 const fir::ExtendedValue &box, 575 unsigned dim, 576 mlir::Value defaultValue) { 577 assert(box.rank() > dim); 578 auto lb = box.match( 579 [&](const fir::ArrayBoxValue &x) -> mlir::Value { 580 return x.getLBounds().empty() ? mlir::Value{} : x.getLBounds()[dim]; 581 }, 582 [&](const fir::CharArrayBoxValue &x) -> mlir::Value { 583 return x.getLBounds().empty() ? mlir::Value{} : x.getLBounds()[dim]; 584 }, 585 [&](const fir::BoxValue &x) -> mlir::Value { 586 return x.getLBounds().empty() ? mlir::Value{} : x.getLBounds()[dim]; 587 }, 588 [&](const fir::MutableBoxValue &x) -> mlir::Value { 589 return readLowerBound(builder, loc, 590 fir::factory::genMutableBoxRead(builder, loc, x), 591 dim, defaultValue); 592 }, 593 [&](const auto &) -> mlir::Value { 594 fir::emitFatalError(loc, "lower bound inquiry on scalar"); 595 }); 596 if (lb) 597 return lb; 598 return defaultValue; 599 } 600 601 llvm::SmallVector<mlir::Value> 602 fir::factory::readExtents(fir::FirOpBuilder &builder, mlir::Location loc, 603 const fir::BoxValue &box) { 604 llvm::SmallVector<mlir::Value> result; 605 auto explicitExtents = box.getExplicitExtents(); 606 if (!explicitExtents.empty()) { 607 result.append(explicitExtents.begin(), explicitExtents.end()); 608 return result; 609 } 610 auto rank = box.rank(); 611 auto idxTy = builder.getIndexType(); 612 for (decltype(rank) dim = 0; dim < rank; ++dim) { 613 auto dimVal = builder.createIntegerConstant(loc, idxTy, dim); 614 auto dimInfo = builder.create<fir::BoxDimsOp>(loc, idxTy, idxTy, idxTy, 615 box.getAddr(), dimVal); 616 result.emplace_back(dimInfo.getResult(1)); 617 } 618 return result; 619 } 620 621 llvm::SmallVector<mlir::Value> 622 fir::factory::getExtents(fir::FirOpBuilder &builder, mlir::Location loc, 623 const fir::ExtendedValue &box) { 624 return box.match( 625 [&](const fir::ArrayBoxValue &x) -> llvm::SmallVector<mlir::Value> { 626 return {x.getExtents().begin(), x.getExtents().end()}; 627 }, 628 [&](const fir::CharArrayBoxValue &x) -> llvm::SmallVector<mlir::Value> { 629 return {x.getExtents().begin(), x.getExtents().end()}; 630 }, 631 [&](const fir::BoxValue &x) -> llvm::SmallVector<mlir::Value> { 632 return fir::factory::readExtents(builder, loc, x); 633 }, 634 [&](const fir::MutableBoxValue &x) -> llvm::SmallVector<mlir::Value> { 635 auto load = fir::factory::genMutableBoxRead(builder, loc, x); 636 return fir::factory::getExtents(builder, loc, load); 637 }, 638 [&](const auto &) -> llvm::SmallVector<mlir::Value> { return {}; }); 639 } 640 641 fir::ExtendedValue fir::factory::readBoxValue(fir::FirOpBuilder &builder, 642 mlir::Location loc, 643 const fir::BoxValue &box) { 644 assert(!box.isUnlimitedPolymorphic() && !box.hasAssumedRank() && 645 "cannot read unlimited polymorphic or assumed rank fir.box"); 646 auto addr = 647 builder.create<fir::BoxAddrOp>(loc, box.getMemTy(), box.getAddr()); 648 if (box.isCharacter()) { 649 auto len = fir::factory::readCharLen(builder, loc, box); 650 if (box.rank() == 0) 651 return fir::CharBoxValue(addr, len); 652 return fir::CharArrayBoxValue(addr, len, 653 fir::factory::readExtents(builder, loc, box), 654 box.getLBounds()); 655 } 656 if (box.isDerivedWithLengthParameters()) 657 TODO(loc, "read fir.box with length parameters"); 658 if (box.rank() == 0) 659 return addr; 660 return fir::ArrayBoxValue(addr, fir::factory::readExtents(builder, loc, box), 661 box.getLBounds()); 662 } 663 664 llvm::SmallVector<mlir::Value> 665 fir::factory::getNonDefaultLowerBounds(fir::FirOpBuilder &builder, 666 mlir::Location loc, 667 const fir::ExtendedValue &exv) { 668 return exv.match( 669 [&](const fir::ArrayBoxValue &array) -> llvm::SmallVector<mlir::Value> { 670 return {array.getLBounds().begin(), array.getLBounds().end()}; 671 }, 672 [&](const fir::CharArrayBoxValue &array) 673 -> llvm::SmallVector<mlir::Value> { 674 return {array.getLBounds().begin(), array.getLBounds().end()}; 675 }, 676 [&](const fir::BoxValue &box) -> llvm::SmallVector<mlir::Value> { 677 return {box.getLBounds().begin(), box.getLBounds().end()}; 678 }, 679 [&](const fir::MutableBoxValue &box) -> llvm::SmallVector<mlir::Value> { 680 auto load = fir::factory::genMutableBoxRead(builder, loc, box); 681 return fir::factory::getNonDefaultLowerBounds(builder, loc, load); 682 }, 683 [&](const auto &) -> llvm::SmallVector<mlir::Value> { return {}; }); 684 } 685 686 llvm::SmallVector<mlir::Value> 687 fir::factory::getNonDeferredLengthParams(const fir::ExtendedValue &exv) { 688 return exv.match( 689 [&](const fir::CharArrayBoxValue &character) 690 -> llvm::SmallVector<mlir::Value> { return {character.getLen()}; }, 691 [&](const fir::CharBoxValue &character) 692 -> llvm::SmallVector<mlir::Value> { return {character.getLen()}; }, 693 [&](const fir::MutableBoxValue &box) -> llvm::SmallVector<mlir::Value> { 694 return {box.nonDeferredLenParams().begin(), 695 box.nonDeferredLenParams().end()}; 696 }, 697 [&](const fir::BoxValue &box) -> llvm::SmallVector<mlir::Value> { 698 return {box.getExplicitParameters().begin(), 699 box.getExplicitParameters().end()}; 700 }, 701 [&](const auto &) -> llvm::SmallVector<mlir::Value> { return {}; }); 702 } 703 704 std::string fir::factory::uniqueCGIdent(llvm::StringRef prefix, 705 llvm::StringRef name) { 706 // For "long" identifiers use a hash value 707 if (name.size() > nameLengthHashSize) { 708 llvm::MD5 hash; 709 hash.update(name); 710 llvm::MD5::MD5Result result; 711 hash.final(result); 712 llvm::SmallString<32> str; 713 llvm::MD5::stringifyResult(result, str); 714 std::string hashName = prefix.str(); 715 hashName.append(".").append(str.c_str()); 716 return fir::NameUniquer::doGenerated(hashName); 717 } 718 // "Short" identifiers use a reversible hex string 719 std::string nm = prefix.str(); 720 return fir::NameUniquer::doGenerated( 721 nm.append(".").append(llvm::toHex(name))); 722 } 723 724 mlir::Value fir::factory::locationToFilename(fir::FirOpBuilder &builder, 725 mlir::Location loc) { 726 if (auto flc = loc.dyn_cast<mlir::FileLineColLoc>()) { 727 // must be encoded as asciiz, C string 728 auto fn = flc.getFilename().str() + '\0'; 729 return fir::getBase(createStringLiteral(builder, loc, fn)); 730 } 731 return builder.createNullConstant(loc); 732 } 733 734 mlir::Value fir::factory::locationToLineNo(fir::FirOpBuilder &builder, 735 mlir::Location loc, 736 mlir::Type type) { 737 if (auto flc = loc.dyn_cast<mlir::FileLineColLoc>()) 738 return builder.createIntegerConstant(loc, type, flc.getLine()); 739 return builder.createIntegerConstant(loc, type, 0); 740 } 741 742 fir::ExtendedValue fir::factory::createStringLiteral(fir::FirOpBuilder &builder, 743 mlir::Location loc, 744 llvm::StringRef str) { 745 std::string globalName = fir::factory::uniqueCGIdent("cl", str); 746 auto type = fir::CharacterType::get(builder.getContext(), 1, str.size()); 747 auto global = builder.getNamedGlobal(globalName); 748 if (!global) 749 global = builder.createGlobalConstant( 750 loc, type, globalName, 751 [&](fir::FirOpBuilder &builder) { 752 auto stringLitOp = builder.createStringLitOp(loc, str); 753 builder.create<fir::HasValueOp>(loc, stringLitOp); 754 }, 755 builder.createLinkOnceLinkage()); 756 auto addr = builder.create<fir::AddrOfOp>(loc, global.resultType(), 757 global.getSymbol()); 758 auto len = builder.createIntegerConstant( 759 loc, builder.getCharacterLengthType(), str.size()); 760 return fir::CharBoxValue{addr, len}; 761 } 762 763 llvm::SmallVector<mlir::Value> 764 fir::factory::createExtents(fir::FirOpBuilder &builder, mlir::Location loc, 765 fir::SequenceType seqTy) { 766 llvm::SmallVector<mlir::Value> extents; 767 auto idxTy = builder.getIndexType(); 768 for (auto ext : seqTy.getShape()) 769 extents.emplace_back( 770 ext == fir::SequenceType::getUnknownExtent() 771 ? builder.create<fir::UndefOp>(loc, idxTy).getResult() 772 : builder.createIntegerConstant(loc, idxTy, ext)); 773 return extents; 774 } 775 776 // FIXME: This needs some work. To correctly determine the extended value of a 777 // component, one needs the base object, its type, and its type parameters. (An 778 // alternative would be to provide an already computed address of the final 779 // component rather than the base object's address, the point being the result 780 // will require the address of the final component to create the extended 781 // value.) One further needs the full path of components being applied. One 782 // needs to apply type-based expressions to type parameters along this said 783 // path. (See applyPathToType for a type-only derivation.) Finally, one needs to 784 // compose the extended value of the terminal component, including all of its 785 // parameters: array lower bounds expressions, extents, type parameters, etc. 786 // Any of these properties may be deferred until runtime in Fortran. This 787 // operation may therefore generate a sizeable block of IR, including calls to 788 // type-based helper functions, so caching the result of this operation in the 789 // client would be advised as well. 790 fir::ExtendedValue fir::factory::componentToExtendedValue( 791 fir::FirOpBuilder &builder, mlir::Location loc, mlir::Value component) { 792 auto fieldTy = component.getType(); 793 if (auto ty = fir::dyn_cast_ptrEleTy(fieldTy)) 794 fieldTy = ty; 795 if (fieldTy.isa<fir::BoxType>()) { 796 llvm::SmallVector<mlir::Value> nonDeferredTypeParams; 797 auto eleTy = fir::unwrapSequenceType(fir::dyn_cast_ptrOrBoxEleTy(fieldTy)); 798 if (auto charTy = eleTy.dyn_cast<fir::CharacterType>()) { 799 auto lenTy = builder.getCharacterLengthType(); 800 if (charTy.hasConstantLen()) 801 nonDeferredTypeParams.emplace_back( 802 builder.createIntegerConstant(loc, lenTy, charTy.getLen())); 803 // TODO: Starting, F2003, the dynamic character length might be dependent 804 // on a PDT length parameter. There is no way to make a difference with 805 // deferred length here yet. 806 } 807 if (auto recTy = eleTy.dyn_cast<fir::RecordType>()) 808 if (recTy.getNumLenParams() > 0) 809 TODO(loc, "allocatable and pointer components non deferred length " 810 "parameters"); 811 812 return fir::MutableBoxValue(component, nonDeferredTypeParams, 813 /*mutableProperties=*/{}); 814 } 815 llvm::SmallVector<mlir::Value> extents; 816 if (auto seqTy = fieldTy.dyn_cast<fir::SequenceType>()) { 817 fieldTy = seqTy.getEleTy(); 818 auto idxTy = builder.getIndexType(); 819 for (auto extent : seqTy.getShape()) { 820 if (extent == fir::SequenceType::getUnknownExtent()) 821 TODO(loc, "array component shape depending on length parameters"); 822 extents.emplace_back(builder.createIntegerConstant(loc, idxTy, extent)); 823 } 824 } 825 if (auto charTy = fieldTy.dyn_cast<fir::CharacterType>()) { 826 auto cstLen = charTy.getLen(); 827 if (cstLen == fir::CharacterType::unknownLen()) 828 TODO(loc, "get character component length from length type parameters"); 829 auto len = builder.createIntegerConstant( 830 loc, builder.getCharacterLengthType(), cstLen); 831 if (!extents.empty()) 832 return fir::CharArrayBoxValue{component, len, extents}; 833 return fir::CharBoxValue{component, len}; 834 } 835 if (auto recordTy = fieldTy.dyn_cast<fir::RecordType>()) 836 if (recordTy.getNumLenParams() != 0) 837 TODO(loc, 838 "lower component ref that is a derived type with length parameter"); 839 if (!extents.empty()) 840 return fir::ArrayBoxValue{component, extents}; 841 return component; 842 } 843 844 fir::ExtendedValue fir::factory::arrayElementToExtendedValue( 845 fir::FirOpBuilder &builder, mlir::Location loc, 846 const fir::ExtendedValue &array, mlir::Value element) { 847 return array.match( 848 [&](const fir::CharBoxValue &cb) -> fir::ExtendedValue { 849 return cb.clone(element); 850 }, 851 [&](const fir::CharArrayBoxValue &bv) -> fir::ExtendedValue { 852 return bv.cloneElement(element); 853 }, 854 [&](const fir::BoxValue &box) -> fir::ExtendedValue { 855 if (box.isCharacter()) { 856 auto len = fir::factory::readCharLen(builder, loc, box); 857 return fir::CharBoxValue{element, len}; 858 } 859 if (box.isDerivedWithLengthParameters()) 860 TODO(loc, "get length parameters from derived type BoxValue"); 861 return element; 862 }, 863 [&](const auto &) -> fir::ExtendedValue { return element; }); 864 } 865 866 fir::ExtendedValue fir::factory::arraySectionElementToExtendedValue( 867 fir::FirOpBuilder &builder, mlir::Location loc, 868 const fir::ExtendedValue &array, mlir::Value element, mlir::Value slice) { 869 if (!slice) 870 return arrayElementToExtendedValue(builder, loc, array, element); 871 auto sliceOp = mlir::dyn_cast_or_null<fir::SliceOp>(slice.getDefiningOp()); 872 assert(sliceOp && "slice must be a sliceOp"); 873 if (sliceOp.getFields().empty()) 874 return arrayElementToExtendedValue(builder, loc, array, element); 875 // For F95, using componentToExtendedValue will work, but when PDTs are 876 // lowered. It will be required to go down the slice to propagate the length 877 // parameters. 878 return fir::factory::componentToExtendedValue(builder, loc, element); 879 } 880 881 mlir::TupleType 882 fir::factory::getRaggedArrayHeaderType(fir::FirOpBuilder &builder) { 883 mlir::IntegerType i64Ty = builder.getIntegerType(64); 884 auto arrTy = fir::SequenceType::get(builder.getIntegerType(8), 1); 885 auto buffTy = fir::HeapType::get(arrTy); 886 auto extTy = fir::SequenceType::get(i64Ty, 1); 887 auto shTy = fir::HeapType::get(extTy); 888 return mlir::TupleType::get(builder.getContext(), {i64Ty, buffTy, shTy}); 889 } 890 891 mlir::Value fir::factory::createZeroValue(fir::FirOpBuilder &builder, 892 mlir::Location loc, mlir::Type type) { 893 mlir::Type i1 = builder.getIntegerType(1); 894 if (type.isa<fir::LogicalType>() || type == i1) 895 return builder.createConvert(loc, type, builder.createBool(loc, false)); 896 if (fir::isa_integer(type)) 897 return builder.createIntegerConstant(loc, type, 0); 898 if (fir::isa_real(type)) 899 return builder.createRealZeroConstant(loc, type); 900 if (fir::isa_complex(type)) { 901 fir::factory::Complex complexHelper(builder, loc); 902 mlir::Type partType = complexHelper.getComplexPartType(type); 903 mlir::Value zeroPart = builder.createRealZeroConstant(loc, partType); 904 return complexHelper.createComplex(type, zeroPart, zeroPart); 905 } 906 fir::emitFatalError(loc, "internal: trying to generate zero value of non " 907 "numeric or logical type"); 908 } 909 910 void fir::factory::genScalarAssignment(fir::FirOpBuilder &builder, 911 mlir::Location loc, 912 const fir::ExtendedValue &lhs, 913 const fir::ExtendedValue &rhs) { 914 assert(lhs.rank() == 0 && rhs.rank() == 0 && "must be scalars"); 915 auto type = fir::unwrapSequenceType( 916 fir::unwrapPassByRefType(fir::getBase(lhs).getType())); 917 if (type.isa<fir::CharacterType>()) { 918 const fir::CharBoxValue *toChar = lhs.getCharBox(); 919 const fir::CharBoxValue *fromChar = rhs.getCharBox(); 920 assert(toChar && fromChar); 921 fir::factory::CharacterExprHelper helper{builder, loc}; 922 helper.createAssign(fir::ExtendedValue{*toChar}, 923 fir::ExtendedValue{*fromChar}); 924 } else if (type.isa<fir::RecordType>()) { 925 fir::factory::genRecordAssignment(builder, loc, lhs, rhs); 926 } else { 927 assert(!fir::hasDynamicSize(type)); 928 auto rhsVal = fir::getBase(rhs); 929 if (fir::isa_ref_type(rhsVal.getType())) 930 rhsVal = builder.create<fir::LoadOp>(loc, rhsVal); 931 mlir::Value lhsAddr = fir::getBase(lhs); 932 rhsVal = builder.createConvert(loc, fir::unwrapRefType(lhsAddr.getType()), 933 rhsVal); 934 builder.create<fir::StoreOp>(loc, rhsVal, lhsAddr); 935 } 936 } 937 938 static void genComponentByComponentAssignment(fir::FirOpBuilder &builder, 939 mlir::Location loc, 940 const fir::ExtendedValue &lhs, 941 const fir::ExtendedValue &rhs) { 942 auto baseType = fir::unwrapPassByRefType(fir::getBase(lhs).getType()); 943 auto lhsType = baseType.dyn_cast<fir::RecordType>(); 944 assert(lhsType && "lhs must be a scalar record type"); 945 auto fieldIndexType = fir::FieldType::get(lhsType.getContext()); 946 for (auto [fieldName, fieldType] : lhsType.getTypeList()) { 947 assert(!fir::hasDynamicSize(fieldType)); 948 mlir::Value field = builder.create<fir::FieldIndexOp>( 949 loc, fieldIndexType, fieldName, lhsType, fir::getTypeParams(lhs)); 950 auto fieldRefType = builder.getRefType(fieldType); 951 mlir::Value fromCoor = builder.create<fir::CoordinateOp>( 952 loc, fieldRefType, fir::getBase(rhs), field); 953 mlir::Value toCoor = builder.create<fir::CoordinateOp>( 954 loc, fieldRefType, fir::getBase(lhs), field); 955 llvm::Optional<fir::DoLoopOp> outerLoop; 956 if (auto sequenceType = fieldType.dyn_cast<fir::SequenceType>()) { 957 // Create loops to assign array components elements by elements. 958 // Note that, since these are components, they either do not overlap, 959 // or are the same and exactly overlap. They also have compile time 960 // constant shapes. 961 mlir::Type idxTy = builder.getIndexType(); 962 llvm::SmallVector<mlir::Value> indices; 963 mlir::Value zero = builder.createIntegerConstant(loc, idxTy, 0); 964 mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1); 965 for (auto extent : llvm::reverse(sequenceType.getShape())) { 966 // TODO: add zero size test ! 967 mlir::Value ub = builder.createIntegerConstant(loc, idxTy, extent - 1); 968 auto loop = builder.create<fir::DoLoopOp>(loc, zero, ub, one); 969 if (!outerLoop) 970 outerLoop = loop; 971 indices.push_back(loop.getInductionVar()); 972 builder.setInsertionPointToStart(loop.getBody()); 973 } 974 // Set indices in column-major order. 975 std::reverse(indices.begin(), indices.end()); 976 auto elementRefType = builder.getRefType(sequenceType.getEleTy()); 977 toCoor = builder.create<fir::CoordinateOp>(loc, elementRefType, toCoor, 978 indices); 979 fromCoor = builder.create<fir::CoordinateOp>(loc, elementRefType, 980 fromCoor, indices); 981 } 982 auto fieldElementType = fir::unwrapSequenceType(fieldType); 983 if (fieldElementType.isa<fir::BoxType>()) { 984 assert(fieldElementType.cast<fir::BoxType>() 985 .getEleTy() 986 .isa<fir::PointerType>() && 987 "allocatable require deep copy"); 988 auto fromPointerValue = builder.create<fir::LoadOp>(loc, fromCoor); 989 builder.create<fir::StoreOp>(loc, fromPointerValue, toCoor); 990 } else { 991 auto from = 992 fir::factory::componentToExtendedValue(builder, loc, fromCoor); 993 auto to = fir::factory::componentToExtendedValue(builder, loc, toCoor); 994 fir::factory::genScalarAssignment(builder, loc, to, from); 995 } 996 if (outerLoop) 997 builder.setInsertionPointAfter(*outerLoop); 998 } 999 } 1000 1001 /// Can the assignment of this record type be implement with a simple memory 1002 /// copy (it requires no deep copy or user defined assignment of components )? 1003 static bool recordTypeCanBeMemCopied(fir::RecordType recordType) { 1004 if (fir::hasDynamicSize(recordType)) 1005 return false; 1006 for (auto [_, fieldType] : recordType.getTypeList()) { 1007 // Derived type component may have user assignment (so far, we cannot tell 1008 // in FIR, so assume it is always the case, TODO: get the actual info). 1009 if (fir::unwrapSequenceType(fieldType).isa<fir::RecordType>()) 1010 return false; 1011 // Allocatable components need deep copy. 1012 if (auto boxType = fieldType.dyn_cast<fir::BoxType>()) 1013 if (boxType.getEleTy().isa<fir::HeapType>()) 1014 return false; 1015 } 1016 // Constant size components without user defined assignment and pointers can 1017 // be memcopied. 1018 return true; 1019 } 1020 1021 void fir::factory::genRecordAssignment(fir::FirOpBuilder &builder, 1022 mlir::Location loc, 1023 const fir::ExtendedValue &lhs, 1024 const fir::ExtendedValue &rhs) { 1025 assert(lhs.rank() == 0 && rhs.rank() == 0 && "assume scalar assignment"); 1026 auto baseTy = fir::dyn_cast_ptrOrBoxEleTy(fir::getBase(lhs).getType()); 1027 assert(baseTy && "must be a memory type"); 1028 // Box operands may be polymorphic, it is not entirely clear from 10.2.1.3 1029 // if the assignment is performed on the dynamic of declared type. Use the 1030 // runtime assuming it is performed on the dynamic type. 1031 bool hasBoxOperands = fir::getBase(lhs).getType().isa<fir::BoxType>() || 1032 fir::getBase(rhs).getType().isa<fir::BoxType>(); 1033 auto recTy = baseTy.dyn_cast<fir::RecordType>(); 1034 assert(recTy && "must be a record type"); 1035 if (hasBoxOperands || !recordTypeCanBeMemCopied(recTy)) { 1036 auto to = fir::getBase(builder.createBox(loc, lhs)); 1037 auto from = fir::getBase(builder.createBox(loc, rhs)); 1038 // The runtime entry point may modify the LHS descriptor if it is 1039 // an allocatable. Allocatable assignment is handle elsewhere in lowering, 1040 // so just create a fir.ref<fir.box<>> from the fir.box to comply with the 1041 // runtime interface, but assume the fir.box is unchanged. 1042 // TODO: does this holds true with polymorphic entities ? 1043 auto toMutableBox = builder.createTemporary(loc, to.getType()); 1044 builder.create<fir::StoreOp>(loc, to, toMutableBox); 1045 fir::runtime::genAssign(builder, loc, toMutableBox, from); 1046 return; 1047 } 1048 // Otherwise, the derived type has compile time constant size and for which 1049 // the component by component assignment can be replaced by a memory copy. 1050 // Since we do not know the size of the derived type in lowering, do a 1051 // component by component assignment. Note that a single fir.load/fir.store 1052 // could be used on "small" record types, but as the type size grows, this 1053 // leads to issues in LLVM (long compile times, long IR files, and even 1054 // asserts at some point). Since there is no good size boundary, just always 1055 // use component by component assignment here. 1056 genComponentByComponentAssignment(builder, loc, lhs, rhs); 1057 } 1058 1059 mlir::Value fir::factory::genLenOfCharacter( 1060 fir::FirOpBuilder &builder, mlir::Location loc, fir::ArrayLoadOp arrLoad, 1061 llvm::ArrayRef<mlir::Value> path, llvm::ArrayRef<mlir::Value> substring) { 1062 llvm::SmallVector<mlir::Value> typeParams(arrLoad.getTypeparams()); 1063 return genLenOfCharacter(builder, loc, 1064 arrLoad.getType().cast<fir::SequenceType>(), 1065 arrLoad.getMemref(), typeParams, path, substring); 1066 } 1067 1068 mlir::Value fir::factory::genLenOfCharacter( 1069 fir::FirOpBuilder &builder, mlir::Location loc, fir::SequenceType seqTy, 1070 mlir::Value memref, llvm::ArrayRef<mlir::Value> typeParams, 1071 llvm::ArrayRef<mlir::Value> path, llvm::ArrayRef<mlir::Value> substring) { 1072 auto idxTy = builder.getIndexType(); 1073 auto zero = builder.createIntegerConstant(loc, idxTy, 0); 1074 auto saturatedDiff = [&](mlir::Value lower, mlir::Value upper) { 1075 auto diff = builder.create<mlir::arith::SubIOp>(loc, upper, lower); 1076 auto one = builder.createIntegerConstant(loc, idxTy, 1); 1077 auto size = builder.create<mlir::arith::AddIOp>(loc, diff, one); 1078 auto cmp = builder.create<mlir::arith::CmpIOp>( 1079 loc, mlir::arith::CmpIPredicate::sgt, size, zero); 1080 return builder.create<mlir::arith::SelectOp>(loc, cmp, size, zero); 1081 }; 1082 if (substring.size() == 2) { 1083 auto upper = builder.createConvert(loc, idxTy, substring.back()); 1084 auto lower = builder.createConvert(loc, idxTy, substring.front()); 1085 return saturatedDiff(lower, upper); 1086 } 1087 auto lower = zero; 1088 if (substring.size() == 1) 1089 lower = builder.createConvert(loc, idxTy, substring.front()); 1090 auto eleTy = fir::applyPathToType(seqTy, path); 1091 if (!fir::hasDynamicSize(eleTy)) { 1092 if (auto charTy = eleTy.dyn_cast<fir::CharacterType>()) { 1093 // Use LEN from the type. 1094 return builder.createIntegerConstant(loc, idxTy, charTy.getLen()); 1095 } 1096 // Do we need to support !fir.array<!fir.char<k,n>>? 1097 fir::emitFatalError(loc, 1098 "application of path did not result in a !fir.char"); 1099 } 1100 if (fir::isa_box_type(memref.getType())) { 1101 if (memref.getType().isa<fir::BoxCharType>()) 1102 return builder.create<fir::BoxCharLenOp>(loc, idxTy, memref); 1103 if (memref.getType().isa<fir::BoxType>()) 1104 return CharacterExprHelper(builder, loc).readLengthFromBox(memref); 1105 fir::emitFatalError(loc, "memref has wrong type"); 1106 } 1107 if (typeParams.empty()) { 1108 fir::emitFatalError(loc, "array_load must have typeparams"); 1109 } 1110 if (fir::isa_char(seqTy.getEleTy())) { 1111 assert(typeParams.size() == 1 && "too many typeparams"); 1112 return typeParams.front(); 1113 } 1114 TODO(loc, "LEN of character must be computed at runtime"); 1115 } 1116