Skip to content

[flang] Set LLVM specific attributes to fir.call's of Fortran runtime. #128093

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Feb 24, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions flang/include/flang/Optimizer/Builder/FIRBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,15 @@ class FirOpBuilder : public mlir::OpBuilder, public mlir::OpBuilder::Listener {
mlir::FunctionType ty,
mlir::SymbolTable *);

/// Returns a named function for a Fortran runtime API, creating
/// it, if it does not exist in the module yet.
/// If \p isIO is set to true, then the function corresponds
/// to one of Fortran runtime IO APIs.
mlir::func::FuncOp createRuntimeFunction(mlir::Location loc,
llvm::StringRef name,
mlir::FunctionType ty,
bool isIO = false);

/// Cast the input value to IndexType.
mlir::Value convertToIndexType(mlir::Location loc, mlir::Value val) {
return createConvert(loc, getIndexType(), val);
Expand Down
42 changes: 38 additions & 4 deletions flang/include/flang/Optimizer/Builder/Runtime/RTBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "flang/Optimizer/Builder/FIRBuilder.h"
#include "flang/Optimizer/Dialect/FIRDialect.h"
#include "flang/Optimizer/Dialect/FIRType.h"
#include "flang/Runtime/io-api-consts.h"
#include "flang/Runtime/reduce.h"
#include "flang/Support/Fortran.h"
#include "mlir/IR/BuiltinTypes.h"
Expand Down Expand Up @@ -586,6 +587,33 @@ constexpr TypeBuilderFunc getModel<void>() {
};
}

// Define additional runtime type models specific to IO.
template <>
constexpr TypeBuilderFunc getModel<Fortran::runtime::io::IoStatementState *>() {
return getModel<char *>();
}
template <>
constexpr TypeBuilderFunc getModel<Fortran::runtime::io::Iostat>() {
return [](mlir::MLIRContext *context) -> mlir::Type {
return mlir::IntegerType::get(context,
8 * sizeof(Fortran::runtime::io::Iostat));
};
}
template <>
constexpr TypeBuilderFunc
getModel<const Fortran::runtime::io::NamelistGroup &>() {
return [](mlir::MLIRContext *context) -> mlir::Type {
return fir::ReferenceType::get(mlir::TupleType::get(context));
};
}
template <>
constexpr TypeBuilderFunc
getModel<const Fortran::runtime::io::NonTbpDefinedIoTable *>() {
return [](mlir::MLIRContext *context) -> mlir::Type {
return fir::ReferenceType::get(mlir::TupleType::get(context));
};
}

REDUCTION_REF_OPERATION_MODEL(std::int8_t)
REDUCTION_VALUE_OPERATION_MODEL(std::int8_t)
REDUCTION_REF_OPERATION_MODEL(std::int16_t)
Expand Down Expand Up @@ -778,16 +806,22 @@ struct RuntimeTableEntry<RuntimeTableKey<KT>, RuntimeIdentifier<Cs...>> {
/// argument is intended to be of the form: <mkRTKey(runtime function name)>.
template <typename RuntimeEntry>
static mlir::func::FuncOp getRuntimeFunc(mlir::Location loc,
fir::FirOpBuilder &builder) {
fir::FirOpBuilder &builder,
bool isIO = false) {
using namespace Fortran::runtime;
auto name = RuntimeEntry::name;
auto func = builder.getNamedFunction(name);
if (func)
return func;
auto funTy = RuntimeEntry::getTypeModel()(builder.getContext());
func = builder.createFunction(loc, name, funTy);
func->setAttr(FIROpsDialect::getFirRuntimeAttrName(), builder.getUnitAttr());
return func;
return builder.createRuntimeFunction(loc, name, funTy, isIO);
}

/// Get (or generate) the MLIR FuncOp for a given IO runtime function.
template <typename E>
static mlir::func::FuncOp getIORuntimeFunc(mlir::Location loc,
fir::FirOpBuilder &builder) {
return getRuntimeFunc<E>(loc, builder, /*isIO=*/true);
}

namespace helper {
Expand Down
12 changes: 12 additions & 0 deletions flang/include/flang/Optimizer/Dialect/FIRDialect.td
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,18 @@ def FIROpsDialect : Dialect {
static constexpr llvm::StringRef getFirRuntimeAttrName() {
return "fir.runtime";
}
// Return string name of fir.memory attributes.
// It is attached to fir.call operations to convey
// llvm.memory attributes to LLVM IR.
// Its value is intended to be mlir::LLVM::MemoryEffectsAttr.
// TODO: we should probably make it an inherent attribute
// of fir.call, though, it is supposed to be a short-lived
// attribute that appears right before CodeGen and only
// meaningful for LLVM, so it is unclear if embedding
// it into fir.call makes sense.
static constexpr llvm::StringRef getFirCallMemoryAttrName() {
return "fir.llvm_memory";
}
}];
}

