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