diff options
| author | Slava Zakharin <szakharin@nvidia.com> | 2023-09-07 11:41:22 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-09-07 11:41:22 -0700 |
| commit | f8843efbb2190db85c696001ffd6211a2c20ac37 (patch) | |
| tree | 9ff62554e07a27c25115857f18c0d35eecd9f33d /flang/lib | |
| parent | 88359213ee499ed2cc02c4bf0dba7b5e9af37ff6 (diff) | |
| download | llvm-f8843efbb2190db85c696001ffd6211a2c20ac37.zip llvm-f8843efbb2190db85c696001ffd6211a2c20ac37.tar.gz llvm-f8843efbb2190db85c696001ffd6211a2c20ac37.tar.bz2 | |
[flang][hlfir] Lower Cray pointee references. (#65563)
A Cray pointee reference must be done using the characteristics
(bounds, type params) of the original pointee declaration, but
using the actual address value of the associated Cray pointer.
There might be multiple Cray pointees associated with the same
Cray pointer.
The proposed solution is to lower each Cray pointee into a POINTER
variable with a descriptor. The descriptor is initialized at the point
of declaration of the pointee, though its base_addr is set to null.
Before each reference of the Cray pointee its descriptor's base_addr
is updated to the current value of the Cray pointer.
The update of the base_addr is done using PointerAssociateScalar
runtime call, which just updates the base_addr of the descriptor.
This is a temporary solution just to make Cray pointers work
to the same extent they work with FIR lowering.
Diffstat (limited to 'flang/lib')
| -rw-r--r-- | flang/lib/Lower/Bridge.cpp | 2 | ||||
| -rw-r--r-- | flang/lib/Lower/ConvertExpr.cpp | 19 | ||||
| -rw-r--r-- | flang/lib/Lower/ConvertExprToHLFIR.cpp | 31 | ||||
| -rw-r--r-- | flang/lib/Lower/ConvertVariable.cpp | 60 | ||||
| -rw-r--r-- | flang/lib/Optimizer/Builder/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | flang/lib/Optimizer/Builder/Runtime/Pointer.cpp | 27 |
6 files changed, 122 insertions, 18 deletions
diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp index d7dec54c..0f86f90 100644 --- a/flang/lib/Lower/Bridge.cpp +++ b/flang/lib/Lower/Bridge.cpp @@ -3629,7 +3629,7 @@ private: sym->Rank() == 0) { // get the corresponding Cray pointer - auto ptrSym = Fortran::lower::getPointer(*sym); + auto ptrSym = Fortran::lower::getCrayPointer(*sym); fir::ExtendedValue ptr = getSymbolExtendedValue(ptrSym, nullptr); mlir::Value ptrVal = fir::getBase(ptr); diff --git a/flang/lib/Lower/ConvertExpr.cpp b/flang/lib/Lower/ConvertExpr.cpp index 191319c..a9298be 100644 --- a/flang/lib/Lower/ConvertExpr.cpp +++ b/flang/lib/Lower/ConvertExpr.cpp @@ -863,7 +863,7 @@ public: addr); } else if (sym->test(Fortran::semantics::Symbol::Flag::CrayPointee)) { // get the corresponding Cray pointer - auto ptrSym = Fortran::lower::getPointer(sym); + auto ptrSym = Fortran::lower::getCrayPointer(sym); ExtValue ptr = gen(ptrSym); mlir::Value ptrVal = fir::getBase(ptr); mlir::Type ptrTy = converter.genType(*ptrSym); @@ -1571,7 +1571,7 @@ public: auto baseSym = getFirstSym(aref); if (baseSym.test(Fortran::semantics::Symbol::Flag::CrayPointee)) { // get the corresponding Cray pointer - auto ptrSym = Fortran::lower::getPointer(baseSym); + auto ptrSym = Fortran::lower::getCrayPointer(baseSym); fir::ExtendedValue ptr = gen(ptrSym); mlir::Value ptrVal = fir::getBase(ptr); @@ -6974,7 +6974,7 @@ private: ComponentPath &components) { mlir::Value ptrVal = nullptr; if (x.test(Fortran::semantics::Symbol::Flag::CrayPointee)) { - auto ptrSym = Fortran::lower::getPointer(x); + auto ptrSym = Fortran::lower::getCrayPointer(x); ExtValue ptr = converter.getSymbolExtendedValue(ptrSym); ptrVal = fir::getBase(ptr); } @@ -7629,19 +7629,6 @@ void Fortran::lower::createArrayMergeStores( esp.incrementCounter(); } -Fortran::semantics::SymbolRef -Fortran::lower::getPointer(Fortran::semantics::SymbolRef sym) { - assert(!sym->owner().crayPointers().empty() && - "empty Cray pointer/pointee map"); - for (const auto &[pointee, pointer] : sym->owner().crayPointers()) { - if (pointee == sym->name()) { - Fortran::semantics::SymbolRef v{pointer.get()}; - return v; - } - } - llvm_unreachable("corresponding Cray pointer cannot be found"); -} - mlir::Value Fortran::lower::addCrayPointerInst(mlir::Location loc, fir::FirOpBuilder &builder, mlir::Value ptrVal, diff --git a/flang/lib/Lower/ConvertExprToHLFIR.cpp b/flang/lib/Lower/ConvertExprToHLFIR.cpp index 7305215..ee4d307 100644 --- a/flang/lib/Lower/ConvertExprToHLFIR.cpp +++ b/flang/lib/Lower/ConvertExprToHLFIR.cpp @@ -28,6 +28,7 @@ #include "flang/Optimizer/Builder/MutableBox.h" #include "flang/Optimizer/Builder/Runtime/Character.h" #include "flang/Optimizer/Builder/Runtime/Derived.h" +#include "flang/Optimizer/Builder/Runtime/Pointer.h" #include "flang/Optimizer/Builder/Todo.h" #include "flang/Optimizer/HLFIR/HLFIROps.h" #include "llvm/ADT/TypeSwitch.h" @@ -268,8 +269,36 @@ private: fir::FortranVariableOpInterface gen(const Fortran::evaluate::SymbolRef &symbolRef) { if (std::optional<fir::FortranVariableOpInterface> varDef = - getSymMap().lookupVariableDefinition(symbolRef)) + getSymMap().lookupVariableDefinition(symbolRef)) { + if (symbolRef->test(Fortran::semantics::Symbol::Flag::CrayPointee)) { + // The pointee is represented with a descriptor inheriting + // the shape and type parameters of the pointee. + // We have to update the base_addr to point to the current + // value of the Cray pointer variable. + fir::FirOpBuilder &builder = getBuilder(); + fir::FortranVariableOpInterface ptrVar = + gen(Fortran::lower::getCrayPointer(symbolRef)); + mlir::Value ptrAddr = ptrVar.getBase(); + + // Reinterpret the reference to a Cray pointer so that + // we have a pointer-compatible value after loading + // the Cray pointer value. + mlir::Type refPtrType = builder.getRefType( + fir::PointerType::get(fir::dyn_cast_ptrEleTy(ptrAddr.getType()))); + mlir::Value cast = builder.createConvert(loc, refPtrType, ptrAddr); + mlir::Value ptrVal = builder.create<fir::LoadOp>(loc, cast); + + // Update the base_addr to the value of the Cray pointer. + // This is a hacky way to do the update, and it may harm + // performance around Cray pointer references. + // TODO: we should introduce an operation that updates + // just the base_addr of the given box. The CodeGen + // will just convert it into a single store. + fir::runtime::genPointerAssociateScalar(builder, loc, varDef->getBase(), + ptrVal); + } return *varDef; + } TODO(getLoc(), "lowering symbol to HLFIR"); } diff --git a/flang/lib/Lower/ConvertVariable.cpp b/flang/lib/Lower/ConvertVariable.cpp index 15731f1..726b848 100644 --- a/flang/lib/Lower/ConvertVariable.cpp +++ b/flang/lib/Lower/ConvertVariable.cpp @@ -1477,6 +1477,8 @@ static void genDeclareSymbol(Fortran::lower::AbstractConverter &converter, if (converter.getLoweringOptions().getLowerToHighLevelFIR() && !Fortran::semantics::IsProcedure(sym) && !sym.detailsIf<Fortran::semantics::CommonBlockDetails>()) { + bool isCrayPointee = + sym.test(Fortran::semantics::Symbol::Flag::CrayPointee); fir::FirOpBuilder &builder = converter.getFirOpBuilder(); const mlir::Location loc = genLocation(converter, sym); mlir::Value shapeOrShift; @@ -1492,6 +1494,51 @@ static void genDeclareSymbol(Fortran::lower::AbstractConverter &converter, auto name = converter.mangleName(sym); fir::FortranVariableFlagsAttr attributes = Fortran::lower::translateSymbolAttributes(builder.getContext(), sym); + + if (isCrayPointee) { + mlir::Type baseType = + hlfir::getFortranElementOrSequenceType(base.getType()); + if (auto seqType = mlir::dyn_cast<fir::SequenceType>(baseType)) { + // The pointer box's sequence type must be with unknown shape. + llvm::SmallVector<int64_t> shape(seqType.getDimension(), + fir::SequenceType::getUnknownExtent()); + baseType = fir::SequenceType::get(shape, seqType.getEleTy()); + } + fir::BoxType ptrBoxType = + fir::BoxType::get(fir::PointerType::get(baseType)); + mlir::Value boxAlloc = builder.createTemporary(loc, ptrBoxType); + + // Declare a local pointer variable. + attributes = fir::FortranVariableFlagsAttr::get( + builder.getContext(), fir::FortranVariableFlagsEnum::pointer); + auto newBase = builder.create<hlfir::DeclareOp>( + loc, boxAlloc, name, /*shape=*/nullptr, lenParams, attributes); + mlir::Value nullAddr = + builder.createNullConstant(loc, ptrBoxType.getEleTy()); + + // If the element type is known-length character, then + // EmboxOp does not need the length parameters. + if (auto charType = mlir::dyn_cast<fir::CharacterType>( + fir::unwrapSequenceType(baseType))) + if (!charType.hasDynamicLen()) + lenParams.clear(); + + // Inherit the shape (and maybe length parameters) from the pointee + // declaration. + mlir::Value initVal = + builder.create<fir::EmboxOp>(loc, ptrBoxType, nullAddr, shapeOrShift, + /*slice=*/nullptr, lenParams); + builder.create<fir::StoreOp>(loc, initVal, newBase.getBase()); + + // Any reference to the pointee is going to be using the pointer + // box from now on. The base_addr of the descriptor must be updated + // to hold the value of the Cray pointer at the point of the pointee + // access. + // Note that the same Cray pointer may be associated with + // multiple pointees and each of them has its own descriptor. + symMap.addVariableDefinition(sym, newBase, force); + return; + } auto newBase = builder.create<hlfir::DeclareOp>( loc, base, name, shapeOrShift, lenParams, attributes); symMap.addVariableDefinition(sym, newBase, force); @@ -2056,3 +2103,16 @@ void Fortran::lower::createRuntimeTypeInfoGlobal( mlir::StringAttr linkage = getLinkageAttribute(builder, var); defineGlobal(converter, var, globalName, linkage); } + +Fortran::semantics::SymbolRef +Fortran::lower::getCrayPointer(Fortran::semantics::SymbolRef sym) { + assert(!sym->owner().crayPointers().empty() && + "empty Cray pointer/pointee map"); + for (const auto &[pointee, pointer] : sym->owner().crayPointers()) { + if (pointee == sym->name()) { + Fortran::semantics::SymbolRef v{pointer.get()}; + return v; + } + } + llvm_unreachable("corresponding Cray pointer cannot be found"); +} diff --git a/flang/lib/Optimizer/Builder/CMakeLists.txt b/flang/lib/Optimizer/Builder/CMakeLists.txt index 7665ca1..5e5daffd3 100644 --- a/flang/lib/Optimizer/Builder/CMakeLists.txt +++ b/flang/lib/Optimizer/Builder/CMakeLists.txt @@ -22,6 +22,7 @@ add_flang_library(FIRBuilder Runtime/Inquiry.cpp Runtime/Intrinsics.cpp Runtime/Numeric.cpp + Runtime/Pointer.cpp Runtime/Ragged.cpp Runtime/Reduction.cpp Runtime/Stop.cpp diff --git a/flang/lib/Optimizer/Builder/Runtime/Pointer.cpp b/flang/lib/Optimizer/Builder/Runtime/Pointer.cpp new file mode 100644 index 0000000..160c651 --- /dev/null +++ b/flang/lib/Optimizer/Builder/Runtime/Pointer.cpp @@ -0,0 +1,27 @@ +//===-- Pointer.cpp -- generate pointer runtime API calls------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "flang/Optimizer/Builder/Runtime/Pointer.h" +#include "flang/Optimizer/Builder/FIRBuilder.h" +#include "flang/Optimizer/Builder/Runtime/RTBuilder.h" +#include "flang/Runtime/pointer.h" + +using namespace Fortran::runtime; + +void fir::runtime::genPointerAssociateScalar(fir::FirOpBuilder &builder, + mlir::Location loc, + mlir::Value desc, + mlir::Value target) { + mlir::func::FuncOp func{ + fir::runtime::getRuntimeFunc<mkRTKey(PointerAssociateScalar)>(loc, + builder)}; + mlir::FunctionType fTy{func.getFunctionType()}; + llvm::SmallVector<mlir::Value> args{ + fir::runtime::createArguments(builder, loc, fTy, desc, target)}; + builder.create<fir::CallOp>(loc, func, args); +} |
