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