From ca0a0bf9638c9705862ef2684aba192376c7d7cb Mon Sep 17 00:00:00 2001 From: Jean Perier Date: Thu, 20 Oct 2022 10:30:42 +0200 Subject: [PATCH] [flang] optionally lower scalar and explicit shape with fir.declare Lower scalar and explicit shape arrays to fir.declare under the -hlfir option. Update the SymMap so that it can hold fir::FortranVariableInterface. The plan is to go towards a SymMap that only contains fir::FortranVariableInterface once current expression lowering can be replaced. This should make the SymMap lighter than it is today (SymBox/ExtendedValue are above 256 bytes). Assumed shape, allocatable and pointer are left TODOs for now. Anything with a specification expression that is not a constant expression will only be able to be lowered when the HLFIR expression lowering skeleton is added. Differential Revision: https://reviews.llvm.org/D136252 --- flang/include/flang/Lower/SymbolMap.h | 14 +++- flang/include/flang/Optimizer/Builder/FIRBuilder.h | 1 + flang/lib/Lower/ConvertVariable.cpp | 62 +++++++++++++- flang/lib/Lower/SymbolMap.cpp | 36 ++++++-- flang/lib/Optimizer/Builder/FIRBuilder.cpp | 6 ++ flang/test/Lower/HLFIR/convert-variable.f90 | 97 ++++++++++++++++++++++ flang/test/Lower/HLFIR/expr-addr.f90 | 2 +- 7 files changed, 208 insertions(+), 10 deletions(-) create mode 100644 flang/test/Lower/HLFIR/convert-variable.f90 diff --git a/flang/include/flang/Lower/SymbolMap.h b/flang/include/flang/Lower/SymbolMap.h index d2dd1bb..cd959b6 100644 --- a/flang/include/flang/Lower/SymbolMap.h +++ b/flang/include/flang/Lower/SymbolMap.h @@ -16,6 +16,7 @@ #include "flang/Common/reference.h" #include "flang/Optimizer/Builder/BoxValue.h" #include "flang/Optimizer/Dialect/FIRType.h" +#include "flang/Optimizer/Dialect/FortranVariableInterface.h" #include "flang/Optimizer/Support/Matcher.h" #include "flang/Semantics/symbol.h" #include "mlir/IR/Value.h" @@ -338,6 +339,15 @@ public: /// Dump the map. For debugging. LLVM_DUMP_METHOD void dump() const { llvm::errs() << *this << '\n'; } + void addVariableDefinition(semantics::SymbolRef symRef, + fir::FortranVariableOpInterface definingOp, + bool force = false) { + const auto *sym = &symRef.get().GetUltimate(); + if (force) + symbolMapStack.back().erase(sym); + symbolMapStack.back().try_emplace(sym, definingOp); + } + private: /// Add `symbol` to the current map and bind a `box`. void makeSym(semantics::SymbolRef symRef, const SymbolBox &box, @@ -349,7 +359,9 @@ private: symbolMapStack.back().try_emplace(sym, box); } - llvm::SmallVector> + llvm::SmallVector< + llvm::DenseMap>> symbolMapStack; // Implied DO induction variables are not represented as Se::Symbol in diff --git a/flang/include/flang/Optimizer/Builder/FIRBuilder.h b/flang/include/flang/Optimizer/Builder/FIRBuilder.h index 5cfd2ef..3567bc4 100644 --- a/flang/include/flang/Optimizer/Builder/FIRBuilder.h +++ b/flang/include/flang/Optimizer/Builder/FIRBuilder.h @@ -294,6 +294,7 @@ public: mlir::Value genShape(mlir::Location loc, llvm::ArrayRef shift, llvm::ArrayRef exts); mlir::Value genShape(mlir::Location loc, llvm::ArrayRef exts); + mlir::Value genShift(mlir::Location loc, llvm::ArrayRef shift); /// Create one of the shape ops given an extended value. For a boxed value, /// this may create a `fir.shift` op. diff --git a/flang/lib/Lower/ConvertVariable.cpp b/flang/lib/Lower/ConvertVariable.cpp index ff8eba4..d2b1e6b 100644 --- a/flang/lib/Lower/ConvertVariable.cpp +++ b/flang/lib/Lower/ConvertVariable.cpp @@ -1293,6 +1293,42 @@ recoverShapeVector(llvm::ArrayRef shapeVec, mlir::Value initVal) { return result; } +static fir::FortranVariableFlagsAttr +translateSymbolAttributes(mlir::MLIRContext *mlirContext, + const Fortran::semantics::Symbol &sym) { + fir::FortranVariableFlagsEnum flags = fir::FortranVariableFlagsEnum::None; + const auto &attrs = sym.attrs(); + if (attrs.test(Fortran::semantics::Attr::ALLOCATABLE)) + flags = flags | fir::FortranVariableFlagsEnum::allocatable; + if (attrs.test(Fortran::semantics::Attr::ASYNCHRONOUS)) + flags = flags | fir::FortranVariableFlagsEnum::asynchronous; + if (attrs.test(Fortran::semantics::Attr::BIND_C)) + flags = flags | fir::FortranVariableFlagsEnum::bind_c; + if (attrs.test(Fortran::semantics::Attr::CONTIGUOUS)) + flags = flags | fir::FortranVariableFlagsEnum::contiguous; + if (attrs.test(Fortran::semantics::Attr::INTENT_IN)) + flags = flags | fir::FortranVariableFlagsEnum::intent_in; + if (attrs.test(Fortran::semantics::Attr::INTENT_INOUT)) + flags = flags | fir::FortranVariableFlagsEnum::intent_inout; + if (attrs.test(Fortran::semantics::Attr::INTENT_OUT)) + flags = flags | fir::FortranVariableFlagsEnum::intent_out; + if (attrs.test(Fortran::semantics::Attr::OPTIONAL)) + flags = flags | fir::FortranVariableFlagsEnum::optional; + if (attrs.test(Fortran::semantics::Attr::PARAMETER)) + flags = flags | fir::FortranVariableFlagsEnum::parameter; + if (attrs.test(Fortran::semantics::Attr::POINTER)) + flags = flags | fir::FortranVariableFlagsEnum::pointer; + if (attrs.test(Fortran::semantics::Attr::TARGET)) + flags = flags | fir::FortranVariableFlagsEnum::target; + if (attrs.test(Fortran::semantics::Attr::VALUE)) + flags = flags | fir::FortranVariableFlagsEnum::value; + if (attrs.test(Fortran::semantics::Attr::VOLATILE)) + flags = flags | fir::FortranVariableFlagsEnum::fortran_volatile; + if (flags == fir::FortranVariableFlagsEnum::None) + return {}; + return fir::FortranVariableFlagsAttr::get(mlirContext, flags); +} + /// Map a symbol to its FIR address and evaluated specification expressions. /// Not for symbols lowered to fir.box. /// Will optionally create fir.declare. @@ -1303,9 +1339,29 @@ static void genDeclareSymbol(Fortran::lower::AbstractConverter &converter, llvm::ArrayRef shape = llvm::None, llvm::ArrayRef lbounds = llvm::None, bool force = false) { - if (converter.getLoweringOptions().getLowerToHighLevelFIR()) - TODO(genLocation(converter, sym), - "generate fir.declare when lowering symbol"); + if (converter.getLoweringOptions().getLowerToHighLevelFIR()) { + fir::FirOpBuilder &builder = converter.getFirOpBuilder(); + const mlir::Location loc = genLocation(converter, sym); + mlir::Value shapeOrShift; + if (!shape.empty() && !lbounds.empty()) + shapeOrShift = builder.genShape(loc, shape, lbounds); + else if (!shape.empty()) + shapeOrShift = builder.genShape(loc, shape); + else if (!lbounds.empty()) + shapeOrShift = builder.genShift(loc, lbounds); + llvm::SmallVector lenParams; + if (len) + lenParams.emplace_back(len); + auto name = mlir::StringAttr::get(builder.getContext(), + Fortran::lower::mangle::mangleName(sym)); + fir::FortranVariableFlagsAttr attributes = + translateSymbolAttributes(builder.getContext(), sym); + auto newBase = builder.create( + loc, base.getType(), base, shapeOrShift, lenParams, name, attributes); + base = newBase; + symMap.addVariableDefinition(sym, newBase); + return; + } if (len) { if (!shape.empty()) { diff --git a/flang/lib/Lower/SymbolMap.cpp b/flang/lib/Lower/SymbolMap.cpp index c081c8a..2862341 100644 --- a/flang/lib/Lower/SymbolMap.cpp +++ b/flang/lib/Lower/SymbolMap.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "flang/Lower/SymbolMap.h" +#include "flang/Optimizer/Builder/Todo.h" #include "mlir/IR/BuiltinTypes.h" #include "llvm/Support/Debug.h" @@ -30,6 +31,17 @@ void Fortran::lower::SymMap::addSymbol(Fortran::semantics::SymbolRef sym, }); } +Fortran::lower::SymbolBox toSymbolBox( + std::variant + symboxOrdefiningOp) { + if (const Fortran::lower::SymbolBox *symBox = + std::get_if(&symboxOrdefiningOp)) + return *symBox; + auto definingOp = + std::get(symboxOrdefiningOp); + TODO(definingOp.getLoc(), "FortranVariableOpInterface lookup as SymbolBox"); +} + Fortran::lower::SymbolBox Fortran::lower::SymMap::lookupSymbol(Fortran::semantics::SymbolRef symRef) { Fortran::semantics::SymbolRef sym = symRef.get().GetUltimate(); @@ -37,7 +49,7 @@ Fortran::lower::SymMap::lookupSymbol(Fortran::semantics::SymbolRef symRef) { jmap != jend; ++jmap) { auto iter = jmap->find(&*sym); if (iter != jmap->end()) - return iter->second; + return toSymbolBox(iter->second); } return SymbolBox::None{}; } @@ -47,7 +59,7 @@ Fortran::lower::SymbolBox Fortran::lower::SymMap::shallowLookupSymbol( auto &map = symbolMapStack.back(); auto iter = map.find(&symRef.get().GetUltimate()); if (iter != map.end()) - return iter->second; + return toSymbolBox(iter->second); return SymbolBox::None{}; } @@ -65,7 +77,7 @@ Fortran::lower::SymbolBox Fortran::lower::SymMap::lookupOneLevelUpSymbol( for (++jmap; jmap != jend; ++jmap) { auto iter = jmap->find(&*sym); if (iter != jmap->end()) - return iter->second; + return toSymbolBox(iter->second); } return SymbolBox::None{}; } @@ -92,15 +104,29 @@ Fortran::lower::operator<<(llvm::raw_ostream &os, return os; } +static llvm::raw_ostream & +dump(llvm::raw_ostream &os, + const std::variant &symboxOrdefiningOp) { + if (const Fortran::lower::SymbolBox *symBox = + std::get_if(&symboxOrdefiningOp)) + return os << *symBox; + auto definingOp = + std::get(symboxOrdefiningOp); + return os << definingOp << "\n"; +} + llvm::raw_ostream & Fortran::lower::operator<<(llvm::raw_ostream &os, const Fortran::lower::SymMap &symMap) { os << "Symbol map:\n"; for (auto i : llvm::enumerate(symMap.symbolMapStack)) { os << " level " << i.index() << "<{\n"; - for (auto iter : i.value()) + for (auto iter : i.value()) { os << " symbol @" << static_cast(iter.first) << " [" - << *iter.first << "] ->\n " << iter.second; + << *iter.first << "] ->\n "; + dump(os, iter.second); + } os << " }>\n"; } return os; diff --git a/flang/lib/Optimizer/Builder/FIRBuilder.cpp b/flang/lib/Optimizer/Builder/FIRBuilder.cpp index e4ff316..2d65d16 100644 --- a/flang/lib/Optimizer/Builder/FIRBuilder.cpp +++ b/flang/lib/Optimizer/Builder/FIRBuilder.cpp @@ -392,6 +392,12 @@ mlir::Value fir::FirOpBuilder::genShape(mlir::Location loc, return genShape(loc, arr.getLBounds(), arr.getExtents()); } +mlir::Value fir::FirOpBuilder::genShift(mlir::Location loc, + llvm::ArrayRef shift) { + auto shiftType = fir::ShiftType::get(getContext(), shift.size()); + return create(loc, shiftType, shift); +} + mlir::Value fir::FirOpBuilder::createShape(mlir::Location loc, const fir::ExtendedValue &exv) { return exv.match( diff --git a/flang/test/Lower/HLFIR/convert-variable.f90 b/flang/test/Lower/HLFIR/convert-variable.f90 new file mode 100644 index 0000000..6c46232 --- /dev/null +++ b/flang/test/Lower/HLFIR/convert-variable.f90 @@ -0,0 +1,97 @@ +! Test lowering of variables to fir.declare +! RUN: bbc -emit-fir -hlfir %s -o - | FileCheck %s + +subroutine scalar_numeric(x) + integer :: x +end subroutine +! CHECK-LABEL: func.func @_QPscalar_numeric( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref +! CHECK: %[[VAL_1:.*]] = fir.declare %[[VAL_0]] {uniq_name = "_QFscalar_numericEx"} : (!fir.ref) -> !fir.ref + +subroutine scalar_character(c) + character(*) :: c +end subroutine +! CHECK-LABEL: func.func @_QPscalar_character( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.boxchar<1> +! CHECK: %[[VAL_1:.*]]:2 = fir.unboxchar %[[VAL_0]] : (!fir.boxchar<1>) -> (!fir.ref>, index) +! CHECK: %[[VAL_2:.*]] = fir.declare %[[VAL_1]]#0 typeparams %[[VAL_1]]#1 {uniq_name = "_QFscalar_characterEc"} : (!fir.ref>, index) -> !fir.ref> + +subroutine scalar_character_cst_len(c) + character(10) :: c +end subroutine +! CHECK-LABEL: func.func @_QPscalar_character_cst_len( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.boxchar<1> +! CHECK: %[[VAL_1:.*]]:2 = fir.unboxchar %[[VAL_0]] : (!fir.boxchar<1>) -> (!fir.ref>, index) +! CHECK: %[[VAL_2:.*]] = arith.constant 10 : index +! CHECK: %[[VAL_3:.*]] = fir.declare %[[VAL_1]]#0 typeparams %[[VAL_2]] {uniq_name = "_QFscalar_character_cst_lenEc"} : (!fir.ref>, index) -> !fir.ref> + +subroutine array_numeric(x) + integer :: x(10, 20) +end subroutine +! CHECK-LABEL: func.func @_QParray_numeric( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref> +! CHECK: %[[VAL_1:.*]] = arith.constant 10 : index +! CHECK: %[[VAL_2:.*]] = arith.constant 20 : index +! CHECK: %[[VAL_3:.*]] = fir.shape %[[VAL_1]], %[[VAL_2]] : (index, index) -> !fir.shape<2> +! CHECK: %[[VAL_4:.*]] = fir.declare %[[VAL_0]](%[[VAL_3]]) {uniq_name = "_QFarray_numericEx"} : (!fir.ref>, !fir.shape<2>) -> !fir.ref> + + +subroutine array_numeric_lbounds(x) + integer :: x(-1:10, -2:20) +end subroutine +! CHECK-LABEL: func.func @_QParray_numeric_lbounds( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref> +! CHECK: %[[VAL_1:.*]] = arith.constant -1 : index +! CHECK: %[[VAL_2:.*]] = arith.constant 12 : index +! CHECK: %[[VAL_3:.*]] = arith.constant -2 : index +! CHECK: %[[VAL_4:.*]] = arith.constant 23 : index +! CHECK: %[[VAL_5:.*]] = fir.shape_shift %[[VAL_2]], %[[VAL_1]], %[[VAL_4]], %[[VAL_3]] : (index, index, index, index) -> !fir.shapeshift<2> +! CHECK: %[[VAL_6:.*]] = fir.declare %[[VAL_0]](%[[VAL_5]]) {uniq_name = "_QFarray_numeric_lboundsEx"} : (!fir.ref>, !fir.shapeshift<2>) -> !fir.ref> + +subroutine array_character(c) + character(*) :: c(50) +end subroutine +! CHECK-LABEL: func.func @_QParray_character( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.boxchar<1> +! CHECK: %[[VAL_1:.*]]:2 = fir.unboxchar %[[VAL_0]] : (!fir.boxchar<1>) -> (!fir.ref>, index) +! CHECK: %[[VAL_2:.*]] = fir.convert %[[VAL_1]]#0 : (!fir.ref>) -> !fir.ref>> +! CHECK: %[[VAL_3:.*]] = arith.constant 50 : index +! CHECK: %[[VAL_4:.*]] = fir.shape %[[VAL_3]] : (index) -> !fir.shape<1> +! CHECK: %[[VAL_5:.*]] = fir.declare %[[VAL_2]](%[[VAL_4]]) typeparams %[[VAL_1]]#1 {uniq_name = "_QFarray_characterEc"} : (!fir.ref>>, !fir.shape<1>, index) -> !fir.ref>> + +subroutine scalar_numeric_attributes(x) + integer, optional, target, intent(in) :: x +end subroutine +! CHECK-LABEL: func.func @_QPscalar_numeric_attributes( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref +! CHECK: %[[VAL_1:.*]] = fir.declare %[[VAL_0]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFscalar_numeric_attributesEx"} : (!fir.ref) -> !fir.ref + +subroutine scalar_numeric_attributes_2(x) + real(16), value :: x(100) +end subroutine +! CHECK-LABEL: func.func @_QPscalar_numeric_attributes_2( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref> +! CHECK: %[[VAL_1:.*]] = arith.constant 100 : index +! CHECK: %[[VAL_2:.*]] = fir.shape %[[VAL_1]] : (index) -> !fir.shape<1> +! CHECK: %[[VAL_3:.*]] = fir.declare %[[VAL_0]](%[[VAL_2]]) {fortran_attrs = #fir.var_attrs, uniq_name = "_QFscalar_numeric_attributes_2Ex"} : (!fir.ref>, !fir.shape<1>) -> !fir.ref> + +subroutine scalar_numeric_attributes_3(x) + real, intent(in) :: x +end subroutine +! CHECK-LABEL: func.func @_QPscalar_numeric_attributes_3( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref +! CHECK: %[[VAL_1:.*]] = fir.declare %[[VAL_0]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFscalar_numeric_attributes_3Ex"} : (!fir.ref) -> !fir.ref + +subroutine scalar_numeric_attributes_4(x) + logical(8), intent(out) :: x +end subroutine +! CHECK-LABEL: func.func @_QPscalar_numeric_attributes_4( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref> +! CHECK: %[[VAL_1:.*]] = fir.declare %[[VAL_0]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFscalar_numeric_attributes_4Ex"} : (!fir.ref>) -> !fir.ref> + +subroutine scalar_numeric_parameter() + integer, parameter :: p = 42 +end subroutine +! CHECK-LABEL: func.func @_QPscalar_numeric_parameter() { +! CHECK: %[[VAL_0:.*]] = fir.address_of(@_QFscalar_numeric_parameterECp) : !fir.ref +! CHECK: %[[VAL_1:.*]] = fir.declare %[[VAL_0]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFscalar_numeric_parameterECp"} : (!fir.ref) -> !fir.ref diff --git a/flang/test/Lower/HLFIR/expr-addr.f90 b/flang/test/Lower/HLFIR/expr-addr.f90 index 0ae9df5..1af59e6c 100644 --- a/flang/test/Lower/HLFIR/expr-addr.f90 +++ b/flang/test/Lower/HLFIR/expr-addr.f90 @@ -3,6 +3,6 @@ subroutine foo(x) integer :: x - ! CHECK: not yet implemented: generate fir.declare when lowering symbol + ! CHECK: not yet implemented: lower expr to HLFIR address read (*,*) x end subroutine -- 2.7.4