brintos

brintos / llvm-project-archived public Read only

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