Skip to content

Commit 27d9a47

Browse files
authored
[flang] Add struct passing target rewrite hooks and partial X86-64 impl (#74829)
In the context of C/Fortran interoperability (BIND(C)), it is possible to give the VALUE attribute to a BIND(C) derived type dummy, which according to Fortran 2018 18.3.6 - 2. (4) implies that it must be passed like the equivalent C structure value. The way C structure value are passed is ABI dependent. LLVM does not implement the C struct ABI passing for LLVM aggregate type arguments. It is up to the front-end, like clang is doing, to split the struct into registers or pass the struct on the stack (llvm "byval") as required by the target ABI. So the logic for C struct passing sits in clang. Using it from flang requires setting up a lot of clang context and to bridge FIR/MLIR representation to clang AST representation for function signatures (in both directions). It is a non trivial task. See https://stackoverflow.com/questions/39438033/passing-structs-by-value-in-llvm-ir/75002581#75002581. Since BIND(C) struct are rather limited as opposed to generic C struct (e.g. no bit fields). It is easier to provide a limited implementation of it for the case that matter to Fortran. This patch: - Updates the generic target rewrite pass to keep track of both the new argument type and attributes. The motivation for this is to be able to tell if a previously marshalled argument is passed in memory (it is a C pointer), or if it is being passed on the stack (has the byval llvm attributes). - Adds an entry point in the target specific codegen to marshal struct arguments, and use it in the generic target rewrite pass. - Implements limited support for the X86-64 case. So far, the support allows telling if a struct must be passed in register or on the stack, and to deal with the stack case. The register case is left TODO in this patch. The X86-64 ABI implemented is the System V ABI for AMD64 version 1.0
1 parent 2bab0e0 commit 27d9a47

File tree

13 files changed

+828
-190
lines changed

13 files changed

+828
-190
lines changed

flang/include/flang/Optimizer/CodeGen/CGPasses.td

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ def FIRToLLVMLowering : Pass<"fir-to-llvm-ir", "mlir::ModuleOp"> {
2323
will also convert ops in the standard and FIRCG dialects.
2424
}];
2525
let constructor = "::fir::createFIRToLLVMPass()";
26-
let dependentDialects = ["mlir::LLVM::LLVMDialect"];
26+
let dependentDialects = ["mlir::LLVM::LLVMDialect", "mlir::DLTIDialect"];
2727
let options = [
2828
Option<"forcedTargetTriple", "target", "std::string", /*default=*/"",
2929
"Override module's target triple.">,
@@ -53,7 +53,8 @@ def TargetRewritePass : Pass<"target-rewrite", "mlir::ModuleOp"> {
5353
representations that may differ based on the target machine.
5454
}];
5555
let constructor = "::fir::createFirTargetRewritePass()";
56-
let dependentDialects = [ "fir::FIROpsDialect", "mlir::func::FuncDialect" ];
56+
let dependentDialects = [ "fir::FIROpsDialect", "mlir::func::FuncDialect",
57+
"mlir::DLTIDialect" ];
5758
let options = [
5859
Option<"forcedTargetTriple", "target", "std::string", /*default=*/"",
5960
"Override module's target triple.">,

flang/include/flang/Optimizer/CodeGen/Target.h

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,18 @@
1313
#ifndef FORTRAN_OPTMIZER_CODEGEN_TARGET_H
1414
#define FORTRAN_OPTMIZER_CODEGEN_TARGET_H
1515

16+
#include "flang/Optimizer/Dialect/FIRType.h"
1617
#include "flang/Optimizer/Dialect/Support/KindMapping.h"
1718
#include "mlir/IR/BuiltinTypes.h"
1819
#include "llvm/TargetParser/Triple.h"
1920
#include <memory>
2021
#include <tuple>
2122
#include <vector>
2223

24+
namespace mlir {
25+
class DataLayout;
26+
}
27+
2328
namespace fir {
2429

2530
namespace details {
@@ -62,14 +67,20 @@ class Attributes {
6267
class CodeGenSpecifics {
6368
public:
6469
using Attributes = details::Attributes;
65-
using Marshalling = std::vector<std::tuple<mlir::Type, Attributes>>;
70+
using TypeAndAttr = std::tuple<mlir::Type, Attributes>;
71+
using Marshalling = std::vector<TypeAndAttr>;
72+
73+
static std::unique_ptr<CodeGenSpecifics> get(mlir::MLIRContext *ctx,
74+
llvm::Triple &&trp,
75+
KindMapping &&kindMap,
76+
const mlir::DataLayout &dl);
6677

67-
static std::unique_ptr<CodeGenSpecifics>
68-
get(mlir::MLIRContext *ctx, llvm::Triple &&trp, KindMapping &&kindMap);
78+
static TypeAndAttr getTypeAndAttr(mlir::Type t) { return TypeAndAttr{t, {}}; }
6979

7080
CodeGenSpecifics(mlir::MLIRContext *ctx, llvm::Triple &&trp,
71-
KindMapping &&kindMap)
72-
: context{*ctx}, triple{std::move(trp)}, kindMap{std::move(kindMap)} {}
81+
KindMapping &&kindMap, const mlir::DataLayout &dl)
82+
: context{*ctx}, triple{std::move(trp)}, kindMap{std::move(kindMap)},
83+
dataLayout{&dl} {}
7384
CodeGenSpecifics() = delete;
7485
virtual ~CodeGenSpecifics() {}
7586

@@ -90,6 +101,13 @@ class CodeGenSpecifics {
90101
/// Type presentation of a `boxchar<n>` type value in memory.
91102
virtual mlir::Type boxcharMemoryType(mlir::Type eleTy) const = 0;
92103

104+
/// Type representation of a `fir.type<T>` type argument when passed by
105+
/// value. It may have to be split into several arguments, or be passed
106+
/// as a byval reference argument (on the stack).
107+
virtual Marshalling
108+
structArgumentType(mlir::Location loc, fir::RecordType recTy,
109+
const Marshalling &previousArguments) const = 0;
110+
93111
/// Type representation of a `boxchar<n>` type argument when passed by value.
94112
/// An argument value may need to be passed as a (safe) reference argument.
95113
///
@@ -143,10 +161,16 @@ class CodeGenSpecifics {
143161
// Returns width in bits of C/C++ 'int' type size.
144162
virtual unsigned char getCIntTypeWidth() const = 0;
145163

164+
const mlir::DataLayout &getDataLayout() const {
165+
assert(dataLayout && "dataLayout must be set");
166+
return *dataLayout;
167+
}
168+
146169
protected:
147170
mlir::MLIRContext &context;
148171
llvm::Triple triple;
149172
KindMapping kindMap;
173+
const mlir::DataLayout *dataLayout = nullptr;
150174
};
151175

152176
} // namespace fir

flang/include/flang/Optimizer/CodeGen/TypeConverter.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,18 @@ static constexpr unsigned kDimLowerBoundPos = 0;
3939
static constexpr unsigned kDimExtentPos = 1;
4040
static constexpr unsigned kDimStridePos = 2;
4141

42+
namespace mlir {
43+
class DataLayout;
44+
}
45+
4246
namespace fir {
4347

4448
/// FIR type converter
4549
/// This converts FIR types to LLVM types (for now)
4650
class LLVMTypeConverter : public mlir::LLVMTypeConverter {
4751
public:
4852
LLVMTypeConverter(mlir::ModuleOp module, bool applyTBAA,
49-
bool forceUnifiedTBAATree);
53+
bool forceUnifiedTBAATree, const mlir::DataLayout &);
5054

5155
// i32 is used here because LLVM wants i32 constants when indexing into struct
5256
// types. Indexing into other aggregate types is more flexible.

flang/include/flang/Optimizer/Dialect/FIRTypes.td

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,8 @@ def fir_RealType : FIR_Type<"Real", "real"> {
326326

327327
let extraClassDeclaration = [{
328328
using KindTy = unsigned;
329+
// Get MLIR float type with same semantics.
330+
mlir::Type getFloatType(const fir::KindMapping &kindMap) const;
329331
}];
330332

331333
let genVerifyDecl = 1;
@@ -495,6 +497,14 @@ def fir_SequenceType : FIR_Type<"Sequence", "array"> {
495497
static constexpr Extent getUnknownExtent() {
496498
return mlir::ShapedType::kDynamic;
497499
}
500+
501+
std::uint64_t getConstantArraySize() {
502+
assert(!hasDynamicExtents() && "array type must have constant shape");
503+
std::uint64_t size = 1;
504+
for (Extent extent : getShape())
505+
size = size * static_cast<std::uint64_t>(extent);
506+
return size;
507+
}
498508
}];
499509
}
500510

flang/include/flang/Optimizer/Support/DataLayout.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
#ifndef FORTRAN_OPTIMIZER_SUPPORT_DATALAYOUT_H
1414
#define FORTRAN_OPTIMIZER_SUPPORT_DATALAYOUT_H
1515

16+
#include "mlir/Interfaces/DataLayoutInterfaces.h"
17+
#include <optional>
18+
1619
namespace mlir {
1720
class ModuleOp;
1821
}
@@ -34,6 +37,15 @@ void setMLIRDataLayout(mlir::ModuleOp mlirModule, const llvm::DataLayout &dl);
3437
/// nothing.
3538
void setMLIRDataLayoutFromAttributes(mlir::ModuleOp mlirModule,
3639
bool allowDefaultLayout);
40+
41+
/// Create mlir::DataLayout from the data layout information on the
42+
/// mlir::Module. Creates the data layout information attributes with
43+
/// setMLIRDataLayoutFromAttributes if the DLTI attribute is not yet set. If no
44+
/// information is present at all and \p allowDefaultLayout is false, returns
45+
/// std::nullopt.
46+
std::optional<mlir::DataLayout>
47+
getOrSetDataLayout(mlir::ModuleOp mlirModule, bool allowDefaultLayout = false);
48+
3749
} // namespace fir::support
3850

3951
#endif // FORTRAN_OPTIMIZER_SUPPORT_DATALAYOUT_H

flang/lib/Optimizer/CodeGen/CodeGen.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "flang/Optimizer/Dialect/FIRAttr.h"
1717
#include "flang/Optimizer/Dialect/FIROps.h"
1818
#include "flang/Optimizer/Dialect/FIRType.h"
19+
#include "flang/Optimizer/Support/DataLayout.h"
1920
#include "flang/Optimizer/Support/InternalNames.h"
2021
#include "flang/Optimizer/Support/TypeCode.h"
2122
#include "flang/Optimizer/Support/Utils.h"
@@ -34,6 +35,7 @@
3435
#include "mlir/Conversion/ReconcileUnrealizedCasts/ReconcileUnrealizedCasts.h"
3536
#include "mlir/Conversion/VectorToLLVM/ConvertVectorToLLVM.h"
3637
#include "mlir/Dialect/Arith/IR/Arith.h"
38+
#include "mlir/Dialect/DLTI/DLTI.h"
3739
#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
3840
#include "mlir/Dialect/LLVMIR/Transforms/AddComdats.h"
3941
#include "mlir/Dialect/OpenACC/OpenACC.h"
@@ -3831,10 +3833,20 @@ class FIRToLLVMLowering
38313833
if (mlir::failed(runPipeline(mathConvertionPM, mod)))
38323834
return signalPassFailure();
38333835

3836+
std::optional<mlir::DataLayout> dl =
3837+
fir::support::getOrSetDataLayout(mod, /*allowDefaultLayout=*/true);
3838+
if (!dl) {
3839+
mlir::emitError(mod.getLoc(),
3840+
"module operation must carry a data layout attribute "
3841+
"to generate llvm IR from FIR");
3842+
signalPassFailure();
3843+
return;
3844+
}
3845+
38343846
auto *context = getModule().getContext();
38353847
fir::LLVMTypeConverter typeConverter{getModule(),
38363848
options.applyTBAA || applyTBAA,
3837-
options.forceUnifiedTBAATree};
3849+
options.forceUnifiedTBAATree, *dl};
38383850
mlir::RewritePatternSet pattern(context);
38393851
pattern.insert<
38403852
AbsentOpConversion, AddcOpConversion, AddrOfOpConversion,

0 commit comments

Comments
 (0)