Skip to content

Commit e1a1276

Browse files
committed
[flang] Initial lowering for empty program
This patch enable lowering from Fortran to FIR for a basic empty program. It brings all the infrastructure needed for that. As discussed previously, this is the first patch for lowering and follow up patches should be smaller. With this patch we can lower the following code: ``` program basic end program ``` To a the FIR equivalent: ``` func @_QQmain() { return } ``` Follow up patch will add lowering of more complex constructs. Reviewed By: kiranchandramohan, schweitz, PeteSteinfeld Differential Revision: https://reviews.llvm.org/D118436
1 parent b62e592 commit e1a1276

21 files changed

+1386
-269
lines changed

flang/include/flang/Lower/AbstractConverter.h

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,23 @@
55
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
66
//
77
//===----------------------------------------------------------------------===//
8+
//
9+
// Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
10+
//
11+
//===----------------------------------------------------------------------===//
812

913
#ifndef FORTRAN_LOWER_ABSTRACTCONVERTER_H
1014
#define FORTRAN_LOWER_ABSTRACTCONVERTER_H
1115

1216
#include "flang/Common/Fortran.h"
17+
#include "flang/Optimizer/Builder/BoxValue.h"
1318
#include "mlir/IR/BuiltinOps.h"
19+
#include "llvm/ADT/ArrayRef.h"
20+
21+
namespace fir {
22+
class KindMapping;
23+
class FirOpBuilder;
24+
} // namespace fir
1425

1526
namespace fir {
1627
class KindMapping;
@@ -22,6 +33,7 @@ namespace common {
2233
template <typename>
2334
class Reference;
2435
}
36+
2537
namespace evaluate {
2638
struct DataRef;
2739
template <typename>
@@ -35,7 +47,8 @@ class CharBlock;
3547
}
3648
namespace semantics {
3749
class Symbol;
38-
}
50+
class DerivedTypeSpec;
51+
} // namespace semantics
3952