Expand Down
2 changes: 2 additions & 0 deletions flang/include/flang/Optimizer/Transforms/Passes.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ namespace fir {
#define GEN_PASS_DECL_FUNCTIONATTR
#define GEN_PASS_DECL_CONSTANTARGUMENTGLOBALISATIONOPT
#define GEN_PASS_DECL_COMPILERGENERATEDNAMESCONVERSION
#define GEN_PASS_DECL_SETRUNTIMECALLATTRIBUTES
#define GEN_PASS_DECL_GENRUNTIMECALLSFORTEST

#include "flang/Optimizer/Transforms/Passes.h.inc"

Expand Down
33 changes: 33 additions & 0 deletions flang/include/flang/Optimizer/Transforms/Passes.td
Original file line number Diff line number Diff line change
Expand Up @@ -453,4 +453,37 @@ def CUFGPUToLLVMConversion : Pass<"cuf-gpu-convert-to-llvm", "mlir::ModuleOp"> {
];
}

def SetRuntimeCallAttributes
: Pass<"set-runtime-call-attrs", "mlir::func::FuncOp"> {
let summary = "Set Fortran runtime fir.call attributes targeting LLVM IR";
let description = [{
This pass sets different attributes for Fortran runtime calls
that enable more optimizations in LLVM backend.
For the time being, the meaning of these attributes is not
strictly defined for HLFIR/FIR.
}];
let dependentDialects = ["fir::FIROpsDialect", "mlir::LLVM::LLVMDialect"];
}

def GenRuntimeCallsForTest
: Pass<"gen-runtime-calls-for-test", "mlir::ModuleOp"> {
let summary =
"Print FIR containing declarations/calls of Fortran runtime functions";
let description = [{
This pass is only for developers to be able to print FIR
that declares and calls Fortran runtime functions.
It helps producing/updating tests for passes that modify
the func/call operations based on some knowledge of
Fortran runtime.
}];
let options =
[Option<"doGenerateCalls", "do-generate-calls", "bool",
/*default=*/"false",
"Generate thin wrapper functions that call Fortran runtime "
"functions. If it is set to false, then only the declarations "
"are generated.">,
];
let dependentDialects = ["fir::FIROpsDialect", "mlir::func::FuncDialect"];
}

#endif // FLANG_OPTIMIZER_TRANSFORMS_PASSES
111 changes: 111 additions & 0 deletions flang/include/flang/Optimizer/Transforms/RuntimeFunctions.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
//===-- Optimizer/Transforms/RuntimeFunctions.inc ---------------*- C++ -*-===//
//
// 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
//
//===----------------------------------------------------------------------===//

#ifndef KNOWN_IO_FUNC
#error "Define KNOWN_IO_FUNC before including this file"
#endif
#ifndef KNOWN_RUNTIME_FUNC
#error "Define KNOWN_RUNTIME_FUNC before including this file"
#endif

// Fortran runtime functions that SetRuntimeCallAttributesPass recognizes.
// WARNING: if you add a function entry here, you must make sure
// that the attribute computation callbacks that end up being
// used are correct for this function. If needed, add
// specializations for the types that provide attribute
// computation callbacks in SetRuntimeCallAttributesPass.

