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 std::string fir::factory::uniqueCGIdent(llvm::StringRef prefix, 665 llvm::StringRef name) { 666 // For "long" identifiers use a hash value 667 if (name.size() > nameLengthHashSize) { 668 llvm::MD5 hash; 669 hash.update(name); 670 llvm::MD5::MD5Result result; 671 hash.final(result); 672 llvm::SmallString<32> str; 673 llvm::MD5::stringifyResult(result, str); 674 std::string hashName = prefix.str(); 675 hashName.append(".").append(str.c_str()); 676 return fir::NameUniquer::doGenerated(hashName); 677 } 678 // "Short" identifiers use a reversible hex string 679 std::string nm = prefix.str(); 680 return fir::NameUniquer::doGenerated( 681 nm.append(".").append(llvm::toHex(name))); 682 } 683 684 mlir::Value fir::factory::locationToFilename(fir::FirOpBuilder &builder, 685 mlir::Location loc) { 686 if (auto flc = loc.dyn_cast<mlir::FileLineColLoc>()) { 687 // must be encoded as asciiz, C string 688 auto fn = flc.getFilename().str() + '\0'; 689 return fir::getBase(createStringLiteral(builder, loc, fn)); 690 } 691 return builder.createNullConstant(loc); 692 } 693 694 mlir::Value fir::factory::locationToLineNo(fir::FirOpBuilder &builder, 695 mlir::Location loc, 696 mlir::Type type) { 697 if (auto flc = loc.dyn_cast<mlir::FileLineColLoc>()) 698 return builder.createIntegerConstant(loc, type, flc.getLine()); 699 return builder.createIntegerConstant(loc, type, 0); 700 } 701 702 fir::ExtendedValue fir::factory::createStringLiteral(fir::FirOpBuilder &builder, 703 mlir::Location loc, 704 llvm::StringRef str) { 705 std::string globalName = fir::factory::uniqueCGIdent("cl", str); 706 auto type = fir::CharacterType::get(builder.getContext(), 1, str.size()); 707 auto global = builder.getNamedGlobal(globalName); 708 if (!global) 709 global = builder.createGlobalConstant( 710 loc, type, globalName, 711 [&](fir::FirOpBuilder &builder) { 712 auto stringLitOp = builder.createStringLitOp(loc, str); 713 builder.create<fir::HasValueOp>(loc, stringLitOp); 714 }, 715 builder.createLinkOnceLinkage()); 716 auto addr = builder.create<fir::AddrOfOp>(loc, global.resultType(), 717 global.getSymbol()); 718 auto len = builder.createIntegerConstant( 719 loc, builder.getCharacterLengthType(), str.size()); 720 return fir::CharBoxValue{addr, len}; 721 } 722 723 llvm::SmallVector<mlir::Value> 724 fir::factory::createExtents(fir::FirOpBuilder &builder, mlir::Location loc, 725 fir::SequenceType seqTy) { 726 llvm::SmallVector<mlir::Value> extents; 727 auto idxTy = builder.getIndexType(); 728 for (auto ext : seqTy.getShape()) 729 extents.emplace_back( 730 ext == fir::SequenceType::getUnknownExtent() 731 ? builder.create<fir::UndefOp>(loc, idxTy).getResult() 732 : builder.createIntegerConstant(loc, idxTy, ext)); 733 return extents; 734 } 735 736 // FIXME: This needs some work. To correctly determine the extended value of a 737 // component, one needs the base object, its type, and its type parameters. (An 738 // alternative would be to provide an already computed address of the final 739 // component rather than the base object's address, the point being the result 740 // will require the address of the final component to create the extended 741 // value.) One further needs the full path of components being applied. One 742 // needs to apply type-based expressions to type parameters along this said 743 // path. (See applyPathToType for a type-only derivation.) Finally, one needs to 744 // compose the extended value of the terminal component, including all of its 745 // parameters: array lower bounds expressions, extents, type parameters, etc. 746 // Any of these properties may be deferred until runtime in Fortran. This 747 // operation may therefore generate a sizeable block of IR, including calls to 748 // type-based helper functions, so caching the result of this operation in the 749 // client would be advised as well. 750 fir::ExtendedValue fir::factory::componentToExtendedValue( 751 fir::FirOpBuilder &builder, mlir::Location loc, mlir::Value component) { 752 auto fieldTy = component.getType(); 753 if (auto ty = fir::dyn_cast_ptrEleTy(fieldTy)) 754 fieldTy = ty; 755 if (fieldTy.isa<fir::BoxType>()) { 756 llvm::SmallVector<mlir::Value> nonDeferredTypeParams; 757 auto eleTy = fir::unwrapSequenceType(fir::dyn_cast_ptrOrBoxEleTy(fieldTy)); 758 if (auto charTy = eleTy.dyn_cast<fir::CharacterType>()) { 759 auto lenTy = builder.getCharacterLengthType(); 760 if (charTy.hasConstantLen()) 761 nonDeferredTypeParams.emplace_back( 762 builder.createIntegerConstant(loc, lenTy, charTy.getLen())); 763 // TODO: Starting, F2003, the dynamic character length might be dependent 764 // on a PDT length parameter. There is no way to make a difference with 765 // deferred length here yet. 766 } 767 if (auto recTy = eleTy.dyn_cast<fir::RecordType>()) 768 if (recTy.getNumLenParams() > 0) 769 TODO(loc, "allocatable and pointer components non deferred length " 770 "parameters"); 771 772 return fir::MutableBoxValue(component, nonDeferredTypeParams, 773 /*mutableProperties=*/{}); 774 } 775 llvm::SmallVector<mlir::Value> extents; 776 if (auto seqTy = fieldTy.dyn_cast<fir::SequenceType>()) { 777 fieldTy = seqTy.getEleTy(); 778 auto idxTy = builder.getIndexType(); 779 for (auto extent : seqTy.getShape()) { 780 if (extent == fir::SequenceType::getUnknownExtent()) 781 TODO(loc, "array component shape depending on length parameters"); 782 extents.emplace_back(builder.createIntegerConstant(loc, idxTy, extent)); 783 } 784 } 785 if (auto charTy = fieldTy.dyn_cast<fir::CharacterType>()) { 786 auto cstLen = charTy.getLen(); 787 if (cstLen == fir::CharacterType::unknownLen()) 788 TODO(loc, "get character component length from length type parameters"); 789 auto len = builder.createIntegerConstant( 790 loc, builder.getCharacterLengthType(), cstLen); 791 if (!extents.empty()) 792 return fir::CharArrayBoxValue{component, len, extents}; 793 return fir::CharBoxValue{component, len}; 794 } 795 if (auto recordTy = fieldTy.dyn_cast<fir::RecordType>()) 796 if (recordTy.getNumLenParams() != 0) 797 TODO(loc, 798 "lower component ref that is a derived type with length parameter"); 799 if (!extents.empty()) 800 return fir::ArrayBoxValue{component, extents}; 801 return component; 802 } 803 804 fir::ExtendedValue fir::factory::arrayElementToExtendedValue( 805 fir::FirOpBuilder &builder, mlir::Location loc, 806 const fir::ExtendedValue &array, mlir::Value element) { 807 return array.match( 808 [&](const fir::CharBoxValue &cb) -> fir::ExtendedValue { 809 return cb.clone(element); 810 }, 811 [&](const fir::CharArrayBoxValue &bv) -> fir::ExtendedValue { 812 return bv.cloneElement(element); 813 }, 814 [&](const fir::BoxValue &box) -> fir::ExtendedValue { 815 if (box.isCharacter()) { 816 auto len = fir::factory::readCharLen(builder, loc, box); 817 return fir::CharBoxValue{element, len}; 818 } 819 if (box.isDerivedWithLengthParameters()) 820 TODO(loc, "get length parameters from derived type BoxValue"); 821 return element; 822 }, 823 [&](const auto &) -> fir::ExtendedValue { return element; }); 824 } 825 826 fir::ExtendedValue fir::factory::arraySectionElementToExtendedValue( 827 fir::FirOpBuilder &builder, mlir::Location loc, 828 const fir::ExtendedValue &array, mlir::Value element, mlir::Value slice) { 829 if (!slice) 830 return arrayElementToExtendedValue(builder, loc, array, element); 831 auto sliceOp = mlir::dyn_cast_or_null<fir::SliceOp>(slice.getDefiningOp()); 832 assert(sliceOp && "slice must be a sliceOp"); 833 if (sliceOp.getFields().empty()) 834 return arrayElementToExtendedValue(builder, loc, array, element); 835 // For F95, using componentToExtendedValue will work, but when PDTs are 836 // lowered. It will be required to go down the slice to propagate the length 837 // parameters. 838 return fir::factory::componentToExtendedValue(builder, loc, element); 839 } 840 841 mlir::TupleType 842 fir::factory::getRaggedArrayHeaderType(fir::FirOpBuilder &builder) { 843 mlir::IntegerType i64Ty = builder.getIntegerType(64); 844 auto arrTy = fir::SequenceType::get(builder.getIntegerType(8), 1); 845 auto buffTy = fir::HeapType::get(arrTy); 846 auto extTy = fir::SequenceType::get(i64Ty, 1); 847 auto shTy = fir::HeapType::get(extTy); 848 return mlir::TupleType::get(builder.getContext(), {i64Ty, buffTy, shTy}); 849 } 850 851 mlir::Value fir::factory::createZeroValue(fir::FirOpBuilder &builder, 852 mlir::Location loc, mlir::Type type) { 853 mlir::Type i1 = builder.getIntegerType(1); 854 if (type.isa<fir::LogicalType>() || type == i1) 855 return builder.createConvert(loc, type, builder.createBool(loc, false)); 856 if (fir::isa_integer(type)) 857 return builder.createIntegerConstant(loc, type, 0); 858 if (fir::isa_real(type)) 859 return builder.createRealZeroConstant(loc, type); 860 if (fir::isa_complex(type)) { 861 fir::factory::Complex complexHelper(builder, loc); 862 mlir::Type partType = complexHelper.getComplexPartType(type); 863 mlir::Value zeroPart = builder.createRealZeroConstant(loc, partType); 864 return complexHelper.createComplex(type, zeroPart, zeroPart); 865 } 866 fir::emitFatalError(loc, "internal: trying to generate zero value of non " 867 "numeric or logical type"); 868 } 869 870 void fir::factory::genScalarAssignment(fir::FirOpBuilder &builder, 871 mlir::Location loc, 872 const fir::ExtendedValue &lhs, 873 const fir::ExtendedValue &rhs) { 874 assert(lhs.rank() == 0 && rhs.rank() == 0 && "must be scalars"); 875 auto type = fir::unwrapSequenceType( 876 fir::unwrapPassByRefType(fir::getBase(lhs).getType())); 877 if (type.isa<fir::CharacterType>()) { 878 const fir::CharBoxValue *toChar = lhs.getCharBox(); 879 const fir::CharBoxValue *fromChar = rhs.getCharBox(); 880 assert(toChar && fromChar); 881 fir::factory::CharacterExprHelper helper{builder, loc}; 882 helper.createAssign(fir::ExtendedValue{*toChar}, 883 fir::ExtendedValue{*fromChar}); 884 } else if (type.isa<fir::RecordType>()) { 885 fir::factory::genRecordAssignment(builder, loc, lhs, rhs); 886 } else { 887 assert(!fir::hasDynamicSize(type)); 888 auto rhsVal = fir::getBase(rhs); 889 if (fir::isa_ref_type(rhsVal.getType())) 890 rhsVal = builder.create<fir::LoadOp>(loc, rhsVal); 891 mlir::Value lhsAddr = fir::getBase(lhs); 892 rhsVal = builder.createConvert(loc, fir::unwrapRefType(lhsAddr.getType()), 893 rhsVal); 894 builder.create<fir::StoreOp>(loc, rhsVal, lhsAddr); 895 } 896 } 897 898 static void genComponentByComponentAssignment(fir::FirOpBuilder &builder, 899 mlir::Location loc, 900 const fir::ExtendedValue &lhs, 901 const fir::ExtendedValue &rhs) { 902 auto baseType = fir::unwrapPassByRefType(fir::getBase(lhs).getType()); 903 auto lhsType = baseType.dyn_cast<fir::RecordType>(); 904 assert(lhsType && "lhs must be a scalar record type"); 905 auto fieldIndexType = fir::FieldType::get(lhsType.getContext()); 906 for (auto [fieldName, fieldType] : lhsType.getTypeList()) { 907 assert(!fir::hasDynamicSize(fieldType)); 908 mlir::Value field = builder.create<fir::FieldIndexOp>( 909 loc, fieldIndexType, fieldName, lhsType, fir::getTypeParams(lhs)); 910 auto fieldRefType = builder.getRefType(fieldType); 911 mlir::Value fromCoor = builder.create<fir::CoordinateOp>( 912 loc, fieldRefType, fir::getBase(rhs), field); 913 mlir::Value toCoor = builder.create<fir::CoordinateOp>( 914 loc, fieldRefType, fir::getBase(lhs), field); 915 llvm::Optional<fir::DoLoopOp> outerLoop; 916 if (auto sequenceType = fieldType.dyn_cast<fir::SequenceType>()) { 917 // Create loops to assign array components elements by elements. 918 // Note that, since these are components, they either do not overlap, 919 // or are the same and exactly overlap. They also have compile time 920 // constant shapes. 921 mlir::Type idxTy = builder.getIndexType(); 922 llvm::SmallVector<mlir::Value> indices; 923 mlir::Value zero = builder.createIntegerConstant(loc, idxTy, 0); 924 mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1); 925 for (auto extent : llvm::reverse(sequenceType.getShape())) { 926 // TODO: add zero size test ! 927 mlir::Value ub = builder.createIntegerConstant(loc, idxTy, extent - 1); 928 auto loop = builder.create<fir::DoLoopOp>(loc, zero, ub, one); 929 if (!outerLoop) 930 outerLoop = loop; 931 indices.push_back(loop.getInductionVar()); 932 builder.setInsertionPointToStart(loop.getBody()); 933 } 934 // Set indices in column-major order. 935 std::reverse(indices.begin(), indices.end()); 936 auto elementRefType = builder.getRefType(sequenceType.getEleTy()); 937 toCoor = builder.create<fir::CoordinateOp>(loc, elementRefType, toCoor, 938 indices); 939 fromCoor = builder.create<fir::CoordinateOp>(loc, elementRefType, 940 fromCoor, indices); 941 } 942 auto fieldElementType = fir::unwrapSequenceType(fieldType); 943 if (fieldElementType.isa<fir::BoxType>()) { 944 assert(fieldElementType.cast<fir::BoxType>() 945 .getEleTy() 946 .isa<fir::PointerType>() && 947 "allocatable require deep copy"); 948 auto fromPointerValue = builder.create<fir::LoadOp>(loc, fromCoor); 949 builder.create<fir::StoreOp>(loc, fromPointerValue, toCoor); 950 } else { 951 auto from = 952 fir::factory::componentToExtendedValue(builder, loc, fromCoor); 953 auto to = fir::factory::componentToExtendedValue(builder, loc, toCoor); 954 fir::factory::genScalarAssignment(builder, loc, to, from); 955 } 956 if (outerLoop) 957 builder.setInsertionPointAfter(*outerLoop); 958 } 959 } 960 961 /// Can the assignment of this record type be implement with a simple memory 962 /// copy (it requires no deep copy or user defined assignment of components )? 963 static bool recordTypeCanBeMemCopied(fir::RecordType recordType) { 964 if (fir::hasDynamicSize(recordType)) 965 return false; 966 for (auto [_, fieldType] : recordType.getTypeList()) { 967 // Derived type component may have user assignment (so far, we cannot tell 968 // in FIR, so assume it is always the case, TODO: get the actual info). 969 if (fir::unwrapSequenceType(fieldType).isa<fir::RecordType>()) 970 return false; 971 // Allocatable components need deep copy. 972 if (auto boxType = fieldType.dyn_cast<fir::BoxType>()) 973 if (boxType.getEleTy().isa<fir::HeapType>()) 974 return false; 975 } 976 // Constant size components without user defined assignment and pointers can 977 // be memcopied. 978 return true; 979 } 980 981 void fir::factory::genRecordAssignment(fir::FirOpBuilder &builder, 982 mlir::Location loc, 983 const fir::ExtendedValue &lhs, 984 const fir::ExtendedValue &rhs) { 985 assert(lhs.rank() == 0 && rhs.rank() == 0 && "assume scalar assignment"); 986 auto baseTy = fir::dyn_cast_ptrOrBoxEleTy(fir::getBase(lhs).getType()); 987 assert(baseTy && "must be a memory type"); 988 // Box operands may be polymorphic, it is not entirely clear from 10.2.1.3 989 // if the assignment is performed on the dynamic of declared type. Use the 990 // runtime assuming it is performed on the dynamic type. 991 bool hasBoxOperands = fir::getBase(lhs).getType().isa<fir::BoxType>() || 992 fir::getBase(rhs).getType().isa<fir::BoxType>(); 993 auto recTy = baseTy.dyn_cast<fir::RecordType>(); 994 assert(recTy && "must be a record type"); 995 if (hasBoxOperands || !recordTypeCanBeMemCopied(recTy)) { 996 auto to = fir::getBase(builder.createBox(loc, lhs)); 997 auto from = fir::getBase(builder.createBox(loc, rhs)); 998 // The runtime entry point may modify the LHS descriptor if it is 999 // an allocatable. Allocatable assignment is handle elsewhere in lowering, 1000 // so just create a fir.ref<fir.box<>> from the fir.box to comply with the 1001 // runtime interface, but assume the fir.box is unchanged. 1002 // TODO: does this holds true with polymorphic entities ? 1003 auto toMutableBox = builder.createTemporary(loc, to.getType()); 1004 builder.create<fir::StoreOp>(loc, to, toMutableBox); 1005 fir::runtime::genAssign(builder, loc, toMutableBox, from); 1006 return; 1007 } 1008 // Otherwise, the derived type has compile time constant size and for which 1009 // the component by component assignment can be replaced by a memory copy. 1010 // Since we do not know the size of the derived type in lowering, do a 1011 // component by component assignment. Note that a single fir.load/fir.store 1012 // could be used on "small" record types, but as the type size grows, this 1013 // leads to issues in LLVM (long compile times, long IR files, and even 1014 // asserts at some point). Since there is no good size boundary, just always 1015 // use component by component assignment here. 1016 genComponentByComponentAssignment(builder, loc, lhs, rhs); 1017 } 1018 1019 mlir::Value fir::factory::genLenOfCharacter( 1020 fir::FirOpBuilder &builder, mlir::Location loc, fir::ArrayLoadOp arrLoad, 1021 llvm::ArrayRef<mlir::Value> path, llvm::ArrayRef<mlir::Value> substring) { 1022 llvm::SmallVector<mlir::Value> typeParams(arrLoad.getTypeparams()); 1023 return genLenOfCharacter(builder, loc, 1024 arrLoad.getType().cast<fir::SequenceType>(), 1025 arrLoad.getMemref(), typeParams, path, substring); 1026 } 1027 1028 mlir::Value fir::factory::genLenOfCharacter( 1029 fir::FirOpBuilder &builder, mlir::Location loc, fir::SequenceType seqTy, 1030 mlir::Value memref, llvm::ArrayRef<mlir::Value> typeParams, 1031 llvm::ArrayRef<mlir::Value> path, llvm::ArrayRef<mlir::Value> substring) { 1032 auto idxTy = builder.getIndexType(); 1033 auto zero = builder.createIntegerConstant(loc, idxTy, 0); 1034 auto saturatedDiff = [&](mlir::Value lower, mlir::Value upper) { 1035 auto diff = builder.create<mlir::arith::SubIOp>(loc, upper, lower); 1036 auto one = builder.createIntegerConstant(loc, idxTy, 1); 1037 auto size = builder.create<mlir::arith::AddIOp>(loc, diff, one); 1038 auto cmp = builder.create<mlir::arith::CmpIOp>( 1039 loc, mlir::arith::CmpIPredicate::sgt, size, zero); 1040 return builder.create<mlir::arith::SelectOp>(loc, cmp, size, zero); 1041 }; 1042 if (substring.size() == 2) { 1043 auto upper = builder.createConvert(loc, idxTy, substring.back()); 1044 auto lower = builder.createConvert(loc, idxTy, substring.front()); 1045 return saturatedDiff(lower, upper); 1046 } 1047 auto lower = zero; 1048 if (substring.size() == 1) 1049 lower = builder.createConvert(loc, idxTy, substring.front()); 1050 auto eleTy = fir::applyPathToType(seqTy, path); 1051 if (!fir::hasDynamicSize(eleTy)) { 1052 if (auto charTy = eleTy.dyn_cast<fir::CharacterType>()) { 1053 // Use LEN from the type. 1054 return builder.createIntegerConstant(loc, idxTy, charTy.getLen()); 1055 } 1056 // Do we need to support !fir.array<!fir.char<k,n>>? 1057 fir::emitFatalError(loc, 1058 "application of path did not result in a !fir.char"); 1059 } 1060 if (fir::isa_box_type(memref.getType())) { 1061 if (memref.getType().isa<fir::BoxCharType>()) 1062 return builder.create<fir::BoxCharLenOp>(loc, idxTy, memref); 1063 if (memref.getType().isa<fir::BoxType>()) 1064 return CharacterExprHelper(builder, loc).readLengthFromBox(memref); 1065 fir::emitFatalError(loc, "memref has wrong type"); 1066 } 1067 if (typeParams.empty()) { 1068 fir::emitFatalError(loc, "array_load must have typeparams"); 1069 } 1070 if (fir::isa_char(seqTy.getEleTy())) { 1071 assert(typeParams.size() == 1 && "too many typeparams"); 1072 return typeParams.front(); 1073 } 1074 TODO(loc, "LEN of character must be computed at runtime"); 1075 } 1076