Skip to content

Commit ff852b2

Browse files
committed
Add flang
1 parent 8b75560 commit ff852b2

9 files changed

+2117
-0
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#!/bin/bash
2+
3+
set -ex
4+
5+
cmake -S llvm -B _fbuild -GNinja \
6+
-DCMAKE_BUILD_TYPE=Release \
7+
-DCMAKE_INSTALL_PREFIX=$PREFIX \
8+
-DLLVM_DEFAULT_TARGET_TRIPLE=wasm32-unknown-emscripten \
9+
-DLLVM_TARGETS_TO_BUILD=WebAssembly \
10+
-DLLVM_ENABLE_PROJECTS="clang;flang;mlir"
11+
cmake --build _fbuild
12+
cmake --build _fbuild --target install
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
From 9832ab8489970b1b872ada88e21e2cea9f4925bd Mon Sep 17 00:00:00 2001
2+
From: serge-sans-paille <sguelton@mozilla.com>
3+
Date: Fri, 5 Jul 2024 22:45:47 +0200
4+
Subject: [PATCH 1/7] Instructions for building a functional Flang cross
5+
compiler
6+
7+
---
8+
README.wasm.md | 31 +++++++++++++++++++++++++++++++
9+
1 file changed, 31 insertions(+)
10+
create mode 100644 README.wasm.md
11+
12+
diff --git a/README.wasm.md b/README.wasm.md
13+
new file mode 100644
14+
index 000000000000..4f6e64a4766d
15+
--- /dev/null
16+
+++ b/README.wasm.md
17+
@@ -0,0 +1,31 @@
18+
+# Building Flang as a WASM cross-compiler
19+
+
20+
+From the branch ``feature/flang-wasm`` of
21+
+https://github.com/serge-sans-paille/llvm-project.
22+
+
23+
+This work is inspired by https://gws.phd/posts/fortran_wasm/.
24+
+
25+
+## Building the compiler itself
26+
+
27+
+```
28+
+$ cmake -S llvm -B _fbuild -GNinja \
29+
+ -DCMAKE_BUILD_TYPE=Release \
30+
+ -DCMAKE_INSTALL_PREFIX=_finstall \
31+
+ -DLLVM_DEFAULT_TARGET_TRIPLE=wasm32-unknown-emscripten \
32+
+ -DLLVM_TARGETS_TO_BUILD=WebAssembly \
33+
+ -DLLVM_ENABLE_PROJECTS="clang;flang;mlir"
34+
+$ cmake --build _fbuild
35+
+$ cmake --build _fbuild --target install
36+
+```
37+
+
38+
+## Building Flang runtmine
39+
+
40+
+Assuming you have ``emcmake`` available somewhere in your ``PATH``.
41+
+
42+
+```
43+
+$ emcmake cmake -S flang/runtime -B _fbuild_runtime -GNinja \
44+
+ -DCMAKE_BUILD_TYPE=Release \
45+
+ -DCMAKE_INSTALL_PREFIX=_finstall
46+
+$ cmake --build _fbuild_runtime
47+
+$ cmake --build _fbuild_runtime --target install
48+
+```
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
From 50a109a4f3a37b27daf5b05503edc5a918f6a826 Mon Sep 17 00:00:00 2001
2+
From: serge-sans-paille <sguelton@mozilla.com>
3+
Date: Tue, 18 Jun 2024 22:19:09 +0200
4+
Subject: [PATCH 2/7] Minimal WASM support for flang
5+
6+
Original patch from https://gws.phd/posts/fortran_wasm/
7+
---
8+
flang/lib/Optimizer/CodeGen/Target.cpp | 41 ++++++++++++++++++++++++++
9+
1 file changed, 41 insertions(+)
10+
11+
diff --git a/flang/lib/Optimizer/CodeGen/Target.cpp b/flang/lib/Optimizer/CodeGen/Target.cpp
12+
index 25141102a8c4..715daefc0ba5 100644
13+
--- a/flang/lib/Optimizer/CodeGen/Target.cpp
14+
+++ b/flang/lib/Optimizer/CodeGen/Target.cpp
15+
@@ -1055,6 +1055,44 @@ struct TargetLoongArch64 : public GenericTarget<TargetLoongArch64> {
16+
};
17+
} // namespace
18+
19+
+//===----------------------------------------------------------------------===//
20+
+// WebAssembly (wasm32) target specifics.
21+
+//===----------------------------------------------------------------------===//
22+
+
23+
+namespace {
24+
+struct TargetWasm32 : public GenericTarget<TargetWasm32> {
25+
+ using GenericTarget::GenericTarget;
26+
+
27+
+ static constexpr int defaultWidth = 32;
28+
+
29+
+ CodeGenSpecifics::Marshalling
30+
+ complexArgumentType(mlir::Location, mlir::Type eleTy) const override {
31+
+ assert(fir::isa_real(eleTy));
32+
+ CodeGenSpecifics::Marshalling marshal;
33+
+ // Use a type that will be translated into LLVM as:
34+
+ // { t, t } struct of 2 eleTy, byval, align 4
35+
+ auto structTy =
36+
+ mlir::TupleType::get(eleTy.getContext(), mlir::TypeRange{eleTy, eleTy});
37+
+ marshal.emplace_back(fir::ReferenceType::get(structTy),
38+
+ AT{/*alignment=*/4, /*byval=*/true});
39+
+ return marshal;
40+
+ }
41+
+
42+
+ CodeGenSpecifics::Marshalling
43+
+ complexReturnType(mlir::Location loc, mlir::Type eleTy) const override {
44+
+ assert(fir::isa_real(eleTy));
45+
+ CodeGenSpecifics::Marshalling marshal;
46+
+ // Use a type that will be translated into LLVM as:
47+
+ // { t, t } struct of 2 eleTy, sret, align 4
48+
+ auto structTy =
49+
+ mlir::TupleType::get(eleTy.getContext(), mlir::TypeRange{eleTy, eleTy});
50+
+ marshal.emplace_back(fir::ReferenceType::get(structTy),
51+
+ AT{/*alignment=*/4, /*byval=*/false, /*sret=*/true});
52+
+ return marshal;
53+
+ }
54+
+};
55+
+} // namespace
56+
+
57+
// Instantiate the overloaded target instance based on the triple value.
58+
// TODO: Add other targets to this file as needed.
59+
std::unique_ptr<fir::CodeGenSpecifics>
60+
@@ -1110,6 +1148,9 @@ fir::CodeGenSpecifics::get(mlir::MLIRContext *ctx, llvm::Triple &&trp,
61+
case llvm::Triple::ArchType::loongarch64:
62+
return std::make_unique<TargetLoongArch64>(
63+
ctx, std::move(trp), std::move(kindMap), targetCPU, targetFeatures, dl);
64+
+ case llvm::Triple::ArchType::wasm32:
65+
+ return std::make_unique<TargetWasm32>(
66+
+ ctx, std::move(trp), std::move(kindMap), targetCPU, targetFeatures, dl);
67+
}
68+
TODO(mlir::UnknownLoc::get(ctx), "target not implemented");
69+
}
Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
From a15e14e27fdbb7e874f51d02e06b4c6c9349f798 Mon Sep 17 00:00:00 2001
2+
From: serge-sans-paille <sguelton@mozilla.com>
3+
Date: Wed, 10 Jul 2024 22:42:19 +0200
4+
Subject: [PATCH 3/7] Specialize Flang to target WASM
5+
6+
Many values were explicitly encoded under the assumation that host and target have
7+
the same architecture.
8+
---
9+
.../Optimizer/Builder/Runtime/RTBuilder.h | 31 ++++++++++---------
10+
.../flang/Optimizer/Support/DataLayout.h | 16 ++++++++++
11+
flang/lib/Optimizer/CodeGen/CodeGen.cpp | 8 +++--
12+
3 files changed, 38 insertions(+), 17 deletions(-)
13+
14+
diff --git a/flang/include/flang/Optimizer/Builder/Runtime/RTBuilder.h b/flang/include/flang/Optimizer/Builder/Runtime/RTBuilder.h
15+
index 845ba385918d..adc6479f9cbf 100644
16+
--- a/flang/include/flang/Optimizer/Builder/Runtime/RTBuilder.h
17+
+++ b/flang/include/flang/Optimizer/Builder/Runtime/RTBuilder.h
18+
@@ -22,6 +22,7 @@
19+
#include "flang/Optimizer/Builder/FIRBuilder.h"
20+
#include "flang/Optimizer/Dialect/FIRDialect.h"
21+
#include "flang/Optimizer/Dialect/FIRType.h"
22+
+#include "flang/Optimizer/Support/DataLayout.h"
23+
#include "flang/Runtime/reduce.h"
24+
#include "mlir/IR/BuiltinTypes.h"
25+
#include "mlir/IR/MLIRContext.h"
26+
@@ -85,7 +86,7 @@ using FuncTypeBuilderFunc = mlir::FunctionType (*)(mlir::MLIRContext *);
27+
auto voidTy = fir::LLVMPointerType::get( \
28+
context, mlir::IntegerType::get(context, 8)); \
29+
auto size_tTy = \
30+
- mlir::IntegerType::get(context, 8 * sizeof(std::size_t)); \
31+
+ mlir::IntegerType::get(context, 8 * FLANG_TARGET_SIZEOF_SIZE_T); \
32+
auto refTy = fir::ReferenceType::get(f(context)); \
33+
return mlir::FunctionType::get( \
34+
context, {refTy, size_tTy, refTy, refTy, size_tTy, size_tTy}, \
35+
@@ -113,13 +114,13 @@ static constexpr TypeBuilderFunc getModel();
36+
template <>
37+
constexpr TypeBuilderFunc getModel<unsigned int>() {
38+
return [](mlir::MLIRContext *context) -> mlir::Type {
39+
- return mlir::IntegerType::get(context, 8 * sizeof(unsigned int));
40+
+ return mlir::IntegerType::get(context, 8 * FLANG_TARGET_SIZEOF_UINT);
41+
};
42+
}
43+
template <>
44+
constexpr TypeBuilderFunc getModel<short int>() {
45+
return [](mlir::MLIRContext *context) -> mlir::Type {
46+
- return mlir::IntegerType::get(context, 8 * sizeof(short int));
47+
+ return mlir::IntegerType::get(context, 8 * FLANG_TARGET_SIZEOF_SHORT);
48+
};
49+
}
50+
template <>
51+
@@ -136,7 +137,7 @@ constexpr TypeBuilderFunc getModel<const short int *>() {
52+
template <>
53+
constexpr TypeBuilderFunc getModel<int>() {
54+
return [](mlir::MLIRContext *context) -> mlir::Type {
55+
- return mlir::IntegerType::get(context, 8 * sizeof(int));
56+
+ return mlir::IntegerType::get(context, 8 * FLANG_TARGET_SIZEOF_INT);
57+
};
58+
}
59+
template <>
60+
@@ -182,13 +183,13 @@ constexpr TypeBuilderFunc getModel<const char32_t *>() {
61+
template <>
62+
constexpr TypeBuilderFunc getModel<char>() {
63+
return [](mlir::MLIRContext *context) -> mlir::Type {
64+
- return mlir::IntegerType::get(context, 8 * sizeof(char));
65+
+ return mlir::IntegerType::get(context, 8 * FLANG_TARGET_SIZEOF_CHAR);
66+
};
67+
}
68+
template <>
69+
constexpr TypeBuilderFunc getModel<signed char>() {
70+
return [](mlir::MLIRContext *context) -> mlir::Type {
71+
- return mlir::IntegerType::get(context, 8 * sizeof(signed char));
72+
+ return mlir::IntegerType::get(context, 8 * FLANG_TARGET_SIZEOF_SCHAR);
73+
};
74+
}
75+
template <>
76+
@@ -205,7 +206,7 @@ constexpr TypeBuilderFunc getModel<const signed char *>() {
77+
template <>
78+
constexpr TypeBuilderFunc getModel<char16_t>() {
79+
return [](mlir::MLIRContext *context) -> mlir::Type {
80+
- return mlir::IntegerType::get(context, 8 * sizeof(char16_t));
81+
+ return mlir::IntegerType::get(context, 8 * FLANG_TARGET_SIZEOF_CHAR16);
82+
};
83+
}
84+
template <>
85+
@@ -218,7 +219,7 @@ constexpr TypeBuilderFunc getModel<char16_t *>() {
86+
template <>
87+
constexpr TypeBuilderFunc getModel<char32_t>() {
88+
return [](mlir::MLIRContext *context) -> mlir::Type {
89+
- return mlir::IntegerType::get(context, 8 * sizeof(char32_t));
90+
+ return mlir::IntegerType::get(context, 8 * FLANG_TARGET_SIZEOF_CHAR32);
91+
};
92+
}
93+
template <>
94+
@@ -231,7 +232,7 @@ constexpr TypeBuilderFunc getModel<char32_t *>() {
95+
template <>
96+
constexpr TypeBuilderFunc getModel<unsigned char>() {
97+
return [](mlir::MLIRContext *context) -> mlir::Type {
98+
- return mlir::IntegerType::get(context, 8 * sizeof(unsigned char));
99+
+ return mlir::IntegerType::get(context, 8 * FLANG_TARGET_SIZEOF_UCHAR);
100+
};
101+
}
102+
template <>
103+
@@ -259,7 +260,7 @@ constexpr TypeBuilderFunc getModel<void **>() {
104+
template <>
105+
constexpr TypeBuilderFunc getModel<long>() {
106+
return [](mlir::MLIRContext *context) -> mlir::Type {
107+
- return mlir::IntegerType::get(context, 8 * sizeof(long));
108+
+ return mlir::IntegerType::get(context, 8 * FLANG_TARGET_SIZEOF_LONG);
109+
};
110+
}
111+
template <>
112+
@@ -280,7 +281,7 @@ constexpr TypeBuilderFunc getModel<const long *>() {
113+
template <>
114+
constexpr TypeBuilderFunc getModel<long long>() {
115+
return [](mlir::MLIRContext *context) -> mlir::Type {
116+
- return mlir::IntegerType::get(context, 8 * sizeof(long long));
117+
+ return mlir::IntegerType::get(context, 8 * FLANG_TARGET_SIZEOF_LONGLONG);
118+
};
119+
}
120+
template <>
121+
@@ -308,13 +309,13 @@ constexpr TypeBuilderFunc getModel<const long long *>() {
122+
template <>
123+
constexpr TypeBuilderFunc getModel<unsigned long>() {
124+
return [](mlir::MLIRContext *context) -> mlir::Type {
125+
- return mlir::IntegerType::get(context, 8 * sizeof(unsigned long));
126+
+ return mlir::IntegerType::get(context, 8 * FLANG_TARGET_SIZEOF_ULONG);
127+
};
128+
}
129+
template <>
130+
constexpr TypeBuilderFunc getModel<unsigned long long>() {
131+
return [](mlir::MLIRContext *context) -> mlir::Type {
132+
- return mlir::IntegerType::get(context, 8 * sizeof(unsigned long long));
133+
+ return mlir::IntegerType::get(context, 8 * FLANG_TARGET_SIZEOF_ULONGLONG);
134+
};
135+
}
136+
template <>
137+
@@ -434,13 +435,13 @@ constexpr TypeBuilderFunc getModel<const std::complex<double> *>() {
138+
template <>
139+
constexpr TypeBuilderFunc getModel<c_float_complex_t>() {
140+
return [](mlir::MLIRContext *context) -> mlir::Type {
141+
- return fir::ComplexType::get(context, sizeof(float));
142+
+ return fir::ComplexType::get(context, FLANG_TARGET_SIZEOF_FLOAT);
143+
};
144+
}
145+
template <>
146+
constexpr TypeBuilderFunc getModel<c_double_complex_t>() {
147+
return [](mlir::MLIRContext *context) -> mlir::Type {
148+
- return fir::ComplexType::get(context, sizeof(double));
149+
+ return fir::ComplexType::get(context, FLANG_TARGET_SIZEOF_DOUBLE);
150+
};
151+
}
152+
template <>
153+
diff --git a/flang/include/flang/Optimizer/Support/DataLayout.h b/flang/include/flang/Optimizer/Support/DataLayout.h
154+
index d21576bb95f7..5372039d8702 100644
155+
--- a/flang/include/flang/Optimizer/Support/DataLayout.h
156+
+++ b/flang/include/flang/Optimizer/Support/DataLayout.h
157+
@@ -23,6 +23,22 @@ namespace llvm {
158+
class DataLayout;
159+
}
160+
161+
+constexpr size_t FLANG_TARGET_SIZEOF_UINT = 4;
162+
+constexpr size_t FLANG_TARGET_SIZEOF_INT = 4;
163+
+constexpr size_t FLANG_TARGET_SIZEOF_SHORT = 2;
164+
+constexpr size_t FLANG_TARGET_SIZEOF_CHAR = 1;
165+
+constexpr size_t FLANG_TARGET_SIZEOF_SCHAR = 1;
166+
+constexpr size_t FLANG_TARGET_SIZEOF_UCHAR = 1;
167+
+constexpr size_t FLANG_TARGET_SIZEOF_CHAR16 = 2;
168+
+constexpr size_t FLANG_TARGET_SIZEOF_CHAR32 = 4;
169+
+constexpr size_t FLANG_TARGET_SIZEOF_LONG = 4;
170+
+constexpr size_t FLANG_TARGET_SIZEOF_LONGLONG = 8;
171+
+constexpr size_t FLANG_TARGET_SIZEOF_ULONG = 4;
172+
+constexpr size_t FLANG_TARGET_SIZEOF_ULONGLONG = 8;
173+
+constexpr size_t FLANG_TARGET_SIZEOF_SIZE_T = 4;
174+
+constexpr size_t FLANG_TARGET_SIZEOF_FLOAT = 4;
175+
+constexpr size_t FLANG_TARGET_SIZEOF_DOUBLE = 8;
176+
+
177+
namespace fir::support {
178+
/// Create an mlir::DataLayoutSpecInterface attribute from an llvm::DataLayout
179+
/// and set it on the provided mlir::ModuleOp.
180+
diff --git a/flang/lib/Optimizer/CodeGen/CodeGen.cpp b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
181+
index f9ea92a843b2..ca72d67400b0 100644
182+
--- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp
183+
+++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
184+
@@ -909,7 +909,8 @@ getMalloc(fir::AllocMemOp op, mlir::ConversionPatternRewriter &rewriter) {
185+
return mlir::SymbolRefAttr::get(userMalloc);
186+
mlir::OpBuilder moduleBuilder(
187+
op->getParentOfType<mlir::ModuleOp>().getBodyRegion());
188+
- auto indexType = mlir::IntegerType::get(op.getContext(), 64);
189+
+ auto indexType =
190+
+ mlir::IntegerType::get(op.getContext(), 8 * FLANG_TARGET_SIZEOF_SIZE_T);
191+
auto mallocDecl = moduleBuilder.create<mlir::LLVM::LLVMFuncOp>(
192+
op.getLoc(), mallocName,
193+
mlir::LLVM::LLVMFunctionType::get(getLlvmPtrType(op.getContext()),
194+
@@ -976,8 +977,11 @@ struct AllocMemOpConversion : public fir::FIROpConversion<fir::AllocMemOp> {
195+
size = rewriter.create<mlir::LLVM::MulOp>(
196+
loc, ity, size, integerCast(loc, rewriter, ity, opnd));
197+
heap->setAttr("callee", getMalloc(heap, rewriter));
198+
+ auto szt_ty = mlir::IntegerType::get(rewriter.getContext(),
199+
+ 8 * FLANG_TARGET_SIZEOF_SIZE_T);
200+
+ auto size_szt = integerCast(loc, rewriter, szt_ty, size);
201+
rewriter.replaceOpWithNewOp<mlir::LLVM::CallOp>(
202+
- heap, ::getLlvmPtrType(heap.getContext()), size, heap->getAttrs());
203+
+ heap, ::getLlvmPtrType(heap.getContext()), size_szt, heap->getAttrs());
204+
return mlir::success();
205+
}
206+
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
From d248b70f49ae63689962b0f8bd0cab8e2f35a592 Mon Sep 17 00:00:00 2001
2+
From: serge-sans-paille <serge.guelton@telecom-bretagne.eu>
3+
Date: Fri, 26 Jul 2024 07:34:39 +0000
4+
Subject: [PATCH 4/7] [Flang][Runtime] Explicitly convert shift value to
5+
SubscriptValue (#99822)
6+
7+
Shift value are within the range of SubscriptValue but the API forces
8+
them to 64bits. This assumption doesn't hold for 32bit machine, so add
9+
an explicit cast.
10+
---
11+
flang/runtime/transformational.cpp | 5 +++--
12+
1 file changed, 3 insertions(+), 2 deletions(-)
13+
14+
diff --git a/flang/runtime/transformational.cpp b/flang/runtime/transformational.cpp
15+
index cf1e61c0844d..b6b204be4418 100644
16+
--- a/flang/runtime/transformational.cpp
17+
+++ b/flang/runtime/transformational.cpp
18+
@@ -508,7 +508,8 @@ void RTDEF(CshiftVector)(Descriptor &result, const Descriptor &source,
19+
SubscriptValue lb{sourceDim.LowerBound()};
20+
for (SubscriptValue j{0}; j < extent; ++j) {
21+
SubscriptValue resultAt{1 + j};
22+
- SubscriptValue sourceAt{lb + (j + shift) % extent};
23+
+ SubscriptValue sourceAt{
24+
+ lb + static_cast<SubscriptValue>(j + shift) % extent};
25+
if (sourceAt < lb) {
26+
sourceAt += extent;
27+
}
28+
@@ -619,7 +620,7 @@ void RTDEF(EoshiftVector)(Descriptor &result, const Descriptor &source,
29+
}
30+
SubscriptValue lb{source.GetDimension(0).LowerBound()};
31+
for (SubscriptValue j{1}; j <= extent; ++j) {
32+
- SubscriptValue sourceAt{lb + j - 1 + shift};
33+
+ SubscriptValue sourceAt{lb + j - 1 + static_cast<SubscriptValue>(shift)};
34+
if (sourceAt >= lb && sourceAt < lb + extent) {
35+
CopyElement(result, &j, source, &sourceAt, terminator);
36+
} else if (boundary) {

0 commit comments

Comments
 (0)