// clang-format off
KNOWN_IO_FUNC(BeginBackspace),
KNOWN_IO_FUNC(BeginClose),
KNOWN_IO_FUNC(BeginEndfile),
KNOWN_IO_FUNC(BeginExternalFormattedInput),
KNOWN_IO_FUNC(BeginExternalFormattedOutput),
KNOWN_IO_FUNC(BeginExternalListInput),
KNOWN_IO_FUNC(BeginExternalListOutput),
KNOWN_IO_FUNC(BeginFlush),
KNOWN_IO_FUNC(BeginInquireFile),
KNOWN_IO_FUNC(BeginInquireIoLength),
KNOWN_IO_FUNC(BeginInquireUnit),
KNOWN_IO_FUNC(BeginInternalArrayFormattedInput),
KNOWN_IO_FUNC(BeginInternalArrayFormattedOutput),
KNOWN_IO_FUNC(BeginInternalArrayListInput),
KNOWN_IO_FUNC(BeginInternalArrayListOutput),
KNOWN_IO_FUNC(BeginInternalFormattedInput),
KNOWN_IO_FUNC(BeginInternalFormattedOutput),
KNOWN_IO_FUNC(BeginInternalListInput),
KNOWN_IO_FUNC(BeginInternalListOutput),
KNOWN_IO_FUNC(BeginOpenNewUnit),
KNOWN_IO_FUNC(BeginOpenUnit),
KNOWN_IO_FUNC(BeginRewind),
KNOWN_IO_FUNC(BeginUnformattedInput),
KNOWN_IO_FUNC(BeginUnformattedOutput),
KNOWN_IO_FUNC(BeginWait),
KNOWN_IO_FUNC(BeginWaitAll),
KNOWN_IO_FUNC(CheckUnitNumberInRange128),
KNOWN_IO_FUNC(CheckUnitNumberInRange64),
KNOWN_IO_FUNC(EnableHandlers),
KNOWN_IO_FUNC(EndIoStatement),
KNOWN_IO_FUNC(GetAsynchronousId),
KNOWN_IO_FUNC(GetIoLength),
KNOWN_IO_FUNC(GetIoMsg),
KNOWN_IO_FUNC(GetNewUnit),
KNOWN_IO_FUNC(GetSize),
KNOWN_IO_FUNC(InputAscii),
KNOWN_IO_FUNC(InputComplex32),
KNOWN_IO_FUNC(InputComplex64),
KNOWN_IO_FUNC(InputDerivedType),
KNOWN_IO_FUNC(InputDescriptor),
KNOWN_IO_FUNC(InputInteger),
KNOWN_IO_FUNC(InputLogical),
KNOWN_IO_FUNC(InputNamelist),
KNOWN_IO_FUNC(InputReal32),
KNOWN_IO_FUNC(InputReal64),
KNOWN_IO_FUNC(InquireCharacter),
KNOWN_IO_FUNC(InquireInteger64),
KNOWN_IO_FUNC(InquireLogical),
KNOWN_IO_FUNC(InquirePendingId),
KNOWN_IO_FUNC(OutputAscii),
KNOWN_IO_FUNC(OutputComplex32),
KNOWN_IO_FUNC(OutputComplex64),
KNOWN_IO_FUNC(OutputDerivedType),
KNOWN_IO_FUNC(OutputDescriptor),
KNOWN_IO_FUNC(OutputInteger128),
KNOWN_IO_FUNC(OutputInteger16),
KNOWN_IO_FUNC(OutputInteger32),
KNOWN_IO_FUNC(OutputInteger64),
KNOWN_IO_FUNC(OutputInteger8),
KNOWN_IO_FUNC(OutputLogical),
KNOWN_IO_FUNC(OutputNamelist),
KNOWN_IO_FUNC(OutputReal32),
KNOWN_IO_FUNC(OutputReal64),
KNOWN_IO_FUNC(SetAccess),
KNOWN_IO_FUNC(SetAction),
KNOWN_IO_FUNC(SetAdvance),
KNOWN_IO_FUNC(SetAsynchronous),
KNOWN_IO_FUNC(SetBlank),
KNOWN_IO_FUNC(SetCarriagecontrol),
KNOWN_IO_FUNC(SetConvert),
KNOWN_IO_FUNC(SetDecimal),
KNOWN_IO_FUNC(SetDelim),
KNOWN_IO_FUNC(SetEncoding),
KNOWN_IO_FUNC(SetFile),
KNOWN_IO_FUNC(SetForm),
KNOWN_IO_FUNC(SetPad),
KNOWN_IO_FUNC(SetPos),
KNOWN_IO_FUNC(SetPosition),
KNOWN_IO_FUNC(SetRec),
KNOWN_IO_FUNC(SetRecl),
KNOWN_IO_FUNC(SetRound),
KNOWN_IO_FUNC(SetSign),
KNOWN_IO_FUNC(SetStatus)

// clang-format on

#undef KNOWN_IO_FUNC
#undef KNOWN_RUNTIME_FUNC
Loading