llvm_unreachable("getting host associated type in CallerInterface");
}
+ /// Set attributes on MLIR function.
+ void setFuncAttrs(mlir::func::FuncOp) const {}
+
private:
/// Check that the input vector is complete.
bool verifyActualInputs() const;
bool hasHostAssociated() const;
mlir::Type getHostAssociatedTy() const;
mlir::Value getHostAssociatedTuple() const;
+ void setFuncAttrs(mlir::func::FuncOp) const;
private:
Fortran::lower::pft::FunctionLikeUnit &funit;
namespace Fortran {
namespace semantics {
class Symbol;
-}
+class Scope;
+} // namespace semantics
namespace lower {
class AbstractConverter;
class HostAssociations {
public:
/// Returns true iff there are no host associations.
- bool empty() const { return symbols.empty(); }
+ bool empty() const { return tupleSymbols.empty() && globalSymbols.empty(); }
+
+ /// Returns true iff there are host associations that are conveyed through
+ /// an extra tuple argument.
+ bool hasTupleAssociations() const { return !tupleSymbols.empty(); }
/// Adds a set of Symbols that will be the host associated bindings for this
/// host procedure.
void addSymbolsToBind(
- const llvm::SetVector<const Fortran::semantics::Symbol *> &s) {
- assert(empty() && "symbol set must be initially empty");
- symbols = s;
- }
+ const llvm::SetVector<const Fortran::semantics::Symbol *> &symbols,
+ const Fortran::semantics::Scope &hostScope);
/// Code gen the FIR for the local bindings for the host associated symbols
/// for the host (parent) procedure using `builder`.
/// Is \p symbol host associated ?
bool isAssociated(const Fortran::semantics::Symbol &symbol) const {
- return symbols.contains(&symbol);
+ return tupleSymbols.contains(&symbol) || globalSymbols.contains(&symbol);
}
private:
- /// Canonical vector of host associated symbols.
- llvm::SetVector<const Fortran::semantics::Symbol *> symbols;
+ /// Canonical vector of host associated local symbols.
+ llvm::SetVector<const Fortran::semantics::Symbol *> tupleSymbols;
+
+ /// Canonical vector of host associated global symbols.
+ llvm::SetVector<const Fortran::semantics::Symbol *> globalSymbols;
/// The type of the extra argument to be added to each internal procedure.
mlir::Type argType;
+
+ /// Scope of the parent procedure if addSymbolsToBind was called.
+ const Fortran::semantics::Scope *hostScope;
};
} // namespace lower
} // namespace Fortran
void setHostAssociatedSymbols(
const llvm::SetVector<const semantics::Symbol *> &symbols) {
- hostAssociations.addSymbolsToBind(symbols);
+ hostAssociations.addSymbolsToBind(symbols, getScope());
}
/// Return the host associations, if any, from the parent (host) procedure.
HostAssociations &parentHostAssoc();
/// Return true iff the parent is a procedure and the parent has a non-empty
- /// set of host associations.
+ /// set of host associations that are conveyed through an extra tuple
+ /// argument.
+ bool parentHasTupleHostAssoc();
+
+ /// Return true iff the parent is a procedure and the parent has a non-empty
+ /// set of host associations for variables.
bool parentHasHostAssoc();
/// Return the host associations for this function like unit. The list of host
return "fir.host_assoc";
}
+/// Attribute to mark an internal procedure.
+static constexpr llvm::StringRef getInternalProcedureAttrName() {
+ return "fir.internal_proc";
+}
+
/// Does the function, \p func, have a host-associations tuple argument?
/// Some internal procedures may have access to host procedure variables.
bool hasHostAssociationArgument(mlir::func::FuncOp func);
+/// Is the function, \p func an internal procedure ?
+/// Some internal procedures may have access to saved host procedure
+/// variables even when they do not have a tuple argument.
+inline bool isInternalPorcedure(mlir::func::FuncOp func) {
+ return func->hasAttr(fir::getInternalProcedureAttrName());
+}
+
/// Tell if \p value is:
/// - a function argument that has attribute \p attributeName
/// - or, the result of fir.alloca/fir.allocamem op that has attribute \p
}
addSymbol(arg.entity->get(), arg.firArgument);
} else {
- assert(funit.parentHasHostAssoc());
- funit.parentHostAssoc().internalProcedureBindings(*this,
- localSymbols);
+ assert(funit.parentHasTupleHostAssoc() && "expect tuple argument");
}
}
};
mapDummiesAndResults(funit, callee);
+ // Map host associated symbols from parent procedure if any.
+ if (funit.parentHasHostAssoc())
+ funit.parentHostAssoc().internalProcedureBindings(*this, localSymbols);
+
// Non-primary results of a function with multiple entry points.
// These result values share storage with the primary result.
llvm::SmallVector<Fortran::lower::pft::Variable> deferredFuncResultList;
// to the host variable, which must be in the map.
const Fortran::semantics::Symbol &ultimate = sym.GetUltimate();
if (funit.parentHostAssoc().isAssociated(ultimate)) {
- Fortran::lower::SymbolBox hostBox = lookupSymbol(ultimate);
- assert(hostBox && "host association is not in map");
- localSymbols.addSymbol(sym, hostBox.toExtendedValue());
+ copySymbolBinding(ultimate, sym);
continue;
}
}
}
bool Fortran::lower::CalleeInterface::hasHostAssociated() const {
- return funit.parentHasHostAssoc();
+ return funit.parentHasTupleHostAssoc();
}
mlir::Type Fortran::lower::CalleeInterface::getHostAssociatedTy() const {
return converter.hostAssocTupleValue();
}
+void Fortran::lower::CalleeInterface::setFuncAttrs(
+ mlir::func::FuncOp func) const {
+ if (funit.parentHasHostAssoc())
+ func->setAttr(fir::getInternalProcedureAttrName(),
+ mlir::UnitAttr::get(func->getContext()));
+}
+
//===----------------------------------------------------------------------===//
// CallInterface implementation: this part is common to both caller and caller
// sides.
for (const auto &placeHolder : llvm::enumerate(inputs))
if (!placeHolder.value().attributes.empty())
func.setArgAttrs(placeHolder.index(), placeHolder.value().attributes);
+ side().setFuncAttrs(func);
}
}
}
#include "flang/Lower/BoxAnalyzer.h"
#include "flang/Lower/CallInterface.h"
#include "flang/Lower/ConvertType.h"
+#include "flang/Lower/ConvertVariable.h"
#include "flang/Lower/PFTBuilder.h"
#include "flang/Lower/SymbolMap.h"
#include "flang/Optimizer/Builder/Character.h"
return builder.create<fir::CoordinateOp>(loc, ty, tupleArg, offset);
}
+void Fortran::lower::HostAssociations::addSymbolsToBind(
+ const llvm::SetVector<const Fortran::semantics::Symbol *> &symbols,
+ const Fortran::semantics::Scope &hostScope) {
+ assert(tupleSymbols.empty() && globalSymbols.empty() &&
+ "must be initially empty");
+ this->hostScope = &hostScope;
+ for (const auto *s : symbols)
+ if (Fortran::lower::symbolIsGlobal(*s))
+ // The ultimate symbol is stored here so that global symbols from the
+ // host scope can later be searched in this set.
+ globalSymbols.insert(&s->GetUltimate());
+ else
+ tupleSymbols.insert(s);
+}
+
void Fortran::lower::HostAssociations::hostProcedureBindings(
Fortran::lower::AbstractConverter &converter,
Fortran::lower::SymMap &symMap) {
- if (symbols.empty())
+ if (tupleSymbols.empty())
return;
// Create the tuple variable.
auto hostTuple = builder.create<fir::AllocaOp>(loc, tupTy);
mlir::IntegerType offTy = builder.getIntegerType(32);
- // Walk the list of symbols and update the pointers in the tuple.
- for (auto s : llvm::enumerate(symbols)) {
+ // Walk the list of tupleSymbols and update the pointers in the tuple.
+ for (auto s : llvm::enumerate(tupleSymbols)) {
auto indexInTuple = s.index();
mlir::Value off = builder.createIntegerConstant(loc, offTy, indexInTuple);
mlir::Type varTy = tupTy.getType(indexInTuple);
void Fortran::lower::HostAssociations::internalProcedureBindings(
Fortran::lower::AbstractConverter &converter,
Fortran::lower::SymMap &symMap) {
- if (symbols.empty())
+ if (!globalSymbols.empty()) {
+ assert(hostScope && "host scope must have been set");
+ Fortran::lower::AggregateStoreMap storeMap;
+ // The host scope variable list is required to deal with host variables
+ // that are equivalenced and requires instantiating the right global
+ // AggregateStore.
+ for (auto &hostVariable : pft::getScopeVariableList(*hostScope))
+ if ((hostVariable.isAggregateStore() && hostVariable.isGlobal()) ||
+ (hostVariable.hasSymbol() &&
+ globalSymbols.contains(&hostVariable.getSymbol().GetUltimate())))
+ Fortran::lower::instantiateVariable(converter, hostVariable, symMap,
+ storeMap);
+ }
+ if (tupleSymbols.empty())
return;
// Find the argument with the tuple type. The argument ought to be appended.
mlir::IntegerType offTy = builder.getIntegerType(32);
// Walk the list and add the bindings to the symbol table.
- for (auto s : llvm::enumerate(symbols)) {
+ for (auto s : llvm::enumerate(tupleSymbols)) {
mlir::Value off = builder.createIntegerConstant(loc, offTy, s.index());
mlir::Type varTy = tupTy.getType(s.index());
mlir::Value eleOff = genTupleCoor(builder, loc, varTy, tupleArg, off);
mlir::Type Fortran::lower::HostAssociations::getArgumentType(
Fortran::lower::AbstractConverter &converter) {
- if (symbols.empty())
+ if (tupleSymbols.empty())
return {};
if (argType)
return argType;
// to a tuple.
mlir::MLIRContext *ctxt = &converter.getMLIRContext();
llvm::SmallVector<mlir::Type> tupleTys;
- for (const Fortran::semantics::Symbol *sym : symbols)
+ for (const Fortran::semantics::Symbol *sym : tupleSymbols)
tupleTys.emplace_back(
walkCaptureCategories(GetTypeInTuple{}, converter, *sym));
argType = fir::ReferenceType::get(mlir::TupleType::get(ctxt, tupleTys));
llvm::report_fatal_error("parent is not a function");
}
+bool Fortran::lower::pft::FunctionLikeUnit::parentHasTupleHostAssoc() {
+ if (auto *par = parent.getIf<FunctionLikeUnit>())
+ return par->hostAssociations.hasTupleAssociations();
+ return false;
+}
+
bool Fortran::lower::pft::FunctionLikeUnit::parentHasHostAssoc() {
if (auto *par = parent.getIf<FunctionLikeUnit>())
return !par->hostAssociations.empty();
if (auto callee =
call.getCallableForCallee().dyn_cast<mlir::SymbolRefAttr>()) {
auto module = op->getParentOfType<mlir::ModuleOp>();
- return hasHostAssociationArgument(
+ return isInternalPorcedure(
module.lookupSymbol<mlir::func::FuncOp>(callee));
}
return false;
call internal_proc_a()
contains
! CHECK-LABEL: func @_QFhost4Pinternal_proc_a
-! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<tuple<!fir.ref<i32>>> {fir.host_assoc}) {
+! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<tuple<!fir.ref<i32>>> {fir.host_assoc}) attributes {fir.internal_proc} {
subroutine internal_proc_a()
call takes_array(return_array())
! CHECK: %[[VAL_1:.*]] = arith.constant 0 : i32
! Test internal procedure A calling array internal procedure B.
! Result depends on a common block variable declared in the host.
-! Note that the current implementation captures the common block variable
-! address, even though it could recompute it in the internal procedure.
subroutine host9()
implicit none
integer :: n_common
call internal_proc_a()
contains
! CHECK-LABEL: func @_QFhost9Pinternal_proc_a
-! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<tuple<!fir.ref<i32>>> {fir.host_assoc}) {
subroutine internal_proc_a()
-! CHECK: %[[VAL_1:.*]] = arith.constant 0 : i32
-! CHECK: %[[VAL_2:.*]] = fir.coordinate_of %[[VAL_0]], %[[VAL_1]] : (!fir.ref<tuple<!fir.ref<i32>>>, i32) -> !fir.llvm_ptr<!fir.ref<i32>>
-! CHECK: %[[VAL_3:.*]] = fir.load %[[VAL_2]] : !fir.llvm_ptr<!fir.ref<i32>>
-! CHECK: %[[VAL_4:.*]] = fir.load %[[VAL_3]] : !fir.ref<i32>
-! CHECK: %[[VAL_5:.*]] = fir.convert %[[VAL_4]] : (i32) -> index
-! CHECK: %[[CMPI:.*]] = arith.cmpi sgt, %[[VAL_5]], %{{.*}} : index
-! CHECK: %[[SELECT:.*]] = arith.select %[[CMPI]], %[[VAL_5]], %{{.*}} : index
-! CHECK: %[[VAL_6:.*]] = fir.alloca !fir.array<?xf32>, %[[SELECT]] {bindc_name = ".result"}
+! CHECK: %[[VAL_0:.*]] = arith.constant 0 : index
+! CHECK: %[[VAL_1:.*]] = fir.address_of(@_QBmycom) : !fir.ref<!fir.array<4xi8>>
+! CHECK: %[[VAL_2:.*]] = fir.convert %[[VAL_1]] : (!fir.ref<!fir.array<4xi8>>) -> !fir.ref<!fir.array<?xi8>>
+! CHECK: %[[VAL_3:.*]] = fir.coordinate_of %[[VAL_2]], %[[VAL_0]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+! CHECK: %[[VAL_4:.*]] = fir.convert %[[VAL_3]] : (!fir.ref<i8>) -> !fir.ref<i32>
+! CHECK: %[[VAL_5:.*]] = fir.load %[[VAL_4]] : !fir.ref<i32>
+! CHECK: %[[VAL_6:.*]] = fir.convert %[[VAL_5]] : (i32) -> index
+! CHECK: %[[VAL_7:.*]] = arith.cmpi sgt, %[[VAL_6]], %[[VAL_0]] : index
+! CHECK: %[[VAL_8:.*]] = arith.select %[[VAL_7]], %[[VAL_6]], %[[VAL_0]] : index
+! CHECK: %[[VAL_10:.*]] = fir.alloca !fir.array<?xf32>, %[[VAL_8]] {bindc_name = ".result"}
call takes_array(return_array())
end subroutine
function return_array()
call internal()
contains
! CHECK-LABEL: func @_QFcapture_char_func_dummyPinternal(
- ! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<tuple<tuple<!fir.boxproc<() -> ()>, i64>, !fir.ref<i32>>> {fir.host_assoc}) {
+ ! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<tuple<tuple<!fir.boxproc<() -> ()>, i64>, !fir.ref<i32>>> {fir.host_assoc}) attributes {fir.internal_proc} {
subroutine internal()
! CHECK: %[[VAL_1:.*]] = arith.constant 0 : i32
! CHECK: %[[VAL_2:.*]] = fir.coordinate_of %[[VAL_0]], %[[VAL_1]] : (!fir.ref<tuple<tuple<!fir.boxproc<() -> ()>, i64>, !fir.ref<i32>>>, i32) -> !fir.ref<tuple<!fir.boxproc<() -> ()>, i64>>
call internal()
contains
! CHECK-LABEL: func @_QFcapture_char_func_assumed_dummyPinternal(
-! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<tuple<tuple<!fir.boxproc<() -> ()>, i64>>> {fir.host_assoc}) {
+! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<tuple<tuple<!fir.boxproc<() -> ()>, i64>>> {fir.host_assoc}) attributes {fir.internal_proc} {
subroutine internal()
! CHECK: %[[VAL_1:.*]] = arith.constant 0 : i32
! CHECK: %[[VAL_2:.*]] = fir.coordinate_of %[[VAL_0]], %[[VAL_1]] : (!fir.ref<tuple<tuple<!fir.boxproc<() -> ()>, i64>>>, i32) -> !fir.ref<tuple<!fir.boxproc<() -> ()>, i64>>
contains
subroutine internal()
! CHECK-LABEL: func @_QFcapture_array_funcPinternal(
-! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<tuple<!fir.ref<i32>>> {fir.host_assoc}) {
+! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<tuple<!fir.ref<i32>>> {fir.host_assoc}) attributes {fir.internal_proc} {
! CHECK: %[[VAL_1:.*]] = arith.constant 0 : i32
! CHECK: %[[VAL_2:.*]] = fir.coordinate_of %[[VAL_0]], %[[VAL_1]] : (!fir.ref<tuple<!fir.ref<i32>>>, i32) -> !fir.llvm_ptr<!fir.ref<i32>>
! CHECK: %[[VAL_3:.*]] = fir.load %[[VAL_2]] : !fir.llvm_ptr<!fir.ref<i32>>
--- /dev/null
+! Test lowering of internal procedure host association for global variables
+! A tuple function argument should not be created for associated globals, and
+! instead globals should be instantiated with a fir.address_of inside the
+! contained procedures.
+! RUN: bbc -emit-fir %s -o - | FileCheck %s
+
+module test_mod_used_in_host
+ integer :: i, j_in_equiv
+ integer :: not_in_equiv
+ equivalence (i,j_in_equiv)
+end module
+
+subroutine module_var()
+ use test_mod_used_in_host
+ call bar()
+contains
+ subroutine bar()
+ print *, j_in_equiv, not_in_equiv
+ end subroutine
+end subroutine
+! CHECK-LABEL: func.func @_QFmodule_varPbar()
+! CHECK: %[[VAL_0:.*]] = fir.address_of(@_QMtest_mod_used_in_hostEi) : !fir.ref<!fir.array<4xi8>>
+! CHECK: %[[VAL_1:.*]] = arith.constant 0 : index
+! CHECK: %[[VAL_2:.*]] = fir.coordinate_of %[[VAL_0]], %[[VAL_1]] : (!fir.ref<!fir.array<4xi8>>, index) -> !fir.ref<i8>
+! CHECK: %[[VAL_3:.*]] = fir.convert %[[VAL_2]] : (!fir.ref<i8>) -> !fir.ptr<i32>
+! CHECK: %[[VAL_4:.*]] = fir.address_of(@_QMtest_mod_used_in_hostEnot_in_equiv) : !fir.ref<i32>
+
+subroutine test_common()
+ integer, save :: i(2)
+ integer, save :: j_in_equiv
+ integer, save :: not_in_equiv
+ equivalence (i(2),j_in_equiv)
+ common /x/ i, not_in_equiv
+ call bar()
+contains
+ subroutine bar()
+ print *, j_in_equiv, not_in_equiv
+ end subroutine
+end subroutine
+! CHECK-LABEL: func.func @_QFtest_commonPbar() attributes {fir.internal_proc} {
+! CHECK: %[[VAL_0:.*]] = fir.address_of(@_QBx) : !fir.ref<!fir.array<12xi8>>
+! CHECK: %[[VAL_1:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<!fir.array<12xi8>>) -> !fir.ref<!fir.array<?xi8>>
+! CHECK: %[[VAL_2:.*]] = arith.constant 4 : index
+! CHECK: %[[VAL_3:.*]] = fir.coordinate_of %[[VAL_1]], %[[VAL_2]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+! CHECK: %[[VAL_4:.*]] = fir.convert %[[VAL_3]] : (!fir.ref<i8>) -> !fir.ptr<i32>
+! CHECK: %[[VAL_5:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<!fir.array<12xi8>>) -> !fir.ref<!fir.array<?xi8>>
+! CHECK: %[[VAL_6:.*]] = arith.constant 8 : index
+! CHECK: %[[VAL_7:.*]] = fir.coordinate_of %[[VAL_5]], %[[VAL_6]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+! CHECK: %[[VAL_8:.*]] = fir.convert %[[VAL_7]] : (!fir.ref<i8>) -> !fir.ref<i32>
+
+subroutine saved_equiv()
+ integer, save :: i(2)
+ integer, save :: j_in_equiv
+ integer, save :: not_in_equiv
+ equivalence (i(2),j_in_equiv)
+ call bar()
+contains
+ subroutine bar()
+ print *, j_in_equiv, not_in_equiv
+ end subroutine
+end subroutine
+! CHECK-LABEL: func.func @_QFsaved_equivPbar() attributes {fir.internal_proc} {
+! CHECK: %[[VAL_0:.*]] = fir.address_of(@_QFsaved_equivEi) : !fir.ref<!fir.array<8xi8>>
+! CHECK: %[[VAL_1:.*]] = arith.constant 4 : index
+! CHECK: %[[VAL_2:.*]] = fir.coordinate_of %[[VAL_0]], %[[VAL_1]] : (!fir.ref<!fir.array<8xi8>>, index) -> !fir.ref<i8>
+! CHECK: %[[VAL_3:.*]] = fir.convert %[[VAL_2]] : (!fir.ref<i8>) -> !fir.ptr<i32>
+! CHECK: %[[VAL_4:.*]] = fir.address_of(@_QFsaved_equivEnot_in_equiv) : !fir.ref<i32>
+
+subroutine mixed_capture()
+ integer, save :: saved_i
+ integer, save :: saved_j
+ equivalence (saved_i, saved_j)
+ integer :: i
+ integer :: j
+ equivalence (i,j)
+ call bar()
+contains
+ subroutine bar()
+ call test(saved_j, j)
+ end subroutine
+end subroutine
+! CHECK-LABEL: func.func @_QFmixed_capturePbar(
+! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<tuple<!fir.ref<i32>>> {fir.host_assoc}) attributes {fir.internal_proc} {
+! CHECK: %[[VAL_1:.*]] = fir.address_of(@_QFmixed_captureEsaved_i) : !fir.ref<!fir.array<4xi8>>
+! CHECK: %[[VAL_2:.*]] = arith.constant 0 : index
+! CHECK: %[[VAL_3:.*]] = fir.coordinate_of %[[VAL_1]], %[[VAL_2]] : (!fir.ref<!fir.array<4xi8>>, index) -> !fir.ref<i8>
+! CHECK: %[[VAL_4:.*]] = fir.convert %[[VAL_3]] : (!fir.ref<i8>) -> !fir.ptr<i32>
+! CHECK: %[[VAL_5:.*]] = arith.constant 0 : i32
+! CHECK: %[[VAL_6:.*]] = fir.coordinate_of %[[VAL_0]], %[[VAL_5]] : (!fir.ref<tuple<!fir.ref<i32>>>, i32) -> !fir.llvm_ptr<!fir.ref<i32>>
+! CHECK: %[[VAL_7:.*]] = fir.load %[[VAL_6]] : !fir.llvm_ptr<!fir.ref<i32>>
+! CHECK: %[[VAL_9:.*]] = fir.convert %[[VAL_4]] : (!fir.ptr<i32>) -> !fir.ref<i32>
+! CHECK: fir.call @_QPtest(%[[VAL_9]], %[[VAL_7]]) {{.*}} : (!fir.ref<i32>, !fir.ref<i32>) -> ()
print *, i
contains
! CHECK-LABEL: func @_QFtest1Ptest1_internal(
- ! CHECK-SAME: %[[arg:[^:]*]]: !fir.ref<tuple<!fir.ref<i32>>> {fir.host_assoc}) {
+ ! CHECK-SAME: %[[arg:[^:]*]]: !fir.ref<tuple<!fir.ref<i32>>> {fir.host_assoc}) attributes {fir.internal_proc} {
! CHECK: %[[iaddr:.*]] = fir.coordinate_of %[[arg]], %c0
! CHECK: %[[i:.*]] = fir.load %[[iaddr]] : !fir.llvm_ptr<!fir.ref<i32>>
! CHECK: %[[val:.*]] = fir.call @_QPifoo() {{.*}}: () -> i32
print *, a, b
contains
! CHECK-LABEL: func @_QFtest2Ptest2_internal(
- ! CHECK-SAME: %[[arg:[^:]*]]: !fir.ref<tuple<!fir.ref<f32>, !fir.ref<f32>>> {fir.host_assoc}) {
+ ! CHECK-SAME: %[[arg:[^:]*]]: !fir.ref<tuple<!fir.ref<f32>, !fir.ref<f32>>> {fir.host_assoc}) attributes {fir.internal_proc} {
subroutine test2_internal
! CHECK: %[[a:.*]] = fir.coordinate_of %[[arg]], %c0
! CHECK: %[[aa:.*]] = fir.load %[[a]] : !fir.llvm_ptr<!fir.ref<f32>>
end subroutine test2_internal
! CHECK-LABEL: func @_QFtest2Ptest2_inner(
- ! CHECK-SAME: %[[arg:[^:]*]]: !fir.ref<tuple<!fir.ref<f32>, !fir.ref<f32>>> {fir.host_assoc}) {
+ ! CHECK-SAME: %[[arg:[^:]*]]: !fir.ref<tuple<!fir.ref<f32>, !fir.ref<f32>>> {fir.host_assoc}) attributes {fir.internal_proc} {
subroutine test2_inner
! CHECK: %[[a:.*]] = fir.coordinate_of %[[arg]], %c0
! CHECK: %[[aa:.*]] = fir.load %[[a]] : !fir.llvm_ptr<!fir.ref<f32>>
contains
! CHECK-LABEL: func @_QFtest6Ptest6_inner(
- ! CHECK-SAME: %[[tup:.*]]: !fir.ref<tuple<!fir.boxchar<1>>> {fir.host_assoc}) {
+ ! CHECK-SAME: %[[tup:.*]]: !fir.ref<tuple<!fir.boxchar<1>>> {fir.host_assoc}) attributes {fir.internal_proc} {
subroutine test6_inner
! CHECK: %[[coor:.*]] = fir.coordinate_of %[[tup]], %c0{{.*}} : (!fir.ref<tuple<!fir.boxchar<1>>>, i32) -> !fir.ref<!fir.boxchar<1>>
! CHECK: %[[load:.*]] = fir.load %[[coor]] : !fir.ref<!fir.boxchar<1>>
contains
! CHECK-LABEL: func @_QFtest3Ptest3_inner(
- ! CHECK-SAME: %[[tup:.*]]: !fir.ref<tuple<!fir.box<!fir.array<?xf32>>, !fir.box<!fir.array<?xf32>>>> {fir.host_assoc}) {
+ ! CHECK-SAME: %[[tup:.*]]: !fir.ref<tuple<!fir.box<!fir.array<?xf32>>, !fir.box<!fir.array<?xf32>>>> {fir.host_assoc}) attributes {fir.internal_proc} {
subroutine test3_inner
! CHECK: %[[pcoor:.*]] = fir.coordinate_of %[[tup]], %c0{{.*}} : (!fir.ref<tuple<!fir.box<!fir.array<?xf32>>, !fir.box<!fir.array<?xf32>>>>, i32) -> !fir.ref<!fir.box<!fir.array<?xf32>>>
! CHECK: %[[p:.*]] = fir.load %[[pcoor]] : !fir.ref<!fir.box<!fir.array<?xf32>>>
contains
! CHECK: func @_QFtest3aPtest3a_inner(
- ! CHECK-SAME: %[[tup:.*]]: !fir.ref<tuple<!fir.box<!fir.array<10xf32>>, !fir.box<!fir.array<10xf32>>>> {fir.host_assoc}) {
+ ! CHECK-SAME: %[[tup:.*]]: !fir.ref<tuple<!fir.box<!fir.array<10xf32>>, !fir.box<!fir.array<10xf32>>>> {fir.host_assoc}) attributes {fir.internal_proc} {
subroutine test3a_inner
! CHECK: %[[pcoor:.*]] = fir.coordinate_of %[[tup]], %c0{{.*}} : (!fir.ref<tuple<!fir.box<!fir.array<10xf32>>, !fir.box<!fir.array<10xf32>>>>, i32) -> !fir.ref<!fir.box<!fir.array<10xf32>>>
! CHECK: %[[p:.*]] = fir.load %[[pcoor]] : !fir.ref<!fir.box<!fir.array<10xf32>>>
contains
! CHECK-LABEL: func @_QFtest4Ptest4_inner(
- ! CHECK-SAME:%[[tup:.*]]: !fir.ref<tuple<!fir.ref<!fir.box<!fir.ptr<f32>>>, !fir.ref<!fir.box<!fir.heap<f32>>>>> {fir.host_assoc}) {
+ ! CHECK-SAME:%[[tup:.*]]: !fir.ref<tuple<!fir.ref<!fir.box<!fir.ptr<f32>>>, !fir.ref<!fir.box<!fir.heap<f32>>>>> {fir.host_assoc}) attributes {fir.internal_proc} {
subroutine test4_inner
! CHECK: %[[ptup:.*]] = fir.coordinate_of %[[tup]], %c0{{.*}} : (!fir.ref<tuple<!fir.ref<!fir.box<!fir.ptr<f32>>>, !fir.ref<!fir.box<!fir.heap<f32>>>>>, i32) -> !fir.llvm_ptr<!fir.ref<!fir.box<!fir.ptr<f32>>>>
! CHECK: %[[p:.*]] = fir.load %[[ptup]] : !fir.llvm_ptr<!fir.ref<!fir.box<!fir.ptr<f32>>>>
contains
! CHECK-LABEL: func @_QFtest5Ptest5_inner(
- ! CHECK-SAME:%[[tup:.*]]: !fir.ref<tuple<!fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>>> {fir.host_assoc}) {
+ ! CHECK-SAME:%[[tup:.*]]: !fir.ref<tuple<!fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>>> {fir.host_assoc}) attributes {fir.internal_proc} {
subroutine test5_inner
! CHECK: %[[ptup:.*]] = fir.coordinate_of %[[tup]], %c0{{.*}} : (!fir.ref<tuple<!fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>>>, i32) -> !fir.llvm_ptr<!fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>>
! CHECK: %[[p:.*]] = fir.load %[[ptup]] : !fir.llvm_ptr<!fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>>
contains
! CHECK-LABEL: func @_QFtest7Ptest7_inner(
-! CHECK-SAME: %[[i:.*]]: !fir.ref<i32>{{.*}}, %[[tup:.*]]: !fir.ref<tuple<!fir.ref<i32>>> {fir.host_assoc}) -> i32 {
+! CHECK-SAME: %[[i:.*]]: !fir.ref<i32>{{.*}}, %[[tup:.*]]: !fir.ref<tuple<!fir.ref<i32>>> {fir.host_assoc}) -> i32 attributes {fir.internal_proc} {
elemental integer function test7_inner(i)
implicit none
integer, intent(in) :: i
call bar()
contains
! CHECK-LABEL: func @_QFissue990Pbar(
-! CHECK-SAME: %[[tup:.*]]: !fir.ref<tuple<!fir.ref<i32>>> {fir.host_assoc}) {
+! CHECK-SAME: %[[tup:.*]]: !fir.ref<tuple<!fir.ref<i32>>> {fir.host_assoc}) attributes {fir.internal_proc} {
subroutine bar()
integer :: stmt_func, i
stmt_func(i) = i + captured
call bar()
contains
! CHECK-LABEL: func @_QFissue990bPbar(
-! CHECK-SAME: %[[tup:.*]]: !fir.ref<tuple<!fir.ref<i32>>> {fir.host_assoc}) {
+! CHECK-SAME: %[[tup:.*]]: !fir.ref<tuple<!fir.ref<i32>>> {fir.host_assoc}) attributes {fir.internal_proc} {
subroutine bar()
! CHECK: %[[tupAddr:.*]] = fir.coordinate_of %[[tup]], %c0{{.*}} : (!fir.ref<tuple<!fir.ref<i32>>>, i32) -> !fir.llvm_ptr<!fir.ref<i32>>
! CHECK: %[[addr:.*]] = fir.load %[[tupAddr]] : !fir.llvm_ptr<!fir.ref<i32>>
call bar()
contains
! CHECK-LABEL: func @_QFtest8Pbar(
-! CHECK-SAME: %[[tup:.*]]: !fir.ref<tuple<!fir.boxproc<() -> ()>>> {fir.host_assoc}) {
+! CHECK-SAME: %[[tup:.*]]: !fir.ref<tuple<!fir.boxproc<() -> ()>>> {fir.host_assoc}) attributes {fir.internal_proc} {
subroutine bar()
! CHECK: %[[tupAddr:.*]] = fir.coordinate_of %[[tup]], %c0{{.*}} : (!fir.ref<tuple<!fir.boxproc<() -> ()>>>, i32) -> !fir.ref<!fir.boxproc<() -> ()>>
! CHECK: %[[dummyProc:.*]] = fir.load %[[tupAddr]] : !fir.ref<!fir.boxproc<() -> ()>>
call bar()
contains
! CHECK-LABEL: func @_QFtest9Pbar(
-! CHECK-SAME: %[[tup:.*]]: !fir.ref<tuple<!fir.boxproc<() -> ()>>> {fir.host_assoc}) {
+! CHECK-SAME: %[[tup:.*]]: !fir.ref<tuple<!fir.boxproc<() -> ()>>> {fir.host_assoc}) attributes {fir.internal_proc} {
subroutine bar()
! CHECK: %[[tupAddr:.*]] = fir.coordinate_of %[[tup]], %c0{{.*}} : (!fir.ref<tuple<!fir.boxproc<() -> ()>>>, i32) -> !fir.ref<!fir.boxproc<() -> ()>>
! CHECK: %[[dummyProc:.*]] = fir.load %[[tupAddr]] : !fir.ref<!fir.boxproc<() -> ()>>
call bar()
contains
! CHECK-LABEL: func @_QFtest10Pbar(
-! CHECK-SAME: %[[tup:.*]]: !fir.ref<tuple<!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>>> {fir.host_assoc}) {
+! CHECK-SAME: %[[tup:.*]]: !fir.ref<tuple<!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>>> {fir.host_assoc}) attributes {fir.internal_proc} {
subroutine bar()
! CHECK: %[[tupAddr:.*]] = fir.coordinate_of %[[tup]], %c0{{.*}} : (!fir.ref<tuple<!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>>>, i32) -> !fir.llvm_ptr<!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>>
! CHECK: fir.load %[[tupAddr]] : !fir.llvm_ptr<!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>>
! CHECK-LABEL: func @_QFtest_proc_dummyPtest_proc_dummy_a(
! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<i32> {fir.bindc_name = "j"},
-! CHECK-SAME: %[[VAL_1:.*]]: !fir.ref<tuple<!fir.ref<i32>>> {fir.host_assoc}) {
+! CHECK-SAME: %[[VAL_1:.*]]: !fir.ref<tuple<!fir.ref<i32>>> {fir.host_assoc}) attributes {fir.internal_proc} {
! CHECK: %[[VAL_2:.*]] = arith.constant 0 : i32
! CHECK: %[[VAL_3:.*]] = fir.coordinate_of %[[VAL_1]], %[[VAL_2]] : (!fir.ref<tuple<!fir.ref<i32>>>, i32) -> !fir.llvm_ptr<!fir.ref<i32>>
! CHECK: %[[VAL_4:.*]] = fir.load %[[VAL_3]] : !fir.llvm_ptr<!fir.ref<i32>>
! CHECK-LABEL: func @_QFtest_proc_dummy_charPgen_message(
! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<!fir.char<1,10>>,
! CHECK-SAME: %[[VAL_1:.*]]: index,
-! CHECK-SAME: %[[VAL_2:.*]]: !fir.ref<tuple<!fir.boxchar<1>>> {fir.host_assoc}) -> !fir.boxchar<1> {
+! CHECK-SAME: %[[VAL_2:.*]]: !fir.ref<tuple<!fir.boxchar<1>>> {fir.host_assoc}) -> !fir.boxchar<1> attributes {fir.internal_proc} {
! CHECK-DAG: %[[VAL_3:.*]] = arith.constant 0 : i32
! CHECK-DAG: %[[VAL_4:.*]] = arith.constant 10 : index
! CHECK-DAG: %[[VAL_5:.*]] = arith.constant false
! CHECK-DAG: %[[VAL_6:.*]] = arith.constant 1 : index
! CHECK-DAG: %[[VAL_7:.*]] = arith.constant 32 : i8
! CHECK-DAG: %[[VAL_8:.*]] = arith.constant 0 : index
+! CHECK: %[[VAL_12:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<!fir.char<1,10>>) -> !fir.ref<!fir.char<1,?>>
! CHECK: %[[VAL_9:.*]] = fir.coordinate_of %[[VAL_2]], %[[VAL_3]] : (!fir.ref<tuple<!fir.boxchar<1>>>, i32) -> !fir.ref<!fir.boxchar<1>>
! CHECK: %[[VAL_10:.*]] = fir.load %[[VAL_9]] : !fir.ref<!fir.boxchar<1>>
! CHECK: %[[VAL_11:.*]]:2 = fir.unboxchar %[[VAL_10]] : (!fir.boxchar<1>) -> (!fir.ref<!fir.char<1,?>>, index)
-! CHECK: %[[VAL_12:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<!fir.char<1,10>>) -> !fir.ref<!fir.char<1,?>>
! CHECK: %[[VAL_13:.*]] = arith.cmpi sgt, %[[VAL_11]]#1, %[[VAL_4]] : index
! CHECK: %[[VAL_14:.*]] = arith.select %[[VAL_13]], %[[VAL_4]], %[[VAL_11]]#1 : index
! CHECK: %[[VAL_15:.*]] = fir.convert %[[VAL_14]] : (index) -> i64
end subroutine
! CHECK-LABEL: func.func @_QMpolymorphic_testFhost_assocPinternal(
-! CHECK-SAME: %[[TUPLE:.*]]: !fir.ref<tuple<!fir.class<!fir.type<_QMpolymorphic_testTp1{a:i32,b:i32}>>>> {fir.host_assoc}) {
+! CHECK-SAME: %[[TUPLE:.*]]: !fir.ref<tuple<!fir.class<!fir.type<_QMpolymorphic_testTp1{a:i32,b:i32}>>>> {fir.host_assoc}) attributes {fir.internal_proc} {
! CHECK: %[[POS_IN_TUPLE:.*]] = arith.constant 0 : i32
! CHECK: %[[COORD_OF_CLASS:.*]] = fir.coordinate_of %[[TUPLE]], %[[POS_IN_TUPLE]] : (!fir.ref<tuple<!fir.class<!fir.type<_QMpolymorphic_testTp1{a:i32,b:i32}>>>>, i32) -> !fir.ref<!fir.class<!fir.type<_QMpolymorphic_testTp1{a:i32,b:i32}>>>
! CHECK: %[[CLASS:.*]] = fir.load %[[COORD_OF_CLASS]] : !fir.ref<!fir.class<!fir.type<_QMpolymorphic_testTp1{a:i32,b:i32}>>>