[flang-commits] [flang] [flang] Add CodeGen target support for WebAssembly (PR #226427)
via flang-commits
flang-commits at lists.llvm.org
Fri Sep 25 03:22:34 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-flang-codegen
@llvm/pr-subscribers-flang-fir-hlfir
Author: Anutosh Bhat (anutosh491)
<details>
<summary>Changes</summary>
I'm interested in Flang cross-compilation to wasm32/wasm64 (as my [RFC](https://discourse.llvm.org/t/rfc-proposing-an-interactive-fortran-workflow-with-flang-using-jupyter-notebooks/89116) here says).
While working on it, I found that FIR target rewriting did not have CodeGen support for wasm32 or wasm64.
I'm adding a WebAssembly target implementation for complex arguments and results, matching Clang’s default WebAssembly ABI:
- complex arguments are passed indirectly with `byval`;
- complex results are returned indirectly with `sret`;
- alignment is derived from the target data layout.
The tests cover both wasm32 and wasm64, including `complex<f32>` and `complex<f64>`. This is limited to FIR CodeGen target support and does not include runtime or Emscripten integration changes. I plan to make more PRs on this front soon.
---
Full diff: https://github.com/llvm/llvm-project/pull/226427.diff
2 Files Affected:
- (modified) flang/lib/Optimizer/CodeGen/Target.cpp (+46)
- (added) flang/test/Fir/target-rewrite-wasm.fir (+30)
``````````diff
diff --git a/flang/lib/Optimizer/CodeGen/Target.cpp b/flang/lib/Optimizer/CodeGen/Target.cpp
index 3e6a2151fb311..b190b1dd8cbbb 100644
--- a/flang/lib/Optimizer/CodeGen/Target.cpp
+++ b/flang/lib/Optimizer/CodeGen/Target.cpp
@@ -2031,6 +2031,44 @@ struct TargetSystemZ : public GenericTarget<TargetSystemZ> {
};
} // namespace
+//===----------------------------------------------------------------------===//
+// WebAssembly (wasm32 / wasm64) target specifics.
+//===----------------------------------------------------------------------===//
+
+namespace {
+template <int Width>
+struct TargetWasm : public GenericTarget<TargetWasm<Width>> {
+ using GenericTarget<TargetWasm<Width>>::GenericTarget;
+ using AT = CodeGenSpecifics::Attributes;
+
+ static constexpr int defaultWidth = Width;
+
+ CodeGenSpecifics::Marshalling complexType(mlir::Type eleTy,
+ bool isResult) const {
+ assert(fir::isa_real(eleTy));
+ CodeGenSpecifics::Marshalling marshal;
+ auto structTy =
+ mlir::TupleType::get(eleTy.getContext(), mlir::TypeRange{eleTy, eleTy});
+ auto alignment = static_cast<unsigned short>(
+ this->getDataLayout().getTypeABIAlignment(eleTy));
+ marshal.emplace_back(fir::ReferenceType::get(structTy),
+ AT{/*alignment=*/alignment, /*byval=*/!isResult,
+ /*sret=*/isResult});
+ return marshal;
+ }
+
+ CodeGenSpecifics::Marshalling
+ complexArgumentType(mlir::Location, mlir::Type eleTy) const override {
+ return complexType(eleTy, /*isResult=*/false);
+ }
+
+ CodeGenSpecifics::Marshalling
+ complexReturnType(mlir::Location, mlir::Type eleTy) const override {
+ return complexType(eleTy, /*isResult=*/true);
+ }
+};
+} // namespace
+
// Instantiate the overloaded target instance based on the triple value.
// TODO: Add other targets to this file as needed.
std::unique_ptr<fir::CodeGenSpecifics> fir::CodeGenSpecifics::get(
@@ -2102,6 +2140,14 @@ std::unique_ptr<fir::CodeGenSpecifics> fir::CodeGenSpecifics::get(
return std::make_unique<TargetSystemZ>(ctx, std::move(trp),
std::move(kindMap), targetCPU,
targetFeatures, targetABI, dl);
+ case llvm::Triple::ArchType::wasm32:
+ return std::make_unique<TargetWasm<32>>(
+ ctx, std::move(trp), std::move(kindMap), targetCPU, targetFeatures,
+ targetABI, dl);
+ case llvm::Triple::ArchType::wasm64:
+ return std::make_unique<TargetWasm<64>>(
+ ctx, std::move(trp), std::move(kindMap), targetCPU, targetFeatures,
+ targetABI, dl);
}
TODO(mlir::UnknownLoc::get(ctx), "target not implemented");
}
diff --git a/flang/test/Fir/target-rewrite-wasm.fir b/flang/test/Fir/target-rewrite-wasm.fir
new file mode 100644
index 0000000000000..6754119d46aca
--- /dev/null
+++ b/flang/test/Fir/target-rewrite-wasm.fir
@@ -0,0 +1,30 @@
+// RUN: fir-opt --target-rewrite="target=wasm32-unknown-emscripten" %s | FileCheck %s
+// RUN: fir-opt --target-rewrite="target=wasm64-unknown-emscripten" %s | FileCheck %s
+
+// Verify the WebAssembly ABI lowering for complex arguments and results.
+
+// CHECK-LABEL: func.func @complex_result_f64(
+// CHECK-SAME: %[[RESULT:.*]]: !fir.ref<tuple<f64, f64>> {llvm.align = 8 : i32, llvm.sret = tuple<f64, f64>})
+func.func @complex_result_f64() -> complex<f64> {
+ %0 = fir.undefined complex<f64>
+ return %0 : complex<f64>
+}
+
+// CHECK-LABEL: func.func @complex_argument_f64(
+// CHECK-SAME: %[[ARG:.*]]: !fir.ref<tuple<f64, f64>> {llvm.align = 8 : i32, llvm.byval = tuple<f64, f64>})
+func.func @complex_argument_f64(%arg0: complex<f64>) {
+ return
+}
+
+// CHECK-LABEL: func.func @complex_result_f32(
+// CHECK-SAME: %[[RESULT:.*]]: !fir.ref<tuple<f32, f32>> {llvm.align = 4 : i32, llvm.sret = tuple<f32, f32>})
+func.func @complex_result_f32() -> complex<f32> {
+ %0 = fir.undefined complex<f32>
+ return %0 : complex<f32>
+}
+
+// CHECK-LABEL: func.func @complex_argument_f32(
+// CHECK-SAME: %[[ARG:.*]]: !fir.ref<tuple<f32, f32>> {llvm.align = 4 : i32, llvm.byval = tuple<f32, f32>})
+func.func @complex_argument_f32(%arg0: complex<f32>) {
+ return
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/226427
More information about the flang-commits
mailing list