4053
namespace lower {
4154
namespace pft {
@@ -109,7 +122,7 @@ class AbstractConverter {
109122
/// Get the converter's current location
110123
virtual mlir::Location getCurrentLocation() = 0;
111124
/// Generate a dummy location
112-
virtual mlir::Location genLocation() = 0;
125+
virtual mlir::Location genUnknownLocation() = 0;
113126
/// Generate the location as converted from a CharBlock
114127
virtual mlir::Location genLocation(const Fortran::parser::CharBlock &) = 0;
115128

@@ -125,10 +138,8 @@ class AbstractConverter {
125138
virtual mlir::MLIRContext &getMLIRContext() = 0;
126139
/// Unique a symbol
127140
virtual std::string mangleName(const Fortran::semantics::Symbol &) = 0;
128-
/// Unique a compiler generated identifier. A short prefix should be provided
129-
/// to hint at the origin of the identifier.
130-
virtual std::string uniqueCGIdent(llvm::StringRef prefix,
131-
llvm::StringRef name) = 0;
141+
/// Get the KindMap.
142+
virtual const fir::KindMapping &getKindMap() = 0;
132143

133144
virtual ~AbstractConverter() = default;
134145
};

flang/include/flang/Lower/Bridge.h

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -50,17 +50,20 @@ class LoweringBridge {
5050
public:
5151
/// Create a lowering bridge instance.
5252
static LoweringBridge
53-
create(const Fortran::common::IntrinsicTypeDefaultKinds &defaultKinds,
53+
create(mlir::MLIRContext &ctx,
54+
const Fortran::common::IntrinsicTypeDefaultKinds &defaultKinds,
5455
const Fortran::evaluate::IntrinsicProcTable &intrinsics,
55-
const Fortran::parser::AllCookedSources &allCooked) {
56-
return LoweringBridge{defaultKinds, intrinsics, allCooked};
56+
const Fortran::parser::AllCookedSources &allCooked,
57+
llvm::StringRef triple, fir::KindMapping &kindMap) {
58+
return LoweringBridge(ctx, defaultKinds, intrinsics, allCooked, triple,
59+
kindMap);
5760
}
5861

5962
//===--------------------------------------------------------------------===//
6063
// Getters
6164
//===--------------------------------------------------------------------===//
6265

63-
mlir::MLIRContext &getMLIRContext() { return *context.get(); }
66+
mlir::MLIRContext &getMLIRContext() { return context; }
6467
mlir::ModuleOp &getModule() { return *module.get(); }
6568
const Fortran::common::IntrinsicTypeDefaultKinds &getDefaultKinds() const {
6669
return defaultKinds;
@@ -94,18 +97,20 @@ class LoweringBridge {
9497

9598
private:
9699
explicit LoweringBridge(
100+
mlir::MLIRContext &ctx,
97101
const Fortran::common::IntrinsicTypeDefaultKinds &defaultKinds,
98102
const Fortran::evaluate::IntrinsicProcTable &intrinsics,
99-
const Fortran::parser::AllCookedSources &);
103+
const Fortran::parser::AllCookedSources &cooked, llvm::StringRef triple,
104+
fir::KindMapping &kindMap);
100105
LoweringBridge() = delete;
101106
LoweringBridge(const LoweringBridge &) = delete;
102107

103108
const Fortran::common::IntrinsicTypeDefaultKinds &defaultKinds;
104109
const Fortran::evaluate::IntrinsicProcTable &intrinsics;
105110
const Fortran::parser::AllCookedSources *cooked;
106-
std::unique_ptr<mlir::MLIRContext> context;
111+
mlir::MLIRContext &context;
107112
std::unique_ptr<mlir::ModuleOp> module;
108-
fir::KindMapping kindMap;
113+
fir::KindMapping &kindMap;
109114
};
110115

111116
} // namespace lower
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
//===-- Lower/CallInterface.h -- Procedure call interface ------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// Utility that defines fir call interface for procedure both on caller and
14+
// and callee side and get the related FuncOp.
15+
// It does not emit any FIR code but for the created mlir::FuncOp, instead it
16+
// provides back a container of Symbol (callee side)/ActualArgument (caller
17+
// side) with additional information for each element describing how it must be
18+
// plugged with the mlir::FuncOp.
19+
// It handles the fact that hidden arguments may be inserted for the result.
20+
// while lowering.
21+
//
22+
// This utility uses the characteristic of Fortran procedures to operate, which
23+
// is a term and concept used in Fortran to refer to the signature of a function
24+
// or subroutine.
25+
//===----------------------------------------------------------------------===//
26+
27+
#ifndef FORTRAN_LOWER_CALLINTERFACE_H
28+
#define FORTRAN_LOWER_CALLINTERFACE_H
29+
30+
#include "flang/Common/reference.h"
31+
#include "flang/Evaluate/characteristics.h"
32+
#include "mlir/IR/BuiltinOps.h"
33+
#include <memory>
34+
#include <optional>
35+
36+
namespace Fortran::semantics {
37+
class Symbol;
38+
}
39+
40+
namespace mlir {
41+
class Location;
42+
}
43+
44+
namespace Fortran::lower {
45+
class AbstractConverter;
46+
namespace pft {
47+
struct FunctionLikeUnit;
48+
}
49+
50+
/// PassedEntityTypes helps abstract whether CallInterface is mapping a
51+
/// Symbol to mlir::Value (callee side) or an ActualArgument to a position
52+
/// inside the input vector for the CallOp (caller side. It will be up to the
53+
/// CallInterface user to produce the mlir::Value that will go in this input
54+
/// vector).
55+
class CalleeInterface;
56+
template <typename T>
57+
struct PassedEntityTypes {};
58+
template <>
59+
struct PassedEntityTypes<CalleeInterface> {
60+
using FortranEntity =
61+
std::optional<common::Reference<const semantics::Symbol>>;
62+
using FirValue = mlir::Value;
63+
};
64+
65+
/// Implementation helper
66+
template <typename T>
67+
class CallInterfaceImpl;
68+
69+
/// CallInterface defines all the logic to determine FIR function interfaces
70+
/// from a characteristic, build the mlir::FuncOp and describe back the argument
71+
/// mapping to its user.
72+
/// The logic is shared between the callee and caller sides that it accepts as
73+
/// a curiously recursive template to handle the few things that cannot be
74+
/// shared between both sides (getting characteristics, mangled name, location).
75+
/// It maps FIR arguments to front-end Symbol (callee side) or ActualArgument
76+
/// (caller side) with the same code using the abstract FortranEntity type that
77+
/// can be either a Symbol or an ActualArgument.
78+
/// It works in two passes: a first pass over the characteristics that decides
79+
/// how the interface must be. Then, the funcOp is created for it. Then a simple
80+
/// pass over fir arguments finalizes the interface information that must be
81+
/// passed back to the user (and may require having the funcOp). All these
82+
/// passes are driven from the CallInterface constructor.
83+
template <typename T>
84+
class CallInterface {
85+
friend CallInterfaceImpl<T>;
86+
87+
public:
88+
/// Different properties of an entity that can be passed/returned.
89+
/// One-to-One mapping with PassEntityBy but for
90+
/// PassEntityBy::AddressAndLength that has two properties.
91+
enum class Property {
92+
BaseAddress,
93+
BoxChar,
94+
CharAddress,
95+
CharLength,
96+
CharProcTuple,
97+
Box,
98+
MutableBox,
99+
Value
100+
};
101+
102+
using FortranEntity = typename PassedEntityTypes<T>::FortranEntity;
103+
using FirValue = typename PassedEntityTypes<T>::FirValue;
104+
105+
/// Returns the mlir function type
106+
mlir::FunctionType genFunctionType();
107+
108+
protected:
109+
CallInterface(Fortran::lower::AbstractConverter &c) : converter{c} {}
110+
/// CRTP handle.
111+
T &side() { return *static_cast<T *>(this); }
112+
/// Entry point to be called by child ctor to analyze the signature and
113+
/// create/find the mlir::FuncOp. Child needs to be initialized first.
114+
void declare();
115+
116+
mlir::FuncOp func;
117+
118+
Fortran::lower::AbstractConverter &converter;
119+
};
120+
121+
//===----------------------------------------------------------------------===//
122+
// Callee side interface
123+
//===----------------------------------------------------------------------===//
124+
125+
/// CalleeInterface only provides the helpers needed by CallInterface
126+
/// to abstract the specificities of the callee side.
127+
class CalleeInterface : public CallInterface<CalleeInterface> {
128+
public:
129+
CalleeInterface(Fortran::lower::pft::FunctionLikeUnit &f,
130+
Fortran::lower::AbstractConverter &c)
131+
: CallInterface{c}, funit{f} {
132+
declare();
133+
}
134+
135+
std::string getMangledName() const;
136+
mlir::Location getCalleeLocation() const;
137+
Fortran::evaluate::characteristics::Procedure characterize() const;
138+
139+
/// On the callee side it does not matter whether the procedure is
140+
/// called through pointers or not.
141+
bool isIndirectCall() const { return false; }
142+
143+
/// Return the procedure symbol if this is a call to a user defined
144+
/// procedure.
145+
const Fortran::semantics::Symbol *getProcedureSymbol() const;
146+
147+
/// Add mlir::FuncOp entry block and map fir block arguments to Fortran dummy
148+
/// argument symbols.
149+
mlir::FuncOp addEntryBlockAndMapArguments();
150+
151+
private:
152+
Fortran::lower::pft::FunctionLikeUnit &funit;
153+
};
154+
155+
} // namespace Fortran::lower
156+
157+
#endif // FORTRAN_LOWER_FIRBUILDER_H

flang/include/flang/Lower/PFTBuilder.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,13 @@ struct ProgramUnit : ProgramVariant {
354354
PftNode parent;
355355
};
356356

357+
/// Helper to get location from FunctionLikeUnit/ModuleLikeUnit begin/end
358+
/// statements.
359+
template <typename T>
360+
static parser::CharBlock stmtSourceLoc(const T &stmt) {
361+
return stmt.visit(common::visitors{[](const auto &x) { return x.source; }});
362+
}
363+
357364
/// A variable captures an object to be created per the declaration part of a
358365
/// function like unit.
359366
///
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//===-- Lower/Support/Verifier.h -- verify pass for lowering ----*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef FORTRAN_LOWER_SUPPORT_VERIFIER_H
14+
#define FORTRAN_LOWER_SUPPORT_VERIFIER_H
15+
16+
#include "mlir/IR/Verifier.h"
17+
#include "mlir/Pass/Pass.h"
18+
19+
namespace Fortran::lower {
20+
21+
/// A verification pass to verify the output from the bridge. This provides a
22+
/// little bit of glue to run a verifier pass directly.
23+
class VerifierPass
24+
: public mlir::PassWrapper<VerifierPass, mlir::OperationPass<>> {
25+
void runOnOperation() override final {
26+
if (mlir::failed(mlir::verify(getOperation())))
27+
signalPassFailure();
28+
markAllAnalysesPreserved();
29+
}
30+
};
31+
32+
} // namespace Fortran::lower
33+
34+
#endif // FORTRAN_LOWER_SUPPORT_VERIFIER_H

0 commit comments

Comments
 (0)