[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