diff --git a/flang/include/flang/Optimizer/Builder/HLFIRTools.h b/flang/include/flang/Optimizer/Builder/HLFIRTools.h --- a/flang/include/flang/Optimizer/Builder/HLFIRTools.h +++ b/flang/include/flang/Optimizer/Builder/HLFIRTools.h @@ -41,6 +41,12 @@ /// original source or can be legally defined: temporaries created to store /// expression values are considered to be variables, and so are PARAMETERs /// global constant address. +inline bool isFortranEntity(mlir::Value value) { + return isFortranValue(value) || isFortranVariableType(value.getType()); +} + +/// Is this a Fortran variable for which the defining op carrying the Fortran +/// attributes is visible? inline bool isFortranVariableWithAttributes(mlir::Value value) { return value.getDefiningOp(); } @@ -51,25 +57,78 @@ return isFortranValue(value) || isFortranVariableWithAttributes(value); } +class Entity : public mlir::Value { +public: + explicit Entity(mlir::Value value) : mlir::Value(value) { + assert(isFortranEntity(value) && + "must be a value representing a Fortran value or variable like"); + } + Entity(fir::FortranVariableOpInterface variable) + : mlir::Value(variable.getBase()) {} + bool isValue() const { return isFortranValue(*this); } + bool isVariable() const { return !isValue(); } + bool isMutableBox() const { + mlir::Type type = fir::dyn_cast_ptrEleTy(getType()); + return type && type.isa(); + } + bool isArray() const { + mlir::Type type = fir::unwrapPassByRefType(fir::unwrapRefType(getType())); + if (type.isa()) + return true; + if (auto exprType = type.dyn_cast()) + return exprType.isArray(); + return false; + } + bool isScalar() const { return !isArray(); } + + mlir::Type getFortranElementType() const { + mlir::Type type = fir::unwrapSequenceType( + fir::unwrapPassByRefType(fir::unwrapRefType(getType()))); + if (auto exprType = type.dyn_cast()) + return exprType.getEleTy(); + return type; + } + + bool hasLengthParameters() const { + mlir::Type eleTy = getFortranElementType(); + return eleTy.isa() || + fir::isRecordWithTypeParameters(eleTy); + } + + fir::FortranVariableOpInterface getIfVariableInterface() const { + return this->getDefiningOp(); + } + + // Get the entity as an mlir SSA value containing all the shape, type + // parameters and dynamic shape information. + mlir::Value getBase() const { return *this; } + + // Get the entity as a FIR base. This may not carry the shape and type + // parameters information, and even when it is a box with shape information. + // it will not contain the local lower bounds of the entity. This should + // be used with care when generating FIR code that does not need this + // information, or has access to it in other ways. Its advantage is that + // it will never be a fir.box for explicit shape arrays, leading to simpler + // FIR code generation. + mlir::Value getFirBase() const; +}; + /// Wrapper over an mlir::Value that can be viewed as a Fortran entity. /// This provides some Fortran specific helpers as well as a guarantee /// in the compiler source that a certain mlir::Value must be a Fortran /// entity, and if it is a variable, its defining operation carrying its /// Fortran attributes must be visible. -class EntityWithAttributes : public mlir::Value { +class EntityWithAttributes : public Entity { public: - explicit EntityWithAttributes(mlir::Value value) : mlir::Value(value) { + explicit EntityWithAttributes(mlir::Value value) : Entity(value) { assert(isFortranEntityWithAttributes(value) && "must be a value representing a Fortran value or variable"); } EntityWithAttributes(fir::FortranVariableOpInterface variable) - : mlir::Value(variable.getBase()) {} - bool isValue() const { return isFortranValue(*this); } - bool isVariable() const { return !isValue(); } + : Entity(variable) {} fir::FortranVariableOpInterface getIfVariable() const { - return this->getDefiningOp(); + return getIfVariableInterface(); } - mlir::Value getBase() const { return *this; } }; /// Functions to translate hlfir::EntityWithAttributes to fir::ExtendedValue. @@ -80,7 +139,7 @@ using CleanupFunction = std::function; std::pair> translateToExtendedValue(mlir::Location loc, fir::FirOpBuilder &builder, - EntityWithAttributes entity); + Entity entity); /// Function to translate FortranVariableOpInterface to fir::ExtendedValue. /// It does not generate any IR, and is a simple packaging operation. @@ -93,6 +152,12 @@ llvm::StringRef name, fir::FortranVariableFlagsAttr flags); +/// If the entity is a variable, load its value (dereference pointers and +/// allocatables if needed). Do nothing if the entity os already a variable or +/// if it is not a scalar entity of numerical or logical type. +Entity loadTrivialScalar(mlir::Location loc, fir::FirOpBuilder &builder, + Entity entity); + } // namespace hlfir #endif // FORTRAN_OPTIMIZER_BUILDER_HLFIRTOOLS_H diff --git a/flang/lib/Lower/ConvertVariable.cpp b/flang/lib/Lower/ConvertVariable.cpp --- a/flang/lib/Lower/ConvertVariable.cpp +++ b/flang/lib/Lower/ConvertVariable.cpp @@ -17,6 +17,7 @@ #include "flang/Lower/CallInterface.h" #include "flang/Lower/ConvertConstant.h" #include "flang/Lower/ConvertExpr.h" +#include "flang/Lower/ConvertExprToHLFIR.h" #include "flang/Lower/IntrinsicCall.h" #include "flang/Lower/Mangler.h" #include "flang/Lower/PFTBuilder.h" @@ -25,11 +26,13 @@ #include "flang/Lower/SymbolMap.h" #include "flang/Optimizer/Builder/Character.h" #include "flang/Optimizer/Builder/FIRBuilder.h" +#include "flang/Optimizer/Builder/HLFIRTools.h" #include "flang/Optimizer/Builder/Runtime/Derived.h" #include "flang/Optimizer/Builder/Todo.h" #include "flang/Optimizer/Dialect/FIRAttr.h" #include "flang/Optimizer/Dialect/FIRDialect.h" #include "flang/Optimizer/Dialect/FIROps.h" +#include "flang/Optimizer/HLFIR/HLFIROps.h" #include "flang/Optimizer/Support/FIRContext.h" #include "flang/Optimizer/Support/FatalError.h" #include "flang/Semantics/runtime-type-info.h" @@ -46,6 +49,13 @@ Fortran::lower::StatementContext &context) { // This does not use the AbstractConverter member function to override the // symbol mapping to be used expression lowering. + if (converter.getLoweringOptions().getLowerToHighLevelFIR()) { + hlfir::EntityWithAttributes loweredExpr = + Fortran::lower::convertExprToHLFIR(loc, converter, expr, symMap, + context); + return hlfir::loadTrivialScalar(loc, converter.getFirOpBuilder(), + loweredExpr); + } return fir::getBase(Fortran::lower::createSomeExtendedExpression( loc, converter, expr, symMap, context)); } @@ -1345,7 +1355,7 @@ const mlir::Location loc = genLocation(converter, sym); mlir::Value shapeOrShift; if (!shape.empty() && !lbounds.empty()) - shapeOrShift = builder.genShape(loc, shape, lbounds); + shapeOrShift = builder.genShape(loc, lbounds, shape); else if (!shape.empty()) shapeOrShift = builder.genShape(loc, shape); else if (!lbounds.empty()) @@ -1353,13 +1363,11 @@ llvm::SmallVector lenParams; if (len) lenParams.emplace_back(len); - auto name = mlir::StringAttr::get(builder.getContext(), - Fortran::lower::mangle::mangleName(sym)); + auto name = 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; + auto newBase = builder.create( + loc, base, name, shapeOrShift, lenParams, attributes); symMap.addVariableDefinition(sym, newBase, force); return; } @@ -1390,11 +1398,20 @@ static void genDeclareSymbol(Fortran::lower::AbstractConverter &converter, Fortran::lower::SymMap &symMap, const Fortran::semantics::Symbol &sym, - const fir::ExtendedValue &exv) { - if (converter.getLoweringOptions().getLowerToHighLevelFIR()) - TODO(genLocation(converter, sym), - "generate fir.declare from ExtendedValue"); - symMap.addSymbol(sym, exv); + const fir::ExtendedValue &exv, + bool force = false) { + if (converter.getLoweringOptions().getLowerToHighLevelFIR()) { + fir::FirOpBuilder &builder = converter.getFirOpBuilder(); + const mlir::Location loc = genLocation(converter, sym); + fir::FortranVariableFlagsAttr attributes = + translateSymbolAttributes(builder.getContext(), sym); + auto name = Fortran::lower::mangle::mangleName(sym); + hlfir::EntityWithAttributes declare = + hlfir::genDeclare(loc, builder, exv, name, attributes); + symMap.addVariableDefinition(sym, declare.getIfVariableInterface(), force); + return; + } + symMap.addSymbol(sym, exv, force); } /// Map an allocatable or pointer symbol to its FIR address and evaluated @@ -1419,8 +1436,11 @@ llvm::ArrayRef explicitParams, llvm::ArrayRef explicitExtents, bool replace = false) { - if (converter.getLoweringOptions().getLowerToHighLevelFIR()) - TODO(genLocation(converter, sym), "generate fir.declare for box"); + if (converter.getLoweringOptions().getLowerToHighLevelFIR()) { + fir::BoxValue boxValue{box, lbounds, explicitParams, explicitExtents}; + genDeclareSymbol(converter, symMap, sym, std::move(boxValue), replace); + return; + } symMap.addBoxSymbol(sym, box, lbounds, explicitParams, explicitExtents, replace); } diff --git a/flang/lib/Optimizer/Builder/HLFIRTools.cpp b/flang/lib/Optimizer/Builder/HLFIRTools.cpp --- a/flang/lib/Optimizer/Builder/HLFIRTools.cpp +++ b/flang/lib/Optimizer/Builder/HLFIRTools.cpp @@ -12,7 +12,9 @@ #include "flang/Optimizer/Builder/HLFIRTools.h" #include "flang/Optimizer/Builder/FIRBuilder.h" +#include "flang/Optimizer/Builder/MutableBox.h" #include "flang/Optimizer/Builder/Todo.h" +#include "flang/Optimizer/HLFIR/HLFIROps.h" // Return explicit extents. If the base is a fir.box, this won't read it to // return the extents and will instead return an empty vector. @@ -68,34 +70,48 @@ std::pair> hlfir::translateToExtendedValue(mlir::Location loc, fir::FirOpBuilder &, - hlfir::EntityWithAttributes entity) { - if (auto variable = entity.getIfVariable()) + hlfir::Entity entity) { + if (auto variable = entity.getIfVariableInterface()) return {hlfir::translateToExtendedValue(variable), {}}; + if (entity.isVariable()) + TODO(loc, "HLFIR variable to fir::ExtendedValue without a " + "FortranVariableOpInterface"); if (entity.getType().isa()) TODO(loc, "hlfir.expr to fir::ExtendedValue"); // use hlfir.associate return {{static_cast(entity)}, {}}; } +mlir::Value hlfir::Entity::getFirBase() const { + if (fir::FortranVariableOpInterface variable = getIfVariableInterface()) + if (auto declareOp = + mlir::dyn_cast(variable.getOperation())) + return declareOp.getOriginalBase(); + return getBase(); +} + fir::ExtendedValue hlfir::translateToExtendedValue(fir::FortranVariableOpInterface variable) { + /// When going towards FIR, use the original base value to avoid + /// introducing descriptors at runtime when they are not required. + mlir::Value firBase = Entity{variable}.getFirBase(); if (variable.isPointer() || variable.isAllocatable()) TODO(variable->getLoc(), "pointer or allocatable " "FortranVariableOpInterface to extendedValue"); - if (variable.getBase().getType().isa()) - return fir::BoxValue(variable.getBase(), getExplicitLbounds(variable), - getExplicitTypeParams(variable), - getExplicitExtents(variable)); + if (firBase.getType().isa()) + return fir::BoxValue(firBase, getExplicitLbounds(variable), + getExplicitTypeParams(variable)); + if (variable.isCharacter()) { if (variable.isArray()) - return fir::CharArrayBoxValue( - variable.getBase(), variable.getExplicitCharLen(), - getExplicitExtents(variable), getExplicitLbounds(variable)); - return fir::CharBoxValue(variable.getBase(), variable.getExplicitCharLen()); + return fir::CharArrayBoxValue(firBase, variable.getExplicitCharLen(), + getExplicitExtents(variable), + getExplicitLbounds(variable)); + return fir::CharBoxValue(firBase, variable.getExplicitCharLen()); } if (variable.isArray()) - return fir::ArrayBoxValue(variable.getBase(), getExplicitExtents(variable), + return fir::ArrayBoxValue(firBase, getExplicitExtents(variable), getExplicitLbounds(variable)); - return variable.getBase(); + return firBase; } hlfir::EntityWithAttributes @@ -130,8 +146,22 @@ box.nonDeferredLenParams().end()); }, [](const auto &) {}); - auto nameAttr = mlir::StringAttr::get(builder.getContext(), name); - auto declareOp = builder.create( - loc, base.getType(), base, shapeOrShift, lenParams, nameAttr, flags); + auto declareOp = builder.create( + loc, base, name, shapeOrShift, lenParams, flags); return mlir::cast(declareOp.getOperation()); } + +/// If the entity is a variable, load its value (dereference pointers and +/// allocatables if needed). Do nothing if the entity os already a variable or +/// if it is not a scalar entity of numerical or logical type. +hlfir::Entity hlfir::loadTrivialScalar(mlir::Location loc, + fir::FirOpBuilder &builder, + Entity entity) { + if (entity.isVariable() && entity.isScalar() && + fir::isa_trivial(entity.getFortranElementType())) { + if (entity.isMutableBox()) + TODO(loc, "load pointer/allocatable scalar"); + return Entity{builder.create(loc, entity)}; + } + return entity; +} diff --git a/flang/test/Lower/HLFIR/constant.f90 b/flang/test/Lower/HLFIR/constant.f90 --- a/flang/test/Lower/HLFIR/constant.f90 +++ b/flang/test/Lower/HLFIR/constant.f90 @@ -16,7 +16,7 @@ print *, "hello" ! CHECK: %[[VAL_5:.*]] = fir.address_of(@[[name:.*]]) : !fir.ref> ! CHECK: %[[VAL_6:.*]] = arith.constant 5 : index -! CHECK: fir.declare %[[VAL_5]] typeparams %[[VAL_6]] {fortran_attrs = #fir.var_attrs, uniq_name = "[[name]]"} : (!fir.ref>, index) -> !fir.ref> +! CHECK: hlfir.declare %[[VAL_5]] typeparams %[[VAL_6]] {fortran_attrs = #fir.var_attrs, uniq_name = "[[name]]"} : (!fir.ref>, index) -> (!fir.ref>, !fir.ref>) end subroutine ! CHECK-LABEL: func.func @_QPtest_constant_array() @@ -25,7 +25,7 @@ ! CHECK: %[[VAL_5:.*]] = fir.address_of(@[[name:.*]]) : !fir.ref> ! CHECK: %[[VAL_6:.*]] = arith.constant 3 : index ! CHECK: %[[VAL_7:.*]] = fir.shape %[[VAL_6]] : (index) -> !fir.shape<1> -! CHECK: fir.declare %[[VAL_5]](%[[VAL_7]]) {fortran_attrs = #fir.var_attrs, uniq_name = "[[name]]"} : (!fir.ref>, !fir.shape<1>) -> !fir.ref> +! CHECK: hlfir.declare %[[VAL_5]](%[[VAL_7]]) {fortran_attrs = #fir.var_attrs, uniq_name = "[[name]]"} : (!fir.ref>, !fir.shape<1>) -> (!fir.ref>, !fir.ref>) end subroutine ! CHECK-LABEL: func.func @_QPtest_constant_array_char() @@ -35,7 +35,7 @@ ! CHECK: %[[VAL_6:.*]] = arith.constant 2 : index ! CHECK: %[[VAL_7:.*]] = arith.constant 3 : index ! CHECK: %[[VAL_8:.*]] = fir.shape %[[VAL_6]] : (index) -> !fir.shape<1> -! CHECK: fir.declare %[[VAL_5]](%[[VAL_8]]) typeparams %[[VAL_7]] {fortran_attrs = #fir.var_attrs, uniq_name = "[[name]]"} : (!fir.ref>>, !fir.shape<1>, index) -> !fir.ref>> +! CHECK: hlfir.declare %[[VAL_5]](%[[VAL_8]]) typeparams %[[VAL_7]] {fortran_attrs = #fir.var_attrs, uniq_name = "[[name]]"} : (!fir.ref>>, !fir.shape<1>, index) -> (!fir.ref>>, !fir.ref>>) end subroutine ! CHECK-LABEL: func.func @_QPtest_constant_with_lower_bounds() @@ -48,5 +48,5 @@ ! CHECK: %[[VAL_15:.*]] = arith.constant -1 : index ! CHECK: %[[VAL_16:.*]] = arith.constant -1 : index ! CHECK: %[[VAL_17:.*]] = fir.shape_shift %[[VAL_15]], %[[VAL_13]], %[[VAL_16]], %[[VAL_14]] : (index, index, index, index) -> !fir.shapeshift<2> -! CHECK: fir.declare %[[VAL_12]](%[[VAL_17]]) {fortran_attrs = #fir.var_attrs, uniq_name = "_QQro[[name]]"} : (!fir.ref>, !fir.shapeshift<2>) -> !fir.ref> +! CHECK: hlfir.declare %[[VAL_12]](%[[VAL_17]]) {fortran_attrs = #fir.var_attrs, uniq_name = "_QQro[[name]]"} : (!fir.ref>, !fir.shapeshift<2>) -> (!fir.box>, !fir.ref>) end subroutine diff --git a/flang/test/Lower/HLFIR/convert-variable.f90 b/flang/test/Lower/HLFIR/convert-variable.f90 --- a/flang/test/Lower/HLFIR/convert-variable.f90 +++ b/flang/test/Lower/HLFIR/convert-variable.f90 @@ -6,7 +6,7 @@ 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 +! CHECK: %[[VAL_1:.*]] = hlfir.declare %[[VAL_0]] {uniq_name = "_QFscalar_numericEx"} : (!fir.ref) -> (!fir.ref, !fir.ref) subroutine scalar_character(c) character(*) :: c @@ -14,7 +14,7 @@ ! 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> +! CHECK: %[[VAL_2:.*]] = hlfir.declare %[[VAL_1]]#0 typeparams %[[VAL_1]]#1 {uniq_name = "_QFscalar_characterEc"} : (!fir.ref>, index) -> (!fir.boxchar<1>, !fir.ref>) subroutine scalar_character_cst_len(c) character(10) :: c @@ -23,7 +23,7 @@ ! 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> +! CHECK: %[[VAL_3:.*]] = hlfir.declare %[[VAL_1]]#0 typeparams %[[VAL_2]] {uniq_name = "_QFscalar_character_cst_lenEc"} : (!fir.ref>, index) -> (!fir.boxchar<1>, !fir.ref>) subroutine array_numeric(x) integer :: x(10, 20) @@ -33,7 +33,7 @@ ! 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> +! CHECK: %[[VAL_4:.*]] = hlfir.declare %[[VAL_0]](%[[VAL_3]]) {uniq_name = "_QFarray_numericEx"} : (!fir.ref>, !fir.shape<2>) -> (!fir.ref>, !fir.ref>) subroutine array_numeric_lbounds(x) @@ -45,8 +45,8 @@ ! 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> +! CHECK: %[[VAL_5:.*]] = fir.shape_shift %[[VAL_1]], %[[VAL_2]], %[[VAL_3]], %[[VAL_4]] : (index, index, index, index) -> !fir.shapeshift<2> +! CHECK: %[[VAL_6:.*]] = hlfir.declare %[[VAL_0]](%[[VAL_5]]) {uniq_name = "_QFarray_numeric_lboundsEx"} : (!fir.ref>, !fir.shapeshift<2>) -> (!fir.box>, !fir.ref>) subroutine array_character(c) character(*) :: c(50) @@ -57,14 +57,14 @@ ! 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>> +! CHECK: %[[VAL_5:.*]] = hlfir.declare %[[VAL_2]](%[[VAL_4]]) typeparams %[[VAL_1]]#1 {uniq_name = "_QFarray_characterEc"} : (!fir.ref>>, !fir.shape<1>, index) -> (!fir.box>>, !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 +! CHECK: %[[VAL_1:.*]] = hlfir.declare %[[VAL_0]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFscalar_numeric_attributesEx"} : (!fir.ref) -> (!fir.ref, !fir.ref) subroutine scalar_numeric_attributes_2(x) real(16), value :: x(100) @@ -73,25 +73,25 @@ ! 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> +! CHECK: %[[VAL_3:.*]] = hlfir.declare %[[VAL_0]](%[[VAL_2]]) {fortran_attrs = #fir.var_attrs, uniq_name = "_QFscalar_numeric_attributes_2Ex"} : (!fir.ref>, !fir.shape<1>) -> (!fir.ref>, !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 +! CHECK: %[[VAL_1:.*]] = hlfir.declare %[[VAL_0]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFscalar_numeric_attributes_3Ex"} : (!fir.ref) -> (!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> +! CHECK: %[[VAL_1:.*]] = hlfir.declare %[[VAL_0]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFscalar_numeric_attributes_4Ex"} : (!fir.ref>) -> (!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 +! CHECK: %[[VAL_1:.*]] = hlfir.declare %[[VAL_0]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFscalar_numeric_parameterECp"} : (!fir.ref) -> (!fir.ref, !fir.ref) diff --git a/flang/test/Lower/HLFIR/expr-addr.f90 b/flang/test/Lower/HLFIR/expr-addr.f90 --- a/flang/test/Lower/HLFIR/expr-addr.f90 +++ b/flang/test/Lower/HLFIR/expr-addr.f90 @@ -6,7 +6,7 @@ subroutine foo(x) integer :: x read (*,*) x - ! CHECK: %[[x:.]] = fir.declare %[[arg0]] {uniq_name = "_QFfooEx"} : (!fir.ref) -> !fir.ref - ! CHECK: %[[x_cast:.*]] = fir.convert %[[x]] : (!fir.ref) -> !fir.ref + ! CHECK: %[[x:.]]:2 = hlfir.declare %[[arg0]] {uniq_name = "_QFfooEx"} : (!fir.ref) -> (!fir.ref, !fir.ref) + ! CHECK: %[[x_cast:.*]] = fir.convert %[[x]]#1 : (!fir.ref) -> !fir.ref ! CHECK: fir.call @_FortranAioInputInteger(%{{.*}}, %[[x_cast]], %{{.*}}) : (!fir.ref, !fir.ref, i32) -> i1 end subroutine diff --git a/flang/test/Lower/HLFIR/expr-box.f90 b/flang/test/Lower/HLFIR/expr-box.f90 --- a/flang/test/Lower/HLFIR/expr-box.f90 +++ b/flang/test/Lower/HLFIR/expr-box.f90 @@ -8,7 +8,7 @@ print *, x ! CHECK-DAG: %[[VAL_3:.*]] = arith.constant 21 : index ! CHECK-DAG: %[[VAL_4:.*]] = arith.constant 10 : index -! CHECK: %[[VAL_5:.*]] = fir.shape_shift %[[VAL_4]], %[[VAL_3]] : (index, index) -> !fir.shapeshift<1> -! CHECK: %[[VAL_6:.*]] = fir.declare %[[VAL_0]](%[[VAL_5]]) {uniq_name = "_QFfooEx"} : (!fir.ref>, !fir.shapeshift<1>) -> !fir.ref> -! CHECK: fir.embox %[[VAL_6]](%[[VAL_5]]) : (!fir.ref>, !fir.shapeshift<1>) -> !fir.box> +! CHECK: %[[VAL_5:.*]] = fir.shape_shift %[[VAL_3]], %[[VAL_4]] : (index, index) -> !fir.shapeshift<1> +! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_0]](%[[VAL_5]]) {uniq_name = "_QFfooEx"} : (!fir.ref>, !fir.shapeshift<1>) -> (!fir.box>, !fir.ref>) +! CHECK: fir.embox %[[VAL_6]]#1(%[[VAL_5]]) : (!fir.ref>, !fir.shapeshift<1>) -> !fir.box> end subroutine diff --git a/flang/test/Lower/HLFIR/expr-value.f90 b/flang/test/Lower/HLFIR/expr-value.f90 --- a/flang/test/Lower/HLFIR/expr-value.f90 +++ b/flang/test/Lower/HLFIR/expr-value.f90 @@ -11,8 +11,8 @@ ! CHECK-LABEL: func.func @_QPfoo_designator( ! CHECK-SAME: %[[arg0:.*]]: !fir.ref subroutine foo_designator(n) - !CHECK: %[[n:.*]] = fir.declare %[[arg0]] {uniq_name = "_QFfoo_designatorEn"} : (!fir.ref) -> !fir.ref + !CHECK: %[[n:.*]]:2 = hlfir.declare %[[arg0]] {uniq_name = "_QFfoo_designatorEn"} : (!fir.ref) -> (!fir.ref, !fir.ref) print *, n - ! CHECK: %[[nval:.*]] = fir.load %[[n]] : !fir.ref + ! CHECK: %[[nval:.*]] = fir.load %[[n]]#1 : !fir.ref ! CHECK: fir.call @_FortranAioOutputInteger32(%{{.*}}, %[[nval]]) : (!fir.ref, i32) -> i1 end subroutine diff --git a/flang/unittests/Optimizer/Builder/HLFIRToolsTest.cpp b/flang/unittests/Optimizer/Builder/HLFIRToolsTest.cpp --- a/flang/unittests/Optimizer/Builder/HLFIRToolsTest.cpp +++ b/flang/unittests/Optimizer/Builder/HLFIRToolsTest.cpp @@ -36,33 +36,8 @@ } mlir::Value createDeclare(fir::ExtendedValue exv) { - mlir::Value addr = fir::getBase(exv); - mlir::Location loc = getLoc(); - mlir::Value shape; - if (exv.rank() > 0) - shape = firBuilder->createShape(loc, exv); - llvm::SmallVector typeParams; - exv.match( - [&](const fir::CharBoxValue &x) { - typeParams.emplace_back(x.getLen()); - }, - [&](const fir::CharArrayBoxValue &x) { - typeParams.emplace_back(x.getLen()); - }, - [&](const fir::BoxValue &x) { - typeParams.append(x.getExplicitParameters().begin(), - x.getExplicitParameters().end()); - }, - [&](const fir::MutableBoxValue &x) { - typeParams.append( - x.nonDeferredLenParams().begin(), x.nonDeferredLenParams().end()); - }, - [](const auto &) {}); - auto name = - mlir::StringAttr::get(&context, "x" + std::to_string(varCounter++)); - return firBuilder->create(loc, addr.getType(), addr, shape, - typeParams, name, - /*fortran_attrs=*/fir::FortranVariableFlagsAttr{}); + return hlfir::genDeclare(getLoc(), *firBuilder, exv, + "x" + std::to_string(varCounter++), fir::FortranVariableFlagsAttr{}); } mlir::Value createConstant(std::int64_t cst) { @@ -92,7 +67,7 @@ auto *unboxed = scalarf32Result.getUnboxed(); EXPECT_FALSE(cleanup.has_value()); ASSERT_NE(unboxed, nullptr); - EXPECT_TRUE(*unboxed == scalarf32Entity.getBase()); + EXPECT_TRUE(*unboxed == scalarf32Entity.getFirBase()); EXPECT_TRUE(scalarf32Entity.isVariable()); EXPECT_FALSE(scalarf32Entity.isValue()); } @@ -118,7 +93,7 @@ ASSERT_NE(res, nullptr); // gtest has a terrible time printing mlir::Value in case of failing // EXPECT_EQ(mlir::Value, mlir::Value). So use EXPECT_TRUE instead. - EXPECT_TRUE(fir::getBase(*res) == arrayf32Entity.getBase()); + EXPECT_TRUE(fir::getBase(*res) == arrayf32Entity.getFirBase()); ASSERT_EQ(res->getExtents().size(), arrayf32.getExtents().size()); for (unsigned i = 0; i < arrayf32.getExtents().size(); ++i) EXPECT_TRUE(res->getExtents()[i] == arrayf32.getExtents()[i]); @@ -144,7 +119,7 @@ auto *res = scalarCharResult.getBoxOf(); EXPECT_FALSE(cleanup.has_value()); ASSERT_NE(res, nullptr); - EXPECT_TRUE(fir::getBase(*res) == scalarCharEntity.getBase()); + EXPECT_TRUE(fir::getBase(*res) == scalarCharEntity.getFirBase()); EXPECT_TRUE(res->getLen() == scalarChar.getLen()); EXPECT_TRUE(scalarCharEntity.isVariable()); EXPECT_FALSE(scalarCharEntity.isValue()); @@ -171,7 +146,7 @@ ASSERT_NE(res, nullptr); // gtest has a terrible time printing mlir::Value in case of failing // EXPECT_EQ(mlir::Value, mlir::Value). So use EXPECT_TRUE instead. - EXPECT_TRUE(fir::getBase(*res) == arrayCharEntity.getBase()); + EXPECT_TRUE(fir::getBase(*res) == arrayCharEntity.getFirBase()); EXPECT_TRUE(res->getLen() == arrayChar.getLen()); ASSERT_EQ(res->getExtents().size(), arrayChar.getExtents().size()); for (unsigned i = 0; i < arrayChar.getExtents().size(); ++i) @@ -204,7 +179,7 @@ ASSERT_NE(res, nullptr); // gtest has a terrible time printing mlir::Value in case of failing // EXPECT_EQ(mlir::Value, mlir::Value). So use EXPECT_TRUE instead. - EXPECT_TRUE(fir::getBase(*res) == arrayCharEntity.getBase()); + EXPECT_TRUE(fir::getBase(*res) == arrayCharEntity.getFirBase()); ASSERT_EQ(res->getExplicitParameters().size(), arrayChar.getExplicitParameters().size()); for (unsigned i = 0; i < arrayChar.getExplicitParameters().size(); ++i)