https://github.com/arjunr2 created 
https://github.com/llvm/llvm-project/pull/156087

This PR adds minimal support to the `clang` frontend, `lld`, and `libcxx` for 
the 
[WALI](https://doc.rust-lang.org/rustc/platform-support/wasm32-wali-linux.html) 
target supported by the `rustc` toolchain

>From 758289d2c19997ada222c82d38afa5ef2debce84 Mon Sep 17 00:00:00 2001
From: Arjun Ramesh <arju...@andrew.cmu.edu>
Date: Fri, 29 Aug 2025 13:28:05 -0400
Subject: [PATCH] Support for `wasm32-wali-linux-musl target` in `clang`,
 `lld`, and `libcxx`

---
 clang/lib/Basic/Targets.cpp             |  7 +-
 clang/lib/Basic/Targets/OSTargets.h     | 17 +++++
 clang/lib/Basic/Targets/WebAssembly.h   | 18 +++--
 clang/lib/Driver/Driver.cpp             |  2 +
 libunwind/src/assembly.h                |  3 +
 lld/wasm/Config.h                       | 10 +++
 lld/wasm/Symbols.cpp                    |  4 +
 lld/wasm/Symbols.h                      |  7 ++
 lld/wasm/Writer.cpp                     | 99 ++++++++++++++++++++-----
 llvm/include/llvm/BinaryFormat/Wasm.h   |  2 +
 llvm/include/llvm/TargetParser/Triple.h |  7 ++
 llvm/lib/TargetParser/Triple.cpp        |  3 +
 12 files changed, 154 insertions(+), 25 deletions(-)

diff --git a/clang/lib/Basic/Targets.cpp b/clang/lib/Basic/Targets.cpp
index e3f9760ac7ce3..11222bc836775 100644
--- a/clang/lib/Basic/Targets.cpp
+++ b/clang/lib/Basic/Targets.cpp
@@ -687,7 +687,8 @@ std::unique_ptr<TargetInfo> AllocateTarget(const 
llvm::Triple &Triple,
   }
   case llvm::Triple::wasm32:
     if (Triple.getSubArch() != llvm::Triple::NoSubArch ||
-        Triple.getVendor() != llvm::Triple::UnknownVendor ||
+        (!Triple.isWALI() &&
+         Triple.getVendor() != llvm::Triple::UnknownVendor) ||
         !Triple.isOSBinFormatWasm())
       return nullptr;
     switch (os) {
@@ -697,6 +698,10 @@ std::unique_ptr<TargetInfo> AllocateTarget(const 
llvm::Triple &Triple,
       case llvm::Triple::Emscripten:
       return std::make_unique<EmscriptenTargetInfo<WebAssembly32TargetInfo>>(
           Triple, Opts);
+      // WALI OS target
+      case llvm::Triple::Linux:
+        return 
std::make_unique<WALITargetInfo<WebAssembly32TargetInfo>>(Triple,
+                                                                         Opts);
       case llvm::Triple::UnknownOS:
       return 
std::make_unique<WebAssemblyOSTargetInfo<WebAssembly32TargetInfo>>(
           Triple, Opts);
diff --git a/clang/lib/Basic/Targets/OSTargets.h 
b/clang/lib/Basic/Targets/OSTargets.h
index a733f6e97b3a4..2199bfcfbd7ab 100644
--- a/clang/lib/Basic/Targets/OSTargets.h
+++ b/clang/lib/Basic/Targets/OSTargets.h
@@ -936,6 +936,23 @@ class LLVM_LIBRARY_VISIBILITY WASITargetInfo
   using WebAssemblyOSTargetInfo<Target>::WebAssemblyOSTargetInfo;
 };
 
+// WALI target
+template <typename Target>
+class LLVM_LIBRARY_VISIBILITY WALITargetInfo
+    : public WebAssemblyOSTargetInfo<Target> {
+  void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+                    MacroBuilder &Builder) const final {
+    WebAssemblyOSTargetInfo<Target>::getOSDefines(Opts, Triple, Builder);
+    // Linux defines; list based off of gcc output
+    DefineStd(Builder, "unix", Opts);
+    DefineStd(Builder, "linux", Opts);
+    Builder.defineMacro("__wali__");
+  }
+
+public:
+  using WebAssemblyOSTargetInfo<Target>::WebAssemblyOSTargetInfo;
+};
+
 // Emscripten target
 template <typename Target>
 class LLVM_LIBRARY_VISIBILITY EmscriptenTargetInfo
diff --git a/clang/lib/Basic/Targets/WebAssembly.h 
b/clang/lib/Basic/Targets/WebAssembly.h
index eba74229dfc14..81fd40a62d3a3 100644
--- a/clang/lib/Basic/Targets/WebAssembly.h
+++ b/clang/lib/Basic/Targets/WebAssembly.h
@@ -88,12 +88,20 @@ class LLVM_LIBRARY_VISIBILITY WebAssemblyTargetInfo : 
public TargetInfo {
     LongDoubleWidth = LongDoubleAlign = 128;
     LongDoubleFormat = &llvm::APFloat::IEEEquad();
     MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64;
-    // size_t being unsigned long for both wasm32 and wasm64 makes mangled 
names
-    // more consistent between the two.
-    SizeType = UnsignedLong;
-    PtrDiffType = SignedLong;
-    IntPtrType = SignedLong;
     HasUnalignedAccess = true;
+    if (T.isWALI()) {
+      // WALI ABI requires 64-bit longs on both wasm32 and wasm64
+      LongAlign = LongWidth = 64;
+      SizeType = UnsignedInt;
+      PtrDiffType = SignedInt;
+      IntPtrType = SignedInt;
+    } else {
+      // size_t being unsigned long for both wasm32 and wasm64 makes mangled
+      // names more consistent between the two.
+      SizeType = UnsignedLong;
+      PtrDiffType = SignedLong;
+      IntPtrType = SignedLong;
+    }
   }
 
   StringRef getABI() const override;
diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp
index f110dbab3e5a5..e99b2263c81c6 100644
--- a/clang/lib/Driver/Driver.cpp
+++ b/clang/lib/Driver/Driver.cpp
@@ -6833,6 +6833,8 @@ const ToolChain &Driver::getToolChain(const ArgList &Args,
         TC = std::make_unique<toolchains::VEToolChain>(*this, Target, Args);
       else if (Target.isOHOSFamily())
         TC = std::make_unique<toolchains::OHOS>(*this, Target, Args);
+      else if (Target.isWALI())
+        TC = std::make_unique<toolchains::WebAssembly>(*this, Target, Args);
       else
         TC = std::make_unique<toolchains::Linux>(*this, Target, Args);
       break;
diff --git a/libunwind/src/assembly.h b/libunwind/src/assembly.h
index f8e83e138eff5..c5097d25b0c63 100644
--- a/libunwind/src/assembly.h
+++ b/libunwind/src/assembly.h
@@ -249,6 +249,9 @@ aliasname:                                                  
                   \
 #define WEAK_ALIAS(name, aliasname)
 #define NO_EXEC_STACK_DIRECTIVE
 
+#elif defined(__wasm__)
+#define NO_EXEC_STACK_DIRECTIVE
+
 // clang-format on
 #else
 
diff --git a/lld/wasm/Config.h b/lld/wasm/Config.h
index 9d903e0c799db..cbc71db083edc 100644
--- a/lld/wasm/Config.h
+++ b/lld/wasm/Config.h
@@ -199,6 +199,16 @@ struct Ctx {
     // Function that initializes passive data segments during instantiation.
     DefinedFunction *initMemory;
 
+    // __wasm_memory_grow
+    // Function to perform memory.grow. Serves as a hook to
+    // relieve engine APIs from performing this internally
+    DefinedFunction *memoryGrow;
+
+    // __wasm_memory_size
+    // Function to perform memory.size. Serves as a hook to
+    // relieve engine APIs from performing this internally
+    DefinedFunction *memorySize;
+
     // __wasm_call_ctors
     // Function that directly calls all ctors in priority order.
     DefinedFunction *callCtors;
diff --git a/lld/wasm/Symbols.cpp b/lld/wasm/Symbols.cpp
index f2040441e6257..2c521745e3414 100644
--- a/lld/wasm/Symbols.cpp
+++ b/lld/wasm/Symbols.cpp
@@ -285,6 +285,10 @@ uint32_t DefinedFunction::getExportedFunctionIndex() const 
{
   return function->getFunctionIndex();
 }
 
+void DefinedFunction::setExportNoWrap(bool v) { exportNoWrap = v; }
+
+bool DefinedFunction::getExportNoWrap() const { return exportNoWrap; }
+
 uint64_t DefinedData::getVA(bool absolute) const {
   LLVM_DEBUG(dbgs() << "getVA: " << getName() << "\n");
   // TLS symbols (by default) are relative to the start of the TLS output
diff --git a/lld/wasm/Symbols.h b/lld/wasm/Symbols.h
index 55ee21939ce07..fb8188a4e749f 100644
--- a/lld/wasm/Symbols.h
+++ b/lld/wasm/Symbols.h
@@ -229,6 +229,10 @@ class DefinedFunction : public FunctionSymbol {
     return s->kind() == DefinedFunctionKind;
   }
 
+  // Get/set the exportNoWrap
+  void setExportNoWrap(bool v);
+  bool getExportNoWrap() const;
+
   // Get the function index to be used when exporting.  This only applies to
   // defined functions and can be differ from the regular function index for
   // weakly defined functions (that are imported and used via one index but
@@ -236,6 +240,9 @@ class DefinedFunction : public FunctionSymbol {
   uint32_t getExportedFunctionIndex() const;
 
   InputFunction *function;
+
+protected:
+  bool exportNoWrap = false;
 };
 
 class UndefinedFunction : public FunctionSymbol {
diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp
index b704677d36c93..0628e37850915 100644
--- a/lld/wasm/Writer.cpp
+++ b/lld/wasm/Writer.cpp
@@ -60,6 +60,8 @@ class Writer {
 
   void createSyntheticInitFunctions();
   void createInitMemoryFunction();
+  void createMemoryGrowFunction();
+  void createMemorySizeFunction();
   void createStartFunction();
   void createApplyDataRelocationsFunction();
   void createApplyGlobalRelocationsFunction();
@@ -888,31 +890,33 @@ void Writer::createCommandExportWrappers() {
         toWrap.push_back(f);
 
   for (auto *f : toWrap) {
-    auto funcNameStr = (f->getName() + ".command_export").str();
-    commandExportWrapperNames.push_back(funcNameStr);
-    const std::string &funcName = commandExportWrapperNames.back();
+    if (!(f->getExportNoWrap())) {
+      auto funcNameStr = (f->getName() + ".command_export").str();
+      commandExportWrapperNames.push_back(funcNameStr);
+      const std::string &funcName = commandExportWrapperNames.back();
 
-    auto func = make<SyntheticFunction>(*f->getSignature(), funcName);
-    if (f->function->getExportName())
-      func->setExportName(f->function->getExportName()->str());
-    else
-      func->setExportName(f->getName().str());
+      auto func = make<SyntheticFunction>(*f->getSignature(), funcName);
+      if (f->function->getExportName())
+        func->setExportName(f->function->getExportName()->str());
+      else
+        func->setExportName(f->getName().str());
 
-    DefinedFunction *def =
-        symtab->addSyntheticFunction(funcName, f->flags, func);
-    def->markLive();
+      DefinedFunction *def =
+          symtab->addSyntheticFunction(funcName, f->flags, func);
+      def->markLive();
 
-    def->flags |= WASM_SYMBOL_EXPORTED;
-    def->flags &= ~WASM_SYMBOL_VISIBILITY_HIDDEN;
-    def->forceExport = f->forceExport;
+      def->flags |= WASM_SYMBOL_EXPORTED;
+      def->flags &= ~WASM_SYMBOL_VISIBILITY_HIDDEN;
+      def->forceExport = f->forceExport;
 
-    f->flags |= WASM_SYMBOL_VISIBILITY_HIDDEN;
-    f->flags &= ~WASM_SYMBOL_EXPORTED;
-    f->forceExport = false;
+      f->flags |= WASM_SYMBOL_VISIBILITY_HIDDEN;
+      f->flags &= ~WASM_SYMBOL_EXPORTED;
+      f->forceExport = false;
 
-    out.functionSec->addFunction(func);
+      out.functionSec->addFunction(func);
 
-    createCommandExportWrapper(f->getFunctionIndex(), def);
+      createCommandExportWrapper(f->getFunctionIndex(), def);
+    }
   }
 }
 
@@ -1136,6 +1140,8 @@ void Writer::createSyntheticInitFunctions() {
     return;
 
   static WasmSignature nullSignature = {{}, {}};
+  static WasmSignature memoryGrowSignature = {{ValType::I32}, {ValType::I32}};
+  static WasmSignature memorySizeSignature = {{ValType::I32}, {}};
 
   createApplyDataRelocationsFunction();
 
@@ -1156,6 +1162,25 @@ void Writer::createSyntheticInitFunctions() {
     }
   }
 
+  // Memory grow/size export hooks
+  auto memoryGrowFunc =
+      make<SyntheticFunction>(memoryGrowSignature, "__wasm_memory_grow");
+  memoryGrowFunc->setExportName("__wasm_memory_grow");
+  ctx.sym.memoryGrow = symtab->addSyntheticFunction(
+      "__wasm_memory_grow",
+      WASM_SYMBOL_VISIBILITY_DEFAULT | WASM_SYMBOL_EXPORTED, memoryGrowFunc);
+  ctx.sym.memoryGrow->markLive();
+  ctx.sym.memoryGrow->setExportNoWrap(true);
+
+  auto memorySizeFunc =
+      make<SyntheticFunction>(memorySizeSignature, "__wasm_memory_size");
+  memorySizeFunc->setExportName("__wasm_memory_size");
+  ctx.sym.memorySize = symtab->addSyntheticFunction(
+      "__wasm_memory_size",
+      WASM_SYMBOL_VISIBILITY_DEFAULT | WASM_SYMBOL_EXPORTED, memorySizeFunc);
+  ctx.sym.memorySize->markLive();
+  ctx.sym.memorySize->setExportNoWrap(true);
+
   if (ctx.arg.sharedMemory) {
     if (out.globalSec->needsTLSRelocations()) {
       ctx.sym.applyGlobalTLSRelocs = symtab->addSyntheticFunction(
@@ -1200,6 +1225,36 @@ void Writer::createSyntheticInitFunctions() {
   }
 }
 
+void Writer::createMemoryGrowFunction() {
+  LLVM_DEBUG(dbgs() << "createMemoryGrowFunction\n");
+  assert(ctx.sym.memoryGrow);
+  std::string bodyContent;
+  {
+    raw_string_ostream os(bodyContent);
+    writeUleb128(os, 0, "num locals");
+    writeU8(os, WASM_OPCODE_LOCAL_GET, "local.get");
+    writeUleb128(os, 0, "local 0");
+    writeU8(os, WASM_OPCODE_MEMORY_GROW, "memory grow");
+    writeUleb128(os, 0, "reserved memory byte");
+    writeU8(os, WASM_OPCODE_END, "END");
+  }
+  createFunction(ctx.sym.memoryGrow, bodyContent);
+}
+
+void Writer::createMemorySizeFunction() {
+  LLVM_DEBUG(dbgs() << "createMemorySizeFunction\n");
+  assert(ctx.sym.memorySize);
+  std::string bodyContent;
+  {
+    raw_string_ostream os(bodyContent);
+    writeUleb128(os, 0, "num locals");
+    writeU8(os, WASM_OPCODE_MEMORY_SIZE, "memory size");
+    writeUleb128(os, 0, "reserved memory byte");
+    writeU8(os, WASM_OPCODE_END, "END");
+  }
+  createFunction(ctx.sym.memorySize, bodyContent);
+}
+
 void Writer::createInitMemoryFunction() {
   LLVM_DEBUG(dbgs() << "createInitMemoryFunction\n");
   assert(ctx.sym.initMemory);
@@ -1788,6 +1843,12 @@ void Writer::run() {
     if (ctx.sym.initMemory) {
       createInitMemoryFunction();
     }
+    if (ctx.sym.memoryGrow) {
+      createMemoryGrowFunction();
+    }
+    if (ctx.sym.memorySize) {
+      createMemorySizeFunction();
+    }
     createStartFunction();
 
     createCallCtorsFunction();
diff --git a/llvm/include/llvm/BinaryFormat/Wasm.h 
b/llvm/include/llvm/BinaryFormat/Wasm.h
index cf90a43d0d7e8..e489026635934 100644
--- a/llvm/include/llvm/BinaryFormat/Wasm.h
+++ b/llvm/include/llvm/BinaryFormat/Wasm.h
@@ -135,6 +135,8 @@ enum : unsigned {
   WASM_OPCODE_BR_TABLE = 0x0e,
   WASM_OPCODE_RETURN = 0x0f,
   WASM_OPCODE_DROP = 0x1a,
+  WASM_OPCODE_MEMORY_SIZE = 0x3f,
+  WASM_OPCODE_MEMORY_GROW = 0x40,
   WASM_OPCODE_MISC_PREFIX = 0xfc,
   WASM_OPCODE_MEMORY_INIT = 0x08,
   WASM_OPCODE_MEMORY_FILL = 0x0b,
diff --git a/llvm/include/llvm/TargetParser/Triple.h 
b/llvm/include/llvm/TargetParser/Triple.h
index ede9797ac7488..447a94a48af67 100644
--- a/llvm/include/llvm/TargetParser/Triple.h
+++ b/llvm/include/llvm/TargetParser/Triple.h
@@ -199,6 +199,7 @@ class Triple {
     SUSE,
     OpenEmbedded,
     Intel,
+    WALI,
     Meta,
     LastVendorType = Meta
   };
@@ -795,6 +796,12 @@ class Triple {
     return getObjectFormat() == Triple::DXContainer;
   }
 
+  /// Tests whether the target uses WALI Wasm
+  bool isWALI() const {
+    return getArch() == Triple::wasm32 && getVendor() == Triple::WALI &&
+           getOS() == Triple::Linux;
+  }
+
   /// Tests whether the target is the PS4 platform.
   bool isPS4() const {
     return getArch() == Triple::x86_64 &&
diff --git a/llvm/lib/TargetParser/Triple.cpp b/llvm/lib/TargetParser/Triple.cpp
index 6acb0bc49ecfe..5fc0086fc8d76 100644
--- a/llvm/lib/TargetParser/Triple.cpp
+++ b/llvm/lib/TargetParser/Triple.cpp
@@ -277,6 +277,8 @@ StringRef Triple::getVendorTypeName(VendorType Kind) {
   case PC: return "pc";
   case SCEI: return "scei";
   case SUSE: return "suse";
+  case WALI:
+    return "wali";
   case Meta:
     return "meta";
   }
@@ -681,6 +683,7 @@ static Triple::VendorType parseVendor(StringRef VendorName) 
{
       .Case("suse", Triple::SUSE)
       .Case("oe", Triple::OpenEmbedded)
       .Case("intel", Triple::Intel)
+      .Case("wali", Triple::WALI)
       .Case("meta", Triple::Meta)
       .Default(Triple::UnknownVendor);
 }

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to