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(mlir::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 mlir::Value fir::FirOpBuilder::genExtentFromTriplet(mlir::Location loc, 511 mlir::Value lb, 512 mlir::Value ub, 513 mlir::Value step, 514 mlir::Type type) { 515 auto zero = createIntegerConstant(loc, type, 0); 516 lb = createConvert(loc, type, lb); 517 ub = createConvert(loc, type, ub); 518 step = createConvert(loc, type, step); 519 auto diff = create<mlir::arith::SubIOp>(loc, ub, lb); 520 auto add = create<mlir::arith::AddIOp>(loc, diff, step); 521 auto div = create<mlir::arith::DivSIOp>(loc, add, step); 522 auto cmp = create<mlir::arith::CmpIOp>(loc, mlir::arith::CmpIPredicate::sgt, 523 div, zero); 524 return create<mlir::arith::SelectOp>(loc, cmp, div, zero); 525 } 526 527 //===--------------------------------------------------------------------===// 528 // ExtendedValue inquiry helper implementation 529 //===--------------------------------------------------------------------===// 530 531 mlir::Value fir::factory::readCharLen(fir::FirOpBuilder &builder, 532 mlir::Location loc, 533 const fir::ExtendedValue &box) { 534 return box.match( 535 [&](const fir::CharBoxValue &x) -> mlir::Value { return x.getLen(); }, 536 [&](const fir::CharArrayBoxValue &x) -> mlir::Value { 537 return x.getLen(); 538 }, 539 [&](const fir::BoxValue &x) -> mlir::Value { 540 assert(x.isCharacter()); 541 if (!x.getExplicitParameters().empty()) 542 return x.getExplicitParameters()[0]; 543 return fir::factory::CharacterExprHelper{builder, loc} 544 .readLengthFromBox(x.getAddr()); 545 }, 546 [&](const fir::MutableBoxValue &x) -> mlir::Value { 547 return readCharLen(builder, loc, 548 fir::factory::genMutableBoxRead(builder, loc, x)); 549 }, 550 [&](const auto &) -> mlir::Value { 551 fir::emitFatalError( 552 loc, "Character length inquiry on a non-character entity"); 553 }); 554 } 555 556 mlir::Value fir::factory::readExtent(fir::FirOpBuilder &builder, 557 mlir::Location loc, 558 const fir::ExtendedValue &box, 559 unsigned dim) { 560 assert(box.rank() > dim); 561 return box.match( 562 [&](const fir::ArrayBoxValue &x) -> mlir::Value { 563 return x.getExtents()[dim]; 564 }, 565 [&](const fir::CharArrayBoxValue &x) -> mlir::Value { 566 return x.getExtents()[dim]; 567 }, 568 [&](const fir::BoxValue &x) -> mlir::Value { 569 if (!x.getExplicitExtents().empty()) 570 return x.getExplicitExtents()[dim]; 571 auto idxTy = builder.getIndexType(); 572 auto dimVal = builder.createIntegerConstant(loc, idxTy, dim); 573 return builder 574 .create<fir::BoxDimsOp>(loc, idxTy, idxTy, idxTy, x.getAddr(), 575 dimVal) 576 .getResult(1); 577 }, 578 [&](const fir::MutableBoxValue &x) -> mlir::Value { 579 // MutableBoxValue must be read into another category to work with them 580 // outside of allocation/assignment contexts. 581 fir::emitFatalError(loc, "readExtents on MutableBoxValue"); 582 }, 583 [&](const auto &) -> mlir::Value { 584 fir::emitFatalError(loc, "extent inquiry on scalar"); 585 }); 586 } 587 588 mlir::Value fir::factory::readLowerBound(fir::FirOpBuilder &builder, 589 mlir::Location loc, 590 const fir::ExtendedValue &box, 591 unsigned dim, 592 mlir::Value defaultValue) { 593 assert(box.rank() > dim); 594 auto lb = box.match( 595 [&](const fir::ArrayBoxValue &x) -> mlir::Value { 596 return x.getLBounds().empty() ? mlir::Value{} : x.getLBounds()[dim]; 597 }, 598 [&](const fir::CharArrayBoxValue &x) -> mlir::Value { 599 return x.getLBounds().empty() ? mlir::Value{} : x.getLBounds()[dim]; 600 }, 601 [&](const fir::BoxValue &x) -> mlir::Value { 602 return x.getLBounds().empty() ? mlir::Value{} : x.getLBounds()[dim]; 603 }, 604 [&](const fir::MutableBoxValue &x) -> mlir::Value { 605 return readLowerBound(builder, loc, 606 fir::factory::genMutableBoxRead(builder, loc, x), 607 dim, defaultValue); 608 }, 609 [&](const auto &) -> mlir::Value { 610 fir::emitFatalError(loc, "lower bound inquiry on scalar"); 611 }); 612 if (lb) 613 return lb; 614 return defaultValue; 615 } 616 617 llvm::SmallVector<mlir::Value> 618 fir::factory::readExtents(fir::FirOpBuilder &builder, mlir::Location loc, 619 const fir::BoxValue &box) { 620 llvm::SmallVector<mlir::Value> result; 621 auto explicitExtents = box.getExplicitExtents(); 622 if (!explicitExtents.empty()) { 623 result.append(explicitExtents.begin(), explicitExtents.end()); 624 return result; 625 } 626 auto rank = box.rank(); 627 auto idxTy = builder.getIndexType(); 628 for (decltype(rank) dim = 0; dim < rank; ++dim) { 629 auto dimVal = builder.createIntegerConstant(loc, idxTy, dim); 630 auto dimInfo = builder.create<fir::BoxDimsOp>(loc, idxTy, idxTy, idxTy, 631 box.getAddr(), dimVal); 632 result.emplace_back(dimInfo.getResult(1)); 633 } 634 return result; 635 } 636 637 llvm::SmallVector<mlir::Value> 638 fir::factory::getExtents(fir::FirOpBuilder &builder, mlir::Location loc, 639 const fir::ExtendedValue &box) { 640 return box.match( 641 [&](const fir::ArrayBoxValue &x) -> llvm::SmallVector<mlir::Value> { 642 return {x.getExtents().begin(), x.getExtents().end()}; 643 }, 644 [&](const fir::CharArrayBoxValue &x) -> llvm::SmallVector<mlir::Value> { 645 return {x.getExtents().begin(), x.getExtents().end()}; 646 }, 647 [&](const fir::BoxValue &x) -> llvm::SmallVector<mlir::Value> { 648 return fir::factory::readExtents(builder, loc, x); 649 }, 650 [&](const fir::MutableBoxValue &x) -> llvm::SmallVector<mlir::Value> { 651 auto load = fir::factory::genMutableBoxRead(builder, loc, x); 652 return fir::factory::getExtents(builder, loc, load); 653 }, 654 [&](const auto &) -> llvm::SmallVector<mlir::Value> { return {}; }); 655 } 656 657 fir::ExtendedValue fir::factory::readBoxValue(fir::FirOpBuilder &builder, 658 mlir::Location loc, 659 const fir::BoxValue &box) { 660 assert(!box.isUnlimitedPolymorphic() && !box.hasAssumedRank() && 661 "cannot read unlimited polymorphic or assumed rank fir.box"); 662 auto addr = 663 builder.create<fir::BoxAddrOp>(loc, box.getMemTy(), box.getAddr()); 664 if (box.isCharacter()) { 665 auto len = fir::factory::readCharLen(builder, loc, box); 666 if (box.rank() == 0) 667 return fir::CharBoxValue(addr, len); 668 return fir::CharArrayBoxValue(addr, len, 669 fir::factory::readExtents(builder, loc, box), 670 box.getLBounds()); 671 } 672 if (box.isDerivedWithLengthParameters()) 673 TODO(loc, "read fir.box with length parameters"); 674 if (box.rank() == 0) 675 return addr; 676 return fir::ArrayBoxValue(addr, fir::factory::readExtents(builder, loc, box), 677 box.getLBounds()); 678 } 679 680 llvm::SmallVector<mlir::Value> 681 fir::factory::getNonDefaultLowerBounds(fir::FirOpBuilder &builder, 682 mlir::Location loc, 683 const fir::ExtendedValue &exv) { 684 return exv.match( 685 [&](const fir::ArrayBoxValue &array) -> llvm::SmallVector<mlir::Value> { 686 return {array.getLBounds().begin(), array.getLBounds().end()}; 687 }, 688 [&](const fir::CharArrayBoxValue &array) 689 -> llvm::SmallVector<mlir::Value> { 690 return {array.getLBounds().begin(), array.getLBounds().end()}; 691 }, 692 [&](const fir::BoxValue &box) -> llvm::SmallVector<mlir::Value> { 693 return {box.getLBounds().begin(), box.getLBounds().end()}; 694 }, 695 [&](const fir::MutableBoxValue &box) -> llvm::SmallVector<mlir::Value> { 696 auto load = fir::factory::genMutableBoxRead(builder, loc, box); 697 return fir::factory::getNonDefaultLowerBounds(builder, loc, load); 698 }, 699 [&](const auto &) -> llvm::SmallVector<mlir::Value> { return {}; }); 700 } 701 702 llvm::SmallVector<mlir::Value> 703 fir::factory::getNonDeferredLengthParams(const fir::ExtendedValue &exv) { 704 return exv.match( 705 [&](const fir::CharArrayBoxValue &character) 706 -> llvm::SmallVector<mlir::Value> { return {character.getLen()}; }, 707 [&](const fir::CharBoxValue &character) 708 -> llvm::SmallVector<mlir::Value> { return {character.getLen()}; }, 709 [&](const fir::MutableBoxValue &box) -> llvm::SmallVector<mlir::Value> { 710 return {box.nonDeferredLenParams().begin(), 711 box.nonDeferredLenParams().end()}; 712 }, 713 [&](const fir::BoxValue &box) -> llvm::SmallVector<mlir::Value> { 714 return {box.getExplicitParameters().begin(), 715 box.getExplicitParameters().end()}; 716 }, 717 [&](const auto &) -> llvm::SmallVector<mlir::Value> { return {}; }); 718 } 719 720 std::string fir::factory::uniqueCGIdent(llvm::StringRef prefix, 721 llvm::StringRef name) { 722 // For "long" identifiers use a hash value 723 if (name.size() > nameLengthHashSize) { 724 llvm::MD5 hash; 725 hash.update(name); 726 llvm::MD5::MD5Result result; 727 hash.final(result); 728 llvm::SmallString<32> str; 729 llvm::MD5::stringifyResult(result, str); 730 std::string hashName = prefix.str(); 731 hashName.append(".").append(str.c_str()); 732 return fir::NameUniquer::doGenerated(hashName); 733 } 734 // "Short" identifiers use a reversible hex string 735 std::string nm = prefix.str(); 736 return fir::NameUniquer::doGenerated( 737 nm.append(".").append(llvm::toHex(name))); 738 } 739 740 mlir::Value fir::factory::locationToFilename(fir::FirOpBuilder &builder, 741 mlir::Location loc) { 742 if (auto flc = loc.dyn_cast<mlir::FileLineColLoc>()) { 743 // must be encoded as asciiz, C string 744 auto fn = flc.getFilename().str() + '\0'; 745 return fir::getBase(createStringLiteral(builder, loc, fn)); 746 } 747 return builder.createNullConstant(loc); 748 } 749 750 mlir::Value fir::factory::locationToLineNo(fir::FirOpBuilder &builder, 751 mlir::Location loc, 752 mlir::Type type) { 753 if (auto flc = loc.dyn_cast<mlir::FileLineColLoc>()) 754 return builder.createIntegerConstant(loc, type, flc.getLine()); 755 return builder.createIntegerConstant(loc, type, 0); 756 } 757 758 fir::ExtendedValue fir::factory::createStringLiteral(fir::FirOpBuilder &builder, 759 mlir::Location loc, 760 llvm::StringRef str) { 761 std::string globalName = fir::factory::uniqueCGIdent("cl", str); 762 auto type = fir::CharacterType::get(builder.getContext(), 1, str.size()); 763 auto global = builder.getNamedGlobal(globalName); 764 if (!global) 765 global = builder.createGlobalConstant( 766 loc, type, globalName, 767 [&](fir::FirOpBuilder &builder) { 768 auto stringLitOp = builder.createStringLitOp(loc, str); 769 builder.create<fir::HasValueOp>(loc, stringLitOp); 770 }, 771 builder.createLinkOnceLinkage()); 772 auto addr = builder.create<fir::AddrOfOp>(loc, global.resultType(), 773 global.getSymbol()); 774 auto len = builder.createIntegerConstant( 775 loc, builder.getCharacterLengthType(), str.size()); 776 return fir::CharBoxValue{addr, len}; 777 } 778 779 llvm::SmallVector<mlir::Value> 780 fir::factory::createExtents(fir::FirOpBuilder &builder, mlir::Location loc, 781 fir::SequenceType seqTy) { 782 llvm::SmallVector<mlir::Value> extents; 783 auto idxTy = builder.getIndexType(); 784 for (auto ext : seqTy.getShape()) 785 extents.emplace_back( 786 ext == fir::SequenceType::getUnknownExtent() 787 ? builder.create<fir::UndefOp>(loc, idxTy).getResult() 788 : builder.createIntegerConstant(loc, idxTy, ext)); 789 return extents; 790 } 791 792 // FIXME: This needs some work. To correctly determine the extended value of a 793 // component, one needs the base object, its type, and its type parameters. (An 794 // alternative would be to provide an already computed address of the final 795 // component rather than the base object's address, the point being the result 796 // will require the address of the final component to create the extended 797 // value.) One further needs the full path of components being applied. One 798 // needs to apply type-based expressions to type parameters along this said 799 // path. (See applyPathToType for a type-only derivation.) Finally, one needs to 800 // compose the extended value of the terminal component, including all of its 801 // parameters: array lower bounds expressions, extents, type parameters, etc. 802 // Any of these properties may be deferred until runtime in Fortran. This 803 // operation may therefore generate a sizeable block of IR, including calls to 804 // type-based helper functions, so caching the result of this operation in the 805 // client would be advised as well. 806 fir::ExtendedValue fir::factory::componentToExtendedValue( 807 fir::FirOpBuilder &builder, mlir::Location loc, mlir::Value component) { 808 auto fieldTy = component.getType(); 809 if (auto ty = fir::dyn_cast_ptrEleTy(fieldTy)) 810 fieldTy = ty; 811 if (fieldTy.isa<fir::BoxType>()) { 812 llvm::SmallVector<mlir::Value> nonDeferredTypeParams; 813 auto eleTy = fir::unwrapSequenceType(fir::dyn_cast_ptrOrBoxEleTy(fieldTy)); 814 if (auto charTy = eleTy.dyn_cast<fir::CharacterType>()) { 815 auto lenTy = builder.getCharacterLengthType(); 816 if (charTy.hasConstantLen()) 817 nonDeferredTypeParams.emplace_back( 818 builder.createIntegerConstant(loc, lenTy, charTy.getLen())); 819 // TODO: Starting, F2003, the dynamic character length might be dependent 820 // on a PDT length parameter. There is no way to make a difference with 821 // deferred length here yet. 822 } 823 if (auto recTy = eleTy.dyn_cast<fir::RecordType>()) 824 if (recTy.getNumLenParams() > 0) 825 TODO(loc, "allocatable and pointer components non deferred length " 826 "parameters"); 827 828 return fir::MutableBoxValue(component, nonDeferredTypeParams, 829 /*mutableProperties=*/{}); 830 } 831 llvm::SmallVector<mlir::Value> extents; 832 if (auto seqTy = fieldTy.dyn_cast<fir::SequenceType>()) { 833 fieldTy = seqTy.getEleTy(); 834 auto idxTy = builder.getIndexType(); 835 for (auto extent : seqTy.getShape()) { 836 if (extent == fir::SequenceType::getUnknownExtent()) 837 TODO(loc, "array component shape depending on length parameters"); 838 extents.emplace_back(builder.createIntegerConstant(loc, idxTy, extent)); 839 } 840 } 841 if (auto charTy = fieldTy.dyn_cast<fir::CharacterType>()) { 842 auto cstLen = charTy.getLen(); 843 if (cstLen == fir::CharacterType::unknownLen()) 844 TODO(loc, "get character component length from length type parameters"); 845 auto len = builder.createIntegerConstant( 846 loc, builder.getCharacterLengthType(), cstLen); 847 if (!extents.empty()) 848 return fir::CharArrayBoxValue{component, len, extents}; 849 return fir::CharBoxValue{component, len}; 850 } 851 if (auto recordTy = fieldTy.dyn_cast<fir::RecordType>()) 852 if (recordTy.getNumLenParams() != 0) 853 TODO(loc, 854 "lower component ref that is a derived type with length parameter"); 855 if (!extents.empty()) 856 return fir::ArrayBoxValue{component, extents}; 857 return component; 858 } 859 860 fir::ExtendedValue fir::factory::arrayElementToExtendedValue( 861 fir::FirOpBuilder &builder, mlir::Location loc, 862 const fir::ExtendedValue &array, mlir::Value element) { 863 return array.match( 864 [&](const fir::CharBoxValue &cb) -> fir::ExtendedValue { 865 return cb.clone(element); 866 }, 867 [&](const fir::CharArrayBoxValue &bv) -> fir::ExtendedValue { 868 return bv.cloneElement(element); 869 }, 870 [&](const fir::BoxValue &box) -> fir::ExtendedValue { 871 if (box.isCharacter()) { 872 auto len = fir::factory::readCharLen(builder, loc, box); 873 return fir::CharBoxValue{element, len}; 874 } 875 if (box.isDerivedWithLengthParameters()) 876 TODO(loc, "get length parameters from derived type BoxValue"); 877 return element; 878 }, 879 [&](const auto &) -> fir::ExtendedValue { return element; }); 880 } 881 882 fir::ExtendedValue fir::factory::arraySectionElementToExtendedValue( 883 fir::FirOpBuilder &builder, mlir::Location loc, 884 const fir::ExtendedValue &array, mlir::Value element, mlir::Value slice) { 885 if (!slice) 886 return arrayElementToExtendedValue(builder, loc, array, element); 887 auto sliceOp = mlir::dyn_cast_or_null<fir::SliceOp>(slice.getDefiningOp()); 888 assert(sliceOp && "slice must be a sliceOp"); 889 if (sliceOp.getFields().empty()) 890 return arrayElementToExtendedValue(builder, loc, array, element); 891 // For F95, using componentToExtendedValue will work, but when PDTs are 892 // lowered. It will be required to go down the slice to propagate the length 893 // parameters. 894 return fir::factory::componentToExtendedValue(builder, loc, element); 895 } 896 897 mlir::TupleType 898 fir::factory::getRaggedArrayHeaderType(fir::FirOpBuilder &builder) { 899 mlir::IntegerType i64Ty = builder.getIntegerType(64); 900 auto arrTy = fir::SequenceType::get(builder.getIntegerType(8), 1); 901 auto buffTy = fir::HeapType::get(arrTy); 902 auto extTy = fir::SequenceType::get(i64Ty, 1); 903 auto shTy = fir::HeapType::get(extTy); 904 return mlir::TupleType::get(builder.getContext(), {i64Ty, buffTy, shTy}); 905 } 906 907 mlir::Value fir::factory::createZeroValue(fir::FirOpBuilder &builder, 908 mlir::Location loc, mlir::Type type) { 909 mlir::Type i1 = builder.getIntegerType(1); 910 if (type.isa<fir::LogicalType>() || type == i1) 911 return builder.createConvert(loc, type, builder.createBool(loc, false)); 912 if (fir::isa_integer(type)) 913 return builder.createIntegerConstant(loc, type, 0); 914 if (fir::isa_real(type)) 915 return builder.createRealZeroConstant(loc, type); 916 if (fir::isa_complex(type)) { 917 fir::factory::Complex complexHelper(builder, loc); 918 mlir::Type partType = complexHelper.getComplexPartType(type); 919 mlir::Value zeroPart = builder.createRealZeroConstant(loc, partType); 920 return complexHelper.createComplex(type, zeroPart, zeroPart); 921 } 922 fir::emitFatalError(loc, "internal: trying to generate zero value of non " 923 "numeric or logical type"); 924 } 925 926 void fir::factory::genScalarAssignment(fir::FirOpBuilder &builder, 927 mlir::Location loc, 928 const fir::ExtendedValue &lhs, 929 const fir::ExtendedValue &rhs) { 930 assert(lhs.rank() == 0 && rhs.rank() == 0 && "must be scalars"); 931 auto type = fir::unwrapSequenceType( 932 fir::unwrapPassByRefType(fir::getBase(lhs).getType())); 933 if (type.isa<fir::CharacterType>()) { 934 const fir::CharBoxValue *toChar = lhs.getCharBox(); 935 const fir::CharBoxValue *fromChar = rhs.getCharBox(); 936 assert(toChar && fromChar); 937 fir::factory::CharacterExprHelper helper{builder, loc}; 938 helper.createAssign(fir::ExtendedValue{*toChar}, 939 fir::ExtendedValue{*fromChar}); 940 } else if (type.isa<fir::RecordType>()) { 941 fir::factory::genRecordAssignment(builder, loc, lhs, rhs); 942 } else { 943 assert(!fir::hasDynamicSize(type)); 944 auto rhsVal = fir::getBase(rhs); 945 if (fir::isa_ref_type(rhsVal.getType())) 946 rhsVal = builder.create<fir::LoadOp>(loc, rhsVal); 947 mlir::Value lhsAddr = fir::getBase(lhs); 948 rhsVal = builder.createConvert(loc, fir::unwrapRefType(lhsAddr.getType()), 949 rhsVal); 950 builder.create<fir::StoreOp>(loc, rhsVal, lhsAddr); 951 } 952 } 953 954 static void genComponentByComponentAssignment(fir::FirOpBuilder &builder, 955 mlir::Location loc, 956 const fir::ExtendedValue &lhs, 957 const fir::ExtendedValue &rhs) { 958 auto baseType = fir::unwrapPassByRefType(fir::getBase(lhs).getType()); 959 auto lhsType = baseType.dyn_cast<fir::RecordType>(); 960 assert(lhsType && "lhs must be a scalar record type"); 961 auto fieldIndexType = fir::FieldType::get(lhsType.getContext()); 962 for (auto [fieldName, fieldType] : lhsType.getTypeList()) { 963 assert(!fir::hasDynamicSize(fieldType)); 964 mlir::Value field = builder.create<fir::FieldIndexOp>( 965 loc, fieldIndexType, fieldName, lhsType, fir::getTypeParams(lhs)); 966 auto fieldRefType = builder.getRefType(fieldType); 967 mlir::Value fromCoor = builder.create<fir::CoordinateOp>( 968 loc, fieldRefType, fir::getBase(rhs), field); 969 mlir::Value toCoor = builder.create<fir::CoordinateOp>( 970 loc, fieldRefType, fir::getBase(lhs), field); 971 llvm::Optional<fir::DoLoopOp> outerLoop; 972 if (auto sequenceType = fieldType.dyn_cast<fir::SequenceType>()) { 973 // Create loops to assign array components elements by elements. 974 // Note that, since these are components, they either do not overlap, 975 // or are the same and exactly overlap. They also have compile time 976 // constant shapes. 977 mlir::Type idxTy = builder.getIndexType(); 978 llvm::SmallVector<mlir::Value> indices; 979 mlir::Value zero = builder.createIntegerConstant(loc, idxTy, 0); 980 mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1); 981 for (auto extent : llvm::reverse(sequenceType.getShape())) { 982 // TODO: add zero size test ! 983 mlir::Value ub = builder.createIntegerConstant(loc, idxTy, extent - 1); 984 auto loop = builder.create<fir::DoLoopOp>(loc, zero, ub, one); 985 if (!outerLoop) 986 outerLoop = loop; 987 indices.push_back(loop.getInductionVar()); 988 builder.setInsertionPointToStart(loop.getBody()); 989 } 990 // Set indices in column-major order. 991 std::reverse(indices.begin(), indices.end()); 992 auto elementRefType = builder.getRefType(sequenceType.getEleTy()); 993 toCoor = builder.create<fir::CoordinateOp>(loc, elementRefType, toCoor, 994 indices); 995 fromCoor = builder.create<fir::CoordinateOp>(loc, elementRefType, 996 fromCoor, indices); 997 } 998 auto fieldElementType = fir::unwrapSequenceType(fieldType); 999 if (fieldElementType.isa<fir::BoxType>()) { 1000 assert(fieldElementType.cast<fir::BoxType>() 1001 .getEleTy() 1002 .isa<fir::PointerType>() && 1003 "allocatable require deep copy"); 1004 auto fromPointerValue = builder.create<fir::LoadOp>(loc, fromCoor); 1005 builder.create<fir::StoreOp>(loc, fromPointerValue, toCoor); 1006 } else { 1007 auto from = 1008 fir::factory::componentToExtendedValue(builder, loc, fromCoor); 1009 auto to = fir::factory::componentToExtendedValue(builder, loc, toCoor); 1010 fir::factory::genScalarAssignment(builder, loc, to, from); 1011 } 1012 if (outerLoop) 1013 builder.setInsertionPointAfter(*outerLoop); 1014 } 1015 } 1016 1017 /// Can the assignment of this record type be implement with a simple memory 1018 /// copy (it requires no deep copy or user defined assignment of components )? 1019 static bool recordTypeCanBeMemCopied(fir::RecordType recordType) { 1020 if (fir::hasDynamicSize(recordType)) 1021 return false; 1022 for (auto [_, fieldType] : recordType.getTypeList()) { 1023 // Derived type component may have user assignment (so far, we cannot tell 1024 // in FIR, so assume it is always the case, TODO: get the actual info). 1025 if (fir::unwrapSequenceType(fieldType).isa<fir::RecordType>()) 1026 return false; 1027 // Allocatable components need deep copy. 1028 if (auto boxType = fieldType.dyn_cast<fir::BoxType>()) 1029 if (boxType.getEleTy().isa<fir::HeapType>()) 1030 return false; 1031 } 1032 // Constant size components without user defined assignment and pointers can 1033 // be memcopied. 1034 return true; 1035 } 1036 1037 void fir::factory::genRecordAssignment(fir::FirOpBuilder &builder, 1038 mlir::Location loc, 1039 const fir::ExtendedValue &lhs, 1040 const fir::ExtendedValue &rhs) { 1041 assert(lhs.rank() == 0 && rhs.rank() == 0 && "assume scalar assignment"); 1042 auto baseTy = fir::dyn_cast_ptrOrBoxEleTy(fir::getBase(lhs).getType()); 1043 assert(baseTy && "must be a memory type"); 1044 // Box operands may be polymorphic, it is not entirely clear from 10.2.1.3 1045 // if the assignment is performed on the dynamic of declared type. Use the 1046 // runtime assuming it is performed on the dynamic type. 1047 bool hasBoxOperands = fir::getBase(lhs).getType().isa<fir::BoxType>() || 1048 fir::getBase(rhs).getType().isa<fir::BoxType>(); 1049 auto recTy = baseTy.dyn_cast<fir::RecordType>(); 1050 assert(recTy && "must be a record type"); 1051 if (hasBoxOperands || !recordTypeCanBeMemCopied(recTy)) { 1052 auto to = fir::getBase(builder.createBox(loc, lhs)); 1053 auto from = fir::getBase(builder.createBox(loc, rhs)); 1054 // The runtime entry point may modify the LHS descriptor if it is 1055 // an allocatable. Allocatable assignment is handle elsewhere in lowering, 1056 // so just create a fir.ref<fir.box<>> from the fir.box to comply with the 1057 // runtime interface, but assume the fir.box is unchanged. 1058 // TODO: does this holds true with polymorphic entities ? 1059 auto toMutableBox = builder.createTemporary(loc, to.getType()); 1060 builder.create<fir::StoreOp>(loc, to, toMutableBox); 1061 fir::runtime::genAssign(builder, loc, toMutableBox, from); 1062 return; 1063 } 1064 // Otherwise, the derived type has compile time constant size and for which 1065 // the component by component assignment can be replaced by a memory copy. 1066 // Since we do not know the size of the derived type in lowering, do a 1067 // component by component assignment. Note that a single fir.load/fir.store 1068 // could be used on "small" record types, but as the type size grows, this 1069 // leads to issues in LLVM (long compile times, long IR files, and even 1070 // asserts at some point). Since there is no good size boundary, just always 1071 // use component by component assignment here. 1072 genComponentByComponentAssignment(builder, loc, lhs, rhs); 1073 } 1074 1075 mlir::Value fir::factory::genLenOfCharacter( 1076 fir::FirOpBuilder &builder, mlir::Location loc, fir::ArrayLoadOp arrLoad, 1077 llvm::ArrayRef<mlir::Value> path, llvm::ArrayRef<mlir::Value> substring) { 1078 llvm::SmallVector<mlir::Value> typeParams(arrLoad.getTypeparams()); 1079 return genLenOfCharacter(builder, loc, 1080 arrLoad.getType().cast<fir::SequenceType>(), 1081 arrLoad.getMemref(), typeParams, path, substring); 1082 } 1083 1084 mlir::Value fir::factory::genLenOfCharacter( 1085 fir::FirOpBuilder &builder, mlir::Location loc, fir::SequenceType seqTy, 1086 mlir::Value memref, llvm::ArrayRef<mlir::Value> typeParams, 1087 llvm::ArrayRef<mlir::Value> path, llvm::ArrayRef<mlir::Value> substring) { 1088 auto idxTy = builder.getIndexType(); 1089 auto zero = builder.createIntegerConstant(loc, idxTy, 0); 1090 auto saturatedDiff = [&](mlir::Value lower, mlir::Value upper) { 1091 auto diff = builder.create<mlir::arith::SubIOp>(loc, upper, lower); 1092 auto one = builder.createIntegerConstant(loc, idxTy, 1); 1093 auto size = builder.create<mlir::arith::AddIOp>(loc, diff, one); 1094 auto cmp = builder.create<mlir::arith::CmpIOp>( 1095 loc, mlir::arith::CmpIPredicate::sgt, size, zero); 1096 return builder.create<mlir::arith::SelectOp>(loc, cmp, size, zero); 1097 }; 1098 if (substring.size() == 2) { 1099 auto upper = builder.createConvert(loc, idxTy, substring.back()); 1100 auto lower = builder.createConvert(loc, idxTy, substring.front()); 1101 return saturatedDiff(lower, upper); 1102 } 1103 auto lower = zero; 1104 if (substring.size() == 1) 1105 lower = builder.createConvert(loc, idxTy, substring.front()); 1106 auto eleTy = fir::applyPathToType(seqTy, path); 1107 if (!fir::hasDynamicSize(eleTy)) { 1108 if (auto charTy = eleTy.dyn_cast<fir::CharacterType>()) { 1109 // Use LEN from the type. 1110 return builder.createIntegerConstant(loc, idxTy, charTy.getLen()); 1111 } 1112 // Do we need to support !fir.array<!fir.char<k,n>>? 1113 fir::emitFatalError(loc, 1114 "application of path did not result in a !fir.char"); 1115 } 1116 if (fir::isa_box_type(memref.getType())) { 1117 if (memref.getType().isa<fir::BoxCharType>()) 1118 return builder.create<fir::BoxCharLenOp>(loc, idxTy, memref); 1119 if (memref.getType().isa<fir::BoxType>()) 1120 return CharacterExprHelper(builder, loc).readLengthFromBox(memref); 1121 fir::emitFatalError(loc, "memref has wrong type"); 1122 } 1123 if (typeParams.empty()) { 1124 fir::emitFatalError(loc, "array_load must have typeparams"); 1125 } 1126 if (fir::isa_char(seqTy.getEleTy())) { 1127 assert(typeParams.size() == 1 && "too many typeparams"); 1128 return typeParams.front(); 1129 } 1130 TODO(loc, "LEN of character must be computed at runtime"); 1131 } 1132