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/Optimizer/Builder/BoxValue.h" 11 #include "flang/Optimizer/Builder/Character.h" 12 #include "flang/Optimizer/Builder/Complex.h" 13 #include "flang/Optimizer/Builder/MutableBox.h" 14 #include "flang/Optimizer/Builder/Runtime/Assign.h" 15 #include "flang/Optimizer/Builder/Runtime/Derived.h" 16 #include "flang/Optimizer/Builder/Todo.h" 17 #include "flang/Optimizer/Dialect/CUF/CUFOps.h" 18 #include "flang/Optimizer/Dialect/FIRAttr.h" 19 #include "flang/Optimizer/Dialect/FIROpsSupport.h" 20 #include "flang/Optimizer/Dialect/FIRType.h" 21 #include "flang/Optimizer/Support/DataLayout.h" 22 #include "flang/Optimizer/Support/FatalError.h" 23 #include "flang/Optimizer/Support/InternalNames.h" 24 #include "flang/Optimizer/Support/Utils.h" 25 #include "mlir/Dialect/LLVMIR/LLVMDialect.h" 26 #include "mlir/Dialect/OpenACC/OpenACC.h" 27 #include "mlir/Dialect/OpenMP/OpenMPDialect.h" 28 #include "llvm/ADT/ArrayRef.h" 29 #include "llvm/ADT/StringExtras.h" 30 #include "llvm/Support/CommandLine.h" 31 #include "llvm/Support/ErrorHandling.h" 32 #include "llvm/Support/MD5.h" 33 #include <optional> 34 35 static llvm::cl::opt<std::size_t> 36 nameLengthHashSize("length-to-hash-string-literal", 37 llvm::cl::desc("string literals that exceed this length" 38 " will use a hash value as their symbol " 39 "name"), 40 llvm::cl::init(32)); 41 42 mlir::func::FuncOp 43 fir::FirOpBuilder::createFunction(mlir::Location loc, mlir::ModuleOp module, 44 llvm::StringRef name, mlir::FunctionType ty, 45 mlir::SymbolTable *symbolTable) { 46 return fir::createFuncOp(loc, module, name, ty, /*attrs*/ {}, symbolTable); 47 } 48 49 mlir::func::FuncOp 50 fir::FirOpBuilder::getNamedFunction(mlir::ModuleOp modOp, 51 const mlir::SymbolTable *symbolTable, 52 llvm::StringRef name) { 53 if (symbolTable) 54 if (auto func = symbolTable->lookup<mlir::func::FuncOp>(name)) { 55 #ifdef EXPENSIVE_CHECKS 56 assert(func == modOp.lookupSymbol<mlir::func::FuncOp>(name) && 57 "symbolTable and module out of sync"); 58 #endif 59 return func; 60 } 61 return modOp.lookupSymbol<mlir::func::FuncOp>(name); 62 } 63 64 mlir::func::FuncOp 65 fir::FirOpBuilder::getNamedFunction(mlir::ModuleOp modOp, 66 const mlir::SymbolTable *symbolTable, 67 mlir::SymbolRefAttr symbol) { 68 if (symbolTable) 69 if (auto func = symbolTable->lookup<mlir::func::FuncOp>( 70 symbol.getLeafReference())) { 71 #ifdef EXPENSIVE_CHECKS 72 assert(func == modOp.lookupSymbol<mlir::func::FuncOp>(symbol) && 73 "symbolTable and module out of sync"); 74 #endif 75 return func; 76 } 77 return modOp.lookupSymbol<mlir::func::FuncOp>(symbol); 78 } 79 80 fir::GlobalOp 81 fir::FirOpBuilder::getNamedGlobal(mlir::ModuleOp modOp, 82 const mlir::SymbolTable *symbolTable, 83 llvm::StringRef name) { 84 if (symbolTable) 85 if (auto global = symbolTable->lookup<fir::GlobalOp>(name)) { 86 #ifdef EXPENSIVE_CHECKS 87 assert(global == modOp.lookupSymbol<fir::GlobalOp>(name) && 88 "symbolTable and module out of sync"); 89 #endif 90 return global; 91 } 92 return modOp.lookupSymbol<fir::GlobalOp>(name); 93 } 94 95 mlir::Type fir::FirOpBuilder::getRefType(mlir::Type eleTy) { 96 assert(!mlir::isa<fir::ReferenceType>(eleTy) && "cannot be a reference type"); 97 return fir::ReferenceType::get(eleTy); 98 } 99 100 mlir::Type fir::FirOpBuilder::getVarLenSeqTy(mlir::Type eleTy, unsigned rank) { 101 fir::SequenceType::Shape shape(rank, fir::SequenceType::getUnknownExtent()); 102 return fir::SequenceType::get(shape, eleTy); 103 } 104 105 mlir::Type fir::FirOpBuilder::getRealType(int kind) { 106 switch (kindMap.getRealTypeID(kind)) { 107 case llvm::Type::TypeID::HalfTyID: 108 return mlir::Float16Type::get(getContext()); 109 case llvm::Type::TypeID::BFloatTyID: 110 return mlir::BFloat16Type::get(getContext()); 111 case llvm::Type::TypeID::FloatTyID: 112 return mlir::Float32Type::get(getContext()); 113 case llvm::Type::TypeID::DoubleTyID: 114 return mlir::Float64Type::get(getContext()); 115 case llvm::Type::TypeID::X86_FP80TyID: 116 return mlir::Float80Type::get(getContext()); 117 case llvm::Type::TypeID::FP128TyID: 118 return mlir::Float128Type::get(getContext()); 119 default: 120 fir::emitFatalError(mlir::UnknownLoc::get(getContext()), 121 "unsupported type !fir.real<kind>"); 122 } 123 } 124 125 mlir::Value fir::FirOpBuilder::createNullConstant(mlir::Location loc, 126 mlir::Type ptrType) { 127 auto ty = ptrType ? ptrType : getRefType(getNoneType()); 128 return create<fir::ZeroOp>(loc, ty); 129 } 130 131 mlir::Value fir::FirOpBuilder::createIntegerConstant(mlir::Location loc, 132 mlir::Type ty, 133 std::int64_t cst) { 134 assert((cst >= 0 || mlir::isa<mlir::IndexType>(ty) || 135 mlir::cast<mlir::IntegerType>(ty).getWidth() <= 64) && 136 "must use APint"); 137 return create<mlir::arith::ConstantOp>(loc, ty, getIntegerAttr(ty, cst)); 138 } 139 140 mlir::Value fir::FirOpBuilder::createAllOnesInteger(mlir::Location loc, 141 mlir::Type ty) { 142 if (mlir::isa<mlir::IndexType>(ty)) 143 return createIntegerConstant(loc, ty, -1); 144 llvm::APInt allOnes = 145 llvm::APInt::getAllOnes(mlir::cast<mlir::IntegerType>(ty).getWidth()); 146 return create<mlir::arith::ConstantOp>(loc, ty, getIntegerAttr(ty, allOnes)); 147 } 148 149 mlir::Value 150 fir::FirOpBuilder::createRealConstant(mlir::Location loc, mlir::Type fltTy, 151 llvm::APFloat::integerPart val) { 152 auto apf = [&]() -> llvm::APFloat { 153 if (fltTy.isF16()) 154 return llvm::APFloat(llvm::APFloat::IEEEhalf(), val); 155 if (fltTy.isBF16()) 156 return llvm::APFloat(llvm::APFloat::BFloat(), val); 157 if (fltTy.isF32()) 158 return llvm::APFloat(llvm::APFloat::IEEEsingle(), val); 159 if (fltTy.isF64()) 160 return llvm::APFloat(llvm::APFloat::IEEEdouble(), val); 161 if (fltTy.isF80()) 162 return llvm::APFloat(llvm::APFloat::x87DoubleExtended(), val); 163 if (fltTy.isF128()) 164 return llvm::APFloat(llvm::APFloat::IEEEquad(), val); 165 llvm_unreachable("unhandled MLIR floating-point type"); 166 }; 167 return createRealConstant(loc, fltTy, apf()); 168 } 169 170 mlir::Value fir::FirOpBuilder::createRealConstant(mlir::Location loc, 171 mlir::Type fltTy, 172 const llvm::APFloat &value) { 173 if (mlir::isa<mlir::FloatType>(fltTy)) { 174 auto attr = getFloatAttr(fltTy, value); 175 return create<mlir::arith::ConstantOp>(loc, fltTy, attr); 176 } 177 llvm_unreachable("should use builtin floating-point type"); 178 } 179 180 llvm::SmallVector<mlir::Value> 181 fir::factory::elideExtentsAlreadyInType(mlir::Type type, 182 mlir::ValueRange shape) { 183 auto arrTy = mlir::dyn_cast<fir::SequenceType>(type); 184 if (shape.empty() || !arrTy) 185 return {}; 186 // elide the constant dimensions before construction 187 assert(shape.size() == arrTy.getDimension()); 188 llvm::SmallVector<mlir::Value> dynamicShape; 189 auto typeShape = arrTy.getShape(); 190 for (unsigned i = 0, end = arrTy.getDimension(); i < end; ++i) 191 if (typeShape[i] == fir::SequenceType::getUnknownExtent()) 192 dynamicShape.push_back(shape[i]); 193 return dynamicShape; 194 } 195 196 llvm::SmallVector<mlir::Value> 197 fir::factory::elideLengthsAlreadyInType(mlir::Type type, 198 mlir::ValueRange lenParams) { 199 if (lenParams.empty()) 200 return {}; 201 if (auto arrTy = mlir::dyn_cast<fir::SequenceType>(type)) 202 type = arrTy.getEleTy(); 203 if (fir::hasDynamicSize(type)) 204 return lenParams; 205 return {}; 206 } 207 208 /// Allocate a local variable. 209 /// A local variable ought to have a name in the source code. 210 mlir::Value fir::FirOpBuilder::allocateLocal( 211 mlir::Location loc, mlir::Type ty, llvm::StringRef uniqName, 212 llvm::StringRef name, bool pinned, llvm::ArrayRef<mlir::Value> shape, 213 llvm::ArrayRef<mlir::Value> lenParams, bool asTarget) { 214 // Convert the shape extents to `index`, as needed. 215 llvm::SmallVector<mlir::Value> indices; 216 llvm::SmallVector<mlir::Value> elidedShape = 217 fir::factory::elideExtentsAlreadyInType(ty, shape); 218 llvm::SmallVector<mlir::Value> elidedLenParams = 219 fir::factory::elideLengthsAlreadyInType(ty, lenParams); 220 auto idxTy = getIndexType(); 221 for (mlir::Value sh : elidedShape) 222 indices.push_back(createConvert(loc, idxTy, sh)); 223 // Add a target attribute, if needed. 224 llvm::SmallVector<mlir::NamedAttribute> attrs; 225 if (asTarget) 226 attrs.emplace_back( 227 mlir::StringAttr::get(getContext(), fir::getTargetAttrName()), 228 getUnitAttr()); 229 // Create the local variable. 230 if (name.empty()) { 231 if (uniqName.empty()) 232 return create<fir::AllocaOp>(loc, ty, pinned, elidedLenParams, indices, 233 attrs); 234 return create<fir::AllocaOp>(loc, ty, uniqName, pinned, elidedLenParams, 235 indices, attrs); 236 } 237 return create<fir::AllocaOp>(loc, ty, uniqName, name, pinned, elidedLenParams, 238 indices, attrs); 239 } 240 241 mlir::Value fir::FirOpBuilder::allocateLocal( 242 mlir::Location loc, mlir::Type ty, llvm::StringRef uniqName, 243 llvm::StringRef name, llvm::ArrayRef<mlir::Value> shape, 244 llvm::ArrayRef<mlir::Value> lenParams, bool asTarget) { 245 return allocateLocal(loc, ty, uniqName, name, /*pinned=*/false, shape, 246 lenParams, asTarget); 247 } 248 249 /// Get the block for adding Allocas. 250 mlir::Block *fir::FirOpBuilder::getAllocaBlock() { 251 if (auto accComputeRegionIface = 252 getRegion().getParentOfType<mlir::acc::ComputeRegionOpInterface>()) { 253 return accComputeRegionIface.getAllocaBlock(); 254 } 255 256 if (auto ompOutlineableIface = 257 getRegion() 258 .getParentOfType<mlir::omp::OutlineableOpenMPOpInterface>()) { 259 return ompOutlineableIface.getAllocaBlock(); 260 } 261 262 if (auto recipeIface = 263 getRegion().getParentOfType<mlir::accomp::RecipeInterface>()) { 264 return recipeIface.getAllocaBlock(getRegion()); 265 } 266 267 return getEntryBlock(); 268 } 269 270 static mlir::ArrayAttr makeI64ArrayAttr(llvm::ArrayRef<int64_t> values, 271 mlir::MLIRContext *context) { 272 llvm::SmallVector<mlir::Attribute, 4> attrs; 273 attrs.reserve(values.size()); 274 for (auto &v : values) 275 attrs.push_back(mlir::IntegerAttr::get(mlir::IntegerType::get(context, 64), 276 mlir::APInt(64, v))); 277 return mlir::ArrayAttr::get(context, attrs); 278 } 279 280 mlir::ArrayAttr fir::FirOpBuilder::create2DI64ArrayAttr( 281 llvm::SmallVectorImpl<llvm::SmallVector<int64_t>> &intData) { 282 llvm::SmallVector<mlir::Attribute> arrayAttr; 283 arrayAttr.reserve(intData.size()); 284 mlir::MLIRContext *context = getContext(); 285 for (auto &v : intData) 286 arrayAttr.push_back(makeI64ArrayAttr(v, context)); 287 return mlir::ArrayAttr::get(context, arrayAttr); 288 } 289 290 mlir::Value fir::FirOpBuilder::createTemporaryAlloc( 291 mlir::Location loc, mlir::Type type, llvm::StringRef name, 292 mlir::ValueRange lenParams, mlir::ValueRange shape, 293 llvm::ArrayRef<mlir::NamedAttribute> attrs, 294 std::optional<Fortran::common::CUDADataAttr> cudaAttr) { 295 assert(!mlir::isa<fir::ReferenceType>(type) && "cannot be a reference"); 296 // If the alloca is inside an OpenMP Op which will be outlined then pin 297 // the alloca here. 298 const bool pinned = 299 getRegion().getParentOfType<mlir::omp::OutlineableOpenMPOpInterface>(); 300 if (cudaAttr) { 301 cuf::DataAttributeAttr attr = cuf::getDataAttribute(getContext(), cudaAttr); 302 return create<cuf::AllocOp>(loc, type, /*unique_name=*/llvm::StringRef{}, 303 name, attr, lenParams, shape, attrs); 304 } else { 305 return create<fir::AllocaOp>(loc, type, /*unique_name=*/llvm::StringRef{}, 306 name, pinned, lenParams, shape, attrs); 307 } 308 } 309 310 /// Create a temporary variable on the stack. Anonymous temporaries have no 311 /// `name` value. Temporaries do not require a uniqued name. 312 mlir::Value fir::FirOpBuilder::createTemporary( 313 mlir::Location loc, mlir::Type type, llvm::StringRef name, 314 mlir::ValueRange shape, mlir::ValueRange lenParams, 315 llvm::ArrayRef<mlir::NamedAttribute> attrs, 316 std::optional<Fortran::common::CUDADataAttr> cudaAttr) { 317 llvm::SmallVector<mlir::Value> dynamicShape = 318 fir::factory::elideExtentsAlreadyInType(type, shape); 319 llvm::SmallVector<mlir::Value> dynamicLength = 320 fir::factory::elideLengthsAlreadyInType(type, lenParams); 321 InsertPoint insPt; 322 const bool hoistAlloc = dynamicShape.empty() && dynamicLength.empty(); 323 if (hoistAlloc) { 324 insPt = saveInsertionPoint(); 325 setInsertionPointToStart(getAllocaBlock()); 326 } 327 328 mlir::Value ae = createTemporaryAlloc(loc, type, name, dynamicLength, 329 dynamicShape, attrs, cudaAttr); 330 331 if (hoistAlloc) 332 restoreInsertionPoint(insPt); 333 return ae; 334 } 335 336 mlir::Value fir::FirOpBuilder::createHeapTemporary( 337 mlir::Location loc, mlir::Type type, llvm::StringRef name, 338 mlir::ValueRange shape, mlir::ValueRange lenParams, 339 llvm::ArrayRef<mlir::NamedAttribute> attrs) { 340 llvm::SmallVector<mlir::Value> dynamicShape = 341 fir::factory::elideExtentsAlreadyInType(type, shape); 342 llvm::SmallVector<mlir::Value> dynamicLength = 343 fir::factory::elideLengthsAlreadyInType(type, lenParams); 344 345 assert(!mlir::isa<fir::ReferenceType>(type) && "cannot be a reference"); 346 return create<fir::AllocMemOp>(loc, type, /*unique_name=*/llvm::StringRef{}, 347 name, dynamicLength, dynamicShape, attrs); 348 } 349 350 mlir::Value fir::FirOpBuilder::genStackSave(mlir::Location loc) { 351 mlir::Type voidPtr = mlir::LLVM::LLVMPointerType::get( 352 getContext(), fir::factory::getAllocaAddressSpace(&getDataLayout())); 353 return create<mlir::LLVM::StackSaveOp>(loc, voidPtr); 354 } 355 356 void fir::FirOpBuilder::genStackRestore(mlir::Location loc, 357 mlir::Value stackPointer) { 358 create<mlir::LLVM::StackRestoreOp>(loc, stackPointer); 359 } 360 361 /// Create a global variable in the (read-only) data section. A global variable 362 /// must have a unique name to identify and reference it. 363 fir::GlobalOp fir::FirOpBuilder::createGlobal( 364 mlir::Location loc, mlir::Type type, llvm::StringRef name, 365 mlir::StringAttr linkage, mlir::Attribute value, bool isConst, 366 bool isTarget, cuf::DataAttributeAttr dataAttr) { 367 if (auto global = getNamedGlobal(name)) 368 return global; 369 auto module = getModule(); 370 auto insertPt = saveInsertionPoint(); 371 setInsertionPoint(module.getBody(), module.getBody()->end()); 372 llvm::SmallVector<mlir::NamedAttribute> attrs; 373 if (dataAttr) { 374 auto globalOpName = mlir::OperationName(fir::GlobalOp::getOperationName(), 375 module.getContext()); 376 attrs.push_back(mlir::NamedAttribute( 377 fir::GlobalOp::getDataAttrAttrName(globalOpName), dataAttr)); 378 } 379 auto glob = create<fir::GlobalOp>(loc, name, isConst, isTarget, type, value, 380 linkage, attrs); 381 restoreInsertionPoint(insertPt); 382 if (symbolTable) 383 symbolTable->insert(glob); 384 return glob; 385 } 386 387 fir::GlobalOp fir::FirOpBuilder::createGlobal( 388 mlir::Location loc, mlir::Type type, llvm::StringRef name, bool isConst, 389 bool isTarget, std::function<void(FirOpBuilder &)> bodyBuilder, 390 mlir::StringAttr linkage, cuf::DataAttributeAttr dataAttr) { 391 if (auto global = getNamedGlobal(name)) 392 return global; 393 auto module = getModule(); 394 auto insertPt = saveInsertionPoint(); 395 setInsertionPoint(module.getBody(), module.getBody()->end()); 396 auto glob = create<fir::GlobalOp>(loc, name, isConst, isTarget, type, 397 mlir::Attribute{}, linkage); 398 auto ®ion = glob.getRegion(); 399 region.push_back(new mlir::Block); 400 auto &block = glob.getRegion().back(); 401 setInsertionPointToStart(&block); 402 bodyBuilder(*this); 403 restoreInsertionPoint(insertPt); 404 if (symbolTable) 405 symbolTable->insert(glob); 406 return glob; 407 } 408 409 std::pair<fir::TypeInfoOp, mlir::OpBuilder::InsertPoint> 410 fir::FirOpBuilder::createTypeInfoOp(mlir::Location loc, 411 fir::RecordType recordType, 412 fir::RecordType parentType) { 413 mlir::ModuleOp module = getModule(); 414 if (fir::TypeInfoOp typeInfo = 415 fir::lookupTypeInfoOp(recordType.getName(), module, symbolTable)) 416 return {typeInfo, InsertPoint{}}; 417 InsertPoint insertPoint = saveInsertionPoint(); 418 setInsertionPoint(module.getBody(), module.getBody()->end()); 419 auto typeInfo = create<fir::TypeInfoOp>(loc, recordType, parentType); 420 if (symbolTable) 421 symbolTable->insert(typeInfo); 422 return {typeInfo, insertPoint}; 423 } 424 425 mlir::Value fir::FirOpBuilder::convertWithSemantics( 426 mlir::Location loc, mlir::Type toTy, mlir::Value val, 427 bool allowCharacterConversion, bool allowRebox) { 428 assert(toTy && "store location must be typed"); 429 auto fromTy = val.getType(); 430 if (fromTy == toTy) 431 return val; 432 fir::factory::Complex helper{*this, loc}; 433 if ((fir::isa_real(fromTy) || fir::isa_integer(fromTy)) && 434 fir::isa_complex(toTy)) { 435 // imaginary part is zero 436 auto eleTy = helper.getComplexPartType(toTy); 437 auto cast = createConvert(loc, eleTy, val); 438 auto imag = createRealZeroConstant(loc, eleTy); 439 return helper.createComplex(toTy, cast, imag); 440 } 441 if (fir::isa_complex(fromTy) && 442 (fir::isa_integer(toTy) || fir::isa_real(toTy))) { 443 // drop the imaginary part 444 auto rp = helper.extractComplexPart(val, /*isImagPart=*/false); 445 return createConvert(loc, toTy, rp); 446 } 447 if (allowCharacterConversion) { 448 if (mlir::isa<fir::BoxCharType>(fromTy)) { 449 // Extract the address of the character string and pass it 450 fir::factory::CharacterExprHelper charHelper{*this, loc}; 451 std::pair<mlir::Value, mlir::Value> unboxchar = 452 charHelper.createUnboxChar(val); 453 return createConvert(loc, toTy, unboxchar.first); 454 } 455 if (auto boxType = mlir::dyn_cast<fir::BoxCharType>(toTy)) { 456 // Extract the address of the actual argument and create a boxed 457 // character value with an undefined length 458 // TODO: We should really calculate the total size of the actual 459 // argument in characters and use it as the length of the string 460 auto refType = getRefType(boxType.getEleTy()); 461 mlir::Value charBase = createConvert(loc, refType, val); 462 // Do not use fir.undef since llvm optimizer is too harsh when it 463 // sees such values (may just delete code). 464 mlir::Value unknownLen = createIntegerConstant(loc, getIndexType(), 0); 465 fir::factory::CharacterExprHelper charHelper{*this, loc}; 466 return charHelper.createEmboxChar(charBase, unknownLen); 467 } 468 } 469 if (fir::isa_ref_type(toTy) && fir::isa_box_type(fromTy)) { 470 // Call is expecting a raw data pointer, not a box. Get the data pointer out 471 // of the box and pass that. 472 assert((fir::unwrapRefType(toTy) == 473 fir::unwrapRefType(fir::unwrapPassByRefType(fromTy)) && 474 "element types expected to match")); 475 return create<fir::BoxAddrOp>(loc, toTy, val); 476 } 477 if (fir::isa_ref_type(fromTy) && mlir::isa<fir::BoxProcType>(toTy)) { 478 // Call is expecting a boxed procedure, not a reference to other data type. 479 // Convert the reference to a procedure and embox it. 480 mlir::Type procTy = mlir::cast<fir::BoxProcType>(toTy).getEleTy(); 481 mlir::Value proc = createConvert(loc, procTy, val); 482 return create<fir::EmboxProcOp>(loc, toTy, proc); 483 } 484 485 // Legacy: remove when removing non HLFIR lowering path. 486 if (allowRebox) 487 if (((fir::isPolymorphicType(fromTy) && 488 (fir::isAllocatableType(fromTy) || fir::isPointerType(fromTy)) && 489 fir::isPolymorphicType(toTy)) || 490 (fir::isPolymorphicType(fromTy) && mlir::isa<fir::BoxType>(toTy))) && 491 !(fir::isUnlimitedPolymorphicType(fromTy) && fir::isAssumedType(toTy))) 492 return create<fir::ReboxOp>(loc, toTy, val, mlir::Value{}, 493 /*slice=*/mlir::Value{}); 494 495 return createConvert(loc, toTy, val); 496 } 497 498 mlir::Value fir::factory::createConvert(mlir::OpBuilder &builder, 499 mlir::Location loc, mlir::Type toTy, 500 mlir::Value val) { 501 if (val.getType() != toTy) { 502 assert((!fir::isa_derived(toTy) || 503 mlir::cast<fir::RecordType>(val.getType()).getTypeList() == 504 mlir::cast<fir::RecordType>(toTy).getTypeList()) && 505 "incompatible record types"); 506 return builder.create<fir::ConvertOp>(loc, toTy, val); 507 } 508 return val; 509 } 510 511 mlir::Value fir::FirOpBuilder::createConvert(mlir::Location loc, 512 mlir::Type toTy, mlir::Value val) { 513 return fir::factory::createConvert(*this, loc, toTy, val); 514 } 515 516 void fir::FirOpBuilder::createStoreWithConvert(mlir::Location loc, 517 mlir::Value val, 518 mlir::Value addr) { 519 mlir::Value cast = 520 createConvert(loc, fir::unwrapRefType(addr.getType()), val); 521 create<fir::StoreOp>(loc, cast, addr); 522 } 523 524 mlir::Value fir::FirOpBuilder::loadIfRef(mlir::Location loc, mlir::Value val) { 525 if (fir::isa_ref_type(val.getType())) 526 return create<fir::LoadOp>(loc, val); 527 return val; 528 } 529 530 fir::StringLitOp fir::FirOpBuilder::createStringLitOp(mlir::Location loc, 531 llvm::StringRef data) { 532 auto type = fir::CharacterType::get(getContext(), 1, data.size()); 533 auto strAttr = mlir::StringAttr::get(getContext(), data); 534 auto valTag = mlir::StringAttr::get(getContext(), fir::StringLitOp::value()); 535 mlir::NamedAttribute dataAttr(valTag, strAttr); 536 auto sizeTag = mlir::StringAttr::get(getContext(), fir::StringLitOp::size()); 537 mlir::NamedAttribute sizeAttr(sizeTag, getI64IntegerAttr(data.size())); 538 llvm::SmallVector<mlir::NamedAttribute> attrs{dataAttr, sizeAttr}; 539 return create<fir::StringLitOp>(loc, llvm::ArrayRef<mlir::Type>{type}, 540 std::nullopt, attrs); 541 } 542 543 mlir::Value fir::FirOpBuilder::genShape(mlir::Location loc, 544 llvm::ArrayRef<mlir::Value> exts) { 545 return create<fir::ShapeOp>(loc, exts); 546 } 547 548 mlir::Value fir::FirOpBuilder::genShape(mlir::Location loc, 549 llvm::ArrayRef<mlir::Value> shift, 550 llvm::ArrayRef<mlir::Value> exts) { 551 auto shapeType = fir::ShapeShiftType::get(getContext(), exts.size()); 552 llvm::SmallVector<mlir::Value> shapeArgs; 553 auto idxTy = getIndexType(); 554 for (auto [lbnd, ext] : llvm::zip(shift, exts)) { 555 auto lb = createConvert(loc, idxTy, lbnd); 556 shapeArgs.push_back(lb); 557 shapeArgs.push_back(ext); 558 } 559 return create<fir::ShapeShiftOp>(loc, shapeType, shapeArgs); 560 } 561 562 mlir::Value fir::FirOpBuilder::genShape(mlir::Location loc, 563 const fir::AbstractArrayBox &arr) { 564 if (arr.lboundsAllOne()) 565 return genShape(loc, arr.getExtents()); 566 return genShape(loc, arr.getLBounds(), arr.getExtents()); 567 } 568 569 mlir::Value fir::FirOpBuilder::genShift(mlir::Location loc, 570 llvm::ArrayRef<mlir::Value> shift) { 571 auto shiftType = fir::ShiftType::get(getContext(), shift.size()); 572 return create<fir::ShiftOp>(loc, shiftType, shift); 573 } 574 575 mlir::Value fir::FirOpBuilder::createShape(mlir::Location loc, 576 const fir::ExtendedValue &exv) { 577 return exv.match( 578 [&](const fir::ArrayBoxValue &box) { return genShape(loc, box); }, 579 [&](const fir::CharArrayBoxValue &box) { return genShape(loc, box); }, 580 [&](const fir::BoxValue &box) -> mlir::Value { 581 if (!box.getLBounds().empty()) { 582 auto shiftType = 583 fir::ShiftType::get(getContext(), box.getLBounds().size()); 584 return create<fir::ShiftOp>(loc, shiftType, box.getLBounds()); 585 } 586 return {}; 587 }, 588 [&](const fir::MutableBoxValue &) -> mlir::Value { 589 // MutableBoxValue must be read into another category to work with them 590 // outside of allocation/assignment contexts. 591 fir::emitFatalError(loc, "createShape on MutableBoxValue"); 592 }, 593 [&](auto) -> mlir::Value { fir::emitFatalError(loc, "not an array"); }); 594 } 595 596 mlir::Value fir::FirOpBuilder::createSlice(mlir::Location loc, 597 const fir::ExtendedValue &exv, 598 mlir::ValueRange triples, 599 mlir::ValueRange path) { 600 if (triples.empty()) { 601 // If there is no slicing by triple notation, then take the whole array. 602 auto fullShape = [&](const llvm::ArrayRef<mlir::Value> lbounds, 603 llvm::ArrayRef<mlir::Value> extents) -> mlir::Value { 604 llvm::SmallVector<mlir::Value> trips; 605 auto idxTy = getIndexType(); 606 auto one = createIntegerConstant(loc, idxTy, 1); 607 if (lbounds.empty()) { 608 for (auto v : extents) { 609 trips.push_back(one); 610 trips.push_back(v); 611 trips.push_back(one); 612 } 613 return create<fir::SliceOp>(loc, trips, path); 614 } 615 for (auto [lbnd, extent] : llvm::zip(lbounds, extents)) { 616 auto lb = createConvert(loc, idxTy, lbnd); 617 auto ext = createConvert(loc, idxTy, extent); 618 auto shift = create<mlir::arith::SubIOp>(loc, lb, one); 619 auto ub = create<mlir::arith::AddIOp>(loc, ext, shift); 620 trips.push_back(lb); 621 trips.push_back(ub); 622 trips.push_back(one); 623 } 624 return create<fir::SliceOp>(loc, trips, path); 625 }; 626 return exv.match( 627 [&](const fir::ArrayBoxValue &box) { 628 return fullShape(box.getLBounds(), box.getExtents()); 629 }, 630 [&](const fir::CharArrayBoxValue &box) { 631 return fullShape(box.getLBounds(), box.getExtents()); 632 }, 633 [&](const fir::BoxValue &box) { 634 auto extents = fir::factory::readExtents(*this, loc, box); 635 return fullShape(box.getLBounds(), extents); 636 }, 637 [&](const fir::MutableBoxValue &) -> mlir::Value { 638 // MutableBoxValue must be read into another category to work with 639 // them outside of allocation/assignment contexts. 640 fir::emitFatalError(loc, "createSlice on MutableBoxValue"); 641 }, 642 [&](auto) -> mlir::Value { fir::emitFatalError(loc, "not an array"); }); 643 } 644 return create<fir::SliceOp>(loc, triples, path); 645 } 646 647 mlir::Value fir::FirOpBuilder::createBox(mlir::Location loc, 648 const fir::ExtendedValue &exv, 649 bool isPolymorphic, 650 bool isAssumedType) { 651 mlir::Value itemAddr = fir::getBase(exv); 652 if (mlir::isa<fir::BaseBoxType>(itemAddr.getType())) 653 return itemAddr; 654 auto elementType = fir::dyn_cast_ptrEleTy(itemAddr.getType()); 655 if (!elementType) { 656 mlir::emitError(loc, "internal: expected a memory reference type ") 657 << itemAddr.getType(); 658 llvm_unreachable("not a memory reference type"); 659 } 660 mlir::Type boxTy; 661 mlir::Value tdesc; 662 // Avoid to wrap a box/class with box/class. 663 if (mlir::isa<fir::BaseBoxType>(elementType)) { 664 boxTy = elementType; 665 } else { 666 boxTy = fir::BoxType::get(elementType); 667 if (isPolymorphic) { 668 elementType = fir::updateTypeForUnlimitedPolymorphic(elementType); 669 if (isAssumedType) 670 boxTy = fir::BoxType::get(elementType); 671 else 672 boxTy = fir::ClassType::get(elementType); 673 } 674 } 675 676 return exv.match( 677 [&](const fir::ArrayBoxValue &box) -> mlir::Value { 678 mlir::Value empty; 679 mlir::ValueRange emptyRange; 680 mlir::Value s = createShape(loc, exv); 681 return create<fir::EmboxOp>(loc, boxTy, itemAddr, s, /*slice=*/empty, 682 /*typeparams=*/emptyRange, 683 isPolymorphic ? box.getSourceBox() : tdesc); 684 }, 685 [&](const fir::CharArrayBoxValue &box) -> mlir::Value { 686 mlir::Value s = createShape(loc, exv); 687 if (fir::factory::CharacterExprHelper::hasConstantLengthInType(exv)) 688 return create<fir::EmboxOp>(loc, boxTy, itemAddr, s); 689 690 mlir::Value emptySlice; 691 llvm::SmallVector<mlir::Value> lenParams{box.getLen()}; 692 return create<fir::EmboxOp>(loc, boxTy, itemAddr, s, emptySlice, 693 lenParams); 694 }, 695 [&](const fir::CharBoxValue &box) -> mlir::Value { 696 if (fir::factory::CharacterExprHelper::hasConstantLengthInType(exv)) 697 return create<fir::EmboxOp>(loc, boxTy, itemAddr); 698 mlir::Value emptyShape, emptySlice; 699 llvm::SmallVector<mlir::Value> lenParams{box.getLen()}; 700 return create<fir::EmboxOp>(loc, boxTy, itemAddr, emptyShape, 701 emptySlice, lenParams); 702 }, 703 [&](const fir::MutableBoxValue &x) -> mlir::Value { 704 return create<fir::LoadOp>( 705 loc, fir::factory::getMutableIRBox(*this, loc, x)); 706 }, 707 [&](const fir::PolymorphicValue &p) -> mlir::Value { 708 mlir::Value empty; 709 mlir::ValueRange emptyRange; 710 return create<fir::EmboxOp>(loc, boxTy, itemAddr, empty, empty, 711 emptyRange, 712 isPolymorphic ? p.getSourceBox() : tdesc); 713 }, 714 [&](const auto &) -> mlir::Value { 715 mlir::Value empty; 716 mlir::ValueRange emptyRange; 717 return create<fir::EmboxOp>(loc, boxTy, itemAddr, empty, empty, 718 emptyRange, tdesc); 719 }); 720 } 721 722 mlir::Value fir::FirOpBuilder::createBox(mlir::Location loc, mlir::Type boxType, 723 mlir::Value addr, mlir::Value shape, 724 mlir::Value slice, 725 llvm::ArrayRef<mlir::Value> lengths, 726 mlir::Value tdesc) { 727 mlir::Type valueOrSequenceType = fir::unwrapPassByRefType(boxType); 728 return create<fir::EmboxOp>( 729 loc, boxType, addr, shape, slice, 730 fir::factory::elideLengthsAlreadyInType(valueOrSequenceType, lengths), 731 tdesc); 732 } 733 734 void fir::FirOpBuilder::dumpFunc() { getFunction().dump(); } 735 736 static mlir::Value 737 genNullPointerComparison(fir::FirOpBuilder &builder, mlir::Location loc, 738 mlir::Value addr, 739 mlir::arith::CmpIPredicate condition) { 740 auto intPtrTy = builder.getIntPtrType(); 741 auto ptrToInt = builder.createConvert(loc, intPtrTy, addr); 742 auto c0 = builder.createIntegerConstant(loc, intPtrTy, 0); 743 return builder.create<mlir::arith::CmpIOp>(loc, condition, ptrToInt, c0); 744 } 745 746 mlir::Value fir::FirOpBuilder::genIsNotNullAddr(mlir::Location loc, 747 mlir::Value addr) { 748 return genNullPointerComparison(*this, loc, addr, 749 mlir::arith::CmpIPredicate::ne); 750 } 751 752 mlir::Value fir::FirOpBuilder::genIsNullAddr(mlir::Location loc, 753 mlir::Value addr) { 754 return genNullPointerComparison(*this, loc, addr, 755 mlir::arith::CmpIPredicate::eq); 756 } 757 758 mlir::Value fir::FirOpBuilder::genExtentFromTriplet(mlir::Location loc, 759 mlir::Value lb, 760 mlir::Value ub, 761 mlir::Value step, 762 mlir::Type type) { 763 auto zero = createIntegerConstant(loc, type, 0); 764 lb = createConvert(loc, type, lb); 765 ub = createConvert(loc, type, ub); 766 step = createConvert(loc, type, step); 767 auto diff = create<mlir::arith::SubIOp>(loc, ub, lb); 768 auto add = create<mlir::arith::AddIOp>(loc, diff, step); 769 auto div = create<mlir::arith::DivSIOp>(loc, add, step); 770 auto cmp = create<mlir::arith::CmpIOp>(loc, mlir::arith::CmpIPredicate::sgt, 771 div, zero); 772 return create<mlir::arith::SelectOp>(loc, cmp, div, zero); 773 } 774 775 mlir::Value fir::FirOpBuilder::genAbsentOp(mlir::Location loc, 776 mlir::Type argTy) { 777 if (!fir::isCharacterProcedureTuple(argTy)) 778 return create<fir::AbsentOp>(loc, argTy); 779 780 auto boxProc = 781 create<fir::AbsentOp>(loc, mlir::cast<mlir::TupleType>(argTy).getType(0)); 782 mlir::Value charLen = create<fir::UndefOp>(loc, getCharacterLengthType()); 783 return fir::factory::createCharacterProcedureTuple(*this, loc, argTy, boxProc, 784 charLen); 785 } 786 787 void fir::FirOpBuilder::setCommonAttributes(mlir::Operation *op) const { 788 auto fmi = mlir::dyn_cast<mlir::arith::ArithFastMathInterface>(*op); 789 if (fmi) { 790 // TODO: use fmi.setFastMathFlagsAttr() after D137114 is merged. 791 // For now set the attribute by the name. 792 llvm::StringRef arithFMFAttrName = fmi.getFastMathAttrName(); 793 if (fastMathFlags != mlir::arith::FastMathFlags::none) 794 op->setAttr(arithFMFAttrName, mlir::arith::FastMathFlagsAttr::get( 795 op->getContext(), fastMathFlags)); 796 } 797 auto iofi = 798 mlir::dyn_cast<mlir::arith::ArithIntegerOverflowFlagsInterface>(*op); 799 if (iofi) { 800 llvm::StringRef arithIOFAttrName = iofi.getIntegerOverflowAttrName(); 801 if (integerOverflowFlags != mlir::arith::IntegerOverflowFlags::none) 802 op->setAttr(arithIOFAttrName, 803 mlir::arith::IntegerOverflowFlagsAttr::get( 804 op->getContext(), integerOverflowFlags)); 805 } 806 } 807 808 void fir::FirOpBuilder::setFastMathFlags( 809 Fortran::common::MathOptionsBase options) { 810 mlir::arith::FastMathFlags arithFMF{}; 811 if (options.getFPContractEnabled()) { 812 arithFMF = arithFMF | mlir::arith::FastMathFlags::contract; 813 } 814 if (options.getNoHonorInfs()) { 815 arithFMF = arithFMF | mlir::arith::FastMathFlags::ninf; 816 } 817 if (options.getNoHonorNaNs()) { 818 arithFMF = arithFMF | mlir::arith::FastMathFlags::nnan; 819 } 820 if (options.getApproxFunc()) { 821 arithFMF = arithFMF | mlir::arith::FastMathFlags::afn; 822 } 823 if (options.getNoSignedZeros()) { 824 arithFMF = arithFMF | mlir::arith::FastMathFlags::nsz; 825 } 826 if (options.getAssociativeMath()) { 827 arithFMF = arithFMF | mlir::arith::FastMathFlags::reassoc; 828 } 829 if (options.getReciprocalMath()) { 830 arithFMF = arithFMF | mlir::arith::FastMathFlags::arcp; 831 } 832 setFastMathFlags(arithFMF); 833 } 834 835 // Construction of an mlir::DataLayout is expensive so only do it on demand and 836 // memoise it in the builder instance 837 mlir::DataLayout &fir::FirOpBuilder::getDataLayout() { 838 if (dataLayout) 839 return *dataLayout; 840 dataLayout = std::make_unique<mlir::DataLayout>(getModule()); 841 return *dataLayout; 842 } 843 844 //===--------------------------------------------------------------------===// 845 // ExtendedValue inquiry helper implementation 846 //===--------------------------------------------------------------------===// 847 848 mlir::Value fir::factory::readCharLen(fir::FirOpBuilder &builder, 849 mlir::Location loc, 850 const fir::ExtendedValue &box) { 851 return box.match( 852 [&](const fir::CharBoxValue &x) -> mlir::Value { return x.getLen(); }, 853 [&](const fir::CharArrayBoxValue &x) -> mlir::Value { 854 return x.getLen(); 855 }, 856 [&](const fir::BoxValue &x) -> mlir::Value { 857 assert(x.isCharacter()); 858 if (!x.getExplicitParameters().empty()) 859 return x.getExplicitParameters()[0]; 860 return fir::factory::CharacterExprHelper{builder, loc} 861 .readLengthFromBox(x.getAddr()); 862 }, 863 [&](const fir::MutableBoxValue &x) -> mlir::Value { 864 return readCharLen(builder, loc, 865 fir::factory::genMutableBoxRead(builder, loc, x)); 866 }, 867 [&](const auto &) -> mlir::Value { 868 fir::emitFatalError( 869 loc, "Character length inquiry on a non-character entity"); 870 }); 871 } 872 873 mlir::Value fir::factory::readExtent(fir::FirOpBuilder &builder, 874 mlir::Location loc, 875 const fir::ExtendedValue &box, 876 unsigned dim) { 877 assert(box.rank() > dim); 878 return box.match( 879 [&](const fir::ArrayBoxValue &x) -> mlir::Value { 880 return x.getExtents()[dim]; 881 }, 882 [&](const fir::CharArrayBoxValue &x) -> mlir::Value { 883 return x.getExtents()[dim]; 884 }, 885 [&](const fir::BoxValue &x) -> mlir::Value { 886 if (!x.getExplicitExtents().empty()) 887 return x.getExplicitExtents()[dim]; 888 auto idxTy = builder.getIndexType(); 889 auto dimVal = builder.createIntegerConstant(loc, idxTy, dim); 890 return builder 891 .create<fir::BoxDimsOp>(loc, idxTy, idxTy, idxTy, x.getAddr(), 892 dimVal) 893 .getResult(1); 894 }, 895 [&](const fir::MutableBoxValue &x) -> mlir::Value { 896 return readExtent(builder, loc, 897 fir::factory::genMutableBoxRead(builder, loc, x), 898 dim); 899 }, 900 [&](const auto &) -> mlir::Value { 901 fir::emitFatalError(loc, "extent inquiry on scalar"); 902 }); 903 } 904 905 mlir::Value fir::factory::readLowerBound(fir::FirOpBuilder &builder, 906 mlir::Location loc, 907 const fir::ExtendedValue &box, 908 unsigned dim, 909 mlir::Value defaultValue) { 910 assert(box.rank() > dim); 911 auto lb = box.match( 912 [&](const fir::ArrayBoxValue &x) -> mlir::Value { 913 return x.getLBounds().empty() ? mlir::Value{} : x.getLBounds()[dim]; 914 }, 915 [&](const fir::CharArrayBoxValue &x) -> mlir::Value { 916 return x.getLBounds().empty() ? mlir::Value{} : x.getLBounds()[dim]; 917 }, 918 [&](const fir::BoxValue &x) -> mlir::Value { 919 return x.getLBounds().empty() ? mlir::Value{} : x.getLBounds()[dim]; 920 }, 921 [&](const fir::MutableBoxValue &x) -> mlir::Value { 922 return readLowerBound(builder, loc, 923 fir::factory::genMutableBoxRead(builder, loc, x), 924 dim, defaultValue); 925 }, 926 [&](const auto &) -> mlir::Value { 927 fir::emitFatalError(loc, "lower bound inquiry on scalar"); 928 }); 929 if (lb) 930 return lb; 931 return defaultValue; 932 } 933 934 llvm::SmallVector<mlir::Value> 935 fir::factory::readExtents(fir::FirOpBuilder &builder, mlir::Location loc, 936 const fir::BoxValue &box) { 937 llvm::SmallVector<mlir::Value> result; 938 auto explicitExtents = box.getExplicitExtents(); 939 if (!explicitExtents.empty()) { 940 result.append(explicitExtents.begin(), explicitExtents.end()); 941 return result; 942 } 943 auto rank = box.rank(); 944 auto idxTy = builder.getIndexType(); 945 for (decltype(rank) dim = 0; dim < rank; ++dim) { 946 auto dimVal = builder.createIntegerConstant(loc, idxTy, dim); 947 auto dimInfo = builder.create<fir::BoxDimsOp>(loc, idxTy, idxTy, idxTy, 948 box.getAddr(), dimVal); 949 result.emplace_back(dimInfo.getResult(1)); 950 } 951 return result; 952 } 953 954 llvm::SmallVector<mlir::Value> 955 fir::factory::getExtents(mlir::Location loc, fir::FirOpBuilder &builder, 956 const fir::ExtendedValue &box) { 957 return box.match( 958 [&](const fir::ArrayBoxValue &x) -> llvm::SmallVector<mlir::Value> { 959 return {x.getExtents().begin(), x.getExtents().end()}; 960 }, 961 [&](const fir::CharArrayBoxValue &x) -> llvm::SmallVector<mlir::Value> { 962 return {x.getExtents().begin(), x.getExtents().end()}; 963 }, 964 [&](const fir::BoxValue &x) -> llvm::SmallVector<mlir::Value> { 965 return fir::factory::readExtents(builder, loc, x); 966 }, 967 [&](const fir::MutableBoxValue &x) -> llvm::SmallVector<mlir::Value> { 968 auto load = fir::factory::genMutableBoxRead(builder, loc, x); 969 return fir::factory::getExtents(loc, builder, load); 970 }, 971 [&](const auto &) -> llvm::SmallVector<mlir::Value> { return {}; }); 972 } 973 974 fir::ExtendedValue fir::factory::readBoxValue(fir::FirOpBuilder &builder, 975 mlir::Location loc, 976 const fir::BoxValue &box) { 977 assert(!box.hasAssumedRank() && 978 "cannot read unlimited polymorphic or assumed rank fir.box"); 979 auto addr = 980 builder.create<fir::BoxAddrOp>(loc, box.getMemTy(), box.getAddr()); 981 if (box.isCharacter()) { 982 auto len = fir::factory::readCharLen(builder, loc, box); 983 if (box.rank() == 0) 984 return fir::CharBoxValue(addr, len); 985 return fir::CharArrayBoxValue(addr, len, 986 fir::factory::readExtents(builder, loc, box), 987 box.getLBounds()); 988 } 989 if (box.isDerivedWithLenParameters()) 990 TODO(loc, "read fir.box with length parameters"); 991 mlir::Value sourceBox; 992 if (box.isPolymorphic()) 993 sourceBox = box.getAddr(); 994 if (box.isPolymorphic() && box.rank() == 0) 995 return fir::PolymorphicValue(addr, sourceBox); 996 if (box.rank() == 0) 997 return addr; 998 return fir::ArrayBoxValue(addr, fir::factory::readExtents(builder, loc, box), 999 box.getLBounds(), sourceBox); 1000 } 1001 1002 llvm::SmallVector<mlir::Value> 1003 fir::factory::getNonDefaultLowerBounds(fir::FirOpBuilder &builder, 1004 mlir::Location loc, 1005 const fir::ExtendedValue &exv) { 1006 return exv.match( 1007 [&](const fir::ArrayBoxValue &array) -> llvm::SmallVector<mlir::Value> { 1008 return {array.getLBounds().begin(), array.getLBounds().end()}; 1009 }, 1010 [&](const fir::CharArrayBoxValue &array) 1011 -> llvm::SmallVector<mlir::Value> { 1012 return {array.getLBounds().begin(), array.getLBounds().end()}; 1013 }, 1014 [&](const fir::BoxValue &box) -> llvm::SmallVector<mlir::Value> { 1015 return {box.getLBounds().begin(), box.getLBounds().end()}; 1016 }, 1017 [&](const fir::MutableBoxValue &box) -> llvm::SmallVector<mlir::Value> { 1018 auto load = fir::factory::genMutableBoxRead(builder, loc, box); 1019 return fir::factory::getNonDefaultLowerBounds(builder, loc, load); 1020 }, 1021 [&](const auto &) -> llvm::SmallVector<mlir::Value> { return {}; }); 1022 } 1023 1024 llvm::SmallVector<mlir::Value> 1025 fir::factory::getNonDeferredLenParams(const fir::ExtendedValue &exv) { 1026 return exv.match( 1027 [&](const fir::CharArrayBoxValue &character) 1028 -> llvm::SmallVector<mlir::Value> { return {character.getLen()}; }, 1029 [&](const fir::CharBoxValue &character) 1030 -> llvm::SmallVector<mlir::Value> { return {character.getLen()}; }, 1031 [&](const fir::MutableBoxValue &box) -> llvm::SmallVector<mlir::Value> { 1032 return {box.nonDeferredLenParams().begin(), 1033 box.nonDeferredLenParams().end()}; 1034 }, 1035 [&](const fir::BoxValue &box) -> llvm::SmallVector<mlir::Value> { 1036 return {box.getExplicitParameters().begin(), 1037 box.getExplicitParameters().end()}; 1038 }, 1039 [&](const auto &) -> llvm::SmallVector<mlir::Value> { return {}; }); 1040 } 1041 1042 // If valTy is a box type, then we need to extract the type parameters from 1043 // the box value. 1044 static llvm::SmallVector<mlir::Value> getFromBox(mlir::Location loc, 1045 fir::FirOpBuilder &builder, 1046 mlir::Type valTy, 1047 mlir::Value boxVal) { 1048 if (auto boxTy = mlir::dyn_cast<fir::BaseBoxType>(valTy)) { 1049 auto eleTy = fir::unwrapAllRefAndSeqType(boxTy.getEleTy()); 1050 if (auto recTy = mlir::dyn_cast<fir::RecordType>(eleTy)) { 1051 if (recTy.getNumLenParams() > 0) { 1052 // Walk each type parameter in the record and get the value. 1053 TODO(loc, "generate code to get LEN type parameters"); 1054 } 1055 } else if (auto charTy = mlir::dyn_cast<fir::CharacterType>(eleTy)) { 1056 if (charTy.hasDynamicLen()) { 1057 auto idxTy = builder.getIndexType(); 1058 auto eleSz = builder.create<fir::BoxEleSizeOp>(loc, idxTy, boxVal); 1059 auto kindBytes = 1060 builder.getKindMap().getCharacterBitsize(charTy.getFKind()) / 8; 1061 mlir::Value charSz = 1062 builder.createIntegerConstant(loc, idxTy, kindBytes); 1063 mlir::Value len = 1064 builder.create<mlir::arith::DivSIOp>(loc, eleSz, charSz); 1065 return {len}; 1066 } 1067 } 1068 } 1069 return {}; 1070 } 1071 1072 // fir::getTypeParams() will get the type parameters from the extended value. 1073 // When the extended value is a BoxValue or MutableBoxValue, it may be necessary 1074 // to generate code, so this factory function handles those cases. 1075 // TODO: fix the inverted type tests, etc. 1076 llvm::SmallVector<mlir::Value> 1077 fir::factory::getTypeParams(mlir::Location loc, fir::FirOpBuilder &builder, 1078 const fir::ExtendedValue &exv) { 1079 auto handleBoxed = [&](const auto &box) -> llvm::SmallVector<mlir::Value> { 1080 if (box.isCharacter()) 1081 return {fir::factory::readCharLen(builder, loc, exv)}; 1082 if (box.isDerivedWithLenParameters()) { 1083 // This should generate code to read the type parameters from the box. 1084 // This requires some consideration however as MutableBoxValues need to be 1085 // in a sane state to be provide the correct values. 1086 TODO(loc, "derived type with type parameters"); 1087 } 1088 return {}; 1089 }; 1090 // Intentionally reuse the original code path to get type parameters for the 1091 // cases that were supported rather than introduce a new path. 1092 return exv.match( 1093 [&](const fir::BoxValue &box) { return handleBoxed(box); }, 1094 [&](const fir::MutableBoxValue &box) { return handleBoxed(box); }, 1095 [&](const auto &) { return fir::getTypeParams(exv); }); 1096 } 1097 1098 llvm::SmallVector<mlir::Value> 1099 fir::factory::getTypeParams(mlir::Location loc, fir::FirOpBuilder &builder, 1100 fir::ArrayLoadOp load) { 1101 mlir::Type memTy = load.getMemref().getType(); 1102 if (auto boxTy = mlir::dyn_cast<fir::BaseBoxType>(memTy)) 1103 return getFromBox(loc, builder, boxTy, load.getMemref()); 1104 return load.getTypeparams(); 1105 } 1106 1107 std::string fir::factory::uniqueCGIdent(llvm::StringRef prefix, 1108 llvm::StringRef name) { 1109 // For "long" identifiers use a hash value 1110 if (name.size() > nameLengthHashSize) { 1111 llvm::MD5 hash; 1112 hash.update(name); 1113 llvm::MD5::MD5Result result; 1114 hash.final(result); 1115 llvm::SmallString<32> str; 1116 llvm::MD5::stringifyResult(result, str); 1117 std::string hashName = prefix.str(); 1118 hashName.append("X").append(str.c_str()); 1119 return fir::NameUniquer::doGenerated(hashName); 1120 } 1121 // "Short" identifiers use a reversible hex string 1122 std::string nm = prefix.str(); 1123 return fir::NameUniquer::doGenerated( 1124 nm.append("X").append(llvm::toHex(name))); 1125 } 1126 1127 mlir::Value fir::factory::locationToFilename(fir::FirOpBuilder &builder, 1128 mlir::Location loc) { 1129 if (auto flc = mlir::dyn_cast<mlir::FileLineColLoc>(loc)) { 1130 // must be encoded as asciiz, C string 1131 auto fn = flc.getFilename().str() + '\0'; 1132 return fir::getBase(createStringLiteral(builder, loc, fn)); 1133 } 1134 return builder.createNullConstant(loc); 1135 } 1136 1137 mlir::Value fir::factory::locationToLineNo(fir::FirOpBuilder &builder, 1138 mlir::Location loc, 1139 mlir::Type type) { 1140 if (auto flc = mlir::dyn_cast<mlir::FileLineColLoc>(loc)) 1141 return builder.createIntegerConstant(loc, type, flc.getLine()); 1142 return builder.createIntegerConstant(loc, type, 0); 1143 } 1144 1145 fir::ExtendedValue fir::factory::createStringLiteral(fir::FirOpBuilder &builder, 1146 mlir::Location loc, 1147 llvm::StringRef str) { 1148 std::string globalName = fir::factory::uniqueCGIdent("cl", str); 1149 auto type = fir::CharacterType::get(builder.getContext(), 1, str.size()); 1150 auto global = builder.getNamedGlobal(globalName); 1151 if (!global) 1152 global = builder.createGlobalConstant( 1153 loc, type, globalName, 1154 [&](fir::FirOpBuilder &builder) { 1155 auto stringLitOp = builder.createStringLitOp(loc, str); 1156 builder.create<fir::HasValueOp>(loc, stringLitOp); 1157 }, 1158 builder.createLinkOnceLinkage()); 1159 auto addr = builder.create<fir::AddrOfOp>(loc, global.resultType(), 1160 global.getSymbol()); 1161 auto len = builder.createIntegerConstant( 1162 loc, builder.getCharacterLengthType(), str.size()); 1163 return fir::CharBoxValue{addr, len}; 1164 } 1165 1166 llvm::SmallVector<mlir::Value> 1167 fir::factory::createExtents(fir::FirOpBuilder &builder, mlir::Location loc, 1168 fir::SequenceType seqTy) { 1169 llvm::SmallVector<mlir::Value> extents; 1170 auto idxTy = builder.getIndexType(); 1171 for (auto ext : seqTy.getShape()) 1172 extents.emplace_back( 1173 ext == fir::SequenceType::getUnknownExtent() 1174 ? builder.create<fir::UndefOp>(loc, idxTy).getResult() 1175 : builder.createIntegerConstant(loc, idxTy, ext)); 1176 return extents; 1177 } 1178 1179 // FIXME: This needs some work. To correctly determine the extended value of a 1180 // component, one needs the base object, its type, and its type parameters. (An 1181 // alternative would be to provide an already computed address of the final 1182 // component rather than the base object's address, the point being the result 1183 // will require the address of the final component to create the extended 1184 // value.) One further needs the full path of components being applied. One 1185 // needs to apply type-based expressions to type parameters along this said 1186 // path. (See applyPathToType for a type-only derivation.) Finally, one needs to 1187 // compose the extended value of the terminal component, including all of its 1188 // parameters: array lower bounds expressions, extents, type parameters, etc. 1189 // Any of these properties may be deferred until runtime in Fortran. This 1190 // operation may therefore generate a sizeable block of IR, including calls to 1191 // type-based helper functions, so caching the result of this operation in the 1192 // client would be advised as well. 1193 fir::ExtendedValue fir::factory::componentToExtendedValue( 1194 fir::FirOpBuilder &builder, mlir::Location loc, mlir::Value component) { 1195 auto fieldTy = component.getType(); 1196 if (auto ty = fir::dyn_cast_ptrEleTy(fieldTy)) 1197 fieldTy = ty; 1198 if (mlir::isa<fir::BaseBoxType>(fieldTy)) { 1199 llvm::SmallVector<mlir::Value> nonDeferredTypeParams; 1200 auto eleTy = fir::unwrapSequenceType(fir::dyn_cast_ptrOrBoxEleTy(fieldTy)); 1201 if (auto charTy = mlir::dyn_cast<fir::CharacterType>(eleTy)) { 1202 auto lenTy = builder.getCharacterLengthType(); 1203 if (charTy.hasConstantLen()) 1204 nonDeferredTypeParams.emplace_back( 1205 builder.createIntegerConstant(loc, lenTy, charTy.getLen())); 1206 // TODO: Starting, F2003, the dynamic character length might be dependent 1207 // on a PDT length parameter. There is no way to make a difference with 1208 // deferred length here yet. 1209 } 1210 if (auto recTy = mlir::dyn_cast<fir::RecordType>(eleTy)) 1211 if (recTy.getNumLenParams() > 0) 1212 TODO(loc, "allocatable and pointer components non deferred length " 1213 "parameters"); 1214 1215 return fir::MutableBoxValue(component, nonDeferredTypeParams, 1216 /*mutableProperties=*/{}); 1217 } 1218 llvm::SmallVector<mlir::Value> extents; 1219 if (auto seqTy = mlir::dyn_cast<fir::SequenceType>(fieldTy)) { 1220 fieldTy = seqTy.getEleTy(); 1221 auto idxTy = builder.getIndexType(); 1222 for (auto extent : seqTy.getShape()) { 1223 if (extent == fir::SequenceType::getUnknownExtent()) 1224 TODO(loc, "array component shape depending on length parameters"); 1225 extents.emplace_back(builder.createIntegerConstant(loc, idxTy, extent)); 1226 } 1227 } 1228 if (auto charTy = mlir::dyn_cast<fir::CharacterType>(fieldTy)) { 1229 auto cstLen = charTy.getLen(); 1230 if (cstLen == fir::CharacterType::unknownLen()) 1231 TODO(loc, "get character component length from length type parameters"); 1232 auto len = builder.createIntegerConstant( 1233 loc, builder.getCharacterLengthType(), cstLen); 1234 if (!extents.empty()) 1235 return fir::CharArrayBoxValue{component, len, extents}; 1236 return fir::CharBoxValue{component, len}; 1237 } 1238 if (auto recordTy = mlir::dyn_cast<fir::RecordType>(fieldTy)) 1239 if (recordTy.getNumLenParams() != 0) 1240 TODO(loc, 1241 "lower component ref that is a derived type with length parameter"); 1242 if (!extents.empty()) 1243 return fir::ArrayBoxValue{component, extents}; 1244 return component; 1245 } 1246 1247 fir::ExtendedValue fir::factory::arrayElementToExtendedValue( 1248 fir::FirOpBuilder &builder, mlir::Location loc, 1249 const fir::ExtendedValue &array, mlir::Value element) { 1250 return array.match( 1251 [&](const fir::CharBoxValue &cb) -> fir::ExtendedValue { 1252 return cb.clone(element); 1253 }, 1254 [&](const fir::CharArrayBoxValue &bv) -> fir::ExtendedValue { 1255 return bv.cloneElement(element); 1256 }, 1257 [&](const fir::BoxValue &box) -> fir::ExtendedValue { 1258 if (box.isCharacter()) { 1259 auto len = fir::factory::readCharLen(builder, loc, box); 1260 return fir::CharBoxValue{element, len}; 1261 } 1262 if (box.isDerivedWithLenParameters()) 1263 TODO(loc, "get length parameters from derived type BoxValue"); 1264 if (box.isPolymorphic()) { 1265 return fir::PolymorphicValue(element, fir::getBase(box)); 1266 } 1267 return element; 1268 }, 1269 [&](const fir::ArrayBoxValue &box) -> fir::ExtendedValue { 1270 if (box.getSourceBox()) 1271 return fir::PolymorphicValue(element, box.getSourceBox()); 1272 return element; 1273 }, 1274 [&](const auto &) -> fir::ExtendedValue { return element; }); 1275 } 1276 1277 fir::ExtendedValue fir::factory::arraySectionElementToExtendedValue( 1278 fir::FirOpBuilder &builder, mlir::Location loc, 1279 const fir::ExtendedValue &array, mlir::Value element, mlir::Value slice) { 1280 if (!slice) 1281 return arrayElementToExtendedValue(builder, loc, array, element); 1282 auto sliceOp = mlir::dyn_cast_or_null<fir::SliceOp>(slice.getDefiningOp()); 1283 assert(sliceOp && "slice must be a sliceOp"); 1284 if (sliceOp.getFields().empty()) 1285 return arrayElementToExtendedValue(builder, loc, array, element); 1286 // For F95, using componentToExtendedValue will work, but when PDTs are 1287 // lowered. It will be required to go down the slice to propagate the length 1288 // parameters. 1289 return fir::factory::componentToExtendedValue(builder, loc, element); 1290 } 1291 1292 void fir::factory::genScalarAssignment(fir::FirOpBuilder &builder, 1293 mlir::Location loc, 1294 const fir::ExtendedValue &lhs, 1295 const fir::ExtendedValue &rhs, 1296 bool needFinalization, 1297 bool isTemporaryLHS) { 1298 assert(lhs.rank() == 0 && rhs.rank() == 0 && "must be scalars"); 1299 auto type = fir::unwrapSequenceType( 1300 fir::unwrapPassByRefType(fir::getBase(lhs).getType())); 1301 if (mlir::isa<fir::CharacterType>(type)) { 1302 const fir::CharBoxValue *toChar = lhs.getCharBox(); 1303 const fir::CharBoxValue *fromChar = rhs.getCharBox(); 1304 assert(toChar && fromChar); 1305 fir::factory::CharacterExprHelper helper{builder, loc}; 1306 helper.createAssign(fir::ExtendedValue{*toChar}, 1307 fir::ExtendedValue{*fromChar}); 1308 } else if (mlir::isa<fir::RecordType>(type)) { 1309 fir::factory::genRecordAssignment(builder, loc, lhs, rhs, needFinalization, 1310 isTemporaryLHS); 1311 } else { 1312 assert(!fir::hasDynamicSize(type)); 1313 auto rhsVal = fir::getBase(rhs); 1314 if (fir::isa_ref_type(rhsVal.getType())) 1315 rhsVal = builder.create<fir::LoadOp>(loc, rhsVal); 1316 mlir::Value lhsAddr = fir::getBase(lhs); 1317 rhsVal = builder.createConvert(loc, fir::unwrapRefType(lhsAddr.getType()), 1318 rhsVal); 1319 builder.create<fir::StoreOp>(loc, rhsVal, lhsAddr); 1320 } 1321 } 1322 1323 static void genComponentByComponentAssignment(fir::FirOpBuilder &builder, 1324 mlir::Location loc, 1325 const fir::ExtendedValue &lhs, 1326 const fir::ExtendedValue &rhs, 1327 bool isTemporaryLHS) { 1328 auto lbaseType = fir::unwrapPassByRefType(fir::getBase(lhs).getType()); 1329 auto lhsType = mlir::dyn_cast<fir::RecordType>(lbaseType); 1330 assert(lhsType && "lhs must be a scalar record type"); 1331 auto rbaseType = fir::unwrapPassByRefType(fir::getBase(rhs).getType()); 1332 auto rhsType = mlir::dyn_cast<fir::RecordType>(rbaseType); 1333 assert(rhsType && "rhs must be a scalar record type"); 1334 auto fieldIndexType = fir::FieldType::get(lhsType.getContext()); 1335 for (auto [lhsPair, rhsPair] : 1336 llvm::zip(lhsType.getTypeList(), rhsType.getTypeList())) { 1337 auto &[lFieldName, lFieldTy] = lhsPair; 1338 auto &[rFieldName, rFieldTy] = rhsPair; 1339 assert(!fir::hasDynamicSize(lFieldTy) && !fir::hasDynamicSize(rFieldTy)); 1340 mlir::Value rField = builder.create<fir::FieldIndexOp>( 1341 loc, fieldIndexType, rFieldName, rhsType, fir::getTypeParams(rhs)); 1342 auto rFieldRefType = builder.getRefType(rFieldTy); 1343 mlir::Value fromCoor = builder.create<fir::CoordinateOp>( 1344 loc, rFieldRefType, fir::getBase(rhs), rField); 1345 mlir::Value field = builder.create<fir::FieldIndexOp>( 1346 loc, fieldIndexType, lFieldName, lhsType, fir::getTypeParams(lhs)); 1347 auto fieldRefType = builder.getRefType(lFieldTy); 1348 mlir::Value toCoor = builder.create<fir::CoordinateOp>( 1349 loc, fieldRefType, fir::getBase(lhs), field); 1350 std::optional<fir::DoLoopOp> outerLoop; 1351 if (auto sequenceType = mlir::dyn_cast<fir::SequenceType>(lFieldTy)) { 1352 // Create loops to assign array components elements by elements. 1353 // Note that, since these are components, they either do not overlap, 1354 // or are the same and exactly overlap. They also have compile time 1355 // constant shapes. 1356 mlir::Type idxTy = builder.getIndexType(); 1357 llvm::SmallVector<mlir::Value> indices; 1358 mlir::Value zero = builder.createIntegerConstant(loc, idxTy, 0); 1359 mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1); 1360 for (auto extent : llvm::reverse(sequenceType.getShape())) { 1361 // TODO: add zero size test ! 1362 mlir::Value ub = builder.createIntegerConstant(loc, idxTy, extent - 1); 1363 auto loop = builder.create<fir::DoLoopOp>(loc, zero, ub, one); 1364 if (!outerLoop) 1365 outerLoop = loop; 1366 indices.push_back(loop.getInductionVar()); 1367 builder.setInsertionPointToStart(loop.getBody()); 1368 } 1369 // Set indices in column-major order. 1370 std::reverse(indices.begin(), indices.end()); 1371 auto elementRefType = builder.getRefType(sequenceType.getEleTy()); 1372 toCoor = builder.create<fir::CoordinateOp>(loc, elementRefType, toCoor, 1373 indices); 1374 fromCoor = builder.create<fir::CoordinateOp>(loc, elementRefType, 1375 fromCoor, indices); 1376 } 1377 if (auto fieldEleTy = fir::unwrapSequenceType(lFieldTy); 1378 mlir::isa<fir::BaseBoxType>(fieldEleTy)) { 1379 assert(mlir::isa<fir::PointerType>( 1380 mlir::cast<fir::BaseBoxType>(fieldEleTy).getEleTy()) && 1381 "allocatable members require deep copy"); 1382 auto fromPointerValue = builder.create<fir::LoadOp>(loc, fromCoor); 1383 auto castTo = builder.createConvert(loc, fieldEleTy, fromPointerValue); 1384 builder.create<fir::StoreOp>(loc, castTo, toCoor); 1385 } else { 1386 auto from = 1387 fir::factory::componentToExtendedValue(builder, loc, fromCoor); 1388 auto to = fir::factory::componentToExtendedValue(builder, loc, toCoor); 1389 // If LHS finalization is needed it is expected to be done 1390 // for the parent record, so that component-by-component 1391 // assignments may avoid finalization calls. 1392 fir::factory::genScalarAssignment(builder, loc, to, from, 1393 /*needFinalization=*/false, 1394 isTemporaryLHS); 1395 } 1396 if (outerLoop) 1397 builder.setInsertionPointAfter(*outerLoop); 1398 } 1399 } 1400 1401 /// Can the assignment of this record type be implement with a simple memory 1402 /// copy (it requires no deep copy or user defined assignment of components )? 1403 static bool recordTypeCanBeMemCopied(fir::RecordType recordType) { 1404 // c_devptr type is a special case. It has a nested c_ptr field but we know it 1405 // can be copied directly. 1406 if (fir::isa_builtin_c_devptr_type(recordType)) 1407 return true; 1408 if (fir::hasDynamicSize(recordType)) 1409 return false; 1410 for (auto [_, fieldType] : recordType.getTypeList()) { 1411 // Derived type component may have user assignment (so far, we cannot tell 1412 // in FIR, so assume it is always the case, TODO: get the actual info). 1413 if (mlir::isa<fir::RecordType>(fir::unwrapSequenceType(fieldType)) && 1414 !fir::isa_builtin_c_devptr_type(fir::unwrapSequenceType(fieldType))) 1415 return false; 1416 // Allocatable components need deep copy. 1417 if (auto boxType = mlir::dyn_cast<fir::BaseBoxType>(fieldType)) 1418 if (mlir::isa<fir::HeapType>(boxType.getEleTy())) 1419 return false; 1420 } 1421 // Constant size components without user defined assignment and pointers can 1422 // be memcopied. 1423 return true; 1424 } 1425 1426 static bool mayHaveFinalizer(fir::RecordType recordType, 1427 fir::FirOpBuilder &builder) { 1428 if (auto typeInfo = builder.getModule().lookupSymbol<fir::TypeInfoOp>( 1429 recordType.getName())) 1430 return !typeInfo.getNoFinal(); 1431 // No info, be pessimistic. 1432 return true; 1433 } 1434 1435 void fir::factory::genRecordAssignment(fir::FirOpBuilder &builder, 1436 mlir::Location loc, 1437 const fir::ExtendedValue &lhs, 1438 const fir::ExtendedValue &rhs, 1439 bool needFinalization, 1440 bool isTemporaryLHS) { 1441 assert(lhs.rank() == 0 && rhs.rank() == 0 && "assume scalar assignment"); 1442 auto baseTy = fir::dyn_cast_ptrOrBoxEleTy(fir::getBase(lhs).getType()); 1443 assert(baseTy && "must be a memory type"); 1444 // Box operands may be polymorphic, it is not entirely clear from 10.2.1.3 1445 // if the assignment is performed on the dynamic of declared type. Use the 1446 // runtime assuming it is performed on the dynamic type. 1447 bool hasBoxOperands = 1448 mlir::isa<fir::BaseBoxType>(fir::getBase(lhs).getType()) || 1449 mlir::isa<fir::BaseBoxType>(fir::getBase(rhs).getType()); 1450 auto recTy = mlir::dyn_cast<fir::RecordType>(baseTy); 1451 assert(recTy && "must be a record type"); 1452 if ((needFinalization && mayHaveFinalizer(recTy, builder)) || 1453 hasBoxOperands || !recordTypeCanBeMemCopied(recTy)) { 1454 auto to = fir::getBase(builder.createBox(loc, lhs)); 1455 auto from = fir::getBase(builder.createBox(loc, rhs)); 1456 // The runtime entry point may modify the LHS descriptor if it is 1457 // an allocatable. Allocatable assignment is handle elsewhere in lowering, 1458 // so just create a fir.ref<fir.box<>> from the fir.box to comply with the 1459 // runtime interface, but assume the fir.box is unchanged. 1460 // TODO: does this holds true with polymorphic entities ? 1461 auto toMutableBox = builder.createTemporary(loc, to.getType()); 1462 builder.create<fir::StoreOp>(loc, to, toMutableBox); 1463 if (isTemporaryLHS) 1464 fir::runtime::genAssignTemporary(builder, loc, toMutableBox, from); 1465 else 1466 fir::runtime::genAssign(builder, loc, toMutableBox, from); 1467 return; 1468 } 1469 1470 // Otherwise, the derived type has compile time constant size and for which 1471 // the component by component assignment can be replaced by a memory copy. 1472 // Since we do not know the size of the derived type in lowering, do a 1473 // component by component assignment. Note that a single fir.load/fir.store 1474 // could be used on "small" record types, but as the type size grows, this 1475 // leads to issues in LLVM (long compile times, long IR files, and even 1476 // asserts at some point). Since there is no good size boundary, just always 1477 // use component by component assignment here. 1478 genComponentByComponentAssignment(builder, loc, lhs, rhs, isTemporaryLHS); 1479 } 1480 1481 mlir::TupleType 1482 fir::factory::getRaggedArrayHeaderType(fir::FirOpBuilder &builder) { 1483 mlir::IntegerType i64Ty = builder.getIntegerType(64); 1484 auto arrTy = fir::SequenceType::get(builder.getIntegerType(8), 1); 1485 auto buffTy = fir::HeapType::get(arrTy); 1486 auto extTy = fir::SequenceType::get(i64Ty, 1); 1487 auto shTy = fir::HeapType::get(extTy); 1488 return mlir::TupleType::get(builder.getContext(), {i64Ty, buffTy, shTy}); 1489 } 1490 1491 mlir::Value fir::factory::genLenOfCharacter( 1492 fir::FirOpBuilder &builder, mlir::Location loc, fir::ArrayLoadOp arrLoad, 1493 llvm::ArrayRef<mlir::Value> path, llvm::ArrayRef<mlir::Value> substring) { 1494 llvm::SmallVector<mlir::Value> typeParams(arrLoad.getTypeparams()); 1495 return genLenOfCharacter(builder, loc, 1496 mlir::cast<fir::SequenceType>(arrLoad.getType()), 1497 arrLoad.getMemref(), typeParams, path, substring); 1498 } 1499 1500 mlir::Value fir::factory::genLenOfCharacter( 1501 fir::FirOpBuilder &builder, mlir::Location loc, fir::SequenceType seqTy, 1502 mlir::Value memref, llvm::ArrayRef<mlir::Value> typeParams, 1503 llvm::ArrayRef<mlir::Value> path, llvm::ArrayRef<mlir::Value> substring) { 1504 auto idxTy = builder.getIndexType(); 1505 auto zero = builder.createIntegerConstant(loc, idxTy, 0); 1506 auto saturatedDiff = [&](mlir::Value lower, mlir::Value upper) { 1507 auto diff = builder.create<mlir::arith::SubIOp>(loc, upper, lower); 1508 auto one = builder.createIntegerConstant(loc, idxTy, 1); 1509 auto size = builder.create<mlir::arith::AddIOp>(loc, diff, one); 1510 auto cmp = builder.create<mlir::arith::CmpIOp>( 1511 loc, mlir::arith::CmpIPredicate::sgt, size, zero); 1512 return builder.create<mlir::arith::SelectOp>(loc, cmp, size, zero); 1513 }; 1514 if (substring.size() == 2) { 1515 auto upper = builder.createConvert(loc, idxTy, substring.back()); 1516 auto lower = builder.createConvert(loc, idxTy, substring.front()); 1517 return saturatedDiff(lower, upper); 1518 } 1519 auto lower = zero; 1520 if (substring.size() == 1) 1521 lower = builder.createConvert(loc, idxTy, substring.front()); 1522 auto eleTy = fir::applyPathToType(seqTy, path); 1523 if (!fir::hasDynamicSize(eleTy)) { 1524 if (auto charTy = mlir::dyn_cast<fir::CharacterType>(eleTy)) { 1525 // Use LEN from the type. 1526 return builder.createIntegerConstant(loc, idxTy, charTy.getLen()); 1527 } 1528 // Do we need to support !fir.array<!fir.char<k,n>>? 1529 fir::emitFatalError(loc, 1530 "application of path did not result in a !fir.char"); 1531 } 1532 if (fir::isa_box_type(memref.getType())) { 1533 if (mlir::isa<fir::BoxCharType>(memref.getType())) 1534 return builder.create<fir::BoxCharLenOp>(loc, idxTy, memref); 1535 if (mlir::isa<fir::BoxType>(memref.getType())) 1536 return CharacterExprHelper(builder, loc).readLengthFromBox(memref); 1537 fir::emitFatalError(loc, "memref has wrong type"); 1538 } 1539 if (typeParams.empty()) { 1540 fir::emitFatalError(loc, "array_load must have typeparams"); 1541 } 1542 if (fir::isa_char(seqTy.getEleTy())) { 1543 assert(typeParams.size() == 1 && "too many typeparams"); 1544 return typeParams.front(); 1545 } 1546 TODO(loc, "LEN of character must be computed at runtime"); 1547 } 1548 1549 mlir::Value fir::factory::createZeroValue(fir::FirOpBuilder &builder, 1550 mlir::Location loc, mlir::Type type) { 1551 mlir::Type i1 = builder.getIntegerType(1); 1552 if (mlir::isa<fir::LogicalType>(type) || type == i1) 1553 return builder.createConvert(loc, type, builder.createBool(loc, false)); 1554 if (fir::isa_integer(type)) 1555 return builder.createIntegerConstant(loc, type, 0); 1556 if (fir::isa_real(type)) 1557 return builder.createRealZeroConstant(loc, type); 1558 if (fir::isa_complex(type)) { 1559 fir::factory::Complex complexHelper(builder, loc); 1560 mlir::Type partType = complexHelper.getComplexPartType(type); 1561 mlir::Value zeroPart = builder.createRealZeroConstant(loc, partType); 1562 return complexHelper.createComplex(type, zeroPart, zeroPart); 1563 } 1564 fir::emitFatalError(loc, "internal: trying to generate zero value of non " 1565 "numeric or logical type"); 1566 } 1567 1568 std::optional<std::int64_t> 1569 fir::factory::getExtentFromTriplet(mlir::Value lb, mlir::Value ub, 1570 mlir::Value stride) { 1571 std::function<std::optional<std::int64_t>(mlir::Value)> getConstantValue = 1572 [&](mlir::Value value) -> std::optional<std::int64_t> { 1573 if (auto valInt = fir::getIntIfConstant(value)) 1574 return *valInt; 1575 auto *definingOp = value.getDefiningOp(); 1576 if (mlir::isa_and_nonnull<fir::ConvertOp>(definingOp)) { 1577 auto valOp = mlir::dyn_cast<fir::ConvertOp>(definingOp); 1578 return getConstantValue(valOp.getValue()); 1579 } 1580 return {}; 1581 }; 1582 if (auto lbInt = getConstantValue(lb)) { 1583 if (auto ubInt = getConstantValue(ub)) { 1584 if (auto strideInt = getConstantValue(stride)) { 1585 if (*strideInt != 0) { 1586 std::int64_t extent = 1 + (*ubInt - *lbInt) / *strideInt; 1587 if (extent > 0) 1588 return extent; 1589 } 1590 } 1591 } 1592 } 1593 return {}; 1594 } 1595 1596 mlir::Value fir::factory::genMaxWithZero(fir::FirOpBuilder &builder, 1597 mlir::Location loc, 1598 mlir::Value value) { 1599 mlir::Value zero = builder.createIntegerConstant(loc, value.getType(), 0); 1600 if (mlir::Operation *definingOp = value.getDefiningOp()) 1601 if (auto cst = mlir::dyn_cast<mlir::arith::ConstantOp>(definingOp)) 1602 if (auto intAttr = mlir::dyn_cast<mlir::IntegerAttr>(cst.getValue())) 1603 return intAttr.getInt() > 0 ? value : zero; 1604 mlir::Value valueIsGreater = builder.create<mlir::arith::CmpIOp>( 1605 loc, mlir::arith::CmpIPredicate::sgt, value, zero); 1606 return builder.create<mlir::arith::SelectOp>(loc, valueIsGreater, value, 1607 zero); 1608 } 1609 1610 static std::pair<mlir::Value, mlir::Type> 1611 genCPtrOrCFunptrFieldIndex(fir::FirOpBuilder &builder, mlir::Location loc, 1612 mlir::Type cptrTy) { 1613 auto recTy = mlir::cast<fir::RecordType>(cptrTy); 1614 assert(recTy.getTypeList().size() == 1); 1615 auto addrFieldName = recTy.getTypeList()[0].first; 1616 mlir::Type addrFieldTy = recTy.getTypeList()[0].second; 1617 auto fieldIndexType = fir::FieldType::get(cptrTy.getContext()); 1618 mlir::Value addrFieldIndex = builder.create<fir::FieldIndexOp>( 1619 loc, fieldIndexType, addrFieldName, recTy, 1620 /*typeParams=*/mlir::ValueRange{}); 1621 return {addrFieldIndex, addrFieldTy}; 1622 } 1623 1624 mlir::Value fir::factory::genCPtrOrCFunptrAddr(fir::FirOpBuilder &builder, 1625 mlir::Location loc, 1626 mlir::Value cPtr, 1627 mlir::Type ty) { 1628 auto [addrFieldIndex, addrFieldTy] = 1629 genCPtrOrCFunptrFieldIndex(builder, loc, ty); 1630 return builder.create<fir::CoordinateOp>(loc, builder.getRefType(addrFieldTy), 1631 cPtr, addrFieldIndex); 1632 } 1633 1634 mlir::Value fir::factory::genCDevPtrAddr(fir::FirOpBuilder &builder, 1635 mlir::Location loc, 1636 mlir::Value cDevPtr, mlir::Type ty) { 1637 auto recTy = mlir::cast<fir::RecordType>(ty); 1638 assert(recTy.getTypeList().size() == 1); 1639 auto cptrFieldName = recTy.getTypeList()[0].first; 1640 mlir::Type cptrFieldTy = recTy.getTypeList()[0].second; 1641 auto fieldIndexType = fir::FieldType::get(ty.getContext()); 1642 mlir::Value cptrFieldIndex = builder.create<fir::FieldIndexOp>( 1643 loc, fieldIndexType, cptrFieldName, recTy, 1644 /*typeParams=*/mlir::ValueRange{}); 1645 auto cptrCoord = builder.create<fir::CoordinateOp>( 1646 loc, builder.getRefType(cptrFieldTy), cDevPtr, cptrFieldIndex); 1647 auto [addrFieldIndex, addrFieldTy] = 1648 genCPtrOrCFunptrFieldIndex(builder, loc, cptrFieldTy); 1649 return builder.create<fir::CoordinateOp>(loc, builder.getRefType(addrFieldTy), 1650 cptrCoord, addrFieldIndex); 1651 } 1652 1653 mlir::Value fir::factory::genCPtrOrCFunptrValue(fir::FirOpBuilder &builder, 1654 mlir::Location loc, 1655 mlir::Value cPtr) { 1656 mlir::Type cPtrTy = fir::unwrapRefType(cPtr.getType()); 1657 if (fir::isa_builtin_cdevptr_type(cPtrTy)) { 1658 // Unwrap c_ptr from c_devptr. 1659 auto [addrFieldIndex, addrFieldTy] = 1660 genCPtrOrCFunptrFieldIndex(builder, loc, cPtrTy); 1661 mlir::Value cPtrCoor; 1662 if (fir::isa_ref_type(cPtr.getType())) { 1663 cPtrCoor = builder.create<fir::CoordinateOp>( 1664 loc, builder.getRefType(addrFieldTy), cPtr, addrFieldIndex); 1665 } else { 1666 auto arrayAttr = builder.getArrayAttr( 1667 {builder.getIntegerAttr(builder.getIndexType(), 0)}); 1668 cPtrCoor = builder.create<fir::ExtractValueOp>(loc, addrFieldTy, cPtr, 1669 arrayAttr); 1670 } 1671 return genCPtrOrCFunptrValue(builder, loc, cPtrCoor); 1672 } 1673 1674 if (fir::isa_ref_type(cPtr.getType())) { 1675 mlir::Value cPtrAddr = 1676 fir::factory::genCPtrOrCFunptrAddr(builder, loc, cPtr, cPtrTy); 1677 return builder.create<fir::LoadOp>(loc, cPtrAddr); 1678 } 1679 auto [addrFieldIndex, addrFieldTy] = 1680 genCPtrOrCFunptrFieldIndex(builder, loc, cPtrTy); 1681 auto arrayAttr = 1682 builder.getArrayAttr({builder.getIntegerAttr(builder.getIndexType(), 0)}); 1683 return builder.create<fir::ExtractValueOp>(loc, addrFieldTy, cPtr, arrayAttr); 1684 } 1685 1686 fir::BoxValue fir::factory::createBoxValue(fir::FirOpBuilder &builder, 1687 mlir::Location loc, 1688 const fir::ExtendedValue &exv) { 1689 if (auto *boxValue = exv.getBoxOf<fir::BoxValue>()) 1690 return *boxValue; 1691 mlir::Value box = builder.createBox(loc, exv); 1692 llvm::SmallVector<mlir::Value> lbounds; 1693 llvm::SmallVector<mlir::Value> explicitTypeParams; 1694 exv.match( 1695 [&](const fir::ArrayBoxValue &box) { 1696 lbounds.append(box.getLBounds().begin(), box.getLBounds().end()); 1697 }, 1698 [&](const fir::CharArrayBoxValue &box) { 1699 lbounds.append(box.getLBounds().begin(), box.getLBounds().end()); 1700 explicitTypeParams.emplace_back(box.getLen()); 1701 }, 1702 [&](const fir::CharBoxValue &box) { 1703 explicitTypeParams.emplace_back(box.getLen()); 1704 }, 1705 [&](const fir::MutableBoxValue &x) { 1706 if (x.rank() > 0) { 1707 // The resulting box lbounds must be coming from the mutable box. 1708 fir::ExtendedValue boxVal = 1709 fir::factory::genMutableBoxRead(builder, loc, x); 1710 // Make sure we do not recurse infinitely. 1711 if (boxVal.getBoxOf<fir::MutableBoxValue>()) 1712 fir::emitFatalError(loc, "mutable box read cannot be mutable box"); 1713 fir::BoxValue box = 1714 fir::factory::createBoxValue(builder, loc, boxVal); 1715 lbounds.append(box.getLBounds().begin(), box.getLBounds().end()); 1716 } 1717 explicitTypeParams.append(x.nonDeferredLenParams().begin(), 1718 x.nonDeferredLenParams().end()); 1719 }, 1720 [](const auto &) {}); 1721 return fir::BoxValue(box, lbounds, explicitTypeParams); 1722 } 1723 1724 mlir::Value fir::factory::createNullBoxProc(fir::FirOpBuilder &builder, 1725 mlir::Location loc, 1726 mlir::Type boxType) { 1727 auto boxTy{mlir::dyn_cast<fir::BoxProcType>(boxType)}; 1728 if (!boxTy) 1729 fir::emitFatalError(loc, "Procedure pointer must be of BoxProcType"); 1730 auto boxEleTy{fir::unwrapRefType(boxTy.getEleTy())}; 1731 mlir::Value initVal{builder.create<fir::ZeroOp>(loc, boxEleTy)}; 1732 return builder.create<fir::EmboxProcOp>(loc, boxTy, initVal); 1733 } 1734 1735 void fir::factory::setInternalLinkage(mlir::func::FuncOp func) { 1736 auto internalLinkage = mlir::LLVM::linkage::Linkage::Internal; 1737 auto linkage = 1738 mlir::LLVM::LinkageAttr::get(func->getContext(), internalLinkage); 1739 func->setAttr("llvm.linkage", linkage); 1740 } 1741 1742 uint64_t fir::factory::getAllocaAddressSpace(mlir::DataLayout *dataLayout) { 1743 if (dataLayout) 1744 if (mlir::Attribute addrSpace = dataLayout->getAllocaMemorySpace()) 1745 return mlir::cast<mlir::IntegerAttr>(addrSpace).getUInt(); 1746 return 0; 1747 } 1748 1749 llvm::SmallVector<mlir::Value> 1750 fir::factory::deduceOptimalExtents(mlir::ValueRange extents1, 1751 mlir::ValueRange extents2) { 1752 llvm::SmallVector<mlir::Value> extents; 1753 extents.reserve(extents1.size()); 1754 for (auto [extent1, extent2] : llvm::zip(extents1, extents2)) { 1755 if (!fir::getIntIfConstant(extent1) && fir::getIntIfConstant(extent2)) 1756 extents.push_back(extent2); 1757 else 1758 extents.push_back(extent1); 1759 } 1760 return extents; 1761 } 1762 1763 llvm::SmallVector<mlir::Value> fir::factory::updateRuntimeExtentsForEmptyArrays( 1764 fir::FirOpBuilder &builder, mlir::Location loc, mlir::ValueRange extents) { 1765 if (extents.size() <= 1) 1766 return extents; 1767 1768 mlir::Type i1Type = builder.getI1Type(); 1769 mlir::Value isEmpty = createZeroValue(builder, loc, i1Type); 1770 1771 llvm::SmallVector<mlir::Value, Fortran::common::maxRank> zeroes; 1772 for (mlir::Value extent : extents) { 1773 mlir::Type type = extent.getType(); 1774 mlir::Value zero = createZeroValue(builder, loc, type); 1775 zeroes.push_back(zero); 1776 mlir::Value isZero = builder.create<mlir::arith::CmpIOp>( 1777 loc, mlir::arith::CmpIPredicate::eq, extent, zero); 1778 isEmpty = builder.create<mlir::arith::OrIOp>(loc, isEmpty, isZero); 1779 } 1780 1781 llvm::SmallVector<mlir::Value, Fortran::common::maxRank> newExtents; 1782 for (auto [zero, extent] : llvm::zip_equal(zeroes, extents)) { 1783 newExtents.push_back( 1784 builder.create<mlir::arith::SelectOp>(loc, isEmpty, zero, extent)); 1785 } 1786 return newExtents; 1787 } 1788